source: src/CodeGen/CodeGenerator.cpp@ 8655363

Last change on this file since 8655363 was c7ebbec, checked in by Andrew Beach <ajbeach@…>, 21 months ago

Reorganization of Linkage::Spec. is_mangled represented two properties with is_gcc_builtin separating them in one case. The second property is_overloadable which replaces is_gcc_builtin.

  • Property mode set to 100644
File size: 34.1 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// CodeGenerator.cpp --
8//
9// Author : Andrew Beach
10// Created On : Tue Oct 17 15:54:00 2023
11// Last Modified By : Andrew Beach
12// Last Modified On : Wed Oct 25 18:28:00 2023
13// Update Count : 0
14//
15
16#include "CodeGenerator.hpp"
17
18#include "AST/Print.hpp"
19#include "OperatorTable.h" // for OperatorInfo, operatorLookup
20#include "CodeGen/GenType.h" // for genType
21#include "Common/ToString.hpp" // for toString
22#include "Common/UniqueName.h" // for UniqueName
23
24namespace CodeGen {
25
26int CodeGenerator::tabsize = 4;
27
28// The kinds of statements that should be followed by whitespace.
29static bool wantSpacing( ast::Stmt const * stmt ) {
30 return dynamic_cast<ast::IfStmt const *>( stmt )
31 || dynamic_cast<ast::CompoundStmt const *>( stmt )
32 || dynamic_cast<ast::WhileDoStmt const *>( stmt )
33 || dynamic_cast<ast::ForStmt const *>( stmt )
34 || dynamic_cast<ast::SwitchStmt const *>( stmt );
35}
36
37void CodeGenerator::extension( ast::Expr const * expr ) {
38 if ( expr->extension ) output << "__extension__ ";
39}
40
41void CodeGenerator::extension( ast::Decl const * decl ) {
42 if ( decl->extension ) output << "__extension__ ";
43}
44
45void CodeGenerator::asmName( ast::DeclWithType const * decl ) {
46 if ( auto asmName = decl->asmName.as<ast::ConstantExpr>() ) {
47 output << " asm ( " << asmName->rep << " )";
48 }
49}
50
51CodeGenerator::LabelPrinter & CodeGenerator::LabelPrinter::operator()(
52 std::vector<ast::Label> const & l ) {
53 labels = &l;
54 return *this;
55}
56
57std::ostream & CodeGenerator::LabelPrinter::operator()( std::ostream & output ) const {
58 const std::vector<ast::Label> & labels = *this->labels;
59 for ( const ast::Label & label : labels ) {
60 output << label.name + ": ";
61 this->cg.genAttributes( label.attributes );
62 }
63 return output;
64}
65
66// Using updateLocation at the beginning of a node and endl within a node
67// should become the method of formating.
68void CodeGenerator::updateLocation( CodeLocation const & to ) {
69 // Skip if linemarks shouldn't appear or if location is unset.
70 if ( !options.lineMarks || to.isUnset() ) return;
71
72 if ( currentLocation.followedBy( to, 0 ) ) {
73 return;
74 } else if ( currentLocation.followedBy( to, 1 ) ) {
75 output << "\n" << indent;
76 currentLocation.first_line += 1;
77 } else if ( currentLocation.followedBy( to, 2 ) ) {
78 output << "\n\n" << indent;
79 currentLocation.first_line += 2;
80 } else {
81 output << "\n# " << to.first_line << " \"" << to.filename
82 << "\"\n" << indent;
83 currentLocation = to;
84 }
85 output << std::flush;
86}
87
88void CodeGenerator::updateLocation( ast::ParseNode const * to ) {
89 updateLocation( to->location );
90}
91
92std::ostream & CodeGenerator::LineEnder::operator()( std::ostream & os ) const {
93 os << "\n" << std::flush;
94 cg.currentLocation.first_line++;
95 return os;
96}
97
98CodeGenerator::CodeGenerator( std::ostream & os, const Options & options ) :
99 indent( 0, CodeGenerator::tabsize ), output( os ),
100 options( options ), printLabels( *this ), endl( *this )
101{}
102
103std::string CodeGenerator::mangleName( ast::DeclWithType const * decl ) {
104 if ( !options.pretty && decl->linkage.is_mangled && decl->mangleName != "" ) {
105 return decl->scopedMangleName();
106 } else {
107 return decl->name;
108 }
109}
110
111void CodeGenerator::genAttributes(
112 const std::vector<ast::ptr<ast::Attribute>> & attributes ) {
113 if ( attributes.empty() ) return;
114 output << "__attribute__ ((";
115 for ( auto attr = attributes.begin() ;; ) {
116 output << (*attr)->name;
117 if ( !(*attr)->params.empty() ) {
118 output << "(";
119 genCommaList( (*attr)->params );
120 output << ")";
121 }
122 if ( ++attr == attributes.end() ) break;
123 output << ",";
124 }
125 output << ")) ";
126}
127
128void CodeGenerator::previsit( ast::Node const * ) {
129 // All traversal is manual.
130 // TODO: Which means the ast::Pass is just providing a default no visit?
131 visit_children = false;
132}
133
134void CodeGenerator::previsit( ast::ParseNode const * node ) {
135 previsit( (ast::Node const *)node );
136 updateLocation( node );
137}
138
139void CodeGenerator::postvisit( ast::Node const * node ) {
140 std::stringstream ss;
141 ast::print( ss, node );
142 assertf( false, "Unhandled node reached in CodeGenerator: %s", ss.str().c_str() );
143}
144
145void CodeGenerator::previsit( ast::Expr const * expr ) {
146 previsit( (ast::ParseNode const *)expr );
147 GuardAction( [this, expr](){
148 if ( options.printExprTypes && expr->result ) {
149 output << " /* " << genType( expr->result, "", options ) << " */ ";
150 }
151 } );
152}
153
154void CodeGenerator::postvisit( ast::FunctionDecl const * decl ) {
155 // Deleted decls should never be used, so don't print them in C.
156 if ( decl->isDeleted && options.genC ) return;
157 extension( decl );
158 genAttributes( decl->attributes );
159
160 handleStorageClass( decl );
161 ast::print( output, decl->funcSpec );
162
163 Options subOptions = options;
164 subOptions.anonymousUnused = decl->stmts;
165
166 std::ostringstream acc;
167 ast::Pass<CodeGenerator> subCG( acc, subOptions );
168 // Add the forall clause.
169 // TODO: These probably should be removed by now and the assert used.
170 if ( !decl->type_params.empty() ) {
171 assertf( !options.genC, "FunctionDecl forall should not reach code generation." );
172 acc << "forall(";
173 subCG.core.genCommaList( decl->type_params );
174 acc << ")" << std::endl;
175 }
176
177 acc << mangleName( decl );
178
179 if ( 0 == decl->params.size() ) {
180 if ( decl->type->isVarArgs ) {
181 acc << "()";
182 } else {
183 acc << "(void)";
184 }
185 } else {
186 acc << "(";
187 subCG.core.genCommaList( decl->params );
188 if ( decl->type->isVarArgs ) {
189 acc << ", ...";
190 }
191 acc << ")";
192 }
193
194 assert( decl->returns.size() < 2 );
195 if ( 1 == decl->returns.size() ) {
196 ast::ptr<ast::Type> const & type = decl->returns[0]->get_type();
197 output << genTypeNoAttr( type, acc.str(), subOptions );
198 } else {
199 output << "void " + acc.str();
200 }
201
202 asmName( decl );
203
204 if ( decl->stmts ) {
205 decl->stmts->accept( *visitor );
206 }
207 if ( decl->isDeleted ) {
208 output << " = void";
209 }
210}
211
212ast::ObjectDecl const * CodeGenerator::postvisit(
213 ast::ObjectDecl const * decl ) {
214 // Deleted decls should never be used, so don't print them in C.
215 if ( decl->isDeleted && options.genC ) return decl;
216
217 // GCC allows an empty declarator (no name) for bit-fields and C
218 // states: 6.7.2.1 Structure and union specifiers, point 4, page 113:
219 // If the (bit field) value is zero, the declaration shall have no
220 // declarator. For anything else, the anonymous name refers to the
221 // anonymous object for plan9 inheritance.
222 if ( decl->name.empty() && options.genC && !decl->bitfieldWidth ) {
223 // TODO: Should this be changed in a pervious pass?
224 auto mutDecl = ast::mutate( decl );
225 // Only generate an anonymous name when generating C code,
226 // otherwise it clutters the output too much.
227 static UniqueName name = { "__anonymous_object" };
228 mutDecl->name = name.newName();
229 // Stops unused parameter warnings.
230 if ( options.anonymousUnused ) {
231 mutDecl->attributes.push_back( new ast::Attribute( "unused" ) );
232 }
233 decl = mutDecl;
234 }
235
236 extension( decl );
237 genAttributes( decl->attributes );
238
239 handleStorageClass( decl );
240 output << genType( decl->type, mangleName( decl ),
241 Options( options.pretty, options.genC, false, false ) );
242
243 asmName( decl );
244
245 if ( decl->init ) {
246 output << " = ";
247 decl->init->accept( *visitor );
248 }
249 if ( decl->isDeleted ) {
250 output << " = void";
251 }
252
253 if ( decl->bitfieldWidth ) {
254 output << ":";
255 decl->bitfieldWidth->accept( *visitor );
256 }
257 return decl;
258}
259
260void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) {
261 if ( decl->storage.any() ) {
262 ast::print( output, decl->storage );
263 }
264}
265
266void CodeGenerator::handleAggregate(
267 ast::AggregateDecl const * decl, std::string const & kind ) {
268 if ( !decl->params.empty() && !options.genC ) {
269 output << "forall(";
270 genCommaList( decl->params );
271 output << ")\n" << indent << std::flush;
272 }
273
274 output << kind;
275 genAttributes( decl->attributes );
276 output << decl->name;
277
278 if ( decl->body ) {
279 auto & members = decl->members;
280 output << " {" << endl;
281
282 ++indent;
283 for ( auto & member : members ) {
284 output << indent;
285 member->accept( *visitor );
286 output << ";" << endl;
287 }
288 --indent;
289
290 output << indent << "}";
291 }
292}
293
294void CodeGenerator::postvisit( ast::StructDecl const * decl ) {
295 extension( decl );
296 handleAggregate( decl, "struct " );
297}
298
299void CodeGenerator::postvisit( ast::UnionDecl const * decl ) {
300 extension( decl );
301 handleAggregate( decl, "union " );
302}
303
304template<typename pass_type>
305inline void genEnumInitializer( ast::Pass<pass_type> * visitor,
306 ast::Type const * baseType, std::ostream & output,
307 ast::Init const * init, long long * curVal, Options options ) {
308 auto baseTypeAsBasic = dynamic_cast<ast::BasicType const *>( baseType );
309 // Value is provided.
310 if ( init ) {
311 output << " = (" << genType( baseType, "", options ) << ")";
312 init->accept( *visitor );
313 // If it is an integral type and initilizer offered,
314 // need to update the curVal.
315 if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
316 ast::Expr const * expr = ((ast::SingleInit const *)(init))->value;
317 // Unwrap introduced cast.
318 while ( auto temp = dynamic_cast<ast::CastExpr const *>( expr ) ) {
319 expr = temp->arg;
320 }
321 *curVal = ((ast::ConstantExpr const *)(expr))->intValue() + 1;
322 }
323 // Generate next value from previous value.
324 } else if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
325 output << " = (" << genType( baseType, "", options ) << ")";
326 output << (*curVal)++;
327 }
328}
329
330void CodeGenerator::postvisit( ast::EnumDecl const * decl ) {
331 extension( decl );
332 auto members = decl->members;
333 if ( decl->base && !members.empty() ) {
334 long long curVal = 0;
335 for ( auto member : members ) {
336 auto obj = member.strict_as<ast::ObjectDecl>();
337 output << "static ";
338 output << genType( decl->base, mangleName( obj ), options );
339 genEnumInitializer( visitor, decl->base, output, obj->init, &curVal, options );
340 output << ";" << endl;
341 }
342 } else {
343 output << "enum ";
344 genAttributes( decl->attributes );
345
346 output << decl->name;
347
348 if ( !members.empty() ) {
349 output << " {" << endl;
350
351 ++indent;
352 for ( auto member : members ) {
353 auto obj = member.strict_as<ast::ObjectDecl>();
354 output << indent << mangleName( obj );
355 if ( obj->init ) {
356 output << " = ";
357 obj->init->accept( *visitor );
358 }
359 output << "," << endl;
360 }
361 --indent;
362
363 output << indent << "}";
364 }
365 }
366}
367
368void CodeGenerator::postvisit( ast::TraitDecl const * decl ) {
369 assertf( !options.genC, "TraitDecls should not reach code generation." );
370 extension( decl );
371 handleAggregate( decl, "trait " );
372}
373
374void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) {
375 assertf( !options.genC, "Typedefs should not reach code generation." );
376 output << "typedef " << genType( decl->base, decl->name, options ) << endl;
377}
378
379void CodeGenerator::postvisit( ast::TypeDecl const * decl ) {
380 assertf( !options.genC, "TypeDecls should not reach code generation." );
381 output << decl->genTypeString() << " " << decl->name;
382 if ( decl->sized ) {
383 output << " | sized(" << decl->name << ")";
384 }
385 if ( !decl->assertions.empty() ) {
386 output << " | { ";
387 for ( ast::DeclWithType const * assert : decl->assertions ) {
388 assert->accept( *visitor );
389 output << "; ";
390 }
391 output << " }";
392 }
393}
394
395void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) {
396 output << "_Static_assert(";
397 decl->cond->accept( *visitor );
398 output << ", ";
399 decl->msg->accept( *visitor );
400 output << ")";
401}
402
403void CodeGenerator::postvisit( ast::Designation const * designation ) {
404 auto designators = designation->designators;
405 if ( 0 == designators.size() ) return;
406 for ( ast::ptr<ast::Expr> const & des : designators ) {
407 // If the expression is a NameExpr or VariableExpr, then it is a field.
408 if ( des.as<ast::NameExpr>() || des.as<ast::VariableExpr>() ) {
409 output << ".";
410 des->accept( *visitor );
411 // Otherwise, it is a ConstantExpr or CastExpr, then it is an index.
412 } else {
413 output << "[";
414 des->accept( *visitor );
415 output << "]";
416 }
417 }
418 output << " = ";
419}
420
421void CodeGenerator::postvisit( ast::SingleInit const * init ) {
422 init->value->accept( *visitor );
423}
424
425void CodeGenerator::postvisit( ast::ListInit const * init ) {
426 auto initBegin = init->initializers.begin();
427 auto initEnd = init->initializers.end();
428 auto desigBegin = init->designations.begin();
429 auto desigEnd = init->designations.end();
430
431 output << "{ ";
432 if ( initBegin != initEnd ) while (true) {
433 (*desigBegin)->accept( *visitor );
434 (*initBegin)->accept( *visitor );
435 ++initBegin, ++desigBegin;
436 if ( initBegin == initEnd ) break;
437 output << ", ";
438 }
439 output << " }";
440 assertf( initBegin == initEnd && desigBegin == desigEnd,
441 "Initializers and designators not the same length. %s", toCString( init ) );
442}
443
444void CodeGenerator::postvisit( ast::ConstructorInit const * init ) {
445 assertf( !options.genC, "ConstructorInit nodes should not reach code generation." );
446 // This isn't actual code, but labels the constructor/destructor pairs.
447 output << "<ctorinit>{" << endl << ++indent << "ctor: ";
448 if ( init->ctor ) init->ctor->accept( *visitor );
449 output << ", " << endl << indent << "dtor: ";
450 if ( init->dtor ) init->dtor->accept( *visitor );
451 output << endl << --indent << "}";
452}
453
454void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) {
455 extension( expr );
456 if ( auto var = expr->func.as<ast::VariableExpr>() ) {
457 const OperatorInfo * opInfo;
458 if ( var->var->linkage == ast::Linkage::Intrinsic &&
459 ( opInfo = operatorLookup( var->var->name ) ) ) {
460 auto arg = expr->args.begin();
461 switch ( opInfo->type ) {
462 case OT_INDEX:
463 assert( 2 == expr->args.size() );
464 (*arg++)->accept( *visitor );
465 output << "[";
466 (*arg)->accept( *visitor );
467 output << "]";
468 break;
469
470 // There are no intrinsic definitions of the function call operator.
471 case OT_CALL:
472 assert( false );
473 break;
474
475 case OT_CTOR:
476 case OT_DTOR:
477 // No-op constructor, but run the internal expression.
478 if ( 1 == expr->args.size() ) {
479 output << "(";
480 (*arg++)->accept( *visitor );
481 output << ") /* " << opInfo->inputName << " */";
482 // These are all implemented as some form of assignment.
483 } else if ( 2 == expr->args.size() ) {
484 output << "(";
485 (*arg++)->accept( *visitor );
486 output << opInfo->symbol;
487 (*arg)->accept( *visitor );
488 output << ") /* " << opInfo->inputName << " */";
489 // No constructors with 0 or more than 2 parameters.
490 } else {
491 assert( false );
492 }
493 break;
494
495 case OT_PREFIX:
496 case OT_PREFIXASSIGN:
497 assert( 1 == expr->args.size() );
498 output << "(" << opInfo->symbol;
499 (*arg)->accept( *visitor );
500 output << ")";
501 break;
502
503 case OT_POSTFIX:
504 case OT_POSTFIXASSIGN:
505 assert( 1 == expr->args.size() );
506 (*arg)->accept( *visitor );
507 output << opInfo->symbol;
508 break;
509
510 case OT_INFIX:
511 case OT_INFIXASSIGN:
512 assert( 2 == expr->args.size() );
513 output << "(";
514 (*arg++)->accept( *visitor );
515 output << opInfo->symbol;
516 (*arg)->accept( *visitor );
517 output << ")";
518 break;
519
520 // There are no intrinsic definitions of 0/1 or label address
521 // as function.
522 case OT_CONSTANT:
523 case OT_LABELADDRESS:
524 assert( false );
525 }
526 // TODO: This is a work-around to make it a constant until a proper
527 // constexpr solution is created.
528 } else if ( var->var->linkage == ast::Linkage::BuiltinCFA &&
529 var->var->name == "intptr" ) {
530 output << "((void*)";
531 auto arg = expr->args.begin();
532 (*arg++)->accept( *visitor );
533 output << ")";
534 } else {
535 var->accept( *visitor );
536 output << "(";
537 genCommaList( expr->args );
538 output << ")";
539 }
540 } else {
541 expr->func->accept( *visitor );
542 output << "(";
543 genCommaList( expr->args );
544 output << ")";
545 }
546}
547
548void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) {
549 extension( expr );
550 if ( auto name = expr->func.as<ast::NameExpr>() ) {
551 if ( const OperatorInfo * opInfo = operatorLookup( name->name ) ) {
552 auto arg = expr->args.begin();
553 switch ( opInfo->type ) {
554 case OT_INDEX:
555 assert( 2 == expr->args.size() );
556 (*arg++)->accept( *visitor );
557 output << "[";
558 (*arg)->accept( *visitor );
559 output << "]";
560 break;
561
562 case OT_CALL:
563 assert( false );
564
565 case OT_CTOR:
566 case OT_DTOR:
567 // No-op constructor, but run the internal expression.
568 if ( 1 == expr->args.size() ) {
569 output << "(";
570 (*arg++)->accept( *visitor );
571 output << ")";
572 // These are all implemented as some form of assignment.
573 } else if ( 2 == expr->args.size() ) {
574 output << "(";
575 (*arg++)->accept( *visitor );
576 output << opInfo->symbol;
577 (*arg)->accept( *visitor );
578 output << ") /* " << opInfo->inputName << " */";
579 // No constructors with 0 or more than 2 parameters.
580 } else {
581 assertf( !options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
582 output << "(";
583 (*arg++)->accept( *visitor );
584 output << opInfo->symbol << "{ ";
585 genCommaList( arg, expr->args.end() );
586 output << "}) /* " << opInfo->inputName << " */";
587 }
588 break;
589
590 case OT_PREFIX:
591 case OT_PREFIXASSIGN:
592 case OT_LABELADDRESS:
593 assert( 1 == expr->args.size() );
594 output << "(" << opInfo->symbol;
595 (*arg)->accept( *visitor );
596 output << ")";
597 break;
598
599 case OT_POSTFIX:
600 case OT_POSTFIXASSIGN:
601 assert( 1 == expr->args.size() );
602 (*arg)->accept( *visitor );
603 output << opInfo->symbol;
604 break;
605
606 case OT_INFIX:
607 case OT_INFIXASSIGN:
608 assert( 2 == expr->args.size() );
609 output << "(";
610 (*arg++)->accept( *visitor );
611 output << opInfo->symbol;
612 (*arg)->accept( *visitor );
613 output << ")";
614 break;
615
616 // There are no intrinsic definitions of 0/1 or label address
617 // as function.
618 case OT_CONSTANT:
619 assert( false );
620 }
621 // builtin routines
622 } else {
623 name->accept( *visitor );
624 output << "(";
625 genCommaList( expr->args );
626 output << ")";
627 }
628 } else {
629 expr->func->accept( *visitor );
630 output << "(";
631 genCommaList( expr->args );
632 output << ")";
633 }
634}
635
636void CodeGenerator::postvisit( ast::RangeExpr const * expr ) {
637 expr->low->accept( *visitor );
638 output << " ... ";
639 expr->high->accept( *visitor );
640}
641
642void CodeGenerator::postvisit( ast::NameExpr const * expr ) {
643 extension( expr );
644 if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) {
645 if ( OT_CONSTANT == opInfo->type ) {
646 output << opInfo->symbol;
647 } else {
648 output << opInfo->outputName;
649 }
650 } else {
651 output << expr->name;
652 }
653}
654
655void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) {
656 extension( expr );
657 output << "/*non-type*/" << expr->name;
658}
659
660void CodeGenerator::postvisit( ast::AddressExpr const * expr ) {
661 extension( expr );
662 output << "(&";
663 expr->arg->accept( *visitor );
664 output << ")";
665}
666
667void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) {
668 extension( expr );
669 output << "(&&" << expr->arg << ")";
670}
671
672void CodeGenerator::postvisit( ast::CastExpr const * expr ) {
673 extension( expr );
674 output << "(";
675 if ( expr->result->isVoid() ) {
676 output << "(void)";
677 } else {
678 output << "(";
679 output << genType( expr->result, "", options );
680 output << ")";
681 }
682 expr->arg->accept( *visitor );
683 output << ")";
684}
685
686void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) {
687 assertf( !options.genC, "KeywordCastExpr should not reach code generation." );
688 extension( expr );
689 output << "((" << expr->targetString() << " &)";
690 expr->arg->accept( *visitor );
691 output << ")";
692}
693
694void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) {
695 assertf( !options.genC, "VirtualCastExpr should not reach code generation." );
696 extension( expr );
697 // TODO: Is this busted?
698 output << "(virtual ";
699 expr->arg->accept( *visitor );
700 output << ")";
701}
702
703void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) {
704 assertf( !options.genC, "UntypedMemberExpr should not reach code generation." );
705 extension( expr );
706 expr->aggregate->accept( *visitor );
707 output << ".";
708 expr->member->accept( *visitor );
709}
710
711void CodeGenerator::postvisit( ast::MemberExpr const * expr ) {
712 extension( expr );
713 expr->aggregate->accept( *visitor );
714 output << "." << mangleName( expr->member );
715}
716
717void CodeGenerator::postvisit( ast::VariableExpr const * expr ) {
718 extension( expr );
719 const OperatorInfo * opInfo;
720 if ( dynamic_cast<ast::ZeroType const *>( expr->var->get_type() ) ) {
721 output << "0";
722 } else if ( expr->var->linkage == ast::Linkage::Intrinsic
723 && ( opInfo = operatorLookup( expr->var->name ) )
724 && opInfo->type == OT_CONSTANT ) {
725 output << opInfo->symbol;
726 } else {
727 output << mangleName( expr->var );
728 }
729}
730
731void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) {
732 extension( expr );
733 output << expr->rep;
734}
735
736void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) {
737 extension( expr );
738 output << "sizeof(";
739 if ( expr->type ) {
740 output << genType( expr->type, "", options );
741 } else {
742 expr->expr->accept( *visitor );
743 }
744 output << ")";
745}
746
747void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) {
748 // Using the GCC extension to avoid changing the std to C11.
749 extension( expr );
750 output << "__alignof__(";
751 if ( expr->type ) {
752 output << genType( expr->type, "", options );
753 } else {
754 expr->expr->accept( *visitor );
755 }
756 output << ")";
757}
758
759void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) {
760 assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." );
761 output << "offsetof(";
762 output << genType( expr->type, "", options );
763 output << ", " << expr->member;
764 output << ")";
765}
766
767void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) {
768 // Use GCC builtin
769 output << "__builtin_offsetof(";
770 output << genType( expr->type, "", options );
771 output << ", " << mangleName( expr->member );
772 output << ")";
773}
774
775void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) {
776 assertf( !options.genC, "OffsetPackExpr should not reach code generation." );
777 output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")";
778}
779
780void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) {
781 extension( expr );
782 output << "(";
783 expr->arg1->accept( *visitor );
784 output << ( ( expr->isAnd ) ? " && " : " || " );
785 expr->arg2->accept( *visitor );
786 output << ")";
787}
788
789void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) {
790 extension( expr );
791 output << "(";
792 expr->arg1->accept( *visitor );
793 output << " ? ";
794 expr->arg2->accept( *visitor );
795 output << " : ";
796 expr->arg3->accept( *visitor );
797 output << ")";
798}
799
800void CodeGenerator::postvisit( ast::CommaExpr const * expr ) {
801 extension( expr );
802 output << "(";
803 if ( options.genC ) {
804 // arg1 of a comma expression is never used, so it can be safely cast
805 // to void to reduce gcc warnings.
806 ast::ptr<ast::Expr> arg1 = new ast::CastExpr( expr->location, expr->arg1 );
807 arg1->accept( *visitor );
808 } else {
809 expr->arg1->accept( *visitor );
810 }
811 output << " , ";
812 expr->arg2->accept( *visitor );
813 output << ")";
814}
815
816void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) {
817 assertf( !options.genC, "TupleAssignExpr should not reach code generation." );
818 expr->stmtExpr->accept( *visitor );
819}
820
821void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) {
822 assertf( !options.genC, "UntypedTupleExpr should not reach code generation." );
823 extension( expr );
824 output << "[";
825 genCommaList( expr->exprs );
826 output << "]";
827}
828
829void CodeGenerator::postvisit( ast::TupleExpr const * expr ) {
830 assertf( !options.genC, "TupleExpr should not reach code generation." );
831 extension( expr );
832 output << "[";
833 genCommaList( expr->exprs );
834 output << "]";
835}
836
837void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) {
838 assertf( !options.genC, "TupleIndexExpr should not reach code generation." );
839 extension( expr );
840 expr->tuple->accept( *visitor );
841 output << "." << expr->index;
842}
843
844void CodeGenerator::postvisit( ast::TypeExpr const * expr ) {
845 // TODO: Should there be an assertion there?
846 if ( !options.genC ) {
847 output << genType( expr->type, "", options );
848 }
849}
850
851void CodeGenerator::postvisit( ast::AsmExpr const * expr ) {
852 if ( !expr->inout.empty() ) {
853 output << "[ " << expr->inout << " ] ";
854 }
855 expr->constraint->accept( *visitor );
856 output << " ( ";
857 expr->operand->accept( *visitor );
858 output << " )";
859}
860
861void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) {
862 //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) );
863 assert( expr->result && expr->init.as<ast::ListInit>() );
864 output << "(" << genType( expr->result, "", options ) << ")";
865 expr->init->accept( *visitor );
866}
867
868void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) {
869 assertf( !options.genC, "UniqueExpr should not reach code generation." );
870 output << "unq<" << expr->id << ">{ ";
871 expr->expr->accept( *visitor );
872 output << " }";
873}
874
875void CodeGenerator::postvisit( ast::StmtExpr const * expr ) {
876 auto stmts = expr->stmts->kids;
877 output << "({" << endl;
878 ++indent;
879 unsigned int numStmts = stmts.size();
880 unsigned int i = 0;
881 for ( ast::ptr<ast::Stmt> const & stmt : stmts ) {
882 output << indent << printLabels( stmt->labels );
883 if ( i + 1 == numStmts ) {
884 // Last statement in a statement expression needs to be handled
885 // specially - cannot cast to void, otherwise the expression
886 // statement has no value.
887 if ( ast::ExprStmt const * exprStmt = stmt.as<ast::ExprStmt>() ) {
888 exprStmt->expr->accept( *visitor );
889 output << ";" << endl;
890 ++i;
891 break;
892 }
893 }
894 stmt->accept( *visitor );
895 output << endl;
896 if ( wantSpacing( stmt ) ) output << endl;
897 ++i;
898 }
899 --indent;
900 output << indent << "})";
901}
902
903void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) {
904 assertf( !options.genC, "ConstructorExpr should not reach code generation." );
905 expr->callExpr->accept( *visitor );
906}
907
908void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) {
909 assertf( !options.genC, "DeletedExpr should not reach code generation." );
910 expr->expr->accept( *visitor );
911}
912
913void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) {
914 assertf( !options.genC, "DefaultArgExpr should not reach code generation." );
915 expr->expr->accept( *visitor );
916}
917
918void CodeGenerator::postvisit( ast::GenericExpr const * expr ) {
919 assertf( !options.genC, "GenericExpr should not reach code generation." );
920 output << "_Generic(";
921 expr->control->accept( *visitor );
922 output << ", ";
923 unsigned int numAssocs = expr->associations.size();
924 unsigned int i = 0;
925 for ( const ast::GenericExpr::Association & assoc : expr->associations ) {
926 if ( nullptr == assoc.type ) {
927 output << "default: ";
928 } else {
929 output << genType( assoc.type, "", options ) << ": ";
930 }
931 assoc.expr->accept( *visitor );
932 ++i;
933 if ( i != numAssocs ) output << ", ";
934 }
935 output << ")";
936}
937
938void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) {
939 output << "{" << endl;
940
941 ++indent;
942 for ( auto kid : stmt->kids ) {
943 output << indent << printLabels( kid->labels );
944 kid->accept( *visitor );
945 output << endl;
946 if ( wantSpacing( kid ) ) output << endl;
947 }
948 --indent;
949
950 output << indent << "}";
951}
952
953void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) {
954 assert( stmt );
955 // Cast the top-level expression to void to reduce gcc warnings.
956 if ( options.genC ) {
957 ast::ptr<ast::Expr> expr = new ast::CastExpr( stmt->location, stmt->expr );
958 expr->accept( *visitor );
959 } else {
960 stmt->expr->accept( *visitor );
961 }
962 output << ";";
963}
964
965void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) {
966 output << "asm ";
967 if ( stmt->isVolatile ) output << "volatile ";
968 if ( !stmt->gotoLabels.empty() ) output << "goto ";
969 output << "( ";
970 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
971 output << " : ";
972 genCommaList( stmt->output );
973 output << " : ";
974 genCommaList( stmt->input );
975 output << " : ";
976 genCommaList( stmt->clobber );
977 if ( !stmt->gotoLabels.empty() ) {
978 output << " : ";
979 auto it = stmt->gotoLabels.begin();
980 while (true) {
981 output << *it++;
982 if ( stmt->gotoLabels.end() == it ) break;
983 output << ", ";
984 }
985 }
986 output << " );";
987}
988
989void CodeGenerator::postvisit( ast::AsmDecl const * decl ) {
990 output << "asm ";
991 ast::AsmStmt const * stmt = decl->stmt;
992 output << "( ";
993 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
994 output << " )";
995}
996
997void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) {
998 // endl prevents spaces before the directive.
999 output << endl << decl->stmt->directive;
1000}
1001
1002void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) {
1003 // endl prevents spaces before the directive.
1004 output << endl << stmt->directive;
1005}
1006
1007void CodeGenerator::postvisit( ast::IfStmt const * stmt ) {
1008 output << "if ( ";
1009 stmt->cond->accept( *visitor );
1010 output << " ) ";
1011
1012 stmt->then->accept( *visitor );
1013
1014 if ( nullptr != stmt->else_ ) {
1015 output << " else ";
1016 stmt->else_->accept( *visitor );
1017 }
1018}
1019
1020void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) {
1021 output << "switch ( ";
1022 stmt->cond->accept( *visitor );
1023 output << " ) ";
1024
1025 output << "{" << endl;
1026 ++indent;
1027 for ( auto node : stmt->cases ) {
1028 node->accept( *visitor );
1029 }
1030 --indent;
1031 output << indent << "}";
1032}
1033
1034void CodeGenerator::postvisit( ast::CaseClause const * clause ) {
1035 updateLocation( clause );
1036 output << indent;
1037 if ( clause->isDefault() ) {
1038 output << "default";
1039 } else {
1040 output << "case ";
1041 clause->cond->accept( *visitor );
1042 }
1043 output << ":" << endl;
1044
1045 ++indent;
1046 for ( auto stmt : clause->stmts ) {
1047 output << indent << printLabels( stmt->labels ) ;
1048 stmt->accept( *visitor );
1049 output << endl;
1050 }
1051 --indent;
1052}
1053
1054void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) {
1055 switch ( stmt->kind ) {
1056 case ast::BranchStmt::Goto:
1057 if ( !stmt->target.empty() ) {
1058 output << "goto " << stmt->target;
1059 } else if ( nullptr != stmt->computedTarget ) {
1060 output << "goto *";
1061 stmt->computedTarget->accept( *visitor );
1062 }
1063 break;
1064 case ast::BranchStmt::Break:
1065 output << "break";
1066 break;
1067 case ast::BranchStmt::Continue:
1068 output << "continue";
1069 break;
1070 case ast::BranchStmt::FallThrough:
1071 case ast::BranchStmt::FallThroughDefault:
1072 assertf( !options.genC, "fallthru should not reach code generation." );
1073 output << "fallthru";
1074 break;
1075 default:
1076 assertf( false, "Bad BranchStmt value." );
1077 }
1078 // Print branch target for labelled break/continue/fallthru in debug mode.
1079 if ( !options.genC && stmt->kind != ast::BranchStmt::Goto ) {
1080 if ( !stmt->target.empty() ) {
1081 output << " " << stmt->target;
1082 } else if ( stmt->kind == ast::BranchStmt::FallThrough ) {
1083 output << " default";
1084 }
1085 }
1086 output << ";";
1087}
1088
1089void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) {
1090 output << "return ";
1091 if ( stmt->expr ) stmt->expr->accept( *visitor );
1092 output << ";";
1093}
1094
1095void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) {
1096 assertf( !options.genC, "ThrowStmt should not reach code generation." );
1097
1098 output << ((stmt->kind == ast::Terminate) ? "throw" : "throwResume");
1099 if ( stmt->expr ) {
1100 output << " ";
1101 stmt->expr->accept( *visitor );
1102 }
1103 if ( stmt->target ) {
1104 output << " _At ";
1105 stmt->target->accept( *visitor );
1106 }
1107 output << ";";
1108}
1109
1110void CodeGenerator::postvisit( ast::CatchClause const * stmt ) {
1111 assertf( !options.genC, "CatchClause should not reach code generation." );
1112
1113 output << ((stmt->kind == ast::Terminate) ? "catch" : "catchResume");
1114 output << "( ";
1115 stmt->decl->accept( *visitor );
1116 if ( stmt->cond ) {
1117 output << " ; ";
1118 stmt->cond->accept( *visitor );
1119 }
1120 output << " ) ";
1121 stmt->body->accept( *visitor );
1122}
1123
1124void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) {
1125 assertf( !options.genC, "WaitforStmt should not reach code generation." );
1126
1127 bool first = true;
1128 for ( ast::ptr<ast::WaitForClause> const & clause : stmt->clauses ) {
1129 if (first) { output << "or "; first = false; }
1130 if ( clause->when_cond ) {
1131 output << "when(";
1132 stmt->timeout_cond->accept( *visitor );
1133 output << ") ";
1134 }
1135 output << "waitfor(";
1136 clause->target->accept( *visitor );
1137 for ( ast::ptr<ast::Expr> const & expr : clause->target_args ) {
1138 output << ",";
1139 expr->accept( *visitor );
1140 }
1141 output << ") ";
1142 clause->stmt->accept( *visitor );
1143 }
1144
1145 if ( stmt->timeout_stmt ) {
1146 output << "or ";
1147 if ( stmt->timeout_cond ) {
1148 output << "when(";
1149 stmt->timeout_cond->accept( *visitor );
1150 output << ") ";
1151 }
1152 output << "timeout(";
1153 stmt->timeout_time->accept( *visitor );
1154 output << ") ";
1155 stmt->timeout_stmt->accept( *visitor );
1156 }
1157
1158 if ( stmt->else_stmt ) {
1159 output << "or ";
1160 if ( stmt->else_cond ) {
1161 output << "when(";
1162 stmt->else_cond->accept( *visitor );
1163 output << ")";
1164 }
1165 output << "else ";
1166 stmt->else_stmt->accept( *visitor );
1167 }
1168}
1169
1170void CodeGenerator::postvisit( ast::WithStmt const * stmt ) {
1171 assertf( !options.genC, "WithStmt should not reach code generation." );
1172
1173 output << "with ( ";
1174 genCommaList( stmt->exprs );
1175 output << " ) ";
1176 stmt->stmt->accept( *visitor );
1177}
1178
1179void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) {
1180 if ( stmt->isDoWhile ) {
1181 output << "do";
1182 } else {
1183 output << "while (";
1184 stmt->cond->accept( *visitor );
1185 output << ")";
1186 }
1187 output << " ";
1188
1189 output << CodeGenerator::printLabels( stmt->body->labels );
1190 stmt->body->accept( *visitor );
1191
1192 output << indent;
1193
1194 if ( stmt->isDoWhile ) {
1195 output << " while (";
1196 stmt->cond->accept( *visitor );
1197 output << ");";
1198 }
1199}
1200
1201void CodeGenerator::postvisit( ast::ForStmt const * stmt ) {
1202 // Initializer is always hoised so don't generate it.
1203 // TODO: Do an assertion check?
1204 output << "for (;";
1205
1206 if ( nullptr != stmt->cond ) {
1207 stmt->cond->accept( *visitor );
1208 }
1209 output << ";";
1210
1211 if ( nullptr != stmt->inc ) {
1212 // cast the top-level expression to void to reduce gcc warnings.
1213 ast::Expr * expr = new ast::CastExpr( stmt->inc );
1214 expr->accept( *visitor );
1215 }
1216 output << ") ";
1217
1218 if ( nullptr != stmt->body ) {
1219 output << printLabels( stmt->body->labels );
1220 stmt->body->accept( *visitor );
1221 }
1222}
1223
1224void CodeGenerator::postvisit( ast::NullStmt const * ) {
1225 output << "/* null statement */ ;";
1226}
1227
1228void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) {
1229 stmt->decl->accept( *visitor );
1230
1231 if ( doSemicolon( stmt->decl ) ) output << ";";
1232}
1233
1234void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
1235 assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." );
1236 stmt->callStmt->accept( *visitor );
1237}
1238
1239void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) {
1240 assertf( !options.genC, "MutexStmt should not reach code generation." );
1241 // TODO: But this isn't what a mutex statement looks like.
1242 stmt->stmt->accept( *visitor );
1243}
1244
1245std::string genName( ast::DeclWithType const * decl ) {
1246 if ( const OperatorInfo * opInfo = operatorLookup( decl->name ) ) {
1247 return opInfo->outputName;
1248 } else {
1249 return decl->name;
1250 }
1251}
1252
1253} // namespace CodeGen
Note: See TracBrowser for help on using the repository browser.