#ifndef GOOSE_CODEGEN_MODULE_H #define GOOSE_CODEGEN_MODULE_H namespace llvm { class TargetMachine; } namespace goose::codegen { class Module { public: Module( const string& name ); bool setupTarget(); void dumpAsLlvmIr( const string& filename ) const; llvm::FunctionType* getOrCreateFuncType( const Context& c, const builtins::FuncType& ftype ); llvm::Function* buildFuncProto( const Context& c, const builtins::Func& func, const string& name, llvm::Function::LinkageTypes linkageType ); llvm::Function* getOrCreateFunc( const Context& c, const builtins::Func& func ); llvm::Function* getOrCreateFunc( const Context& c, const builtins::Func& func, const string& name, llvm::Function::LinkageTypes linkageType ); void runOptimizationPasses(); bool emitToFile( const string& filename, llvm::CodeGenFileType type ); private: struct State { State( const Context& c, size_t numVars, llvm::Function* f ) : context( c ), llvmFunc( f ), temporaries( make_shared< storage_type >( numVars ) ) {} const Context& context; llvm::Function* llvmFunc = nullptr; llvm::BasicBlock* allocaBasicBlock = nullptr; llvm::AllocaInst* lastEmittedAlloca = nullptr; using storage_type = cir::TempStorage< NullInit< llvm::Value* > >; ptr< storage_type > temporaries; Stack stack; }; static llvm::BasicBlock* GetOrCreateLLVMBB( State& st, const ptr< cir::BasicBlock >& pBB ); llvm::Function* getCurrentFunction() const { return m_llvmBuilder.GetInsertBlock()->getParent(); } llvm::BasicBlock* buildCFG( State& st, llvm::Function* llvmFunc, const ptr< cir::CFG >& pCFG ); llvm::BasicBlock* buildBasicBlock( State& st, const ptr< cir::BasicBlock >& pBB ); llvm::Value* buildValue( State& st, const Value& val ); llvm::Constant* buildConstant( State& st, const Value& val ); llvm::Constant* buildConstantPointer( State& st, const builtins::PointerType& ptType, const Value& v ); bool buildInstruction( State& st, const cir::InstrSeq& is ); bool buildInstruction( State& st, const cir::Instruction& instr ); bool buildInstruction( State& st, const monostate& ); bool buildInstruction( State& st, const cir::Call& call ); bool buildInstruction( State& st, const cir::Constant& ct ); bool buildInstruction( State& st, const cir::VarAddr& va ); bool buildInstruction( State& st, const cir::TempAddr& ta ); bool buildInstruction( State& st, const cir::Select& s ); bool buildInstruction( State& st, const cir::CreateTemporary& ct ); bool buildInstruction( State& st, const cir::GetTemporary& gt ); bool buildInstruction( State& st, const cir::AllocVar& av ); bool buildInstruction( State& st, const cir::Load& load ); bool buildInstruction( State& st, const cir::Store& store ); bool buildInstruction( State& st, const cir::Phi& p ); bool buildInstruction( State& st, const cir::Not& uo ); bool buildInstruction( State& st, const cir::And& bo ); bool buildInstruction( State& st, const cir::Or& bo ); bool buildInstruction( State& st, const cir::Xor& bo ); bool buildInstruction( State& st, const cir::Implies& bo ); bool buildInstruction( State& st, const cir::Shl& bo ); bool buildInstruction( State& st, const cir::LShr& bo ); bool buildInstruction( State& st, const cir::AShr& bo ); bool buildInstruction( State& st, const cir::Add& bo ); bool buildInstruction( State& st, const cir::Sub& bo ); bool buildInstruction( State& st, const cir::Mul& bo ); bool buildInstruction( State& st, const cir::UDiv& bo ); bool buildInstruction( State& st, const cir::SDiv& bo ); bool buildInstruction( State& st, const cir::URem& bo ); bool buildInstruction( State& st, const cir::SRem& bo ); bool buildInstruction( State& st, const cir::Eq& bo ); bool buildInstruction( State& st, const cir::Neq& bo ); bool buildInstruction( State& st, const cir::UGT& bo ); bool buildInstruction( State& st, const cir::UGE& bo ); bool buildInstruction( State& st, const cir::ULT& bo ); bool buildInstruction( State& st, const cir::ULE& bo ); bool buildInstruction( State& st, const cir::SGT& bo ); bool buildInstruction( State& st, const cir::SGE& bo ); bool buildInstruction( State& st, const cir::SLT& bo ); bool buildInstruction( State& st, const cir::SLE& bo ); bool buildInstruction( State& st, const cir::Assert& ass ); bool buildInstruction( State& st, const cir::Placeholder& ph ); bool buildInstruction( State& st, const cir::PHOverrideSet& phos ); bool buildInstruction( State& st, const cir::PHOverrideClear& phoc ); bool buildInstruction( State& st, const cir::GhostCall& gc ); bool buildTerminator( State& st, const cir::Terminator& terminator ); bool buildTerminator( State& st, const cir::RetVoid& r ); bool buildTerminator( State& st, const cir::Ret& r ); bool buildTerminator( State& st, const cir::Branch& b ); bool buildTerminator( State& st, const cir::CondBranch& cb ); bool buildTerminator( State& st, const cir::GhostBranch& gb ); template< typename T > bool buildTerminator( State& st, const T& t ) { return false; } llvm::Value* buildAlloca( State& st, llvm::Type* type ); llvm::Value* createTemporary( State& st, uint32_t index, llvm::Value* pValue ) const; llvm::Module m_llvmModule; llvm::DataLayout m_dataLayout; llvm::IRBuilder<> m_llvmBuilder; llvm::TargetMachine* m_targetMachine = nullptr; unordered_map< string, llvm::GlobalVariable* > m_strings; uint32_t m_nextAggregateID = 0; }; } #endif