source: src/CodeGen/CodeGeneratorNew.cpp @ 3c4003b9

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

Box pass Eraser now removes the polymorphic arguments now that the functions are no longer actually polymorphic.

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