source: src/CodeGen/CodeGenerator.cpp @ 454aab2

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

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

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