From f2b051ae3e28135cc02589f3f698c43743cca48e Mon Sep 17 00:00:00 2001 From: _ov4 Date: Fri, 27 Mar 2026 01:50:32 +0000 Subject: feat: generalize typed array support --- lib/CodeGen/ArrayHandler.cc | 326 +++++++++++++-------- lib/CodeGen/CodeGen.cc | 696 ++++++++++++++++++++++++++++++++------------ lib/CodeGen/FunctionGen.cc | 62 ++-- lib/CodeGen/TypeSystem.cc | 156 ++++++++++ 4 files changed, 898 insertions(+), 342 deletions(-) create mode 100644 lib/CodeGen/TypeSystem.cc (limited to 'lib/CodeGen') diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc index 5842f77..fd55009 100644 --- a/lib/CodeGen/ArrayHandler.cc +++ b/lib/CodeGen/ArrayHandler.cc @@ -1,22 +1,35 @@ #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" +#include "llvm/IR/Type.h" +#include using namespace llvm; using namespace cps; -ArrayHandler::ArrayHandler(LLVMContext &C, IRBuilder<> &B, Module &M, std::map &NV, RuntimeCheck &RC) - : TheContext(&C), Builder(&B), TheModule(&M), NamedValues(&NV), RuntimeChecker(RC) { +ArrayHandler::ArrayHandler(LLVMContext &C, + IRBuilder<> &B, + Module &M, + std::map &NV, + std::map &Sym, + TypeSystem &TS, + RuntimeCheck &RC) + : TheContext(&C), + Builder(&B), + TheModule(&M), + NamedValues(&NV), + Symbols(&Sym), + Types(TS), + RuntimeChecker(RC) { setupExternalFunctions(); } void ArrayHandler::setupExternalFunctions() { std::vector MallocArgs; MallocArgs.push_back(Type::getInt64Ty(*TheContext)); - + FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(*TheContext), MallocArgs, false); MallocFunc = TheModule->getOrInsertFunction("malloc", MallocType); @@ -26,89 +39,124 @@ void ArrayHandler::setupExternalFunctions() { FreeFunc = TheModule->getOrInsertFunction("free", FreeType); } +const ArrayMetadata *ArrayHandler::getMetadata(const std::string &Name) const { + auto It = ArrayTable.find(Name); + if (It == ArrayTable.end()) { + return nullptr; + } + return &It->second; +} + +Value *ArrayHandler::computeFlatIndex(const std::string &Name, const std::vector &Indices) { + const ArrayMetadata *Meta = getMetadata(Name); + if (!Meta) return nullptr; + + Value *Offset = ConstantInt::get(*TheContext, APInt(64, 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::getArrayBasePointer(const std::string &Name) { + auto It = NamedValues->find(Name); + if (It == NamedValues->end() || !It->second) { + return nullptr; + } + return Builder->CreateLoad(PointerType::getUnqual(*TheContext), It->second, (Name + "_raw").c_str()); +} + +Value *ArrayHandler::getElementPointer(const std::string &Name, Value *Offset) { + const ArrayMetadata *Meta = getMetadata(Name); + if (!Meta || !Offset) return nullptr; + + Value *RawPtr = getArrayBasePointer(Name); + if (!RawPtr) return nullptr; + + PointerType *TypedPtrTy = PointerType::getUnqual(Meta->ElementType); + Value *TypedPtr = Builder->CreateBitCast(RawPtr, TypedPtrTy, Name + "_typed_ptr"); + return Builder->CreateGEP(Meta->ElementType, TypedPtr, Offset, Name + "_elem_ptr"); +} + void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) { std::string Name = Stmt->getName(); - int Rank = Stmt->getBounds().size(); - - std::vector Lows, Highs, Dims; + int Rank = static_cast(Stmt->getBounds().size()); + + const TypeInfo *ElemInfo = Types.resolve(Stmt->getType()); + if (!ElemInfo || !ElemInfo->LLVMType || ElemInfo->isVoid()) { + fprintf(stderr, "Error: Unknown array element type %s\n", Stmt->getType().c_str()); + return; + } + + std::vector Lows; + std::vector Highs; + std::vector 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()); - + L = CG.coerceValueToType(L, CG.resolveType("INTEGER")); + R = CG.coerceValueToType(R, CG.resolveType("INTEGER")); + 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))); + + Value *Diff = Builder->CreateSub(R, L, Name + "_dim_diff"); + Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1)), Name + "_dim_size"); Dims.push_back(DimSize); - - TotalElements = Builder->CreateMul(TotalElements, DimSize); + TotalElements = Builder->CreateMul(TotalElements, DimSize, Name + "_total_elems"); } - + std::vector Multipliers(Rank); Multipliers[Rank - 1] = ConstantInt::get(*TheContext, APInt(64, 1)); - for (int i = Rank - 2; i >= 0; --i) { - Value *NextMult = Multipliers[i+1]; - Value *NextDimSize = Dims[i+1]; - Multipliers[i] = Builder->CreateMul(NextMult, NextDimSize); + Multipliers[i] = Builder->CreateMul(Multipliers[i + 1], Dims[i + 1], Name + "_mult"); } ArrayMetadata Meta; Meta.Rank = Rank; - Meta.ElementType = Type::getInt64Ty(*TheContext); - Meta.LowerBounds = Lows; - Meta.UpperBounds = Highs; - Meta.Multipliers = Multipliers; + Meta.ElementTypeName = ElemInfo->Name; + Meta.ElementType = ElemInfo->LLVMType; + Meta.ElementSize = ElemInfo->ElementSize; + Meta.LowerBounds = std::move(Lows); + Meta.UpperBounds = std::move(Highs); + Meta.Multipliers = std::move(Multipliers); ArrayTable[Name] = Meta; - - Value *ElemSize = ConstantInt::get(*TheContext, APInt(64, 8)); - Value *TotalBytes = Builder->CreateMul(TotalElements, ElemSize); - - CallInst *Ptr = Builder->CreateCall(MallocFunc, TotalBytes); - + Value *ElemSize = ConstantInt::get(*TheContext, APInt(64, ElemInfo->ElementSize)); + Value *TotalBytes = Builder->CreateMul(TotalElements, ElemSize, Name + "_total_bytes"); + CallInst *Ptr = Builder->CreateCall(MallocFunc, TotalBytes, Name + "_malloc"); + + FunctionType *MemsetType = FunctionType::get(PointerType::getUnqual(*TheContext), + {PointerType::getUnqual(*TheContext), Type::getInt32Ty(*TheContext), Type::getInt64Ty(*TheContext)}, + false); + FunctionCallee MemsetFunc = TheModule->getOrInsertFunction("memset", MemsetType); + Builder->CreateCall(MemsetFunc, + {Ptr, ConstantInt::get(Type::getInt32Ty(*TheContext), 0), TotalBytes}); + Function *TheFunction = Builder->GetInsertBlock()->getParent(); - IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - - AllocaInst *Alloca = TmpB.CreateAlloca(PointerType::getUnqual(*TheContext), nullptr, Name); - + AllocaInst *Alloca = CG.CreateEntryBlockAlloca(TheFunction, PointerType::getUnqual(*TheContext), Name); Builder->CreateStore(Ptr, Alloca); - (*NamedValues)[Name] = Alloca; -} -Value* ArrayHandler::computeFlatIndex(const std::string &Name, const std::vector &Indices) { - if (ArrayTable.find(Name) == ArrayTable.end()) return nullptr; - const auto &Meta = ArrayTable[Name]; - - Value *Offset = ConstantInt::get(*TheContext, APInt(64, 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; + CG.registerSymbol(Name, Alloca, ElemInfo->Name, true); } -Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) { +Value *ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) { std::string Name = Expr->getName(); - if (ArrayTable.find(Name) == ArrayTable.end()) { + const ArrayMetadata *Meta = getMetadata(Name); + if (!Meta) { fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str()); return nullptr; } - - const auto &Meta = ArrayTable[Name]; - if (Expr->getIndices().size() != Meta.Rank) { + + if (Expr->getIndices().size() != static_cast(Meta->Rank)) { fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str()); return nullptr; } @@ -116,125 +164,147 @@ Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) { std::vector Indices; for (size_t i = 0; i < Expr->getIndices().size(); ++i) { Value *Idx = CG.emitExpr(Expr->getIndices()[i].get()); - Indices.push_back(Idx); + Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER")); + if (!Idx) return nullptr; - Value *Lower = Meta.LowerBounds[i]; - Value *Upper = Meta.UpperBounds[i]; - RuntimeChecker.emitIndexCheck(Idx, Lower, Upper, Expr->getLine()); + Indices.push_back(Idx); + RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Expr->getLine()); } - + Value *Offset = computeFlatIndex(Name, Indices); - - Value *Alloca = (*NamedValues)[Name]; - Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); - Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); - Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset); - - return Builder->CreateLoad(Type::getInt64Ty(*TheContext), ElemPtr); + Value *ElemPtr = getElementPointer(Name, Offset); + if (!ElemPtr) return nullptr; + + Value *Val = Builder->CreateLoad(Meta->ElementType, ElemPtr, Name + "_elem"); + if (Meta->ElementTypeName == "STRING") { + Value *IsNull = Builder->CreateICmpEQ(Val, + ConstantPointerNull::get(cast(Meta->ElementType)), + Name + "_str_is_null"); + Val = Builder->CreateSelect(IsNull, CG.EmptyStringStr, Val, Name + "_safe_str"); + } + return Val; } void ArrayHandler::emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG) { std::string Name = Stmt->getName(); - if (ArrayTable.find(Name) == ArrayTable.end()) { + const ArrayMetadata *Meta = getMetadata(Name); + if (!Meta) { fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str()); return; } - + + if (Stmt->getIndices().size() != static_cast(Meta->Rank)) { + fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str()); + return; + } + std::vector Indices; for (size_t i = 0; i < Stmt->getIndices().size(); ++i) { Value *Idx = CG.emitExpr(Stmt->getIndices()[i].get()); - Indices.push_back(Idx); + Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER")); + if (!Idx) return; - const auto &Meta = ArrayTable[Name]; - Value *Lower = Meta.LowerBounds[i]; - Value *Upper = Meta.UpperBounds[i]; - RuntimeChecker.emitIndexCheck(Idx, Lower, Upper, Stmt->getLine()); + Indices.push_back(Idx); + RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Stmt->getLine()); } - + + const TypeInfo *ElemInfo = Types.resolve(Meta->ElementTypeName); Value *Val = CG.emitExpr(Stmt->getExpr()); + Val = CG.coerceValueToType(Val, ElemInfo); + if (!Val) return; + Value *Offset = computeFlatIndex(Name, Indices); - - Value *Alloca = (*NamedValues)[Name]; - Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); - Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); - Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset); - + Value *ElemPtr = getElementPointer(Name, Offset); + if (!ElemPtr) return; + Builder->CreateStore(Val, ElemPtr); } -bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) { +bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG) { std::string Name; std::vector Indices; - + if (auto *Var = dynamic_cast(Expr)) { Name = Var->getName(); - if (ArrayTable.find(Name) == ArrayTable.end()) return false; - } - else if (auto *Acc = dynamic_cast(Expr)) { + if (!getMetadata(Name)) return false; + } else if (auto *Acc = dynamic_cast(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())); + const ArrayMetadata *Meta = getMetadata(Name); + if (!Meta) return false; + + for (size_t i = 0; i < Acc->getIndices().size(); ++i) { + Value *Idx = CG.emitExpr(Acc->getIndices()[i].get()); + Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER")); + if (!Idx) return false; + Indices.push_back(Idx); + RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Acc->getLine()); + } + + if (Indices.size() > static_cast(Meta->Rank)) { + fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str()); + return true; } } else { return false; } - - const auto &Meta = ArrayTable[Name]; - - if (Indices.size() == Meta.Rank) { + + const ArrayMetadata *Meta = getMetadata(Name); + if (!Meta) return false; + if (Indices.size() == static_cast(Meta->Rank)) { return false; } - - emitPrintLoop(Name, Indices.size(), Indices, PrintfFunc, FmtStr); + + emitPrintLoop(Name, static_cast(Indices.size()), Indices, CG); return true; } -void ArrayHandler::emitPrintLoop(const std::string &Name, int CurrentDim, std::vector CurrentIndices, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) { - const auto &Meta = ArrayTable[Name]; - - if (CurrentDim == Meta.Rank) { +void ArrayHandler::emitPrintLoop(const std::string &Name, + int CurrentDim, + std::vector CurrentIndices, + CodeGen &CG) { + const ArrayMetadata *Meta = getMetadata(Name); + if (!Meta) return; + + if (CurrentDim == Meta->Rank) { Value *Offset = computeFlatIndex(Name, CurrentIndices); - - Value *Alloca = (*NamedValues)[Name]; - Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); - Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); - Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset); - Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), ElemPtr); - - std::vector Args; - Args.push_back(FmtStr); - Args.push_back(Val); - Builder->CreateCall(PrintfFunc, Args); + Value *ElemPtr = getElementPointer(Name, Offset); + if (!ElemPtr) return; + + Value *Val = Builder->CreateLoad(Meta->ElementType, ElemPtr, Name + "_print_val"); + if (Meta->ElementTypeName == "STRING") { + Value *IsNull = Builder->CreateICmpEQ(Val, + ConstantPointerNull::get(cast(Meta->ElementType)), + Name + "_print_str_is_null"); + Val = Builder->CreateSelect(IsNull, CG.EmptyStringStr, Val, Name + "_print_safe_str"); + } + + CG.emitOutputValue(Val, Types.resolve(Meta->ElementTypeName), true); 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::getInt64Ty(*TheContext), nullptr, "idx"); - - Value *Start = Meta.LowerBounds[CurrentDim]; - Value *End = Meta.UpperBounds[CurrentDim]; - + + AllocaInst *LoopVar = CG.CreateEntryBlockAlloca(TheFunction, Type::getInt64Ty(*TheContext), "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::getInt64Ty(*TheContext), LoopVar); - + std::vector NextIndices = CurrentIndices; NextIndices.push_back(CurVal); - emitPrintLoop(Name, CurrentDim + 1, NextIndices, PrintfFunc, FmtStr); - + emitPrintLoop(Name, CurrentDim + 1, NextIndices, CG); + Value *NextVal = Builder->CreateAdd(CurVal, ConstantInt::get(*TheContext, APInt(64, 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 c5b0ff3..c77f5d8 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -1,8 +1,9 @@ #include "cps/CodeGen.h" #include "cps/ArrayHandler.h" -#include "llvm/IR/Verifier.h" -#include "llvm/IR/Instructions.h" #include "cps/Lexer.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Verifier.h" +#include using namespace llvm; using namespace cps; @@ -13,12 +14,24 @@ CodeGen::CodeGen() { TheContext = std::make_unique(); TheModule = std::make_unique("cps_module", *TheContext); Builder = std::make_unique>(*TheContext); - + + Types = std::make_unique(*TheContext); RuntimeChecker = std::make_unique(*TheModule, *TheContext, *Builder); - - Arrays = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues, *RuntimeChecker); - - FuncGen = std::make_unique(*TheContext, *TheModule, *Builder, NamedValues); + + Arrays = std::make_unique(*TheContext, + *Builder, + *TheModule, + NamedValues, + Symbols, + *Types, + *RuntimeChecker); + + FuncGen = std::make_unique(*TheContext, + *TheModule, + *Builder, + *Types, + NamedValues, + Symbols); IntHandler = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues); RealHelper = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues); @@ -43,20 +56,316 @@ void CodeGen::SetupExternalFunctions() { PrintfFormatStr = Builder->CreateGlobalStringPtr("%lld\n", "fmt_nl", 0, TheModule.get()); PrintfFloatFormatStr = Builder->CreateGlobalStringPtr("%f\n", "fmt_flt", 0, TheModule.get()); PrintfStringFormatStr = Builder->CreateGlobalStringPtr("%s\n", "fmt_str", 0, TheModule.get()); + PrintfCharFormatStr = Builder->CreateGlobalStringPtr("%c\n", "fmt_chr", 0, TheModule.get()); ScanfFormatStr = Builder->CreateGlobalStringPtr("%lld", "fmt_in", 0, TheModule.get()); ScanfFloatFormatStr = Builder->CreateGlobalStringPtr("%lf", "fmt_in_flt", 0, TheModule.get()); - ScanfStringFormatStr = Builder->CreateGlobalStringPtr("%s", "fmt_in_str", 0, TheModule.get()); // NEW + ScanfStringFormatStr = Builder->CreateGlobalStringPtr("%s", "fmt_in_str", 0, TheModule.get()); TrueStr = Builder->CreateGlobalStringPtr("TRUE", "str_true", 0, TheModule.get()); FalseStr = Builder->CreateGlobalStringPtr("FALSE", "str_false", 0, TheModule.get()); - + EmptyStringStr = Builder->CreateGlobalStringPtr("", "str_empty", 0, TheModule.get()); + Arrays->setupExternalFunctions(); } AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { + return CreateEntryBlockAlloca(TheFunction, Type::getInt64Ty(*TheContext), VarName); +} + +AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction, + Type *AllocType, + const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getInt64Ty(*TheContext), nullptr, VarName); + return TmpB.CreateAlloca(AllocType, nullptr, VarName); +} + +void CodeGen::registerSymbol(const std::string &Name, + Value *Storage, + const std::string &TypeName, + bool IsArray) { + NamedValues[Name] = Storage; + Symbols[Name] = {Storage, TypeName, IsArray}; +} + +const SymbolInfo *CodeGen::getSymbolInfo(const std::string &Name) const { + auto It = Symbols.find(Name); + if (It == Symbols.end()) { + return nullptr; + } + return &It->second; +} + +const TypeInfo *CodeGen::resolveType(const std::string &TypeName) const { + return Types->resolve(TypeName); +} + +Type *CodeGen::getLLVMType(const std::string &TypeName) const { + return Types->getLLVMType(TypeName); +} + +Value *CodeGen::getNamedValue(const std::string &Name) const { + auto It = NamedValues.find(Name); + return It == NamedValues.end() ? nullptr : It->second; +} + +const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const { + if (!Expr) return nullptr; + + if (dynamic_cast(Expr)) return resolveType("INTEGER"); + if (dynamic_cast(Expr)) return resolveType("REAL"); + if (dynamic_cast(Expr)) return resolveType("BOOLEAN"); + if (dynamic_cast(Expr)) return resolveType("CHAR"); + if (dynamic_cast(Expr)) return resolveType("STRING"); + + if (auto *Var = dynamic_cast(Expr)) { + const SymbolInfo *Info = getSymbolInfo(Var->getName()); + return Info ? resolveType(Info->TypeName) : nullptr; + } + + if (auto *Arr = dynamic_cast(Expr)) { + const SymbolInfo *Info = getSymbolInfo(Arr->getName()); + return Info ? resolveType(Info->TypeName) : nullptr; + } + + if (auto *Unary = dynamic_cast(Expr)) { + if (Unary->getOp() == tok_not) { + return resolveType("BOOLEAN"); + } + return getExprTypeInfo(Unary->getOperand()); + } + + if (auto *Bin = dynamic_cast(Expr)) { + switch (Bin->getOp()) { + case tok_eq: + case tok_ne: + case '<': + case '>': + case tok_le: + case tok_ge: + case tok_and: + case tok_or: + return resolveType("BOOLEAN"); + case '&': + return resolveType("STRING"); + default: + break; + } + + const TypeInfo *L = getExprTypeInfo(Bin->getLHS()); + const TypeInfo *R = getExprTypeInfo(Bin->getRHS()); + if ((L && L->Kind == TypeKind::Real) || (R && R->Kind == TypeKind::Real)) { + return resolveType("REAL"); + } + return resolveType("INTEGER"); + } + + if (auto *Call = dynamic_cast(Expr)) { + const std::string &Name = Call->getCallee(); + if (Name == "LENGTH" || Name == "ASC") return resolveType("INTEGER"); + if (Name == "MID" || Name == "RIGHT" || Name == "LEFT" || + Name == "LCASE" || Name == "UCASE" || Name == "CHR" || + Name == "NUM_TO_STR") return resolveType("STRING"); + if (Name == "IS_NUM") return resolveType("BOOLEAN"); + if (Name == "STR_TO_NUM") return resolveType("REAL"); + + Function *CalleeF = TheModule->getFunction(Name); + if (!CalleeF) return resolveType("INTEGER"); + + Type *RetTy = CalleeF->getReturnType(); + if (RetTy->isVoidTy()) return resolveType("VOID"); + if (RetTy->isDoubleTy()) return resolveType("REAL"); + if (RetTy->isIntegerTy(1)) return resolveType("BOOLEAN"); + if (RetTy->isIntegerTy(8)) return resolveType("CHAR"); + if (RetTy->isPointerTy()) return resolveType("STRING"); + return resolveType("INTEGER"); + } + + return nullptr; +} + +Value *CodeGen::coerceValueToType(Value *Val, const TypeInfo *TargetInfo) { + if (!Val || !TargetInfo || !TargetInfo->LLVMType) return nullptr; + + if (Val->getType() == TargetInfo->LLVMType) { + return Val; + } + + switch (TargetInfo->Kind) { + case TypeKind::Real: + if (Val->getType()->isDoubleTy()) return Val; + if (Val->getType()->isIntegerTy(1)) + return Builder->CreateUIToFP(Val, Type::getDoubleTy(*TheContext), "bool_to_real"); + if (Val->getType()->isIntegerTy(8)) + return Builder->CreateUIToFP(Val, Type::getDoubleTy(*TheContext), "char_to_real"); + if (Val->getType()->isIntegerTy()) + return Builder->CreateSIToFP(Val, Type::getDoubleTy(*TheContext), "int_to_real"); + break; + + case TypeKind::Integer: + if (Val->getType()->isIntegerTy(64)) return Val; + if (Val->getType()->isDoubleTy()) + return Builder->CreateFPToSI(Val, Type::getInt64Ty(*TheContext), "real_to_int"); + if (Val->getType()->isIntegerTy(1)) + return Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext), "bool_to_int"); + if (Val->getType()->isIntegerTy(8)) + return Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext), "char_to_int"); + if (Val->getType()->isIntegerTy()) + return Builder->CreateSExtOrTrunc(Val, Type::getInt64Ty(*TheContext), "int_cast"); + break; + + case TypeKind::Boolean: + if (Val->getType()->isIntegerTy(1)) return Val; + if (Val->getType()->isIntegerTy()) + return Builder->CreateICmpNE(Val, Constant::getNullValue(Val->getType()), "to_bool"); + if (Val->getType()->isDoubleTy()) + return Builder->CreateFCmpONE(Val, ConstantFP::get(*TheContext, APFloat(0.0)), "to_bool"); + if (Val->getType()->isPointerTy()) + return Builder->CreateICmpNE(Val, + ConstantPointerNull::get(cast(Val->getType())), + "ptr_to_bool"); + break; + + case TypeKind::Char: + if (Val->getType()->isIntegerTy(8)) return Val; + if (Val->getType()->isIntegerTy(1)) + return Builder->CreateZExt(Val, Type::getInt8Ty(*TheContext), "bool_to_char"); + if (Val->getType()->isDoubleTy()) + return Builder->CreateFPToUI(Val, Type::getInt8Ty(*TheContext), "real_to_char"); + if (Val->getType()->isIntegerTy()) + return Builder->CreateTruncOrBitCast(Val, Type::getInt8Ty(*TheContext), "int_to_char"); + break; + + case TypeKind::String: + if (Val->getType()->isPointerTy()) return Val; + if (Val->getType()->isIntegerTy(1)) { + return Builder->CreateSelect(Val, TrueStr, FalseStr, "bool_to_str"); + } + if (Val->getType()->isDoubleTy()) { + return StrConvHandler->emitNumToStr(Val, true); + } + if (Val->getType()->isIntegerTy(8)) { + Function *MallocF = TheModule->getFunction("malloc"); + if (!MallocF) { + FunctionType *MallocTy = FunctionType::get(PointerType::getUnqual(*TheContext), + {Type::getInt64Ty(*TheContext)}, + false); + MallocF = Function::Create(MallocTy, + Function::ExternalLinkage, + "malloc", + TheModule.get()); + } + Value *Mem = Builder->CreateCall(MallocF, + ConstantInt::get(*TheContext, APInt(64, 2)), + "char_str"); + Builder->CreateStore(Val, Mem); + Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext), + Mem, + ConstantInt::get(*TheContext, APInt(64, 1))); + Builder->CreateStore(ConstantInt::get(Type::getInt8Ty(*TheContext), 0), NullPtr); + return Mem; + } + if (Val->getType()->isIntegerTy()) { + Value *AsInt = coerceValueToType(Val, resolveType("INTEGER")); + return AsInt ? StrConvHandler->emitNumToStr(AsInt, false) : nullptr; + } + break; + + case TypeKind::Void: + return nullptr; + + case TypeKind::Custom: + if (Val->getType() == TargetInfo->LLVMType) return Val; + if (Val->getType()->isPointerTy() && TargetInfo->LLVMType->isPointerTy()) { + return Builder->CreateBitCast(Val, TargetInfo->LLVMType, "custom_ptr_cast"); + } + break; + } + + fprintf(stderr, + "Error: Cannot coerce value of LLVM type to target type %s\n", + TargetInfo->Name.c_str()); + return nullptr; +} + +void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) { + const TypeInfo *Info = resolveType(Stmt->getType()); + if (!Info || !Info->LLVMType || Info->isVoid()) { + fprintf(stderr, "Error: Unknown type %s\n", Stmt->getType().c_str()); + return; + } + + Function *TheFunction = Builder->GetInsertBlock()->getParent(); + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Info->LLVMType, Stmt->getName()); + + Value *InitVal = nullptr; + if (Info->isString()) { + InitVal = EmptyStringStr; + } else { + InitVal = Types->getZeroValue(Info->Name); + } + + if (InitVal) { + Builder->CreateStore(InitVal, Alloca); + } + + registerSymbol(Stmt->getName(), Alloca, Info->Name, false); +} + +void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewline) { + if (!Val || !Info) return; + if (!Info->Printable && Info->Kind == TypeKind::Custom) { + fprintf(stderr, "Error: OUTPUT for custom type %s is not implemented yet\n", Info->Name.c_str()); + return; + } + + std::vector Args; + Value *Fmt = nullptr; + + if (Info->isReal()) { + Fmt = AppendNewline + ? PrintfFloatFormatStr + : Builder->CreateGlobalStringPtr("%f", "fmt_flt_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(Val); + } else if (Info->isBoolean()) { + Value *BoolVal = coerceValueToType(Val, resolveType("BOOLEAN")); + Fmt = AppendNewline + ? PrintfStringFormatStr + : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(Builder->CreateSelect(BoolVal, TrueStr, FalseStr)); + } else if (Info->isString()) { + Value *StrVal = Val; + if (StrVal->getType()->isPointerTy()) { + Value *IsNull = Builder->CreateICmpEQ(StrVal, + ConstantPointerNull::get(cast(StrVal->getType())), + "str_is_null"); + StrVal = Builder->CreateSelect(IsNull, EmptyStringStr, StrVal, "safe_str"); + } + Fmt = AppendNewline + ? PrintfStringFormatStr + : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(StrVal); + } else if (Info->isChar()) { + Value *CharVal = coerceValueToType(Val, resolveType("CHAR")); + Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf"); + Fmt = AppendNewline + ? PrintfCharFormatStr + : Builder->CreateGlobalStringPtr("%c", "fmt_chr_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(Promoted); + } else { + Value *IntVal = coerceValueToType(Val, resolveType("INTEGER")); + Fmt = AppendNewline + ? PrintfFormatStr + : Builder->CreateGlobalStringPtr("%lld", "fmt_int_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(IntVal); + } + + Builder->CreateCall(PrintfFunc, Args); } void CodeGen::compile(const std::vector> &Statements) { @@ -69,9 +378,10 @@ void CodeGen::compile(const std::vector> &Statements) { emitStmt(Stmt.get()); } - if (!Builder->GetInsertBlock()->getTerminator()) + if (!Builder->GetInsertBlock()->getTerminator()) { Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0))); - + } + verifyFunction(*F); } @@ -94,19 +404,38 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { return BoolHandler->createLiteral(Bool->getVal()); } + if (auto *Chr = dynamic_cast(Expr)) { + return ConstantInt::get(Type::getInt8Ty(*TheContext), static_cast(Chr->getVal())); + } + if (auto *Str = dynamic_cast(Expr)) { return StrHandler->createLiteral(Str->getVal()); } - + if (auto *Var = dynamic_cast(Expr)) { - Value *A = NamedValues[Var->getName()]; - if (!A) { + const SymbolInfo *Info = getSymbolInfo(Var->getName()); + if (!Info) { fprintf(stderr, "Error: Unknown variable name %s\n", Var->getName().c_str()); return nullptr; } - - Type *AllocType = cast(A)->getAllocatedType(); - return Builder->CreateLoad(AllocType, A, Var->getName().c_str()); + if (Info->IsArray) { + return Info->Storage; + } + + const TypeInfo *TypeInfo = resolveType(Info->TypeName); + if (!TypeInfo || !TypeInfo->LLVMType) { + fprintf(stderr, "Error: Unknown type for variable %s\n", Var->getName().c_str()); + return nullptr; + } + + Value *Loaded = Builder->CreateLoad(TypeInfo->LLVMType, Info->Storage, Var->getName().c_str()); + if (TypeInfo->isString()) { + Value *IsNull = Builder->CreateICmpEQ(Loaded, + ConstantPointerNull::get(cast(Loaded->getType())), + "str_is_null"); + Loaded = Builder->CreateSelect(IsNull, EmptyStringStr, Loaded, "safe_var_str"); + } + return Loaded; } if (auto *ArrAcc = dynamic_cast(Expr)) { @@ -116,14 +445,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { if (auto *Unary = dynamic_cast(Expr)) { Value *Operand = emitExpr(Unary->getOperand()); if (!Operand) return nullptr; - + if (Unary->getOp() == tok_not) { - if (Operand->getType()->isIntegerTy(64)) { - Operand = Builder->CreateICmpNE(Operand, ConstantInt::get(*TheContext, APInt(64, 0)), "tobool"); - } else if (Operand->getType()->isDoubleTy()) { - Operand = Builder->CreateFCmpONE(Operand, ConstantFP::get(*TheContext, APFloat(0.0)), "tobool"); - } - + Operand = coerceValueToType(Operand, resolveType("BOOLEAN")); return Builder->CreateNot(Operand, "nottmp"); } } @@ -132,7 +456,6 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { Value *L = emitExpr(Bin->getLHS()); Value *R = emitExpr(Bin->getRHS()); if (!L || !R) return nullptr; - return ArithHandler->emitBinaryOp(Bin->getOp(), L, R, Bin->getLine()); } @@ -144,18 +467,18 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (Name == "MID") { if (Call->getArgs().size() != 3) { fprintf(stderr, "MID expects 3 args\n"); return nullptr; } - return StrHandler->emitMid(emitExpr(Call->getArgs()[0].get()), - emitExpr(Call->getArgs()[1].get()), + return StrHandler->emitMid(emitExpr(Call->getArgs()[0].get()), + emitExpr(Call->getArgs()[1].get()), emitExpr(Call->getArgs()[2].get())); } if (Name == "RIGHT") { if (Call->getArgs().size() != 2) { fprintf(stderr, "RIGHT expects 2 args\n"); return nullptr; } - return StrHandler->emitRight(emitExpr(Call->getArgs()[0].get()), + return StrHandler->emitRight(emitExpr(Call->getArgs()[0].get()), emitExpr(Call->getArgs()[1].get())); } if (Name == "LEFT") { if (Call->getArgs().size() != 2) { fprintf(stderr, "LEFT expects 2 args\n"); return nullptr; } - return StrHandler->emitLeft(emitExpr(Call->getArgs()[0].get()), + return StrHandler->emitLeft(emitExpr(Call->getArgs()[0].get()), emitExpr(Call->getArgs()[1].get())); } if (Name == "LCASE") { @@ -168,17 +491,27 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (Name == "ASC") { if (Call->getArgs().size() != 1) return nullptr; - Value *StrPtr = emitExpr(Call->getArgs()[0].get()); - Value *CharVal = Builder->CreateLoad(Type::getInt8Ty(*TheContext), StrPtr, "char_load"); - return ChrHandler->emitAsc(CharVal); + Value *ArgVal = emitExpr(Call->getArgs()[0].get()); + const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get()); + Value *CharVal = nullptr; + if (ArgType && ArgType->isChar()) { + CharVal = coerceValueToType(ArgVal, resolveType("CHAR")); + } else { + CharVal = Builder->CreateLoad(Type::getInt8Ty(*TheContext), ArgVal, "char_load"); + } + Value *AscVal = ChrHandler->emitAsc(CharVal); + return coerceValueToType(AscVal, resolveType("INTEGER")); } if (Name == "CHR") { if (Call->getArgs().size() != 1) return nullptr; - Value *CharVal = ChrHandler->emitChr(emitExpr(Call->getArgs()[0].get())); + Value *IntVal = coerceValueToType(emitExpr(Call->getArgs()[0].get()), resolveType("INTEGER")); + Value *CharVal = ChrHandler->emitChr(IntVal); Function *MallocF = TheModule->getFunction("malloc"); Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 2))); Builder->CreateStore(CharVal, Mem); - Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext), Mem, ConstantInt::get(*TheContext, APInt(64, 1))); + Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext), + Mem, + ConstantInt::get(*TheContext, APInt(64, 1))); Builder->CreateStore(ConstantInt::get(Type::getInt8Ty(*TheContext), 0), NullPtr); return Mem; } @@ -189,8 +522,11 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { if (Name == "NUM_TO_STR") { if (Call->getArgs().size() != 1) return nullptr; Value *NumV = emitExpr(Call->getArgs()[0].get()); - bool isReal = NumV->getType()->isDoubleTy(); - return StrConvHandler->emitNumToStr(NumV, isReal); + bool IsReal = NumV->getType()->isDoubleTy(); + if (NumV->getType()->isIntegerTy(8)) { + NumV = coerceValueToType(NumV, resolveType("INTEGER")); + } + return StrConvHandler->emitNumToStr(NumV, IsReal); } if (Name == "STR_TO_NUM") { if (Call->getArgs().size() != 1) return nullptr; @@ -199,28 +535,28 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { Function *CalleeF = TheModule->getFunction(Call->getCallee()); std::vector Args; - + for (unsigned i = 0; i < Call->getArgs().size(); ++i) { ExprAST *ArgExpr = Call->getArgs()[i].get(); - bool isByRef = false; + bool IsByRef = false; if (CalleeF && i < CalleeF->arg_size()) { if (CalleeF->getArg(i)->getType()->isPointerTy()) { - isByRef = true; + IsByRef = true; } } - if (isByRef) { + if (IsByRef) { if (auto *Var = dynamic_cast(ArgExpr)) { - Value *Ptr = NamedValues[Var->getName()]; + Value *Ptr = getNamedValue(Var->getName()); if (!Ptr) { fprintf(stderr, "Error: Unknown variable %s in BYREF call\n", Var->getName().c_str()); return nullptr; } Args.push_back(Ptr); } else { - fprintf(stderr, "Error: BYREF argument must be a variable.\n"); - return nullptr; + fprintf(stderr, "Error: BYREF argument must be a variable.\n"); + return nullptr; } } else { Args.push_back(emitExpr(ArgExpr)); @@ -236,10 +572,7 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) { Value *CondV = emitExpr(Stmt->getCond()); if (!CondV) return; - if (CondV->getType()->isIntegerTy(64)) - CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "ifcond"); - if (CondV->getType()->isIntegerTy(1)) - CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "ifcond"); + CondV = coerceValueToType(CondV, resolveType("BOOLEAN")); Function *TheFunction = Builder->GetInsertBlock()->getParent(); BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); @@ -261,7 +594,7 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) { void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) { Function *TheFunction = Builder->GetInsertBlock()->getParent(); - + BasicBlock *CondBB = BasicBlock::Create(*TheContext, "whilecond", TheFunction); BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "whileloop", TheFunction); BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "whilecont", TheFunction); @@ -271,16 +604,13 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) { Builder->SetInsertPoint(CondBB); Value *CondV = emitExpr(Stmt->getCond()); if (!CondV) return; - if (CondV->getType()->isIntegerTy(64)) - CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "loopcond"); - if (CondV->getType()->isIntegerTy(1)) - CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "loopcond"); - + CondV = coerceValueToType(CondV, resolveType("BOOLEAN")); + Builder->CreateCondBr(CondV, LoopBB, AfterBB); Builder->SetInsertPoint(LoopBB); for (const auto &S : Stmt->getBody()) emitStmt(S.get()); - + if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(CondBB); @@ -304,11 +634,7 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) { Builder->SetInsertPoint(CondBB); Value *CondV = emitExpr(Stmt->getCond()); if (!CondV) return; - - if (CondV->getType()->isIntegerTy(64)) - CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "untilcond"); - if (CondV->getType()->isIntegerTy(1)) - CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "untilcond"); + CondV = coerceValueToType(CondV, resolveType("BOOLEAN")); Builder->CreateCondBr(CondV, AfterBB, LoopBB); @@ -318,15 +644,21 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) { void CodeGen::emitForStmt(ForStmtAST *Stmt) { Function *TheFunction = Builder->GetInsertBlock()->getParent(); std::string VarName = Stmt->getVarName(); - - Value *StartVal = emitExpr(Stmt->getStart()); - if (!StartVal) return; - Value *Alloca = NamedValues[VarName]; - if (!Alloca) { + const SymbolInfo *Symbol = getSymbolInfo(VarName); + if (!Symbol) { fprintf(stderr, "Error: Unknown variable in FOR loop %s\n", VarName.c_str()); return; } + if (Symbol->TypeName != "INTEGER") { + fprintf(stderr, "Error: FOR loop variable %s must be INTEGER\n", VarName.c_str()); + return; + } + + Value *StartVal = coerceValueToType(emitExpr(Stmt->getStart()), resolveType("INTEGER")); + if (!StartVal) return; + + Value *Alloca = Symbol->Storage; Builder->CreateStore(StartVal, Alloca); BasicBlock *CondBB = BasicBlock::Create(*TheContext, "forcond", TheFunction); @@ -338,22 +670,19 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) { Builder->SetInsertPoint(CondBB); Value *CurVar = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str()); - Value *EndVal = emitExpr(Stmt->getEnd()); + Value *EndVal = coerceValueToType(emitExpr(Stmt->getEnd()), resolveType("INTEGER")); if (!EndVal) return; - bool isNegativeStep = false; + bool IsNegativeStep = false; if (Stmt->getStep()) { if (auto *Num = dynamic_cast(Stmt->getStep())) { - if (Num->getVal() < 0) isNegativeStep = true; + if (Num->getVal() < 0) IsNegativeStep = true; } } - Value *CondV; - if (isNegativeStep) { - CondV = Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge"); - } else { - CondV = Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le"); - } + Value *CondV = IsNegativeStep + ? Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge") + : Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le"); Builder->CreateCondBr(CondV, LoopBB, AfterBB); @@ -363,13 +692,13 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) { Builder->CreateBr(IncBB); Builder->SetInsertPoint(IncBB); - Value *StepVal; + Value *StepVal = nullptr; if (Stmt->getStep()) { - StepVal = emitExpr(Stmt->getStep()); + StepVal = coerceValueToType(emitExpr(Stmt->getStep()), resolveType("INTEGER")); } else { StepVal = ConstantInt::get(*TheContext, APInt(64, 1)); } - + Value *CurValForInc = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str()); Value *NextVal = Builder->CreateAdd(CurValForInc, StepVal, "nextval"); Builder->CreateStore(NextVal, Alloca); @@ -385,7 +714,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { Arrays->emitArrayDeclare(ArrDecl, *this); return; } - + if (auto *ArrAssign = dynamic_cast(Stmt)) { Arrays->emitArrayAssign(ArrAssign, *this); return; @@ -394,40 +723,39 @@ void CodeGen::emitStmt(StmtAST *Stmt) { if (auto *FuncDef = dynamic_cast(Stmt)) { BasicBlock *SavedBlock = Builder->GetInsertBlock(); - FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) { - this->emitStmt(S); + FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) { + this->emitStmt(S); }); if (SavedBlock) Builder->SetInsertPoint(SavedBlock); - return; } - else if (auto *Call = dynamic_cast(Stmt)) { + if (auto *Call = dynamic_cast(Stmt)) { Function *CalleeF = TheModule->getFunction(Call->getCallee()); std::vector Args; - + for (unsigned i = 0; i < Call->getArgs().size(); ++i) { ExprAST *ArgExpr = Call->getArgs()[i].get(); - bool isByRef = false; - + bool IsByRef = false; + if (CalleeF && i < CalleeF->arg_size()) { if (CalleeF->getArg(i)->getType()->isPointerTy()) { - isByRef = true; + IsByRef = true; } } - if (isByRef) { + if (IsByRef) { if (auto *Var = dynamic_cast(ArgExpr)) { - Value *Ptr = NamedValues[Var->getName()]; + Value *Ptr = getNamedValue(Var->getName()); if (!Ptr) { fprintf(stderr, "Error: Unknown variable %s in BYREF call\n", Var->getName().c_str()); return; } Args.push_back(Ptr); } else { - fprintf(stderr, "Error: BYREF argument must be a variable.\n"); - return; + fprintf(stderr, "Error: BYREF argument must be a variable.\n"); + return; } } else { Args.push_back(emitExpr(ArgExpr)); @@ -437,7 +765,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { return; } - else if (auto *Ret = dynamic_cast(Stmt)) { + if (auto *Ret = dynamic_cast(Stmt)) { Value *RetVal = nullptr; if (Ret->getRetVal()) { RetVal = emitExpr(Ret->getRetVal()); @@ -447,120 +775,106 @@ void CodeGen::emitStmt(StmtAST *Stmt) { } if (auto *Decl = dynamic_cast(Stmt)) { - if (Decl->getType() == "INTEGER") IntHandler->emitDeclare(Decl->getName()); - else if (Decl->getType() == "REAL") RealHelper->emitDeclare(Decl->getName()); - else if (Decl->getType() == "BOOLEAN") BoolHandler->emitDeclare(Decl->getName()); - else if (Decl->getType() == "STRING") StrHandler->emitDeclare(Decl->getName()); - else { - fprintf(stderr, "Unknown type %s\n", Decl->getType().c_str()); - } + emitDeclareStmt(Decl); + return; } - else if (auto *Assign = dynamic_cast(Stmt)) { + + if (auto *Assign = dynamic_cast(Stmt)) { + const SymbolInfo *Info = getSymbolInfo(Assign->getName()); + if (!Info) { + fprintf(stderr, "Error: Unknown variable name %s\n", Assign->getName().c_str()); + return; + } + if (Info->IsArray) { + fprintf(stderr, "Error: Cannot assign array %s without indices\n", Assign->getName().c_str()); + return; + } + Value *Val = emitExpr(Assign->getExpr()); - if (Val) { - Value *Alloca = NamedValues[Assign->getName()]; - if (!Alloca) { - fprintf(stderr, "Error: Unknown variable name %s\n", Assign->getName().c_str()); - return; - } - - AllocaInst *AI = cast(Alloca); - - if (AI->getAllocatedType() == Type::getDoubleTy(*TheContext) && Val->getType()->isIntegerTy(64)) { - Val = Builder->CreateSIToFP(Val, Type::getDoubleTy(*TheContext)); - } + const TypeInfo *TargetType = resolveType(Info->TypeName); + Val = coerceValueToType(Val, TargetType); + if (!Val) return; - if (AI->getAllocatedType() == Type::getInt64Ty(*TheContext) && Val->getType()->isDoubleTy()) { - Val = Builder->CreateFPToSI(Val, Type::getInt64Ty(*TheContext), "double_to_int"); - } - - if (AI->getAllocatedType() == Type::getInt64Ty(*TheContext) && Val->getType()->isIntegerTy(1)) { - Val = Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext)); - } + Builder->CreateStore(Val, Info->Storage); + return; + } - Builder->CreateStore(Val, Alloca); + if (auto *In = dynamic_cast(Stmt)) { + const SymbolInfo *Info = getSymbolInfo(In->getName()); + if (!Info) { + fprintf(stderr, "Error: Unknown variable name %s\n", In->getName().c_str()); + return; } - } - else if (auto *In = dynamic_cast(Stmt)) { - Value *Alloca = NamedValues[In->getName()]; - if (Alloca) { - AllocaInst *AI = cast(Alloca); - std::vector Args; - - if (AI->getAllocatedType()->isDoubleTy()) { - Args.push_back(ScanfFloatFormatStr); - Args.push_back(Alloca); - Builder->CreateCall(ScanfFunc, Args); - } else if (AI->getAllocatedType()->isIntegerTy(1)) { - AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input"); - - Args.push_back(ScanfFormatStr); - Args.push_back(TempInt); - Builder->CreateCall(ScanfFunc, Args); - - Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt); - Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast"); - - Builder->CreateStore(BoolVal, Alloca); - } else if (AI->getAllocatedType()->isPointerTy()) { - Value *BufSize = ConstantInt::get(*TheContext, APInt(64, 256)); - - Args.push_back(ScanfStringFormatStr); - - AllocaInst *InputBuf = Builder->CreateAlloca(Type::getInt8Ty(*TheContext), ConstantInt::get(*TheContext, APInt(64, 1024)), "input_buf"); - Args.push_back(InputBuf); - Builder->CreateCall(ScanfFunc, Args); - - Function *MallocF = TheModule->getFunction("malloc"); - if (MallocF) { - Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 1024))); - Args[1] = Mem; - Builder->CreateCall(ScanfFunc, Args); - Builder->CreateStore(Mem, Alloca); - } - } else { - Args.push_back(ScanfFormatStr); - Args.push_back(Alloca); - Builder->CreateCall(ScanfFunc, Args); - } + if (Info->IsArray) { + fprintf(stderr, "Error: INPUT for entire array %s is not supported\n", In->getName().c_str()); + return; } - } - else if (auto *Out = dynamic_cast(Stmt)) { - bool handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this, PrintfFunc, PrintfFormatStr); - - if (!handled) { - Value *Val = emitExpr(Out->getExpr()); - if (Val) { - std::vector Args; - if (Val->getType()->isDoubleTy()) { - Args.push_back(PrintfFloatFormatStr); - Args.push_back(Val); - } else if (Val->getType()->isIntegerTy(1)) { - Args.push_back(PrintfStringFormatStr); - Value *StrPtr = Builder->CreateSelect(Val, TrueStr, FalseStr); - Args.push_back(StrPtr); - } else if (Val->getType()->isPointerTy()) { - Args.push_back(PrintfStringFormatStr); - Args.push_back(Val); - } else { - Args.push_back(PrintfFormatStr); - Args.push_back(Val); - } - - Builder->CreateCall(PrintfFunc, Args); - } + + const TypeInfo *TypeInfo = resolveType(Info->TypeName); + if (!TypeInfo) { + fprintf(stderr, "Error: Unknown type for INPUT %s\n", In->getName().c_str()); + return; } + + std::vector Args; + if (TypeInfo->isReal()) { + Args.push_back(ScanfFloatFormatStr); + Args.push_back(Info->Storage); + Builder->CreateCall(ScanfFunc, Args); + } else if (TypeInfo->isBoolean()) { + AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input"); + Args.push_back(ScanfFormatStr); + Args.push_back(TempInt); + Builder->CreateCall(ScanfFunc, Args); + + Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt); + Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast"); + Builder->CreateStore(BoolVal, Info->Storage); + } else if (TypeInfo->isString()) { + Function *MallocF = TheModule->getFunction("malloc"); + Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 1024)), "input_str"); + Args.push_back(ScanfStringFormatStr); + Args.push_back(Mem); + Builder->CreateCall(ScanfFunc, Args); + Builder->CreateStore(Mem, Info->Storage); + } else if (TypeInfo->isChar()) { + Value *CharFmt = Builder->CreateGlobalStringPtr(" %c", "fmt_in_char", 0, TheModule.get()); + Args.push_back(CharFmt); + Args.push_back(Info->Storage); + Builder->CreateCall(ScanfFunc, Args); + } else { + Args.push_back(ScanfFormatStr); + Args.push_back(Info->Storage); + Builder->CreateCall(ScanfFunc, Args); + } + return; } - else if (auto *IfStmt = dynamic_cast(Stmt)) { + + if (auto *Out = dynamic_cast(Stmt)) { + bool Handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this); + if (Handled) return; + + Value *Val = emitExpr(Out->getExpr()); + const TypeInfo *TypeInfo = getExprTypeInfo(Out->getExpr()); + if (!TypeInfo) TypeInfo = resolveType("INTEGER"); + emitOutputValue(Val, TypeInfo, true); + return; + } + + if (auto *IfStmt = dynamic_cast(Stmt)) { emitIfStmt(IfStmt); + return; } - else if (auto *WhileStmt = dynamic_cast(Stmt)) { + if (auto *WhileStmt = dynamic_cast(Stmt)) { emitWhileStmt(WhileStmt); + return; } - else if (auto *RepeatStmt = dynamic_cast(Stmt)) { + if (auto *RepeatStmt = dynamic_cast(Stmt)) { emitRepeatStmt(RepeatStmt); + return; } - else if (auto *ForStmt = dynamic_cast(Stmt)) { + if (auto *ForStmt = dynamic_cast(Stmt)) { emitForStmt(ForStmt); + return; } } diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index a929943..89aa3d8 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -1,16 +1,17 @@ #include "cps/FunctionGen.h" #include "llvm/IR/Verifier.h" -#include +#include using namespace llvm; using namespace cps; Type *FunctionGen::getLLVMType(const std::string &TypeName) { - if (TypeName == "INTEGER") return Type::getInt64Ty(Context); - if (TypeName == "BOOLEAN") return Type::getInt1Ty(Context); - if (TypeName == "REAL") return Type::getDoubleTy(Context); - if (TypeName == "VOID") return Type::getVoidTy(Context); - return Type::getInt64Ty(Context); + Type *Resolved = Types.getLLVMType(TypeName); + if (!Resolved) { + fprintf(stderr, "Error: Unknown type %s\n", TypeName.c_str()); + return Type::getInt64Ty(Context); + } + return Resolved; } void FunctionGen::createArgumentAllocas(Function *F, const std::vector> &Args) { @@ -19,20 +20,23 @@ void FunctionGen::createArgumentAllocas(Function *F, const std::vector(Args[Idx]); std::string ArgTypeStr = std::get<1>(Args[Idx]); bool IsRef = std::get<2>(Args[Idx]); - + Value *ArgVal = &(*AI); ArgVal->setName(ArgName); if (IsRef) { NamedValues[ArgName] = ArgVal; - } else { - Type *ArgType = getLLVMType(ArgTypeStr); - IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin()); - AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName); - - Builder.CreateStore(ArgVal, Alloca); - NamedValues[ArgName] = Alloca; + Symbols[ArgName] = {ArgVal, ArgTypeStr, false}; + continue; } + + Type *ArgType = getLLVMType(ArgTypeStr); + IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin()); + AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName); + + Builder.CreateStore(ArgVal, Alloca); + NamedValues[ArgName] = Alloca; + Symbols[ArgName] = {Alloca, ArgTypeStr, false}; } } @@ -48,23 +52,28 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { Type *RetType = getLLVMType(Proto->getReturnType()); FunctionType *FT = FunctionType::get(RetType, ArgTypes, false); - Function *F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module); + Function *F = Module.getFunction(Proto->getName()); + if (!F) { + F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module); + } unsigned Idx = 0; for (auto &Arg : F->args()) { - if (Idx < Proto->getArgs().size()) + if (Idx < Proto->getArgs().size()) { Arg.setName(std::get<0>(Proto->getArgs()[Idx++])); + } } return F; } -Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, +Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, const std::function &StmtEmitter) { PrototypeAST *Proto = FuncAST->getProto(); Function *TheFunction = Module.getFunction(Proto->getName()); - if (!TheFunction) + if (!TheFunction) { TheFunction = emitPrototype(Proto); + } if (!TheFunction) return nullptr; if (!TheFunction->empty()) { @@ -76,8 +85,10 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, Builder.SetInsertPoint(BB); std::map OldNamedValues = NamedValues; + std::map OldSymbols = Symbols; NamedValues.clear(); - + Symbols.clear(); + createArgumentAllocas(TheFunction, Proto->getArgs()); for (const auto &Stmt : FuncAST->getBody()) { @@ -85,19 +96,24 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, } if (!Builder.GetInsertBlock()->getTerminator()) { - if (Proto->getReturnType() == "VOID") + if (Proto->getReturnType() == "VOID") { Builder.CreateRetVoid(); - else + } else { Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType())); + } } verifyFunction(*TheFunction); NamedValues = OldNamedValues; + Symbols = OldSymbols; return TheFunction; } -static Value *GenerateCall(llvm::Module &Module, llvm::IRBuilder<> &Builder, llvm::LLVMContext &Context, - const std::string &CalleeName, const std::vector &Args) { +static Value *GenerateCall(llvm::Module &Module, + llvm::IRBuilder<> &Builder, + llvm::LLVMContext &Context, + const std::string &CalleeName, + const std::vector &Args) { Function *CalleeF = Module.getFunction(CalleeName); if (!CalleeF) { std::vector ArgTypes; diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc new file mode 100644 index 0000000..59dcc18 --- /dev/null +++ b/lib/CodeGen/TypeSystem.cc @@ -0,0 +1,156 @@ +#include "cps/TypeSystem.h" +#include "llvm/IR/Constants.h" +#include + +using namespace llvm; +using namespace cps; + +bool TypeInfo::isNumeric() const { + return Kind == TypeKind::Integer || Kind == TypeKind::Real; +} + +bool TypeInfo::isIntegral() const { + return Kind == TypeKind::Integer || Kind == TypeKind::Char; +} + +bool TypeInfo::isReal() const { + return Kind == TypeKind::Real; +} + +bool TypeInfo::isBoolean() const { + return Kind == TypeKind::Boolean; +} + +bool TypeInfo::isString() const { + return Kind == TypeKind::String; +} + +bool TypeInfo::isChar() const { + return Kind == TypeKind::Char; +} + +bool TypeInfo::isVoid() const { + return Kind == TypeKind::Void; +} + +TypeSystem::TypeSystem(LLVMContext &Ctx) : Context(Ctx) { + registerBuiltins(); +} + +void TypeSystem::registerBuiltins() { + registerType("INTEGER", + Type::getInt64Ty(Context), + 8, + TypeKind::Integer, + true, + false, + true); + + registerType("REAL", + Type::getDoubleTy(Context), + 8, + TypeKind::Real, + true, + false, + true); + + registerType("BOOLEAN", + Type::getInt1Ty(Context), + 1, + TypeKind::Boolean, + true, + false, + true); + + registerType("STRING", + PointerType::getUnqual(Context), + 8, + TypeKind::String, + true, + true, + true); + + registerType("CHAR", + Type::getInt8Ty(Context), + 1, + TypeKind::Char, + true, + false, + true); + + registerType("VOID", + Type::getVoidTy(Context), + 0, + TypeKind::Void, + false, + false, + true); +} + +const TypeInfo *TypeSystem::resolve(const std::string &TypeName) const { + auto It = Types.find(TypeName); + if (It == Types.end()) { + return nullptr; + } + return &It->second; +} + +bool TypeSystem::hasType(const std::string &TypeName) const { + return resolve(TypeName) != nullptr; +} + +const TypeInfo *TypeSystem::registerType(const std::string &TypeName, + Type *LLVMType, + uint64_t ElementSize, + TypeKind Kind, + bool Printable, + bool ReferenceLike, + bool Builtin) { + TypeInfo Info; + Info.Name = TypeName; + Info.LLVMType = LLVMType; + Info.ElementSize = ElementSize; + Info.Kind = Kind; + Info.Printable = Printable; + Info.Builtin = Builtin; + Info.ReferenceLike = ReferenceLike; + + auto Result = Types.insert_or_assign(TypeName, std::move(Info)); + return &Result.first->second; +} + +Type *TypeSystem::getLLVMType(const std::string &TypeName) const { + const TypeInfo *Info = resolve(TypeName); + return Info ? Info->LLVMType : nullptr; +} + +uint64_t TypeSystem::getElementSize(const std::string &TypeName) const { + const TypeInfo *Info = resolve(TypeName); + return Info ? Info->ElementSize : 0; +} + +Constant *TypeSystem::getZeroValue(const std::string &TypeName) const { + const TypeInfo *Info = resolve(TypeName); + if (!Info || !Info->LLVMType || Info->LLVMType->isVoidTy()) { + return nullptr; + } + + switch (Info->Kind) { + case TypeKind::Integer: + return ConstantInt::get(Context, APInt(64, 0)); + case TypeKind::Real: + return ConstantFP::get(Context, APFloat(0.0)); + case TypeKind::Boolean: + return ConstantInt::get(Context, APInt(1, 0)); + case TypeKind::Char: + return ConstantInt::get(Context, APInt(8, 0)); + case TypeKind::String: + return ConstantPointerNull::get(cast(Info->LLVMType)); + case TypeKind::Void: + return nullptr; + case TypeKind::Custom: + return Constant::getNullValue(Info->LLVMType); + } + + return Constant::getNullValue(Info->LLVMType); +} -- cgit v1.3.1-4-g156e