#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; ptr< codegen::Function > getOrCreateFunc( const Context& c, const builtins::Func& func ); ptr< codegen::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< ptr< codegen::Value > >; ptr< storage_type > temporaries; Stack stack; }; static llvm::BasicBlock* GetOrCreateLLVMBB( State& st, const ptr< cir::BasicBlock >& pBB ); ptr< codegen::Function > buildFuncProto( const Context& c, const builtins::Func& func, const string& name, llvm::Function::LinkageTypes linkageType ); 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 ); ptr< codegen::Value > buildValue( State& st, const eir::Value& val ); ptr< codegen::Value > buildConstant( State& st, const eir::Value& val ); ptr< codegen::Value > buildConstantPointer( State& st, const builtins::PointerType& ptType, const eir::Value& v ); template< typename F > bool buildUnaryInstruction( State& st, F&& impl ); template< typename F > bool buildBinaryInstruction( State& st, F&& impl ); 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::PushConstant& 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::IsPrefixOf& 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& ); bool buildInstruction( State& st, const cir::Placeholder& ); bool buildInstruction( State& st, const cir::PHOverrideSet& ); bool buildInstruction( State& st, const cir::PHOverrideClear& ); bool buildInstruction( State& st, const cir::GhostCall& ); bool buildInstruction( State& st, const cir::ForAllSetup& ); bool buildInstruction( State& st, const cir::ForAll& ); bool buildInstruction( State& st, const cir::PushType& ); bool buildInstruction( State& st, const cir::PushStringId& ); bool buildInstruction( State& st, const cir::CallCheck& ); 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; } ptr< codegen::Value > buildAlloca( State& st, const codegen::Type* type ); 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