aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/StringConversionHandler.cc
blob: 3b49cbb517259b0e38e538de8cd4fce98b291620 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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.CreateGlobalString("%f");
    } else {
        FormatStr = Builder.CreateGlobalString("%lld");
    }

    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");
}