source: src/CodeGen/FixMain.cc @ bef4f1a

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

Translation of the fix main pass to the new ast data structures.

  • Property mode set to 100644
File size: 6.0 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// FixMain.cc --
8//
9// Author           : Thierry Delisle
10// Created On       : Thr Jan 12 14:11:09 2017
11// Last Modified By :
12// Last Modified On :
13// Update Count     : 0
14//
15
16#include "FixMain.h"
17
18#include <cassert>                 // for assert, assertf
19#include <fstream>                 // for operator<<, basic_ostream::operator<<
20#include <list>                    // for list
21#include <string>                  // for operator<<
22
23#include "AST/Decl.hpp"
24#include "AST/Pass.hpp"
25#include "AST/Type.hpp"
26#include "AST/Vector.hpp"
27#include "Common/PassVisitor.h"
28#include "Common/SemanticError.h"  // for SemanticError
29#include "CodeGen/GenType.h"       // for GenType
30#include "SynTree/Declaration.h"   // for FunctionDecl, operator<<
31#include "SynTree/Type.h"          // for FunctionType
32#include "SymTab/Mangler.h"
33
34namespace CodeGen {
35
36namespace {
37
38struct FindMainCore {
39        FunctionDecl * main_signature = nullptr;
40
41        void previsit( FunctionDecl * decl ) {
42                if ( FixMain::isMain( decl ) ) {
43                        if ( main_signature ) {
44                                SemanticError( decl, "Multiple definition of main routine\n" );
45                        }
46                        main_signature = decl;
47                }
48        }
49};
50
51struct FindMainCore_new {
52        ast::FunctionDecl const * main_declaration = nullptr;
53
54        void previsit( ast::FunctionDecl const * decl ) {
55                if ( FixMain::isMain( decl ) ) {
56                        if ( main_declaration ) {
57                                SemanticError( decl, "Multiple definition of main routine\n" );
58                        }
59                        main_declaration = decl;
60                }
61        }
62};
63
64std::string genTypeAt( const ast::vector<ast::Type> & types, size_t at ) {
65        return genType( types[at], "", Options( false, false, false, false ) );
66}
67
68}
69
70        template<typename container>
71        std::string genTypeAt(const container& p, size_t idx) {
72                return genType((*std::next(p.begin(), idx))->get_type(), "");
73        }
74
75        void FixMain::fix( std::list< Declaration * > & translationUnit,
76                        std::ostream &os, const char* bootloader_filename ) {
77                PassVisitor< FindMainCore > main_finder;
78                acceptAll( translationUnit, main_finder );
79                FunctionDecl * main_signature = main_finder.pass.main_signature;
80
81                if( main_signature ) {
82                        os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
83                        main_signature->mangleName = SymTab::Mangler::mangle(main_signature);
84
85                        os << main_signature->get_scopedMangleName() << "(";
86                        const auto& params = main_signature->get_functionType()->get_parameters();
87                        switch(params.size()) {
88                                case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;
89                                case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;
90                                case 0: break;
91                                default : assert(false);
92                        }
93                        os << "); }\n";
94
95                        std::ifstream bootloader(bootloader_filename, std::ios::in);
96                        assertf( bootloader.is_open(), "cannot open bootloader.c\n" );
97                        os << bootloader.rdbuf();
98                }
99        }
100
101namespace {
102
103ast::ObjectDecl * makeIntObj(){
104        return new ast::ObjectDecl( CodeLocation(), "",
105                new ast::BasicType( ast::BasicType::SignedInt ) );
106}
107
108ast::ObjectDecl * makeCharStarStarObj() {
109        return new ast::ObjectDecl( CodeLocation(), "",
110                new ast::PointerType(
111                        new ast::PointerType(
112                                new ast::BasicType( ast::BasicType::Char ) ) ) );
113}
114
115std::string getMangledNameOfMain(
116                ast::vector<ast::DeclWithType> && params, ast::ArgumentFlag isVarArgs ) {
117        ast::ptr<ast::FunctionDecl> decl = new ast::FunctionDecl(
118                CodeLocation(),
119                "main",
120                ast::vector<ast::TypeDecl>(),
121                ast::vector<ast::DeclWithType>(),
122                std::move( params ),
123                { makeIntObj() },
124                nullptr,
125                ast::Storage::Classes(),
126                ast::Linkage::Spec(),
127                ast::vector<ast::Attribute>(),
128                ast::Function::Specs(),
129                isVarArgs
130        );
131        return Mangle::mangle( decl.get() );
132}
133
134std::string getMangledNameOf0ParameterMain() {
135        return getMangledNameOfMain( {}, ast::VariableArgs );
136}
137
138std::string getMangledNameOf2ParameterMain() {
139        return getMangledNameOfMain( {
140                makeIntObj(),
141                makeCharStarStarObj(),
142        }, ast::FixedArgs );
143}
144
145bool is_main( const std::string & mangled_name ) {
146        // This breaks if you move it out of the function.
147        static const std::string mangled_mains[] = {
148                getMangledNameOf0ParameterMain(),
149                getMangledNameOf2ParameterMain(),
150                //getMangledNameOf3ParameterMain(),
151        };
152
153        for ( auto main_name : mangled_mains ) {
154                if ( main_name == mangled_name ) return true;
155        }
156        return false;
157}
158
159} // namespace
160
161bool FixMain::isMain( FunctionDecl * decl ) {
162        if ( std::string("main") != decl->name ) {
163                return false;
164        }
165        return is_main( SymTab::Mangler::mangle( decl, true, true ) );
166}
167
168bool FixMain::isMain( const ast::FunctionDecl * decl ) {
169        if ( std::string("main") != decl->name ) {
170                return false;
171        }
172        return is_main( Mangle::mangle( decl, Mangle::Type ) );
173}
174
175void FixMain::fix( ast::TranslationUnit & translationUnit,
176                std::ostream &os, const char * bootloader_filename ) {
177
178        ast::Pass<FindMainCore_new> main_finder;
179        ast::accept_all( translationUnit, main_finder );
180        if ( nullptr == main_finder.core.main_declaration ) return;
181
182        ast::FunctionDecl * main_declaration =
183                ast::mutate( main_finder.core.main_declaration );
184
185        main_declaration->mangleName = Mangle::mangle( main_declaration );
186
187        os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
188        os << main_declaration->scopedMangleName() << "(";
189        const auto& params = main_declaration->type->params;
190        switch ( params.size() ) {
191                case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;
192                case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;
193                case 0: break;
194                default : assert(false);
195        }
196        os << "); }\n";
197
198        std::ifstream bootloader( bootloader_filename, std::ios::in );
199        assertf( bootloader.is_open(), "cannot open bootloader.c\n" );
200        os << bootloader.rdbuf();
201}
202
203} // namespace CodeGen
Note: See TracBrowser for help on using the repository browser.