diff options
Diffstat (limited to 'lib/CodeGen')
| -rw-r--r-- | lib/CodeGen/ArrayHandler.cc | 230 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 39 |
2 files changed, 263 insertions, 6 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc new file mode 100644 index 0000000..470cffa --- /dev/null +++ b/lib/CodeGen/ArrayHandler.cc @@ -0,0 +1,230 @@ +#include "cps/ArrayHandler.h" +#include "cps/CodeGen.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" + +using namespace llvm; +using namespace cps; + +ArrayHandler::ArrayHandler(LLVMContext &C, IRBuilder<> &B, Module &M, std::map<std::string, AllocaInst*> &NV) + : TheContext(&C), Builder(&B), TheModule(&M), NamedValues(&NV) { + setupExternalFunctions(); +} + +void ArrayHandler::setupExternalFunctions() { + std::vector<Type*> MallocArgs; + MallocArgs.push_back(Type::getInt64Ty(*TheContext)); + + FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(*TheContext), MallocArgs, false); + MallocFunc = TheModule->getOrInsertFunction("malloc", MallocType); + + std::vector<Type*> FreeArgs; + FreeArgs.push_back(PointerType::getUnqual(*TheContext)); + FunctionType *FreeType = FunctionType::get(Type::getVoidTy(*TheContext), FreeArgs, false); + FreeFunc = TheModule->getOrInsertFunction("free", FreeType); +} + +void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) { + std::string Name = Stmt->getName(); + int Rank = Stmt->getBounds().size(); + + std::vector<Value*> Lows, Highs, Dims; + Value *TotalElements = ConstantInt::get(*TheContext, APInt(64, 1)); + + for (const auto &Pair : Stmt->getBounds()) { + Value *L = CG.emitExpr(Pair.first.get()); + Value *R = CG.emitExpr(Pair.second.get()); + + if (!L || !R) return; + + Value *L64 = Builder->CreateSExt(L, Type::getInt64Ty(*TheContext)); + Value *R64 = Builder->CreateSExt(R, Type::getInt64Ty(*TheContext)); + + Lows.push_back(L); + Highs.push_back(R); + + Value *Diff = Builder->CreateSub(R64, L64); + Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1))); + Dims.push_back(DimSize); + + TotalElements = Builder->CreateMul(TotalElements, DimSize); + } + + std::vector<Value*> Multipliers(Rank); + Multipliers[Rank - 1] = ConstantInt::get(*TheContext, APInt(32, 1)); + + for (int i = Rank - 2; i >= 0; --i) { + Value *NextMult = Multipliers[i+1]; + Value *NextDimSize = Dims[i+1]; + Value *NextDimSize32 = Builder->CreateTrunc(NextDimSize, Type::getInt32Ty(*TheContext)); + Multipliers[i] = Builder->CreateMul(NextMult, NextDimSize32); + } + + ArrayMetadata Meta; + Meta.Rank = Rank; + Meta.ElementType = Type::getInt32Ty(*TheContext); + Meta.LowerBounds = Lows; + Meta.UpperBounds = Highs; + Meta.Multipliers = Multipliers; + ArrayTable[Name] = Meta; + + + Value *ElemSize = ConstantInt::get(*TheContext, APInt(64, 4)); + Value *TotalBytes = Builder->CreateMul(TotalElements, ElemSize); + + CallInst *Ptr = Builder->CreateCall(MallocFunc, TotalBytes); + + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); + + AllocaInst *Alloca = TmpB.CreateAlloca(PointerType::getUnqual(*TheContext), nullptr, Name); + + Builder->CreateStore(Ptr, Alloca); + (*NamedValues)[Name] = Alloca; +} + +Value* ArrayHandler::computeFlatIndex(const std::string &Name, const std::vector<Value*> &Indices) { + if (ArrayTable.find(Name) == ArrayTable.end()) return nullptr; + const auto &Meta = ArrayTable[Name]; + + Value *Offset = ConstantInt::get(*TheContext, APInt(32, 0)); + + for (size_t i = 0; i < Indices.size(); ++i) { + Value *Idx = Indices[i]; + Value *Lower = Meta.LowerBounds[i]; + Value *Diff = Builder->CreateSub(Idx, Lower); + Value *Term = Builder->CreateMul(Diff, Meta.Multipliers[i]); + Offset = Builder->CreateAdd(Offset, Term); + } + return Offset; +} + +Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) { + std::string Name = Expr->getName(); + if (ArrayTable.find(Name) == ArrayTable.end()) { + fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str()); + return nullptr; + } + + const auto &Meta = ArrayTable[Name]; + if (Expr->getIndices().size() != Meta.Rank) { + fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str()); + return nullptr; + } + + std::vector<Value*> Indices; + for (const auto &IdxExpr : Expr->getIndices()) { + Indices.push_back(CG.emitExpr(IdxExpr.get())); + } + + Value *Offset = computeFlatIndex(Name, Indices); + + AllocaInst *Alloca = (*NamedValues)[Name]; + Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); + Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); + Value *ElemPtr = Builder->CreateGEP(Type::getInt32Ty(*TheContext), IntPtr, Offset); + + return Builder->CreateLoad(Type::getInt32Ty(*TheContext), ElemPtr); +} + +void ArrayHandler::emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG) { + std::string Name = Stmt->getName(); + if (ArrayTable.find(Name) == ArrayTable.end()) { + fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str()); + return; + } + + std::vector<Value*> Indices; + for (const auto &IdxExpr : Stmt->getIndices()) { + Indices.push_back(CG.emitExpr(IdxExpr.get())); + } + + Value *Val = CG.emitExpr(Stmt->getExpr()); + Value *Offset = computeFlatIndex(Name, Indices); + + AllocaInst *Alloca = (*NamedValues)[Name]; + Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); + Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); + Value *ElemPtr = Builder->CreateGEP(Type::getInt32Ty(*TheContext), IntPtr, Offset); + + Builder->CreateStore(Val, ElemPtr); +} + +bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) { + std::string Name; + std::vector<Value*> Indices; + + if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) { + Name = Var->getName(); + if (ArrayTable.find(Name) == ArrayTable.end()) return false; + } + else if (auto *Acc = dynamic_cast<ArrayAccessExprAST*>(Expr)) { + Name = Acc->getName(); + if (ArrayTable.find(Name) == ArrayTable.end()) return false; + + for (const auto &Idx : Acc->getIndices()) { + Indices.push_back(CG.emitExpr(Idx.get())); + } + } else { + return false; + } + + const auto &Meta = ArrayTable[Name]; + + if (Indices.size() == Meta.Rank) { + return false; + } + + emitPrintLoop(Name, Indices.size(), Indices, PrintfFunc, FmtStr); + return true; +} + +void ArrayHandler::emitPrintLoop(const std::string &Name, int CurrentDim, std::vector<Value*> CurrentIndices, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) { + const auto &Meta = ArrayTable[Name]; + + if (CurrentDim == Meta.Rank) { + Value *Offset = computeFlatIndex(Name, CurrentIndices); + + AllocaInst *Alloca = (*NamedValues)[Name]; + Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); + Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); + Value *ElemPtr = Builder->CreateGEP(Type::getInt32Ty(*TheContext), IntPtr, Offset); + Value *Val = Builder->CreateLoad(Type::getInt32Ty(*TheContext), ElemPtr); + + std::vector<Value*> Args; + Args.push_back(FmtStr); + Args.push_back(Val); + Builder->CreateCall(PrintfFunc, Args); + return; + } + + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "arr_loop", TheFunction); + BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "arr_after", TheFunction); + + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); + AllocaInst *LoopVar = TmpB.CreateAlloca(Type::getInt32Ty(*TheContext), nullptr, "idx"); + + Value *Start = Meta.LowerBounds[CurrentDim]; + Value *End = Meta.UpperBounds[CurrentDim]; + + Builder->CreateStore(Start, LoopVar); + Builder->CreateBr(LoopBB); + + Builder->SetInsertPoint(LoopBB); + Value *CurVal = Builder->CreateLoad(Type::getInt32Ty(*TheContext), LoopVar); + + std::vector<Value*> NextIndices = CurrentIndices; + NextIndices.push_back(CurVal); + emitPrintLoop(Name, CurrentDim + 1, NextIndices, PrintfFunc, FmtStr); + + Value *NextVal = Builder->CreateAdd(CurVal, ConstantInt::get(*TheContext, APInt(32, 1))); + Builder->CreateStore(NextVal, LoopVar); + + Value *Cond = Builder->CreateICmpSLE(NextVal, End); + Builder->CreateCondBr(Cond, LoopBB, AfterBB); + + Builder->SetInsertPoint(AfterBB); +} diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 31d113a..57d76eb 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -1,15 +1,20 @@ #include "cps/CodeGen.h" +#include "cps/ArrayHandler.h" #include "llvm/IR/Verifier.h" #include "cps/Lexer.h" using namespace llvm; using namespace cps; +CodeGen::~CodeGen() = default; + CodeGen::CodeGen() { TheContext = std::make_unique<LLVMContext>(); TheModule = std::make_unique<Module>("cps_module", *TheContext); Builder = std::make_unique<IRBuilder<>>(*TheContext); + Arrays = std::make_unique<ArrayHandler>(*TheContext, *Builder, *TheModule, NamedValues); + SetupExternalFunctions(); } @@ -24,6 +29,8 @@ void CodeGen::SetupExternalFunctions() { PrintfFormatStr = Builder->CreateGlobalStringPtr("%d\n", "fmt_nl", 0, TheModule.get()); ScanfFormatStr = Builder->CreateGlobalStringPtr("%d", "fmt_in", 0, TheModule.get()); + + Arrays->setupExternalFunctions(); } AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { @@ -64,8 +71,14 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { fprintf(stderr, "Error: Unknown variable name %s\n", Var->getName().c_str()); return nullptr; } + return Builder->CreateLoad(Type::getInt32Ty(*TheContext), A, Var->getName().c_str()); } + + + if (auto *ArrAcc = dynamic_cast<ArrayAccessExprAST*>(Expr)) { + return Arrays->emitArrayAccess(ArrAcc, *this); + } if (auto *Bin = dynamic_cast<BinaryExprAST*>(Expr)) { Value *L = emitExpr(Bin->getLHS()); @@ -234,6 +247,16 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) { void CodeGen::emitStmt(StmtAST *Stmt) { if (!Stmt) return; + if (auto *ArrDecl = dynamic_cast<ArrayDeclareStmtAST*>(Stmt)) { + Arrays->emitArrayDeclare(ArrDecl, *this); + return; + } + + if (auto *ArrAssign = dynamic_cast<ArrayAssignStmtAST*>(Stmt)) { + Arrays->emitArrayAssign(ArrAssign, *this); + return; + } + if (auto *Decl = dynamic_cast<DeclareStmtAST*>(Stmt)) { Function *TheFunction = Builder->GetInsertBlock()->getParent(); AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Decl->getName()); @@ -261,12 +284,16 @@ void CodeGen::emitStmt(StmtAST *Stmt) { } } else if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt)) { - Value *Val = emitExpr(Out->getExpr()); - if (Val) { - std::vector<Value*> Args; - Args.push_back(PrintfFormatStr); - Args.push_back(Val); - Builder->CreateCall(PrintfFunc, Args); + bool handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this, PrintfFunc, PrintfFormatStr); + + if (!handled) { + Value *Val = emitExpr(Out->getExpr()); + if (Val) { + std::vector<Value*> Args; + Args.push_back(PrintfFormatStr); + Args.push_back(Val); + Builder->CreateCall(PrintfFunc, Args); + } } } else if (auto *IfStmt = dynamic_cast<IfStmtAST*>(Stmt)) { |
