source: src/CodeGen/CodeGenerator.cpp@ 4d5c5b6a

Last change on this file since 4d5c5b6a was 7959e56, checked in by Michael Brooks <mlbrooks@…>, 8 months ago

Eliminate libcfa-build warnings of missing int-to-pointer casts.

Replace a zero_t variable use with literal 0 when it's an argument to an intrinsic and we're generating final C code. Partially revert e0330d2cd1a. Such intrinsics are initialization/assignment of pointers; using the variable implies a missing cast, while using literal 0 needs no cast.

CodeGenerator.hpp
CodeGenerator.cpp

Put attibute unused on all zero_t/one_t object decls. It is needed on those whose uses are rewritten by the rule above.

Generate.cpp

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