#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 Infos
{
Infos( const Context& c ) : context( c ) {}
const Context& context;
llvm::BasicBlock* allocaBasicBlock = nullptr;
llvm::AllocaInst* lastEmittedAlloca = nullptr;
using storage_type = llr::TempStorage< NullInit< llvm::Value* > >;
ptr< storage_type > temporaries = make_shared< storage_type >();
};
llvm::Function* getCurrentFunction() const
{
return m_llvmBuilder.GetInsertBlock()->getParent();
}
llvm::BasicBlock* buildCFG( Infos& inf, llvm::Function* llvmFunc, const ptr< llr::CFG >& pCFG );
llvm::BasicBlock* buildBasicBlock( Infos& inf, const ptr< llr::BasicBlock >& pBB );
llvm::Value* buildValue( Infos& inf, const Value& val );
llvm::Value* buildInstruction( Infos& inf, const llr::Instruction& instr );
llvm::Value* buildInstruction( Infos& inf, const llr::Call& call );
llvm::Value* buildInstruction( Infos& inf, const llr::CreateTemporary& ct );
llvm::Value* buildInstruction( Infos& inf, const llr::GetTemporary& gt );
llvm::Value* buildInstruction( Infos& inf, const llr::AllocVar& av );
llvm::Value* buildInstruction( Infos& inf, const llr::GetVar& gv );
llvm::Value* buildInstruction( Infos& inf, const llr::SetVar& sv );
llvm::Value* buildInstruction( Infos& inf, const llr::Load& load );
llvm::Value* buildInstruction( Infos& inf, const llr::Store& store );
llvm::Value* buildInstruction( Infos& inf, const llr::Phi& p );
llvm::Value* buildInstruction( Infos& inf, const llr::LoadConstStr& lcs );
llvm::Value* buildInstruction( Infos& inf, const llr::Not& uo );
llvm::Value* buildInstruction( Infos& inf, const llr::And& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Or& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Xor& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Shl& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::LShr& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::AShr& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Add& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Sub& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Mul& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::UDiv& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::SDiv& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::URem& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::SRem& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Eq& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Neq& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::UGT& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::UGE& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::ULT& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::ULE& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::SGT& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::SGE& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::SLT& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::SLE& bo );
llvm::Value* buildInstruction( Infos& inf, const llr::Assert& ass );
llvm::Value* buildInstruction( Infos& inf, const llr::Placeholder& ph );
bool buildTerminator( Infos& inf, const llr::Terminator& terminator );
bool buildTerminator( Infos& inf, const llr::Ret& r );
bool buildTerminator( Infos& inf, const llr::Branch& b );
bool buildTerminator( Infos& inf, const llr::CondBranch& cb );
template< typename T >
bool buildTerminator( Infos& inf, const T& t )
{
return false;
}
llvm::Value* buildPointer( Infos& inf, const Pointer& ptr );
llvm::Value* buildPointer( Infos& inf, const llr::TemporaryAddress& ta );
llvm::Value* buildPointer( Infos& inf, const llr::VarAddress& va );
llvm::Value* buildPointer( Infos& inf, const unique_ptr< llr::GEP >& gep );
llvm::Value* buildGEP( Infos& inf, llvm::SmallVector< llvm::Value*, 4 >& indices, const Pointer& ptr );
llvm::Value* buildGEP( Infos& inf, llvm::SmallVector< llvm::Value*, 4 >& indices, const llr::TemporaryAddress& ta );
llvm::Value* buildGEP( Infos& inf, llvm::SmallVector< llvm::Value*, 4 >& indices, const llr::VarAddress& va );
llvm::Value* buildGEP( Infos& inf, llvm::SmallVector< llvm::Value*, 4 >& indices, const unique_ptr< llr::GEP >& gep );
llvm::Value* buildAlloca( Infos& inf, llvm::Type* type );
llvm::Value* createTemporary( Infos& inf, uint32_t index, llvm::Value* pValue ) const;
llvm::Module m_llvmModule;
llvm::IRBuilder<> m_llvmBuilder;
llvm::TargetMachine* m_targetMachine = nullptr;
unordered_map< string, llvm::GlobalVariable* > m_strings;
};
}
#endif