source: src/CodeGen/CodeGenerator.cpp@ 464cfc7

Last change on this file since 464cfc7 was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 13 months ago

Removed SizeofExpr::expr and AlignofExpr::expr, expressions that would be stored there are wrapped in TypeofType and stored in the type field. Some special cases to hide the typeof in code generation were added. In addition, initializer length is calculated in more cases so that the full type of more arrays is known sooner. Other than that, most of the code changes were just stripping out the conditional code and checks no longer needed. Some tests had to be updated, because the typeof is not hidden in dumps and the resolver replaces known typeof expressions with the type. The extension case caused some concern but it appears that just hides warnings in the expression which no longer exists.

  • Property mode set to 100644
File size: 34.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 : 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.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()(
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.c_str()
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 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 output << " = ";
254 decl->init->accept( *visitor );
255 }
256 if ( decl->isDeleted ) {
257 output << " = void";
258 }
259
260 if ( decl->bitfieldWidth ) {
261 output << ":";
262 decl->bitfieldWidth->accept( *visitor );
263 }
264 return decl;
265}
266
267void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) {
268 if ( decl->storage.any() ) {
269 ast::print( output, decl->storage );
270 }
271}
272
273void CodeGenerator::handleAggregate(
274 ast::AggregateDecl const * decl, std::string const & kind ) {
275 if ( !decl->params.empty() && !options.genC ) {
276 output << "forall(";
277 genCommaList( decl->params );
278 output << ")\n" << indent << std::flush;
279 }
280
281 output << kind;
282 genAttributes( decl->attributes );
283 output << decl->name;
284
285 if ( decl->body ) {
286 auto & members = decl->members;
287 output << " {" << endl;
288
289 ++indent;
290 for ( auto & member : members ) {
291 output << indent;
292 member->accept( *visitor );
293 output << ";" << endl;
294 }
295 --indent;
296
297 output << indent << "}";
298 }
299}
300
301void CodeGenerator::postvisit( ast::StructDecl const * decl ) {
302 extension( decl );
303 handleAggregate( decl, "struct " );
304}
305
306void CodeGenerator::postvisit( ast::UnionDecl const * decl ) {
307 extension( decl );
308 handleAggregate( decl, "union " );
309}
310
311template<typename pass_type>
312inline void genEnumInitializer( ast::Pass<pass_type> * visitor,
313 ast::Type const * baseType, std::ostream & output,
314 ast::Init const * init, long long * curVal, Options options ) {
315 auto baseTypeAsBasic = dynamic_cast<ast::BasicType const *>( baseType );
316 // Value is provided.
317 if ( init ) {
318 output << " = (" << genType( baseType, "", options ) << ")";
319 init->accept( *visitor );
320 // If it is an integral type and initilizer offered,
321 // need to update the curVal.
322 if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
323 ast::Expr const * expr = ((ast::SingleInit const *)(init))->value;
324 // Unwrap introduced cast.
325 while ( auto temp = dynamic_cast<ast::CastExpr const *>( expr ) ) {
326 expr = temp->arg;
327 }
328 *curVal = ((ast::ConstantExpr const *)(expr))->intValue() + 1;
329 }
330 // Generate next value from previous value.
331 } else if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
332 output << " = (" << genType( baseType, "", options ) << ")";
333 output << (*curVal)++;
334 }
335}
336
337void CodeGenerator::postvisit( ast::EnumDecl const * decl ) {
338 extension( decl );
339 auto members = decl->members;
340 // if ( decl->base && !members.empty() ) {
341 // long long curVal = 0;
342 // for ( auto member : members ) {
343 // auto obj = member.strict_as<ast::ObjectDecl>();
344 // output << "static ";
345 // output << genType( decl->base, mangleName( obj ), options );
346 // genEnumInitializer( visitor, decl->base, output, obj->init, &curVal, options );
347 // output << ";" << endl;
348 // }
349 // } else {
350 output << "enum ";
351 genAttributes( decl->attributes );
352
353 output << decl->name;
354
355 if ( !members.empty() ) {
356 output << " {" << endl;
357
358 ++indent;
359 for ( auto member : members ) {
360 auto obj = member.strict_as<ast::ObjectDecl>();
361 output << indent << mangleName( obj );
362 if ( !decl->base && obj->init ) {
363 output << " = ";
364 obj->init->accept( *visitor );
365 }
366 output << "," << endl;
367 }
368 --indent;
369
370 output << indent << "}";
371 }
372 // }
373}
374
375void CodeGenerator::postvisit( ast::TraitDecl const * decl ) {
376 assertf( !options.genC, "TraitDecls should not reach code generation." );
377 extension( decl );
378 handleAggregate( decl, "trait " );
379}
380
381void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) {
382 assertf( !options.genC, "Typedefs should not reach code generation." );
383 output << "typedef " << genType( decl->base, decl->name, options ) << endl;
384}
385
386void CodeGenerator::postvisit( ast::TypeDecl const * decl ) {
387 assertf( !options.genC, "TypeDecls should not reach code generation." );
388 output << decl->genTypeString() << " " << decl->name;
389 if ( decl->sized ) {
390 output << " | sized(" << decl->name << ")";
391 }
392 if ( !decl->assertions.empty() ) {
393 output << " | { ";
394 for ( ast::DeclWithType const * assert : decl->assertions ) {
395 assert->accept( *visitor );
396 output << "; ";
397 }
398 output << " }";
399 }
400}
401
402void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) {
403 output << "_Static_assert(";
404 decl->cond->accept( *visitor );
405 output << ", ";
406 decl->msg->accept( *visitor );
407 output << ")";
408}
409
410void CodeGenerator::postvisit( ast::Designation const * designation ) {
411 auto designators = designation->designators;
412 if ( 0 == designators.size() ) return;
413 for ( ast::ptr<ast::Expr> const & des : designators ) {
414 // If the expression is a NameExpr or VariableExpr, then it is a field.
415 if ( des.as<ast::NameExpr>() || des.as<ast::VariableExpr>() ) {
416 output << ".";
417 des->accept( *visitor );
418 // Otherwise, it is a ConstantExpr or CastExpr, then it is an index.
419 } else {
420 output << "[";
421 des->accept( *visitor );
422 output << "]";
423 }
424 }
425 output << " = ";
426}
427
428void CodeGenerator::postvisit( ast::SingleInit const * init ) {
429 init->value->accept( *visitor );
430}
431
432void CodeGenerator::postvisit( ast::ListInit const * init ) {
433 auto initBegin = init->initializers.begin();
434 auto initEnd = init->initializers.end();
435 auto desigBegin = init->designations.begin();
436 auto desigEnd = init->designations.end();
437
438 output << "{ ";
439 if ( initBegin != initEnd ) while (true) {
440 (*desigBegin)->accept( *visitor );
441 (*initBegin)->accept( *visitor );
442 ++initBegin, ++desigBegin;
443 if ( initBegin == initEnd ) break;
444 output << ", ";
445 }
446 output << " }";
447 assertf( initBegin == initEnd && desigBegin == desigEnd,
448 "Initializers and designators not the same length. %s", toCString( init ) );
449}
450
451void CodeGenerator::postvisit( ast::ConstructorInit const * init ) {
452 assertf( !options.genC, "ConstructorInit nodes should not reach code generation." );
453 // This isn't actual code, but labels the constructor/destructor pairs.
454 output << "<ctorinit>{" << endl << ++indent << "ctor: ";
455 if ( init->ctor ) init->ctor->accept( *visitor );
456 output << ", " << endl << indent << "dtor: ";
457 if ( init->dtor ) init->dtor->accept( *visitor );
458 output << endl << --indent << "}";
459}
460
461void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) {
462 extension( expr );
463 if ( auto var = expr->func.as<ast::VariableExpr>() ) {
464 const OperatorInfo * opInfo;
465 if ( var->var->linkage == ast::Linkage::Intrinsic &&
466 ( opInfo = operatorLookup( var->var->name ) ) ) {
467 auto arg = expr->args.begin();
468 switch ( opInfo->type ) {
469 case OT_INDEX:
470 assert( 2 == expr->args.size() );
471 (*arg++)->accept( *visitor );
472 output << "[";
473 (*arg)->accept( *visitor );
474 output << "]";
475 break;
476
477 // There are no intrinsic definitions of the function call operator.
478 case OT_CALL:
479 assert( false );
480 break;
481
482 case OT_CTOR:
483 case OT_DTOR:
484 // No-op constructor, but run the internal expression.
485 if ( 1 == expr->args.size() ) {
486 output << "(";
487 (*arg++)->accept( *visitor );
488 output << ") /* " << opInfo->inputName << " */";
489 // These are all implemented as some form of assignment.
490 } else if ( 2 == expr->args.size() ) {
491 output << "(";
492 (*arg++)->accept( *visitor );
493 output << opInfo->symbol;
494 (*arg)->accept( *visitor );
495 output << ") /* " << opInfo->inputName << " */";
496 // No constructors with 0 or more than 2 parameters.
497 } else {
498 assert( false );
499 }
500 break;
501
502 case OT_PREFIX:
503 case OT_PREFIXASSIGN:
504 assert( 1 == expr->args.size() );
505 output << "(" << opInfo->symbol;
506 (*arg)->accept( *visitor );
507 output << ")";
508 break;
509
510 case OT_POSTFIX:
511 case OT_POSTFIXASSIGN:
512 assert( 1 == expr->args.size() );
513 (*arg)->accept( *visitor );
514 output << opInfo->symbol;
515 break;
516
517 case OT_INFIX:
518 case OT_INFIXASSIGN:
519 assert( 2 == expr->args.size() );
520 output << "(";
521 (*arg++)->accept( *visitor );
522 output << opInfo->symbol;
523 (*arg)->accept( *visitor );
524 output << ")";
525 break;
526
527 // There are no intrinsic definitions of 0/1 or label address
528 // as function.
529 case OT_CONSTANT:
530 case OT_LABELADDRESS:
531 assert( false );
532 }
533 // TODO: This is a work-around to make it a constant until a proper
534 // constexpr solution is created.
535 } else if ( var->var->linkage == ast::Linkage::BuiltinCFA &&
536 var->var->name == "intptr" ) {
537 output << "((void*)";
538 auto arg = expr->args.begin();
539 (*arg++)->accept( *visitor );
540 output << ")";
541 } else {
542 var->accept( *visitor );
543 output << "(";
544 genCommaList( expr->args );
545 output << ")";
546 }
547 } else {
548 expr->func->accept( *visitor );
549 output << "(";
550 genCommaList( expr->args );
551 output << ")";
552 }
553}
554
555void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) {
556 extension( expr );
557 if ( auto name = expr->func.as<ast::NameExpr>() ) {
558 if ( const OperatorInfo * opInfo = operatorLookup( name->name ) ) {
559 auto arg = expr->args.begin();
560 switch ( opInfo->type ) {
561 case OT_INDEX:
562 assert( 2 == expr->args.size() );
563 (*arg++)->accept( *visitor );
564 output << "[";
565 (*arg)->accept( *visitor );
566 output << "]";
567 break;
568
569 case OT_CALL:
570 assert( false );
571
572 case OT_CTOR:
573 case OT_DTOR:
574 // No-op constructor, but run the internal expression.
575 if ( 1 == expr->args.size() ) {
576 output << "(";
577 (*arg++)->accept( *visitor );
578 output << ")";
579 // These are all implemented as some form of assignment.
580 } else if ( 2 == expr->args.size() ) {
581 output << "(";
582 (*arg++)->accept( *visitor );
583 output << opInfo->symbol;
584 (*arg)->accept( *visitor );
585 output << ") /* " << opInfo->inputName << " */";
586 // No constructors with 0 or more than 2 parameters.
587 } else {
588 assertf( !options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
589 output << "(";
590 (*arg++)->accept( *visitor );
591 output << opInfo->symbol << "{ ";
592 genCommaList( arg, expr->args.end() );
593 output << "}) /* " << opInfo->inputName << " */";
594 }
595 break;
596
597 case OT_PREFIX:
598 case OT_PREFIXASSIGN:
599 case OT_LABELADDRESS:
600 assert( 1 == expr->args.size() );
601 output << "(" << opInfo->symbol;
602 (*arg)->accept( *visitor );
603 output << ")";
604 break;
605
606 case OT_POSTFIX:
607 case OT_POSTFIXASSIGN:
608 assert( 1 == expr->args.size() );
609 (*arg)->accept( *visitor );
610 output << opInfo->symbol;
611 break;
612
613 case OT_INFIX:
614 case OT_INFIXASSIGN:
615 assert( 2 == expr->args.size() );
616 output << "(";
617 (*arg++)->accept( *visitor );
618 output << opInfo->symbol;
619 (*arg)->accept( *visitor );
620 output << ")";
621 break;
622
623 // There are no intrinsic definitions of 0/1 or label address
624 // as function.
625 case OT_CONSTANT:
626 assert( false );
627 }
628 // builtin routines
629 } else {
630 name->accept( *visitor );
631 output << "(";
632 genCommaList( expr->args );
633 output << ")";
634 }
635 } else {
636 expr->func->accept( *visitor );
637 output << "(";
638 genCommaList( expr->args );
639 output << ")";
640 }
641}
642
643void CodeGenerator::postvisit( ast::RangeExpr const * expr ) {
644 expr->low->accept( *visitor );
645 output << " ... ";
646 expr->high->accept( *visitor );
647}
648
649void CodeGenerator::postvisit( ast::NameExpr const * expr ) {
650 extension( expr );
651 if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) {
652 if ( OT_CONSTANT == opInfo->type ) {
653 output << opInfo->symbol;
654 } else {
655 output << opInfo->outputName;
656 }
657 } else {
658 output << expr->name;
659 }
660}
661
662void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) {
663 extension( expr );
664 output << "/*non-type*/" << expr->name;
665}
666
667void CodeGenerator::postvisit( ast::AddressExpr const * expr ) {
668 extension( expr );
669 output << "(&";
670 expr->arg->accept( *visitor );
671 output << ")";
672}
673
674void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) {
675 extension( expr );
676 output << "(&&" << expr->arg << ")";
677}
678
679void CodeGenerator::postvisit( ast::CastExpr const * expr ) {
680 extension( expr );
681 output << "(";
682 if ( expr->result->isVoid() ) {
683 output << "(void)";
684 } else {
685 output << "(";
686 output << genType( expr->result, "", options );
687 output << ")";
688 }
689 expr->arg->accept( *visitor );
690 output << ")";
691}
692
693void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) {
694 assertf( !options.genC, "KeywordCastExpr should not reach code generation." );
695 extension( expr );
696 output << "((" << expr->targetString() << " &)";
697 expr->arg->accept( *visitor );
698 output << ")";
699}
700
701void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) {
702 assertf( !options.genC, "VirtualCastExpr should not reach code generation." );
703 extension( expr );
704 // TODO: Is this busted?
705 output << "(virtual ";
706 expr->arg->accept( *visitor );
707 output << ")";
708}
709
710void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) {
711 assertf( !options.genC, "UntypedMemberExpr should not reach code generation." );
712 extension( expr );
713 expr->aggregate->accept( *visitor );
714 output << ".";
715 expr->member->accept( *visitor );
716}
717
718void CodeGenerator::postvisit( ast::MemberExpr const * expr ) {
719 extension( expr );
720 expr->aggregate->accept( *visitor );
721 output << "." << mangleName( expr->member );
722}
723
724void CodeGenerator::postvisit( ast::VariableExpr const * expr ) {
725 extension( expr );
726 const OperatorInfo * opInfo;
727 if ( dynamic_cast<ast::ZeroType const *>( expr->var->get_type() ) ) {
728 output << "0";
729 } else if ( expr->var->linkage == ast::Linkage::Intrinsic
730 && ( opInfo = operatorLookup( expr->var->name ) )
731 && opInfo->type == OT_CONSTANT ) {
732 output << opInfo->symbol;
733 } else {
734 output << mangleName( expr->var );
735 }
736}
737
738void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) {
739 extension( expr );
740 output << expr->rep;
741}
742
743void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) {
744 extension( expr );
745 output << "sizeof(";
746 if ( auto type = expr->type.as<ast::TypeofType>() ) {
747 type->expr->accept( *visitor );
748 } else {
749 output << genType( expr->type, "", options );
750 }
751 output << ")";
752}
753
754void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) {
755 // Using the GCC extension to avoid changing the std to C11.
756 extension( expr );
757 output << "__alignof__(";
758 if ( auto type = expr->type.as<ast::TypeofType>() ) {
759 type->expr->accept( *visitor );
760 } else {
761 output << genType( expr->type, "", options );
762 }
763 output << ")";
764}
765
766void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) {
767 assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." );
768 output << "offsetof(";
769 output << genType( expr->type, "", options );
770 output << ", " << expr->member;
771 output << ")";
772}
773
774void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) {
775 // Use GCC builtin
776 output << "__builtin_offsetof(";
777 output << genType( expr->type, "", options );
778 output << ", " << mangleName( expr->member );
779 output << ")";
780}
781
782void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) {
783 assertf( !options.genC, "OffsetPackExpr should not reach code generation." );
784 output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")";
785}
786
787void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) {
788 extension( expr );
789 output << "(";
790 expr->arg1->accept( *visitor );
791 output << ( ( expr->isAnd ) ? " && " : " || " );
792 expr->arg2->accept( *visitor );
793 output << ")";
794}
795
796void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) {
797 extension( expr );
798 output << "(";
799 expr->arg1->accept( *visitor );
800 output << " ? ";
801 expr->arg2->accept( *visitor );
802 output << " : ";
803 expr->arg3->accept( *visitor );
804 output << ")";
805}
806
807void CodeGenerator::postvisit( ast::CommaExpr const * expr ) {
808 extension( expr );
809 output << "(";
810 if ( options.genC ) {
811 // arg1 of a comma expression is never used, so it can be safely cast
812 // to void to reduce gcc warnings.
813 ast::ptr<ast::Expr> arg1 = new ast::CastExpr( expr->location, expr->arg1 );
814 arg1->accept( *visitor );
815 } else {
816 expr->arg1->accept( *visitor );
817 }
818 output << " , ";
819 expr->arg2->accept( *visitor );
820 output << ")";
821}
822
823void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) {
824 assertf( !options.genC, "TupleAssignExpr should not reach code generation." );
825 expr->stmtExpr->accept( *visitor );
826}
827
828void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) {
829 assertf( !options.genC, "UntypedTupleExpr should not reach code generation." );
830 extension( expr );
831 output << "[";
832 genCommaList( expr->exprs );
833 output << "]";
834}
835
836void CodeGenerator::postvisit( ast::TupleExpr const * expr ) {
837 assertf( !options.genC, "TupleExpr should not reach code generation." );
838 extension( expr );
839 output << "[";
840 genCommaList( expr->exprs );
841 output << "]";
842}
843
844void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) {
845 assertf( !options.genC, "TupleIndexExpr should not reach code generation." );
846 extension( expr );
847 expr->tuple->accept( *visitor );
848 output << "." << expr->index;
849}
850
851void CodeGenerator::postvisit( ast::TypeExpr const * expr ) {
852 // TODO: Should there be an assertion there?
853 if ( !options.genC ) {
854 output << genType( expr->type, "", options );
855 }
856}
857
858void CodeGenerator::postvisit( ast::AsmExpr const * expr ) {
859 if ( !expr->inout.empty() ) {
860 output << "[ " << expr->inout << " ] ";
861 }
862 expr->constraint->accept( *visitor );
863 output << " ( ";
864 expr->operand->accept( *visitor );
865 output << " )";
866}
867
868void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) {
869 //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) );
870 assert( expr->result && expr->init.as<ast::ListInit>() );
871 output << "(" << genType( expr->result, "", options ) << ")";
872 expr->init->accept( *visitor );
873}
874
875void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) {
876 assertf( !options.genC, "UniqueExpr should not reach code generation." );
877 output << "unq<" << expr->id << ">{ ";
878 expr->expr->accept( *visitor );
879 output << " }";
880}
881
882void CodeGenerator::postvisit( ast::StmtExpr const * expr ) {
883 auto stmts = expr->stmts->kids;
884 output << "({" << endl;
885 ++indent;
886 unsigned int numStmts = stmts.size();
887 unsigned int i = 0;
888 for ( ast::ptr<ast::Stmt> const & stmt : stmts ) {
889 output << indent << printLabels( stmt->labels );
890 if ( i + 1 == numStmts ) {
891 // Last statement in a statement expression needs to be handled
892 // specially - cannot cast to void, otherwise the expression
893 // statement has no value.
894 if ( ast::ExprStmt const * exprStmt = stmt.as<ast::ExprStmt>() ) {
895 exprStmt->expr->accept( *visitor );
896 output << ";" << endl;
897 ++i;
898 break;
899 }
900 }
901 stmt->accept( *visitor );
902 output << endl;
903 if ( wantSpacing( stmt ) ) output << endl;
904 ++i;
905 }
906 --indent;
907 output << indent << "})";
908}
909
910void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) {
911 assertf( !options.genC, "ConstructorExpr should not reach code generation." );
912 expr->callExpr->accept( *visitor );
913}
914
915void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) {
916 assertf( !options.genC, "DeletedExpr should not reach code generation." );
917 expr->expr->accept( *visitor );
918}
919
920void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) {
921 assertf( !options.genC, "DefaultArgExpr should not reach code generation." );
922 expr->expr->accept( *visitor );
923}
924
925void CodeGenerator::postvisit( ast::GenericExpr const * expr ) {
926 assertf( !options.genC, "GenericExpr should not reach code generation." );
927 output << "_Generic(";
928 expr->control->accept( *visitor );
929 output << ", ";
930 unsigned int numAssocs = expr->associations.size();
931 unsigned int i = 0;
932 for ( const ast::GenericExpr::Association & assoc : expr->associations ) {
933 if ( nullptr == assoc.type ) {
934 output << "default: ";
935 } else {
936 output << genType( assoc.type, "", options ) << ": ";
937 }
938 assoc.expr->accept( *visitor );
939 ++i;
940 if ( i != numAssocs ) output << ", ";
941 }
942 output << ")";
943}
944
945void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) {
946 output << "{" << endl;
947
948 ++indent;
949 for ( auto kid : stmt->kids ) {
950 output << indent << printLabels( kid->labels );
951 kid->accept( *visitor );
952 output << endl;
953 if ( wantSpacing( kid ) ) output << endl;
954 }
955 --indent;
956
957 output << indent << "}";
958}
959
960void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) {
961 assert( stmt );
962 // Cast the top-level expression to void to reduce gcc warnings.
963 if ( options.genC ) {
964 ast::ptr<ast::Expr> expr = new ast::CastExpr( stmt->location, stmt->expr );
965 expr->accept( *visitor );
966 } else {
967 stmt->expr->accept( *visitor );
968 }
969 output << ";";
970}
971
972void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) {
973 output << "asm ";
974 if ( stmt->isVolatile ) output << "volatile ";
975 if ( !stmt->gotoLabels.empty() ) output << "goto ";
976 output << "( ";
977 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
978 output << " : ";
979 genCommaList( stmt->output );
980 output << " : ";
981 genCommaList( stmt->input );
982 output << " : ";
983 genCommaList( stmt->clobber );
984 if ( !stmt->gotoLabels.empty() ) {
985 output << " : ";
986 auto it = stmt->gotoLabels.begin();
987 while (true) {
988 output << *it++;
989 if ( stmt->gotoLabels.end() == it ) break;
990 output << ", ";
991 }
992 }
993 output << " );";
994}
995
996void CodeGenerator::postvisit( ast::AsmDecl const * decl ) {
997 output << "asm ";
998 ast::AsmStmt const * stmt = decl->stmt;
999 output << "( ";
1000 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
1001 output << " )";
1002}
1003
1004void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) {
1005 // endl prevents spaces before the directive.
1006 output << endl << decl->stmt->directive;
1007}
1008
1009void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) {
1010 // endl prevents spaces before the directive.
1011 output << endl << stmt->directive;
1012}
1013
1014void CodeGenerator::postvisit( ast::IfStmt const * stmt ) {
1015 output << "if ( ";
1016 stmt->cond->accept( *visitor );
1017 output << " ) ";
1018
1019 stmt->then->accept( *visitor );
1020
1021 if ( nullptr != stmt->else_ ) {
1022 output << " else ";
1023 stmt->else_->accept( *visitor );
1024 }
1025}
1026
1027void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) {
1028 output << "switch ( ";
1029 stmt->cond->accept( *visitor );
1030 output << " ) ";
1031
1032 output << "{" << endl;
1033 ++indent;
1034 for ( auto node : stmt->cases ) {
1035 node->accept( *visitor );
1036 }
1037 --indent;
1038 output << indent << "}";
1039}
1040
1041void CodeGenerator::postvisit( ast::CaseClause const * clause ) {
1042 updateLocation( clause );
1043 output << indent;
1044 if ( clause->isDefault() ) {
1045 output << "default";
1046 } else {
1047 output << "case ";
1048 clause->cond->accept( *visitor );
1049 }
1050 output << ":" << endl;
1051
1052 ++indent;
1053 for ( auto stmt : clause->stmts ) {
1054 output << indent << printLabels( stmt->labels ) ;
1055 stmt->accept( *visitor );
1056 output << endl;
1057 }
1058 --indent;
1059}
1060
1061void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) {
1062 switch ( stmt->kind ) {
1063 case ast::BranchStmt::Goto:
1064 if ( !stmt->target.empty() ) {
1065 output << "goto " << stmt->target;
1066 } else if ( nullptr != stmt->computedTarget ) {
1067 output << "goto *";
1068 stmt->computedTarget->accept( *visitor );
1069 }
1070 break;
1071 case ast::BranchStmt::Break:
1072 output << "break";
1073 break;
1074 case ast::BranchStmt::Continue:
1075 output << "continue";
1076 break;
1077 case ast::BranchStmt::FallThrough:
1078 case ast::BranchStmt::FallThroughDefault:
1079 assertf( !options.genC, "fallthru should not reach code generation." );
1080 output << "fallthru";
1081 break;
1082 default:
1083 assertf( false, "Bad BranchStmt value." );
1084 }
1085 // Print branch target for labelled break/continue/fallthru in debug mode.
1086 if ( !options.genC && stmt->kind != ast::BranchStmt::Goto ) {
1087 if ( !stmt->target.empty() ) {
1088 output << " " << stmt->target;
1089 } else if ( stmt->kind == ast::BranchStmt::FallThrough ) {
1090 output << " default";
1091 }
1092 }
1093 output << ";";
1094}
1095
1096void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) {
1097 output << "return ";
1098 if ( stmt->expr ) stmt->expr->accept( *visitor );
1099 output << ";";
1100}
1101
1102void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) {
1103 assertf( !options.genC, "ThrowStmt should not reach code generation." );
1104
1105 output << ((stmt->kind == ast::Terminate) ? "throw" : "throwResume");
1106 if ( stmt->expr ) {
1107 output << " ";
1108 stmt->expr->accept( *visitor );
1109 }
1110 if ( stmt->target ) {
1111 output << " _At ";
1112 stmt->target->accept( *visitor );
1113 }
1114 output << ";";
1115}
1116
1117void CodeGenerator::postvisit( ast::CatchClause const * stmt ) {
1118 assertf( !options.genC, "CatchClause should not reach code generation." );
1119
1120 output << ((stmt->kind == ast::Terminate) ? "catch" : "catchResume");
1121 output << "( ";
1122 stmt->decl->accept( *visitor );
1123 if ( stmt->cond ) {
1124 output << " ; ";
1125 stmt->cond->accept( *visitor );
1126 }
1127 output << " ) ";
1128 stmt->body->accept( *visitor );
1129}
1130
1131void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) {
1132 assertf( !options.genC, "WaitforStmt should not reach code generation." );
1133
1134 bool first = true;
1135 for ( ast::ptr<ast::WaitForClause> const & clause : stmt->clauses ) {
1136 if (first) { output << "or "; first = false; }
1137 if ( clause->when_cond ) {
1138 output << "when(";
1139 clause->when_cond->accept( *visitor );
1140 output << ") ";
1141 }
1142 output << "waitfor(";
1143 clause->target->accept( *visitor );
1144 for ( ast::ptr<ast::Expr> const & expr : clause->target_args ) {
1145 output << ",";
1146 expr->accept( *visitor );
1147 }
1148 output << ") ";
1149 clause->stmt->accept( *visitor );
1150 }
1151
1152 if ( stmt->timeout_stmt ) {
1153 output << "or ";
1154 if ( stmt->timeout_cond ) {
1155 output << "when(";
1156 stmt->timeout_cond->accept( *visitor );
1157 output << ") ";
1158 }
1159 output << "timeout(";
1160 stmt->timeout_time->accept( *visitor );
1161 output << ") ";
1162 stmt->timeout_stmt->accept( *visitor );
1163 }
1164
1165 if ( stmt->else_stmt ) {
1166 output << "or ";
1167 if ( stmt->else_cond ) {
1168 output << "when(";
1169 stmt->else_cond->accept( *visitor );
1170 output << ")";
1171 }
1172 output << "else ";
1173 stmt->else_stmt->accept( *visitor );
1174 }
1175}
1176
1177void CodeGenerator::postvisit( ast::WithStmt const * stmt ) {
1178 assertf( !options.genC, "WithStmt should not reach code generation." );
1179
1180 output << "with ( ";
1181 genCommaList( stmt->exprs );
1182 output << " ) ";
1183 stmt->stmt->accept( *visitor );
1184}
1185
1186void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) {
1187 if ( stmt->isDoWhile ) {
1188 output << "do";
1189 } else {
1190 output << "while (";
1191 stmt->cond->accept( *visitor );
1192 output << ")";
1193 }
1194 output << " ";
1195
1196 output << CodeGenerator::printLabels( stmt->body->labels );
1197 stmt->body->accept( *visitor );
1198
1199 if ( stmt->isDoWhile ) {
1200 output << " while (";
1201 stmt->cond->accept( *visitor );
1202 output << ( ( nullptr == stmt->else_ ) ? ");" : ")" );
1203 }
1204 if ( stmt->else_ ) {
1205 output << " else ";
1206 stmt->else_->accept( *visitor );
1207 }
1208}
1209
1210void CodeGenerator::postvisit( ast::ForStmt const * stmt ) {
1211 // Initializer is always hoised so don't generate it.
1212 // TODO: Do an assertion check?
1213 output << "for (;";
1214
1215 if ( nullptr != stmt->cond ) {
1216 stmt->cond->accept( *visitor );
1217 }
1218 output << ";";
1219
1220 if ( nullptr != stmt->inc ) {
1221 // cast the top-level expression to void to reduce gcc warnings.
1222 ast::Expr * expr = new ast::CastExpr( stmt->inc );
1223 expr->accept( *visitor );
1224 }
1225 output << ") ";
1226
1227 if ( nullptr != stmt->body ) {
1228 output << printLabels( stmt->body->labels );
1229 stmt->body->accept( *visitor );
1230 }
1231
1232 if ( nullptr != stmt->else_ ) {
1233 assertf( !options.genC, "Loop else should not reach code generation." );
1234 output << " else ";
1235 stmt->else_->accept( *visitor );
1236 }
1237}
1238
1239void CodeGenerator::postvisit( ast::NullStmt const * ) {
1240 output << "/* null statement */ ;";
1241}
1242
1243void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) {
1244 stmt->decl->accept( *visitor );
1245
1246 if ( doSemicolon( stmt->decl ) ) output << ";";
1247}
1248
1249void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
1250 assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." );
1251 stmt->callStmt->accept( *visitor );
1252}
1253
1254void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) {
1255 assertf( !options.genC, "MutexStmt should not reach code generation." );
1256 // TODO: But this isn't what a mutex statement looks like.
1257 stmt->stmt->accept( *visitor );
1258}
1259
1260std::string genName( ast::DeclWithType const * decl ) {
1261 if ( const OperatorInfo * opInfo = operatorLookup( decl->name ) ) {
1262 return opInfo->outputName;
1263 } else {
1264 return decl->name;
1265 }
1266}
1267
1268} // namespace CodeGen
Note: See TracBrowser for help on using the repository browser.