source: src/CodeGen/CodeGenerator.cpp@ 9ae4f5f

Last change on this file since 9ae4f5f was 550446f, checked in by Andrew Beach <ajbeach@…>, 9 months ago

Added some code to the code generator for printing try statements in intermediate states.

  • Property mode set to 100644
File size: 35.8 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 {
[661e7b0]81 output << "\n# " << to.first_line << " \"" << to.filename.c_str()
[8941b6b]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() ) {
[db19e1d]182 if ( !decl->type->isVarArgs ) {
183 acc << "(void)";
184 } else if ( options.genC ) {
[8941b6b]185 acc << "()";
186 } else {
[db19e1d]187 acc << "(...)";
[8941b6b]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 );
[0139351]201 } else if ( 0 == decl->returns.size() ) {
[8941b6b]202 output << "void " + acc.str();
[0139351]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 );
[8941b6b]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
[0bd3faf]219ast::ObjectDecl const * CodeGenerator::postvisit(
[8941b6b]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
[0bd3faf]267void CodeGenerator::handleStorageClass( ast::DeclWithType const * decl ) {
[8941b6b]268 if ( decl->storage.any() ) {
269 ast::print( output, decl->storage );
270 }
271}
272
[0bd3faf]273void CodeGenerator::handleAggregate(
[8941b6b]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
[0bd3faf]301void CodeGenerator::postvisit( ast::StructDecl const * decl ) {
[8941b6b]302 extension( decl );
303 handleAggregate( decl, "struct " );
304}
305
[0bd3faf]306void CodeGenerator::postvisit( ast::UnionDecl const * decl ) {
[8941b6b]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
[0bd3faf]337void CodeGenerator::postvisit( ast::EnumDecl const * decl ) {
[8941b6b]338 extension( decl );
339 auto members = decl->members;
[c75b30a]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 {
[8941b6b]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 );
[c75b30a]362 if ( !decl->base && obj->init ) {
[8941b6b]363 output << " = ";
364 obj->init->accept( *visitor );
365 }
366 output << "," << endl;
367 }
368 --indent;
369
370 output << indent << "}";
371 }
[c75b30a]372 // }
[8941b6b]373}
374
[0bd3faf]375void CodeGenerator::postvisit( ast::TraitDecl const * decl ) {
[8941b6b]376 assertf( !options.genC, "TraitDecls should not reach code generation." );
377 extension( decl );
378 handleAggregate( decl, "trait " );
379}
380
[0bd3faf]381void CodeGenerator::postvisit( ast::TypedefDecl const * decl ) {
[8941b6b]382 assertf( !options.genC, "Typedefs should not reach code generation." );
383 output << "typedef " << genType( decl->base, decl->name, options ) << endl;
384}
385
[0bd3faf]386void CodeGenerator::postvisit( ast::TypeDecl const * decl ) {
[8941b6b]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
[0bd3faf]402void CodeGenerator::postvisit( ast::StaticAssertDecl const * decl ) {
[8941b6b]403 output << "_Static_assert(";
404 decl->cond->accept( *visitor );
405 output << ", ";
406 decl->msg->accept( *visitor );
407 output << ")";
408}
409
[0bd3faf]410void CodeGenerator::postvisit( ast::Designation const * designation ) {
[8941b6b]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
[0bd3faf]428void CodeGenerator::postvisit( ast::SingleInit const * init ) {
[8941b6b]429 init->value->accept( *visitor );
430}
431
[0bd3faf]432void CodeGenerator::postvisit( ast::ListInit const * init ) {
[8941b6b]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
[0bd3faf]451void CodeGenerator::postvisit( ast::ConstructorInit const * init ) {
[8941b6b]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
[0bd3faf]461void CodeGenerator::postvisit( ast::ApplicationExpr const * expr ) {
[8941b6b]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
[0bd3faf]555void CodeGenerator::postvisit( ast::UntypedExpr const * expr ) {
[8941b6b]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
[0bd3faf]643void CodeGenerator::postvisit( ast::RangeExpr const * expr ) {
[8941b6b]644 expr->low->accept( *visitor );
645 output << " ... ";
646 expr->high->accept( *visitor );
647}
648
[0bd3faf]649void CodeGenerator::postvisit( ast::NameExpr const * expr ) {
[8941b6b]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
[0bd3faf]662void CodeGenerator::postvisit( ast::DimensionExpr const * expr ) {
[8941b6b]663 extension( expr );
664 output << "/*non-type*/" << expr->name;
665}
666
[0bd3faf]667void CodeGenerator::postvisit( ast::AddressExpr const * expr ) {
[8941b6b]668 extension( expr );
669 output << "(&";
670 expr->arg->accept( *visitor );
671 output << ")";
672}
673
[0bd3faf]674void CodeGenerator::postvisit( ast::LabelAddressExpr const * expr ) {
[8941b6b]675 extension( expr );
676 output << "(&&" << expr->arg << ")";
677}
678
[0bd3faf]679void CodeGenerator::postvisit( ast::CastExpr const * expr ) {
[8941b6b]680 extension( expr );
681 output << "(";
[ecf3812]682 switch ( expr->kind ) {
683 case ast::CCast:
684 if ( expr->result->isVoid() ) {
685 output << "(void)";
686 } else {
687 output << "(";
688 output << genType( expr->result, "", options );
689 output << ")";
690 }
691 break;
692 case ast::CoerceCast:
693 assertf( ast::CoerceCast != expr->kind, "Coercion cast is not implemented." );
694 // And likely shouldn't reach code generation when it is implemented.
695 break;
696 case ast::ReturnCast:
697 // This should be invisible in the resulting C code.
698 // Can we insert a check here?
699 //assert( ResolvExpr::typesCompatable(???) );
700 if ( options.genC ) break;
701 output << "(return ";
[8941b6b]702 output << genType( expr->result, "", options );
703 output << ")";
[ecf3812]704 break;
[8941b6b]705 }
706 expr->arg->accept( *visitor );
707 output << ")";
708}
709
[0bd3faf]710void CodeGenerator::postvisit( ast::KeywordCastExpr const * expr ) {
[8941b6b]711 assertf( !options.genC, "KeywordCastExpr should not reach code generation." );
712 extension( expr );
713 output << "((" << expr->targetString() << " &)";
714 expr->arg->accept( *visitor );
715 output << ")";
716}
717
[0bd3faf]718void CodeGenerator::postvisit( ast::VirtualCastExpr const * expr ) {
[8941b6b]719 assertf( !options.genC, "VirtualCastExpr should not reach code generation." );
720 extension( expr );
721 // TODO: Is this busted?
722 output << "(virtual ";
723 expr->arg->accept( *visitor );
724 output << ")";
725}
726
[0bd3faf]727void CodeGenerator::postvisit( ast::UntypedMemberExpr const * expr ) {
[8941b6b]728 assertf( !options.genC, "UntypedMemberExpr should not reach code generation." );
729 extension( expr );
730 expr->aggregate->accept( *visitor );
731 output << ".";
732 expr->member->accept( *visitor );
733}
734
[0bd3faf]735void CodeGenerator::postvisit( ast::MemberExpr const * expr ) {
[8941b6b]736 extension( expr );
737 expr->aggregate->accept( *visitor );
738 output << "." << mangleName( expr->member );
739}
740
[0bd3faf]741void CodeGenerator::postvisit( ast::VariableExpr const * expr ) {
[8941b6b]742 extension( expr );
743 const OperatorInfo * opInfo;
[e0330d2c]744 if ( expr->var->linkage == ast::Linkage::Intrinsic
[8941b6b]745 && ( opInfo = operatorLookup( expr->var->name ) )
746 && opInfo->type == OT_CONSTANT ) {
747 output << opInfo->symbol;
748 } else {
749 output << mangleName( expr->var );
750 }
751}
752
[0bd3faf]753void CodeGenerator::postvisit( ast::ConstantExpr const * expr ) {
[8941b6b]754 extension( expr );
755 output << expr->rep;
756}
757
[0bd3faf]758void CodeGenerator::postvisit( ast::SizeofExpr const * expr ) {
[8941b6b]759 extension( expr );
760 output << "sizeof(";
[b6f2e7ab]761 if ( auto type = expr->type.as<ast::TypeofType>() ) {
762 type->expr->accept( *visitor );
[8941b6b]763 } else {
[b6f2e7ab]764 output << genType( expr->type, "", options );
[8941b6b]765 }
766 output << ")";
767}
768
[0bd3faf]769void CodeGenerator::postvisit( ast::AlignofExpr const * expr ) {
[8941b6b]770 // Using the GCC extension to avoid changing the std to C11.
771 extension( expr );
772 output << "__alignof__(";
[b6f2e7ab]773 if ( auto type = expr->type.as<ast::TypeofType>() ) {
774 type->expr->accept( *visitor );
[8941b6b]775 } else {
[b6f2e7ab]776 output << genType( expr->type, "", options );
[8941b6b]777 }
778 output << ")";
779}
780
[0bd3faf]781void CodeGenerator::postvisit( ast::UntypedOffsetofExpr const * expr ) {
[8941b6b]782 assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." );
783 output << "offsetof(";
784 output << genType( expr->type, "", options );
785 output << ", " << expr->member;
786 output << ")";
787}
788
[0bd3faf]789void CodeGenerator::postvisit( ast::OffsetofExpr const * expr ) {
[8941b6b]790 // Use GCC builtin
791 output << "__builtin_offsetof(";
792 output << genType( expr->type, "", options );
793 output << ", " << mangleName( expr->member );
794 output << ")";
795}
796
[0bd3faf]797void CodeGenerator::postvisit( ast::OffsetPackExpr const * expr ) {
[8941b6b]798 assertf( !options.genC, "OffsetPackExpr should not reach code generation." );
799 output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")";
800}
801
[0bd3faf]802void CodeGenerator::postvisit( ast::LogicalExpr const * expr ) {
[8941b6b]803 extension( expr );
804 output << "(";
805 expr->arg1->accept( *visitor );
806 output << ( ( expr->isAnd ) ? " && " : " || " );
807 expr->arg2->accept( *visitor );
808 output << ")";
809}
810
[0bd3faf]811void CodeGenerator::postvisit( ast::ConditionalExpr const * expr ) {
[8941b6b]812 extension( expr );
813 output << "(";
814 expr->arg1->accept( *visitor );
815 output << " ? ";
816 expr->arg2->accept( *visitor );
817 output << " : ";
818 expr->arg3->accept( *visitor );
819 output << ")";
820}
821
[0bd3faf]822void CodeGenerator::postvisit( ast::CommaExpr const * expr ) {
[8941b6b]823 extension( expr );
824 output << "(";
825 if ( options.genC ) {
826 // arg1 of a comma expression is never used, so it can be safely cast
827 // to void to reduce gcc warnings.
828 ast::ptr<ast::Expr> arg1 = new ast::CastExpr( expr->location, expr->arg1 );
829 arg1->accept( *visitor );
830 } else {
831 expr->arg1->accept( *visitor );
832 }
833 output << " , ";
834 expr->arg2->accept( *visitor );
835 output << ")";
836}
837
[0bd3faf]838void CodeGenerator::postvisit( ast::TupleAssignExpr const * expr ) {
[8941b6b]839 assertf( !options.genC, "TupleAssignExpr should not reach code generation." );
840 expr->stmtExpr->accept( *visitor );
841}
842
[0bd3faf]843void CodeGenerator::postvisit( ast::UntypedTupleExpr const * expr ) {
[8941b6b]844 assertf( !options.genC, "UntypedTupleExpr should not reach code generation." );
845 extension( expr );
846 output << "[";
847 genCommaList( expr->exprs );
848 output << "]";
849}
850
[0bd3faf]851void CodeGenerator::postvisit( ast::TupleExpr const * expr ) {
[8941b6b]852 assertf( !options.genC, "TupleExpr should not reach code generation." );
853 extension( expr );
854 output << "[";
855 genCommaList( expr->exprs );
856 output << "]";
857}
858
[0bd3faf]859void CodeGenerator::postvisit( ast::TupleIndexExpr const * expr ) {
[8941b6b]860 assertf( !options.genC, "TupleIndexExpr should not reach code generation." );
861 extension( expr );
862 expr->tuple->accept( *visitor );
863 output << "." << expr->index;
864}
865
[0bd3faf]866void CodeGenerator::postvisit( ast::TypeExpr const * expr ) {
[8941b6b]867 // TODO: Should there be an assertion there?
868 if ( !options.genC ) {
869 output << genType( expr->type, "", options );
870 }
871}
872
[0bd3faf]873void CodeGenerator::postvisit( ast::AsmExpr const * expr ) {
[8941b6b]874 if ( !expr->inout.empty() ) {
875 output << "[ " << expr->inout << " ] ";
876 }
877 expr->constraint->accept( *visitor );
878 output << " ( ";
879 expr->operand->accept( *visitor );
880 output << " )";
881}
882
[0bd3faf]883void CodeGenerator::postvisit( ast::CompoundLiteralExpr const * expr ) {
[8941b6b]884 //assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) );
885 assert( expr->result && expr->init.as<ast::ListInit>() );
886 output << "(" << genType( expr->result, "", options ) << ")";
887 expr->init->accept( *visitor );
888}
889
[0bd3faf]890void CodeGenerator::postvisit( ast::UniqueExpr const * expr ) {
[8941b6b]891 assertf( !options.genC, "UniqueExpr should not reach code generation." );
892 output << "unq<" << expr->id << ">{ ";
893 expr->expr->accept( *visitor );
894 output << " }";
895}
896
[0bd3faf]897void CodeGenerator::postvisit( ast::StmtExpr const * expr ) {
[8941b6b]898 auto stmts = expr->stmts->kids;
899 output << "({" << endl;
900 ++indent;
901 unsigned int numStmts = stmts.size();
902 unsigned int i = 0;
903 for ( ast::ptr<ast::Stmt> const & stmt : stmts ) {
904 output << indent << printLabels( stmt->labels );
905 if ( i + 1 == numStmts ) {
906 // Last statement in a statement expression needs to be handled
907 // specially - cannot cast to void, otherwise the expression
908 // statement has no value.
909 if ( ast::ExprStmt const * exprStmt = stmt.as<ast::ExprStmt>() ) {
910 exprStmt->expr->accept( *visitor );
911 output << ";" << endl;
912 ++i;
913 break;
914 }
915 }
916 stmt->accept( *visitor );
917 output << endl;
918 if ( wantSpacing( stmt ) ) output << endl;
919 ++i;
920 }
921 --indent;
922 output << indent << "})";
923}
924
[0bd3faf]925void CodeGenerator::postvisit( ast::ConstructorExpr const * expr ) {
[8941b6b]926 assertf( !options.genC, "ConstructorExpr should not reach code generation." );
927 expr->callExpr->accept( *visitor );
928}
929
[0bd3faf]930void CodeGenerator::postvisit( ast::DeletedExpr const * expr ) {
[8941b6b]931 assertf( !options.genC, "DeletedExpr should not reach code generation." );
932 expr->expr->accept( *visitor );
933}
934
[0bd3faf]935void CodeGenerator::postvisit( ast::DefaultArgExpr const * expr ) {
[8941b6b]936 assertf( !options.genC, "DefaultArgExpr should not reach code generation." );
937 expr->expr->accept( *visitor );
938}
939
[0bd3faf]940void CodeGenerator::postvisit( ast::GenericExpr const * expr ) {
[8941b6b]941 assertf( !options.genC, "GenericExpr should not reach code generation." );
942 output << "_Generic(";
943 expr->control->accept( *visitor );
944 output << ", ";
945 unsigned int numAssocs = expr->associations.size();
946 unsigned int i = 0;
947 for ( const ast::GenericExpr::Association & assoc : expr->associations ) {
948 if ( nullptr == assoc.type ) {
949 output << "default: ";
950 } else {
951 output << genType( assoc.type, "", options ) << ": ";
952 }
953 assoc.expr->accept( *visitor );
954 ++i;
955 if ( i != numAssocs ) output << ", ";
956 }
957 output << ")";
958}
959
[0bd3faf]960void CodeGenerator::postvisit( ast::CompoundStmt const * stmt ) {
[8941b6b]961 output << "{" << endl;
962
963 ++indent;
964 for ( auto kid : stmt->kids ) {
965 output << indent << printLabels( kid->labels );
966 kid->accept( *visitor );
967 output << endl;
968 if ( wantSpacing( kid ) ) output << endl;
969 }
970 --indent;
971
972 output << indent << "}";
973}
974
[0bd3faf]975void CodeGenerator::postvisit( ast::ExprStmt const * stmt ) {
[8941b6b]976 assert( stmt );
977 // Cast the top-level expression to void to reduce gcc warnings.
978 if ( options.genC ) {
979 ast::ptr<ast::Expr> expr = new ast::CastExpr( stmt->location, stmt->expr );
980 expr->accept( *visitor );
981 } else {
982 stmt->expr->accept( *visitor );
983 }
984 output << ";";
985}
986
[0bd3faf]987void CodeGenerator::postvisit( ast::AsmStmt const * stmt ) {
[8941b6b]988 output << "asm ";
989 if ( stmt->isVolatile ) output << "volatile ";
990 if ( !stmt->gotoLabels.empty() ) output << "goto ";
991 output << "( ";
992 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
993 output << " : ";
994 genCommaList( stmt->output );
995 output << " : ";
996 genCommaList( stmt->input );
997 output << " : ";
998 genCommaList( stmt->clobber );
999 if ( !stmt->gotoLabels.empty() ) {
1000 output << " : ";
1001 auto it = stmt->gotoLabels.begin();
1002 while (true) {
1003 output << *it++;
1004 if ( stmt->gotoLabels.end() == it ) break;
1005 output << ", ";
1006 }
1007 }
1008 output << " );";
1009}
1010
[0bd3faf]1011void CodeGenerator::postvisit( ast::AsmDecl const * decl ) {
[8941b6b]1012 output << "asm ";
1013 ast::AsmStmt const * stmt = decl->stmt;
1014 output << "( ";
1015 if ( stmt->instruction ) stmt->instruction->accept( *visitor );
1016 output << " )";
1017}
1018
[0bd3faf]1019void CodeGenerator::postvisit( ast::DirectiveDecl const * decl ) {
[8941b6b]1020 // endl prevents spaces before the directive.
1021 output << endl << decl->stmt->directive;
1022}
1023
[0bd3faf]1024void CodeGenerator::postvisit( ast::DirectiveStmt const * stmt ) {
[8941b6b]1025 // endl prevents spaces before the directive.
1026 output << endl << stmt->directive;
1027}
1028
[0bd3faf]1029void CodeGenerator::postvisit( ast::IfStmt const * stmt ) {
[8941b6b]1030 output << "if ( ";
1031 stmt->cond->accept( *visitor );
1032 output << " ) ";
1033
1034 stmt->then->accept( *visitor );
1035
1036 if ( nullptr != stmt->else_ ) {
1037 output << " else ";
1038 stmt->else_->accept( *visitor );
1039 }
1040}
1041
[0bd3faf]1042void CodeGenerator::postvisit( ast::SwitchStmt const * stmt ) {
[8941b6b]1043 output << "switch ( ";
1044 stmt->cond->accept( *visitor );
1045 output << " ) ";
1046
[69ab896]1047 output << "{" << endl;
[8941b6b]1048 ++indent;
1049 for ( auto node : stmt->cases ) {
1050 node->accept( *visitor );
1051 }
1052 --indent;
1053 output << indent << "}";
1054}
1055
[0bd3faf]1056void CodeGenerator::postvisit( ast::CaseClause const * clause ) {
[8941b6b]1057 updateLocation( clause );
1058 output << indent;
1059 if ( clause->isDefault() ) {
1060 output << "default";
1061 } else {
1062 output << "case ";
1063 clause->cond->accept( *visitor );
1064 }
1065 output << ":" << endl;
1066
1067 ++indent;
1068 for ( auto stmt : clause->stmts ) {
1069 output << indent << printLabels( stmt->labels ) ;
1070 stmt->accept( *visitor );
1071 output << endl;
1072 }
1073 --indent;
1074}
1075
[0bd3faf]1076void CodeGenerator::postvisit( ast::BranchStmt const * stmt ) {
[8941b6b]1077 switch ( stmt->kind ) {
1078 case ast::BranchStmt::Goto:
1079 if ( !stmt->target.empty() ) {
1080 output << "goto " << stmt->target;
1081 } else if ( nullptr != stmt->computedTarget ) {
1082 output << "goto *";
1083 stmt->computedTarget->accept( *visitor );
1084 }
1085 break;
1086 case ast::BranchStmt::Break:
1087 output << "break";
1088 break;
1089 case ast::BranchStmt::Continue:
1090 output << "continue";
1091 break;
1092 case ast::BranchStmt::FallThrough:
1093 case ast::BranchStmt::FallThroughDefault:
1094 assertf( !options.genC, "fallthru should not reach code generation." );
1095 output << "fallthru";
1096 break;
1097 default:
1098 assertf( false, "Bad BranchStmt value." );
1099 }
1100 // Print branch target for labelled break/continue/fallthru in debug mode.
1101 if ( !options.genC && stmt->kind != ast::BranchStmt::Goto ) {
1102 if ( !stmt->target.empty() ) {
1103 output << " " << stmt->target;
1104 } else if ( stmt->kind == ast::BranchStmt::FallThrough ) {
1105 output << " default";
1106 }
1107 }
1108 output << ";";
1109}
1110
[0bd3faf]1111void CodeGenerator::postvisit( ast::ReturnStmt const * stmt ) {
[8941b6b]1112 output << "return ";
1113 if ( stmt->expr ) stmt->expr->accept( *visitor );
1114 output << ";";
1115}
1116
[0bd3faf]1117void CodeGenerator::postvisit( ast::ThrowStmt const * stmt ) {
[8941b6b]1118 assertf( !options.genC, "ThrowStmt should not reach code generation." );
1119
1120 output << ((stmt->kind == ast::Terminate) ? "throw" : "throwResume");
1121 if ( stmt->expr ) {
1122 output << " ";
1123 stmt->expr->accept( *visitor );
1124 }
1125 if ( stmt->target ) {
1126 output << " _At ";
1127 stmt->target->accept( *visitor );
1128 }
1129 output << ";";
1130}
1131
[550446f]1132void CodeGenerator::postvisit( ast::TryStmt const * stmt ) {
1133 assertf( !options.genC, "TryStmt should not reach code generation." );
1134
1135 output << "try ";
1136 stmt->body->accept( *visitor );
1137 for ( ast::ptr<ast::CatchClause> const & handler : stmt->handlers ) {
1138 handler->accept( *visitor );
1139 }
1140 if ( stmt->finally ) stmt->finally->accept( *visitor );
1141}
1142
[0bd3faf]1143void CodeGenerator::postvisit( ast::CatchClause const * stmt ) {
[8941b6b]1144 assertf( !options.genC, "CatchClause should not reach code generation." );
1145
[550446f]1146 output << ((stmt->kind == ast::Terminate) ? " catch " : " catchResume ");
[8941b6b]1147 output << "( ";
1148 stmt->decl->accept( *visitor );
1149 if ( stmt->cond ) {
1150 output << " ; ";
1151 stmt->cond->accept( *visitor );
1152 }
1153 output << " ) ";
1154 stmt->body->accept( *visitor );
1155}
1156
[550446f]1157void CodeGenerator::postvisit( ast::FinallyClause const * clause ) {
1158 assertf( !options.genC, "FinallyClause should not reach code generation." );
1159
1160 output << " finally ";
1161 clause->body->accept( *visitor );
1162}
1163
[0bd3faf]1164void CodeGenerator::postvisit( ast::WaitForStmt const * stmt ) {
[8941b6b]1165 assertf( !options.genC, "WaitforStmt should not reach code generation." );
1166
1167 bool first = true;
1168 for ( ast::ptr<ast::WaitForClause> const & clause : stmt->clauses ) {
1169 if (first) { output << "or "; first = false; }
1170 if ( clause->when_cond ) {
1171 output << "when(";
[61e362f]1172 clause->when_cond->accept( *visitor );
[8941b6b]1173 output << ") ";
1174 }
1175 output << "waitfor(";
1176 clause->target->accept( *visitor );
1177 for ( ast::ptr<ast::Expr> const & expr : clause->target_args ) {
1178 output << ",";
1179 expr->accept( *visitor );
1180 }
1181 output << ") ";
1182 clause->stmt->accept( *visitor );
1183 }
1184
1185 if ( stmt->timeout_stmt ) {
1186 output << "or ";
1187 if ( stmt->timeout_cond ) {
1188 output << "when(";
1189 stmt->timeout_cond->accept( *visitor );
1190 output << ") ";
1191 }
1192 output << "timeout(";
1193 stmt->timeout_time->accept( *visitor );
1194 output << ") ";
1195 stmt->timeout_stmt->accept( *visitor );
1196 }
1197
1198 if ( stmt->else_stmt ) {
1199 output << "or ";
1200 if ( stmt->else_cond ) {
1201 output << "when(";
1202 stmt->else_cond->accept( *visitor );
1203 output << ")";
1204 }
1205 output << "else ";
1206 stmt->else_stmt->accept( *visitor );
1207 }
1208}
1209
[0bd3faf]1210void CodeGenerator::postvisit( ast::WithStmt const * stmt ) {
[8941b6b]1211 assertf( !options.genC, "WithStmt should not reach code generation." );
1212
1213 output << "with ( ";
1214 genCommaList( stmt->exprs );
1215 output << " ) ";
1216 stmt->stmt->accept( *visitor );
1217}
1218
[0bd3faf]1219void CodeGenerator::postvisit( ast::WhileDoStmt const * stmt ) {
[8941b6b]1220 if ( stmt->isDoWhile ) {
1221 output << "do";
1222 } else {
1223 output << "while (";
1224 stmt->cond->accept( *visitor );
1225 output << ")";
1226 }
1227 output << " ";
1228
[0bd3faf]1229 output << CodeGenerator::printLabels( stmt->body->labels );
[8941b6b]1230 stmt->body->accept( *visitor );
1231
1232 if ( stmt->isDoWhile ) {
1233 output << " while (";
1234 stmt->cond->accept( *visitor );
[88bc876]1235 output << ( ( nullptr == stmt->else_ ) ? ");" : ")" );
1236 }
1237 if ( stmt->else_ ) {
1238 output << " else ";
1239 stmt->else_->accept( *visitor );
[8941b6b]1240 }
1241}
1242
[0bd3faf]1243void CodeGenerator::postvisit( ast::ForStmt const * stmt ) {
[8941b6b]1244 // Initializer is always hoised so don't generate it.
1245 // TODO: Do an assertion check?
1246 output << "for (;";
1247
1248 if ( nullptr != stmt->cond ) {
1249 stmt->cond->accept( *visitor );
1250 }
1251 output << ";";
1252
1253 if ( nullptr != stmt->inc ) {
1254 // cast the top-level expression to void to reduce gcc warnings.
1255 ast::Expr * expr = new ast::CastExpr( stmt->inc );
1256 expr->accept( *visitor );
1257 }
1258 output << ") ";
1259
1260 if ( nullptr != stmt->body ) {
1261 output << printLabels( stmt->body->labels );
1262 stmt->body->accept( *visitor );
1263 }
[88bc876]1264
1265 if ( nullptr != stmt->else_ ) {
1266 assertf( !options.genC, "Loop else should not reach code generation." );
1267 output << " else ";
1268 stmt->else_->accept( *visitor );
1269 }
[8941b6b]1270}
1271
[0bd3faf]1272void CodeGenerator::postvisit( ast::NullStmt const * ) {
[8941b6b]1273 output << "/* null statement */ ;";
1274}
1275
[0bd3faf]1276void CodeGenerator::postvisit( ast::DeclStmt const * stmt ) {
[8941b6b]1277 stmt->decl->accept( *visitor );
1278
1279 if ( doSemicolon( stmt->decl ) ) output << ";";
1280}
1281
[0bd3faf]1282void CodeGenerator::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
[8941b6b]1283 assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." );
1284 stmt->callStmt->accept( *visitor );
1285}
1286
[0bd3faf]1287void CodeGenerator::postvisit( ast::MutexStmt const * stmt ) {
[8941b6b]1288 assertf( !options.genC, "MutexStmt should not reach code generation." );
1289 // TODO: But this isn't what a mutex statement looks like.
1290 stmt->stmt->accept( *visitor );
1291}
1292
[6e7ed0aa]1293std::string genName( ast::DeclWithType const * decl ) {
1294 if ( const OperatorInfo * opInfo = operatorLookup( decl->name ) ) {
1295 return opInfo->outputName;
1296 } else {
1297 return decl->name;
1298 }
1299}
[8941b6b]1300
1301} // namespace CodeGen
Note: See TracBrowser for help on using the repository browser.