source: src/CodeGen/CodeGenerator.cpp @ 08e0d65

Last change on this file since 08e0d65 was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 2 months ago

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

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