source: src/CodeGen/CodeGenerator.cpp @ cc0aa8c

Last change on this file since cc0aa8c was 661e7b0, checked in by Andrew Beach <ajbeach@…>, 3 months ago

After a years (or at least half a year) the CodeLocation? optimization is merged in. Added Symbol (using Racket's name for interned strings), and used it for CodeLocation? file names. The optimizes for the high number of copies - both instances with the same value and copy operations - and consistently brings down runtime by a few percent.

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