source: src/CodeGen/CodeGeneratorNew.cpp@ 8941b6b

Last change on this file since 8941b6b was 8941b6b, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Direct translation of code generation.

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