source: src/CodeGen/CodeGeneratorNew.cpp @ 8941b6b

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

Direct translation of code generation.

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