source: src/CodeGen/CodeGenerator.cpp@ 00675ed4

Last change on this file since 00675ed4 was 4acd1f8, checked in by Peter A. Buhr <pabuhr@…>, 4 weeks ago

change codegen for loop else-clause to print else-clause as a compound statement

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