source: src/CodeGen/GenType.cc @ 0589e83

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

Direct translation of code generation.

  • Property mode set to 100644
File size: 20.8 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// GenType.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Mon May 18 07:44:20 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri May 20 11:18:00 2022
13// Update Count     : 24
14//
15#include "GenType.h"
16
17#include <cassert>                // for assert, assertf
18#include <list>                   // for _List_iterator, _List_const_iterator
19#include <sstream>                // for operator<<, ostringstream, basic_os...
20
21#include "AST/Print.hpp"          // for print
22#include "AST/Vector.hpp"         // for vector
23#include "CodeGenerator.h"        // for CodeGenerator
24#include "CodeGeneratorNew.hpp"   // for CodeGenerator_new
25#include "SynTree/Declaration.h"  // for DeclarationWithType
26#include "SynTree/Expression.h"   // for Expression
27#include "SynTree/Type.h"         // for PointerType, Type, FunctionType
28#include "SynTree/Visitor.h"      // for Visitor
29
30namespace CodeGen {
31        struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
32                std::string typeString;
33                GenType( const std::string &typeString, const Options &options );
34
35                void previsit( BaseSyntaxNode * );
36                void postvisit( BaseSyntaxNode * );
37
38                void postvisit( FunctionType * funcType );
39                void postvisit( VoidType * voidType );
40                void postvisit( BasicType * basicType );
41                void postvisit( PointerType * pointerType );
42                void postvisit( ArrayType * arrayType );
43                void postvisit( ReferenceType * refType );
44                void postvisit( StructInstType * structInst );
45                void postvisit( UnionInstType * unionInst );
46                void postvisit( EnumInstType * enumInst );
47                void postvisit( TypeInstType * typeInst );
48                void postvisit( TupleType  * tupleType );
49                void postvisit( VarArgsType * varArgsType );
50                void postvisit( ZeroType * zeroType );
51                void postvisit( OneType * oneType );
52                void postvisit( GlobalScopeType * globalType );
53                void postvisit( TraitInstType * inst );
54                void postvisit( TypeofType * typeof );
55                void postvisit( VTableType * vtable );
56                void postvisit( QualifiedType * qualType );
57
58          private:
59                void handleQualifiers( Type *type );
60                std::string handleGeneric( ReferenceToType * refType );
61                void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
62
63                Options options;
64        };
65
66        std::string genType( Type *type, const std::string &baseString, const Options &options ) {
67                PassVisitor<GenType> gt( baseString, options );
68                std::ostringstream os;
69
70                if ( ! type->get_attributes().empty() ) {
71                        PassVisitor<CodeGenerator> cg( os, options );
72                        cg.pass.genAttributes( type->get_attributes() );
73                } // if
74
75                type->accept( gt );
76                return os.str() + gt.pass.typeString;
77        }
78
79        std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
80                return genType( type, baseString, Options(pretty, genC, lineMarks, false ) );
81        }
82
83        std::string genPrettyType( Type * type, const std::string & baseString ) {
84                return genType( type, baseString, true, false );
85        }
86
87        GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {}
88
89        // *** BaseSyntaxNode
90        void GenType::previsit( BaseSyntaxNode * ) {
91                // turn off automatic recursion for all nodes, to allow each visitor to
92                // precisely control the order in which its children are visited.
93                visit_children = false;
94        }
95
96        void GenType::postvisit( BaseSyntaxNode * node ) {
97                std::stringstream ss;
98                node->print( ss );
99                assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
100        }
101
102        void GenType::postvisit( VoidType * voidType ) {
103                typeString = "void " + typeString;
104                handleQualifiers( voidType );
105        }
106
107        void GenType::postvisit( BasicType * basicType ) {
108                BasicType::Kind kind = basicType->kind;
109                assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
110                typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
111                handleQualifiers( basicType );
112        }
113
114        void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {
115                std::ostringstream os;
116                if ( typeString != "" ) {
117                        if ( typeString[ 0 ] == '*' ) {
118                                os << "(" << typeString << ")";
119                        } else {
120                                os << typeString;
121                        } // if
122                } // if
123                os << "[";
124
125                if ( isStatic ) {
126                        os << "static ";
127                } // if
128                if ( qualifiers.is_const ) {
129                        os << "const ";
130                } // if
131                if ( qualifiers.is_volatile ) {
132                        os << "volatile ";
133                } // if
134                if ( qualifiers.is_restrict ) {
135                        os << "__restrict ";
136                } // if
137                if ( qualifiers.is_atomic ) {
138                        os << "_Atomic ";
139                } // if
140                if ( dimension != 0 ) {
141                        PassVisitor<CodeGenerator> cg( os, options );
142                        dimension->accept( cg );
143                } else if ( isVarLen ) {
144                        // no dimension expression on a VLA means it came in with the * token
145                        os << "*";
146                } // if
147                os << "]";
148
149                typeString = os.str();
150
151                base->accept( *visitor );
152        }
153
154        void GenType::postvisit( PointerType * pointerType ) {
155                assert( pointerType->base != 0);
156                if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
157                        genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
158                } else {
159                        handleQualifiers( pointerType );
160                        if ( typeString[ 0 ] == '?' ) {
161                                typeString = "* " + typeString;
162                        } else {
163                                typeString = "*" + typeString;
164                        } // if
165                        pointerType->base->accept( *visitor );
166                } // if
167        }
168
169        void GenType::postvisit( ArrayType * arrayType ) {
170                genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
171        }
172
173        void GenType::postvisit( ReferenceType * refType ) {
174                assert( 0 != refType->base );
175                assertf( ! options.genC, "Reference types should not reach code generation." );
176                handleQualifiers( refType );
177                typeString = "&" + typeString;
178                refType->base->accept( *visitor );
179        }
180
181        void GenType::postvisit( FunctionType * funcType ) {
182                std::ostringstream os;
183
184                if ( typeString != "" ) {
185                        if ( typeString[ 0 ] == '*' ) {
186                                os << "(" << typeString << ")";
187                        } else {
188                                os << typeString;
189                        } // if
190                } // if
191
192                /************* parameters ***************/
193
194                const std::list<DeclarationWithType *> &pars = funcType->parameters;
195
196                if ( pars.empty() ) {
197                        if ( funcType->get_isVarArgs() ) {
198                                os << "()";
199                        } else {
200                                os << "(void)";
201                        } // if
202                } else {
203                        PassVisitor<CodeGenerator> cg( os, options );
204                        os << "(" ;
205
206                        cg.pass.genCommaList( pars.begin(), pars.end() );
207
208                        if ( funcType->get_isVarArgs() ) {
209                                os << ", ...";
210                        } // if
211                        os << ")";
212                } // if
213
214                typeString = os.str();
215
216                if ( funcType->returnVals.size() == 0 ) {
217                        typeString = "void " + typeString;
218                } else {
219                        funcType->returnVals.front()->get_type()->accept( *visitor );
220                } // if
221
222                // add forall
223                if( ! funcType->forall.empty() && ! options.genC ) {
224                        // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
225                        std::ostringstream os;
226                        PassVisitor<CodeGenerator> cg( os, options );
227                        os << "forall(";
228                        cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
229                        os << ")" << std::endl;
230                        typeString = os.str() + typeString;
231                }
232        }
233
234        std::string GenType::handleGeneric( ReferenceToType * refType ) {
235                if ( ! refType->parameters.empty() ) {
236                        std::ostringstream os;
237                        PassVisitor<CodeGenerator> cg( os, options );
238                        os << "(";
239                        cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
240                        os << ") ";
241                        return os.str();
242                }
243                return "";
244        }
245
246        void GenType::postvisit( StructInstType * structInst )  {
247                typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
248                if ( options.genC ) typeString = "struct " + typeString;
249                handleQualifiers( structInst );
250        }
251
252        void GenType::postvisit( UnionInstType * unionInst ) {
253                typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
254                if ( options.genC ) typeString = "union " + typeString;
255                handleQualifiers( unionInst );
256        }
257
258        void GenType::postvisit( EnumInstType * enumInst ) {
259                if ( enumInst->baseEnum && enumInst->baseEnum->base ) {
260                        typeString = genType(enumInst->baseEnum->base, typeString, options);
261                } else {
262                        typeString = enumInst->name + " " + typeString;
263                        if ( options.genC ) {
264                                typeString = "enum " + typeString;
265                        }
266                }
267                handleQualifiers( enumInst );
268        }
269
270        void GenType::postvisit( TypeInstType * typeInst ) {
271                assertf( ! options.genC, "Type instance types should not reach code generation." );
272                typeString = typeInst->name + " " + typeString;
273                handleQualifiers( typeInst );
274        }
275
276        void GenType::postvisit( TupleType * tupleType ) {
277                assertf( ! options.genC, "Tuple types should not reach code generation." );
278                unsigned int i = 0;
279                std::ostringstream os;
280                os << "[";
281                for ( Type * t : *tupleType ) {
282                        i++;
283                        os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");
284                }
285                os << "] ";
286                typeString = os.str() + typeString;
287        }
288
289        void GenType::postvisit( VarArgsType * varArgsType ) {
290                typeString = "__builtin_va_list " + typeString;
291                handleQualifiers( varArgsType );
292        }
293
294        void GenType::postvisit( ZeroType * zeroType ) {
295                // ideally these wouldn't hit codegen at all, but should be safe to make them ints
296                typeString = (options.pretty ? "zero_t " : "long int ") + typeString;
297                handleQualifiers( zeroType );
298        }
299
300        void GenType::postvisit( OneType * oneType ) {
301                // ideally these wouldn't hit codegen at all, but should be safe to make them ints
302                typeString = (options.pretty ? "one_t " : "long int ") + typeString;
303                handleQualifiers( oneType );
304        }
305
306        void GenType::postvisit( GlobalScopeType * globalType ) {
307                assertf( ! options.genC, "Global scope type should not reach code generation." );
308                handleQualifiers( globalType );
309        }
310
311        void GenType::postvisit( TraitInstType * inst ) {
312                assertf( ! options.genC, "Trait types should not reach code generation." );
313                typeString = inst->name + " " + typeString;
314                handleQualifiers( inst );
315        }
316
317        void GenType::postvisit( TypeofType * typeof ) {
318                std::ostringstream os;
319                PassVisitor<CodeGenerator> cg( os, options );
320                os << "typeof(";
321                typeof->expr->accept( cg );
322                os << ") " << typeString;
323                typeString = os.str();
324                handleQualifiers( typeof );
325        }
326
327        void GenType::postvisit( VTableType * vtable ) {
328                assertf( ! options.genC, "Virtual table types should not reach code generation." );
329                std::ostringstream os;
330                os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString;
331                typeString = os.str();
332                handleQualifiers( vtable );
333        }
334
335        void GenType::postvisit( QualifiedType * qualType ) {
336                assertf( ! options.genC, "Qualified types should not reach code generation." );
337                std::ostringstream os;
338                os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString;
339                typeString = os.str();
340                handleQualifiers( qualType );
341        }
342
343        void GenType::handleQualifiers( Type * type ) {
344                if ( type->get_const() ) {
345                        typeString = "const " + typeString;
346                } // if
347                if ( type->get_volatile() ) {
348                        typeString = "volatile " + typeString;
349                } // if
350                if ( type->get_restrict() ) {
351                        typeString = "__restrict " + typeString;
352                } // if
353                if ( type->get_atomic() ) {
354                        typeString = "_Atomic " + typeString;
355                } // if
356        }
357
358namespace {
359
360#warning Remove the _new when old version is removed.
361struct GenType_new :
362                public ast::WithShortCircuiting,
363                public ast::WithVisitorRef<GenType_new> {
364        std::string result;
365        GenType_new( const std::string &typeString, const Options &options );
366
367        void previsit( ast::Node const * );
368        void postvisit( ast::Node const * );
369
370        void postvisit( ast::FunctionType const * type );
371        void postvisit( ast::VoidType const * type );
372        void postvisit( ast::BasicType const * type );
373        void postvisit( ast::PointerType const * type );
374        void postvisit( ast::ArrayType const * type );
375        void postvisit( ast::ReferenceType const * type );
376        void postvisit( ast::StructInstType const * type );
377        void postvisit( ast::UnionInstType const * type );
378        void postvisit( ast::EnumInstType const * type );
379        void postvisit( ast::TypeInstType const * type );
380        void postvisit( ast::TupleType const * type );
381        void postvisit( ast::VarArgsType const * type );
382        void postvisit( ast::ZeroType const * type );
383        void postvisit( ast::OneType const * type );
384        void postvisit( ast::GlobalScopeType const * type );
385        void postvisit( ast::TraitInstType const * type );
386        void postvisit( ast::TypeofType const * type );
387        void postvisit( ast::VTableType const * type );
388        void postvisit( ast::QualifiedType const * type );
389
390private:
391        void handleQualifiers( ast::Type const *type );
392        std::string handleGeneric( ast::BaseInstType const * type );
393        void genArray( const ast::CV::Qualifiers &qualifiers, ast::Type const *base, ast::Expr const *dimension, bool isVarLen, bool isStatic );
394        std::string genParamList( const ast::vector<ast::Type> & );
395
396        Options options;
397};
398
399GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}
400
401void GenType_new::previsit( ast::Node const * ) {
402        // Turn off automatic recursion for all nodes, to allow each visitor to
403        // precisely control the order in which its children are visited.
404        visit_children = false;
405}
406
407void GenType_new::postvisit( ast::Node const * node ) {
408        std::stringstream ss;
409        ast::print( ss, node );
410        assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
411}
412
413void GenType_new::postvisit( ast::VoidType const * type ) {
414        result = "void " + result;
415        handleQualifiers( type );
416}
417
418void GenType_new::postvisit( ast::BasicType const * type ) {
419        ast::BasicType::Kind kind = type->kind;
420        assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES );
421        result = std::string( ast::BasicType::typeNames[kind] ) + " " + result;
422        handleQualifiers( type );
423}
424
425void GenType_new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {
426        std::ostringstream os;
427        if ( result != "" ) {
428                if ( result[ 0 ] == '*' ) {
429                        os << "(" << result << ")";
430                } else {
431                        os << result;
432                }
433        }
434        os << "[";
435        if ( isStatic ) {
436                os << "static ";
437        }
438        if ( qualifiers.is_const ) {
439                os << "const ";
440        }
441        if ( qualifiers.is_volatile ) {
442                os << "volatile ";
443        }
444        if ( qualifiers.is_restrict ) {
445                os << "__restrict ";
446        }
447        if ( qualifiers.is_atomic ) {
448                os << "_Atomic ";
449        }
450        if ( dimension != 0 ) {
451                ast::Pass<CodeGenerator_new>::read( dimension, os, options );
452        } else if ( isVarLen ) {
453                // no dimension expression on a VLA means it came in with the * token
454                os << "*";
455        }
456        os << "]";
457
458        result = os.str();
459
460        base->accept( *visitor );
461}
462
463void GenType_new::postvisit( ast::PointerType const * type ) {
464        if ( type->isStatic || type->isVarLen || type->dimension ) {
465                genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
466        } else {
467                handleQualifiers( type );
468                if ( result[ 0 ] == '?' ) {
469                        result = "* " + result;
470                } else {
471                        result = "*" + result;
472                }
473                type->base->accept( *visitor );
474        }
475}
476
477void GenType_new::postvisit( ast::ArrayType const * type ) {
478        genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
479}
480
481void GenType_new::postvisit( ast::ReferenceType const * type ) {
482        assertf( !options.genC, "Reference types should not reach code generation." );
483        handleQualifiers( type );
484        result = "&" + result;
485        type->base->accept( *visitor );
486}
487
488void GenType_new::postvisit( ast::FunctionType const * type ) {
489        std::ostringstream os;
490
491        if ( result != "" ) {
492                if ( result[ 0 ] == '*' ) {
493                        os << "(" << result << ")";
494                } else {
495                        os << result;
496                }
497        }
498
499        if ( type->params.empty() ) {
500                if ( type->isVarArgs ) {
501                        os << "()";
502                } else {
503                        os << "(void)";
504                }
505        } else {
506                os << "(" ;
507
508                os << genParamList( type->params );
509
510                if ( type->isVarArgs ) {
511                        os << ", ...";
512                }
513                os << ")";
514        }
515
516        result = os.str();
517
518        if ( type->returns.size() == 0 ) {
519                result = "void " + result;
520        } else {
521                type->returns.front()->accept( *visitor );
522        }
523
524        // Add forall clause.
525        if( !type->forall.empty() && !options.genC ) {
526                //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." );
527                std::ostringstream os;
528                ast::Pass<CodeGenerator_new> cg( os, options );
529                os << "forall(";
530                cg.core.genCommaList( type->forall );
531                os << ")" << std::endl;
532                result = os.str() + result;
533        }
534}
535
536std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) {
537        if ( !type->params.empty() ) {
538                std::ostringstream os;
539                ast::Pass<CodeGenerator_new> cg( os, options );
540                os << "(";
541                cg.core.genCommaList( type->params );
542                os << ") ";
543                return os.str();
544        }
545        return "";
546}
547
548void GenType_new::postvisit( ast::StructInstType const * type )  {
549        result = type->name + handleGeneric( type ) + " " + result;
550        if ( options.genC ) result = "struct " + result;
551        handleQualifiers( type );
552}
553
554void GenType_new::postvisit( ast::UnionInstType const * type ) {
555        result = type->name + handleGeneric( type ) + " " + result;
556        if ( options.genC ) result = "union " + result;
557        handleQualifiers( type );
558}
559
560void GenType_new::postvisit( ast::EnumInstType const * type ) {
561        if ( type->base && type->base->base ) {
562                result = genType( type->base->base, result, options );
563        } else {
564                result = type->name + " " + result;
565                if ( options.genC ) {
566                        result = "enum " + result;
567                }
568        }
569        handleQualifiers( type );
570}
571
572void GenType_new::postvisit( ast::TypeInstType const * type ) {
573        assertf( !options.genC, "TypeInstType should not reach code generation." );
574        result = type->name + " " + result;
575        handleQualifiers( type );
576}
577
578void GenType_new::postvisit( ast::TupleType const * type ) {
579        assertf( !options.genC, "TupleType should not reach code generation." );
580        unsigned int i = 0;
581        std::ostringstream os;
582        os << "[";
583        for ( ast::ptr<ast::Type> const & t : type->types ) {
584                i++;
585                os << genType( t, "", options ) << (i == type->size() ? "" : ", ");
586        }
587        os << "] ";
588        result = os.str() + result;
589}
590
591void GenType_new::postvisit( ast::VarArgsType const * type ) {
592        result = "__builtin_va_list " + result;
593        handleQualifiers( type );
594}
595
596void GenType_new::postvisit( ast::ZeroType const * type ) {
597        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
598        result = (options.pretty ? "zero_t " : "long int ") + result;
599        handleQualifiers( type );
600}
601
602void GenType_new::postvisit( ast::OneType const * type ) {
603        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
604        result = (options.pretty ? "one_t " : "long int ") + result;
605        handleQualifiers( type );
606}
607
608void GenType_new::postvisit( ast::GlobalScopeType const * type ) {
609        assertf( !options.genC, "GlobalScopeType should not reach code generation." );
610        handleQualifiers( type );
611}
612
613void GenType_new::postvisit( ast::TraitInstType const * type ) {
614        assertf( !options.genC, "TraitInstType should not reach code generation." );
615        result = type->name + " " + result;
616        handleQualifiers( type );
617}
618
619void GenType_new::postvisit( ast::TypeofType const * type ) {
620        std::ostringstream os;
621        os << "typeof(";
622        ast::Pass<CodeGenerator_new>::read( type, os, options );
623        os << ") " << result;
624        result = os.str();
625        handleQualifiers( type );
626}
627
628void GenType_new::postvisit( ast::VTableType const * type ) {
629        assertf( !options.genC, "Virtual table types should not reach code generation." );
630        std::ostringstream os;
631        os << "vtable(" << genType( type->base, "", options ) << ") " << result;
632        result = os.str();
633        handleQualifiers( type );
634}
635
636void GenType_new::postvisit( ast::QualifiedType const * type ) {
637        assertf( !options.genC, "QualifiedType should not reach code generation." );
638        std::ostringstream os;
639        os << genType( type->parent, "", options ) << "." << genType( type->child, "", options ) << result;
640        result = os.str();
641        handleQualifiers( type );
642}
643
644void GenType_new::handleQualifiers( ast::Type const * type ) {
645        if ( type->is_const() ) {
646                result = "const " + result;
647        }
648        if ( type->is_volatile() ) {
649                result = "volatile " + result;
650        }
651        if ( type->is_restrict() ) {
652                result = "__restrict " + result;
653        }
654        if ( type->is_atomic() ) {
655                result = "_Atomic " + result;
656        }
657}
658
659std::string GenType_new::genParamList( const ast::vector<ast::Type> & range ) {
660        auto cur = range.begin();
661        auto end = range.end();
662        if ( cur == end ) return "";
663        std::ostringstream oss;
664        for ( unsigned int i = 0 ; ; ++i ) {
665                oss << genType( *cur++, "__param_" + std::to_string(i), options );
666                if ( cur == end ) break;
667                oss << ", ";
668        }
669        return oss.str();
670}
671
672} // namespace
673
674std::string genType( ast::Type const * type, const std::string & base, const Options & options ) {
675        std::ostringstream os;
676        if ( !type->attributes.empty() ) {
677                ast::Pass<CodeGenerator_new> cg( os, options );
678                cg.core.genAttributes( type->attributes );
679        }
680
681        return os.str() + ast::Pass<GenType_new>::read( type, base, options );
682}
683
684std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) {
685        return ast::Pass<GenType_new>::read( type, base, options );
686}
687
688} // namespace CodeGen
689
690// Local Variables: //
691// tab-width: 4 //
692// mode: c++ //
693// compile-command: "make install" //
694// End: //
Note: See TracBrowser for help on using the repository browser.