source: src/CodeGen/CodeGenerator.cpp@ d5efcb7

Last change on this file since d5efcb7 was c92bdcc, checked in by Andrew Beach <ajbeach@…>, 17 months ago

Updated the rest of the names in src/ (except for the generated files).

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