diff options
Diffstat (limited to 'lib/CodeGen')
| -rw-r--r-- | lib/CodeGen/ArithmeticHandler.cc | 26 | ||||
| -rw-r--r-- | lib/CodeGen/CharHandler.cc | 15 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 41 | ||||
| -rw-r--r-- | lib/CodeGen/StringConversionHandler.cc | 71 | ||||
| -rw-r--r-- | lib/CodeGen/StringHandler.cc | 29 |
5 files changed, 182 insertions, 0 deletions
diff --git a/lib/CodeGen/ArithmeticHandler.cc b/lib/CodeGen/ArithmeticHandler.cc index df83513..585104d 100644 --- a/lib/CodeGen/ArithmeticHandler.cc +++ b/lib/CodeGen/ArithmeticHandler.cc @@ -11,6 +11,32 @@ Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line) bool LIsDouble = LHS->getType()->isDoubleTy(); bool RIsDouble = RHS->getType()->isDoubleTy(); + if (Op == '&') { + Module *M = Builder.GetInsertBlock()->getParent()->getParent(); + + FunctionType *StrLenTy = FunctionType::get(Type::getInt64Ty(Context), {PointerType::getUnqual(Context)}, false); + FunctionCallee StrLenF = M->getOrInsertFunction("strlen", StrLenTy); + + FunctionType *MallocTy = FunctionType::get(PointerType::getUnqual(Context), {Type::getInt64Ty(Context)}, false); + FunctionCallee MallocF = M->getOrInsertFunction("malloc", MallocTy); + + FunctionType *StrCpyTy = FunctionType::get(PointerType::getUnqual(Context), {PointerType::getUnqual(Context), PointerType::getUnqual(Context)}, false); + FunctionCallee StrCpyF = M->getOrInsertFunction("strcpy", StrCpyTy); + FunctionCallee StrCatF = M->getOrInsertFunction("strcat", StrCpyTy); + + Value *LLen = Builder.CreateCall(StrLenF, {LHS}, "llen"); + Value *RLen = Builder.CreateCall(StrLenF, {RHS}, "rlen"); + Value *TotalLen = Builder.CreateAdd(LLen, RLen, "totallen"); + Value *AllocSize = Builder.CreateAdd(TotalLen, ConstantInt::get(Type::getInt64Ty(Context), 1), "allocsize"); + + Value *NewStr = Builder.CreateCall(MallocF, {AllocSize}, "concat_str"); + + Builder.CreateCall(StrCpyF, {NewStr, LHS}); + Builder.CreateCall(StrCatF, {NewStr, RHS}); + + return NewStr; + } + if (Op == '/') { Value *LVal = LHS; Value *RVal = RHS; diff --git a/lib/CodeGen/CharHandler.cc b/lib/CodeGen/CharHandler.cc new file mode 100644 index 0000000..5e9b502 --- /dev/null +++ b/lib/CodeGen/CharHandler.cc @@ -0,0 +1,15 @@ +#include "cps/CharHandler.h" + +using namespace llvm; +using namespace cps; + +CharHandler::CharHandler(LLVMContext &Ctx, IRBuilder<> &B, llvm::Module &M) + : Context(Ctx), Builder(B), Module(M) {} + +Value *CharHandler::emitAsc(Value *CharVal) { + return Builder.CreateZExt(CharVal, Type::getInt32Ty(Context), "asc_val"); +} + +Value *CharHandler::emitChr(Value *IntVal) { + return Builder.CreateTrunc(IntVal, Type::getInt8Ty(Context), "chr_val"); +} diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index ee7ab04..c5b0ff3 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -25,6 +25,8 @@ CodeGen::CodeGen() { BoolHandler = std::make_unique<BooleanHandler>(*TheContext, *Builder, *TheModule, NamedValues); ArithHandler = std::make_unique<ArithmeticHandler>(*TheContext, *Builder); StrHandler = std::make_unique<StringHandler>(*TheContext, *Builder, *TheModule, NamedValues); + ChrHandler = std::make_unique<CharHandler>(*TheContext, *Builder, *TheModule); + StrConvHandler = std::make_unique<StringConversionHandler>(*TheContext, *Builder, *TheModule); SetupExternalFunctions(); } @@ -151,6 +153,11 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { 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()), + emitExpr(Call->getArgs()[1].get())); + } if (Name == "LCASE") { if (Call->getArgs().size() != 1) { fprintf(stderr, "LCASE expects 1 arg\n"); return nullptr; } return StrHandler->emitLCase(emitExpr(Call->getArgs()[0].get())); @@ -159,6 +166,36 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { if (Call->getArgs().size() != 1) { fprintf(stderr, "UCASE expects 1 arg\n"); return nullptr; } return StrHandler->emitUCase(emitExpr(Call->getArgs()[0].get())); } + 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); + } + if (Name == "CHR") { + if (Call->getArgs().size() != 1) return nullptr; + Value *CharVal = ChrHandler->emitChr(emitExpr(Call->getArgs()[0].get())); + 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))); + Builder->CreateStore(ConstantInt::get(Type::getInt8Ty(*TheContext), 0), NullPtr); + return Mem; + } + if (Name == "IS_NUM") { + if (Call->getArgs().size() != 1) return nullptr; + return StrConvHandler->emitIsNum(emitExpr(Call->getArgs()[0].get())); + } + 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); + } + if (Name == "STR_TO_NUM") { + if (Call->getArgs().size() != 1) return nullptr; + return StrConvHandler->emitStrToNum(emitExpr(Call->getArgs()[0].get()), true); + } Function *CalleeF = TheModule->getFunction(Call->getCallee()); std::vector<Value*> Args; @@ -432,6 +469,10 @@ void CodeGen::emitStmt(StmtAST *Stmt) { if (AI->getAllocatedType() == Type::getDoubleTy(*TheContext) && Val->getType()->isIntegerTy(64)) { Val = Builder->CreateSIToFP(Val, Type::getDoubleTy(*TheContext)); } + + 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)); diff --git a/lib/CodeGen/StringConversionHandler.cc b/lib/CodeGen/StringConversionHandler.cc new file mode 100644 index 0000000..62b99d7 --- /dev/null +++ b/lib/CodeGen/StringConversionHandler.cc @@ -0,0 +1,71 @@ +#include "cps/StringConversionHandler.h" + +using namespace llvm; +using namespace cps; + +StringConversionHandler::StringConversionHandler(LLVMContext &Ctx, IRBuilder<> &B, llvm::Module &M) + : Context(Ctx), Builder(B), Module(M) { + setupExternalFunctions(); +} + +void StringConversionHandler::setupExternalFunctions() { + FunctionType *SprintfType = FunctionType::get(Type::getInt32Ty(Context), {PointerType::getUnqual(Context), PointerType::getUnqual(Context)}, true); + SprintfFunc = Module.getOrInsertFunction("sprintf", SprintfType); + + FunctionType *StrtolType = FunctionType::get(Type::getInt64Ty(Context), {PointerType::getUnqual(Context), PointerType::getUnqual(Context), Type::getInt32Ty(Context)}, false); + StrtolFunc = Module.getOrInsertFunction("strtol", StrtolType); + + FunctionType *StrtodType = FunctionType::get(Type::getDoubleTy(Context), {PointerType::getUnqual(Context), PointerType::getUnqual(Context)}, false); + StrtodFunc = Module.getOrInsertFunction("strtod", StrtodType); + + FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(Context), {Type::getInt64Ty(Context)}, false); + MallocFunc = Module.getOrInsertFunction("malloc", MallocType); +} + +Value *StringConversionHandler::emitNumToStr(Value *Num, bool IsReal) { + Value *AllocSize = ConstantInt::get(Type::getInt64Ty(Context), 64); + Value *Buffer = Builder.CreateCall(MallocFunc, AllocSize, "num_str_buf"); + + Value *FormatStr; + if (IsReal) { + FormatStr = Builder.CreateGlobalStringPtr("%f"); + } else { + FormatStr = Builder.CreateGlobalStringPtr("%d"); + } + + Builder.CreateCall(SprintfFunc, {Buffer, FormatStr, Num}); + return Buffer; +} + +Value *StringConversionHandler::emitStrToNum(Value *Str, bool AsReal) { + Value *NullPtr = ConstantPointerNull::get(PointerType::getUnqual(Context)); + if (AsReal) { + return Builder.CreateCall(StrtodFunc, {Str, NullPtr}, "str_to_real"); + } else { + Value *Base = ConstantInt::get(Type::getInt32Ty(Context), 10); + return Builder.CreateCall(StrtolFunc, {Str, NullPtr, Base}, "str_to_int"); + } +} + +Value *StringConversionHandler::emitIsNum(Value *Str) { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); + AllocaInst *EndPtrAlloc = TmpB.CreateAlloca(PointerType::getUnqual(Context), nullptr, "endptr_alloc"); + + Builder.CreateCall(StrtodFunc, {Str, EndPtrAlloc}); + Value *EndPtrVal = Builder.CreateLoad(PointerType::getUnqual(Context), EndPtrAlloc, "endptr_val"); + + FunctionType *StrLenType = FunctionType::get(Type::getInt64Ty(Context), {PointerType::getUnqual(Context)}, false); + FunctionCallee StrLenFunc = Module.getOrInsertFunction("strlen", StrLenType); + Value *Len = Builder.CreateCall(StrLenFunc, Str, "str_len"); + + Value *ExpectedEndPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Str, Len); + + Value *IsMatch = Builder.CreateICmpEQ(EndPtrVal, ExpectedEndPtr, "is_full_match"); + + Value *Zero = ConstantInt::get(Type::getInt64Ty(Context), 0); + Value *IsNotEmpty = Builder.CreateICmpSGT(Len, Zero, "is_not_empty"); + + return Builder.CreateAnd(IsMatch, IsNotEmpty, "is_num_bool"); +} diff --git a/lib/CodeGen/StringHandler.cc b/lib/CodeGen/StringHandler.cc index fda9ea5..f777059 100644 --- a/lib/CodeGen/StringHandler.cc +++ b/lib/CodeGen/StringHandler.cc @@ -112,6 +112,35 @@ Value *StringHandler::emitRight(Value *Str, Value *Len) { return NewStrMem; } +Value *StringHandler::emitLeft(Value *Str, Value *Len) { + Value *FullLen = emitLength(Str); + if (Len->getType()->isIntegerTy() && Len->getType()->getIntegerBitWidth() != 64) { + Len = Builder.CreateSExt(Len, Type::getInt64Ty(Context), "len_ext"); + } + else if (Len->getType()->isDoubleTy()) { + Len = Builder.CreateFPToSI(Len, Type::getInt64Ty(Context), "len_int"); + } + + Value *Zero = ConstantInt::get(Context, APInt(64, 0)); + Value *IsNeg = Builder.CreateICmpSLT(Len, Zero); + Value *SafeLen = Builder.CreateSelect(IsNeg, Zero, Len); + + Value *IsTooBig = Builder.CreateICmpSGT(SafeLen, FullLen); + Value *ActualLen = Builder.CreateSelect(IsTooBig, FullLen, SafeLen); + + Value *One = ConstantInt::get(Context, APInt(64, 1)); + Value *AllocSize = Builder.CreateAdd(ActualLen, One); + Value *NewStrMem = Builder.CreateCall(MallocFunc, AllocSize, "left_str_mem"); + + std::vector<Value*> Args = {NewStrMem, Str, ActualLen}; + Builder.CreateCall(MemCpyFunc, Args); + + Value *NullTermPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStrMem, ActualLen); + Builder.CreateStore(ConstantInt::get(Type::getInt8Ty(Context), 0), NullTermPtr); + + return NewStrMem; +} + Value *StringHandler::emitLCase(Value *Str) { Value *Len = emitLength(Str); Value *One = ConstantInt::get(Context, APInt(64, 1)); |
