aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/ArithmeticHandler.cc26
-rw-r--r--lib/CodeGen/CharHandler.cc15
-rw-r--r--lib/CodeGen/CodeGen.cc41
-rw-r--r--lib/CodeGen/StringConversionHandler.cc71
-rw-r--r--lib/CodeGen/StringHandler.cc29
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));