source: src/CodeGen/CodeGenerator.cpp @ c7ebbec

Last change on this file since c7ebbec was c7ebbec, checked in by Andrew Beach <ajbeach@…>, 5 months ago

Reorganization of Linkage::Spec. is_mangled represented two properties with is_gcc_builtin separating them in one case. The second property is_overloadable which replaces is_gcc_builtin.

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