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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
#include "cps/StringHandler.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Constants.h"
using namespace llvm;
using namespace cps;
StringHandler::StringHandler(LLVMContext &Ctx, IRBuilder<> &B, llvm::Module &M,
std::map<std::string, Value*> &NV)
: Context(Ctx), Builder(B), Module(M), NamedValues(NV) {
setupExternalFunctions();
}
void StringHandler::setupExternalFunctions() {
FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(Context), {Type::getInt64Ty(Context)}, false);
MallocFunc = Module.getOrInsertFunction("malloc", MallocType);
FunctionType *FreeType = FunctionType::get(Type::getVoidTy(Context), {PointerType::getUnqual(Context)}, false);
FreeFunc = Module.getOrInsertFunction("free", FreeType);
FunctionType *StrLenType = FunctionType::get(Type::getInt64Ty(Context), {PointerType::getUnqual(Context)}, false);
StrLenFunc = Module.getOrInsertFunction("strlen", StrLenType);
std::vector<Type*> MemCpyArgs = {PointerType::getUnqual(Context), PointerType::getUnqual(Context), Type::getInt64Ty(Context)};
FunctionType *MemCpyType = FunctionType::get(PointerType::getUnqual(Context), MemCpyArgs, false);
MemCpyFunc = Module.getOrInsertFunction("memcpy", MemCpyType);
FunctionType *CharCaseType = FunctionType::get(Type::getInt32Ty(Context), {Type::getInt32Ty(Context)}, false);
ToUpperFunc = Module.getOrInsertFunction("toupper", CharCaseType);
ToLowerFunc = Module.getOrInsertFunction("tolower", CharCaseType);
}
void StringHandler::emitDeclare(const std::string &Name) {
Function *TheFunction = Builder.GetInsertBlock()->getParent();
IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
AllocaInst *Alloca = TmpB.CreateAlloca(PointerType::getUnqual(Context), nullptr, Name);
Value *EmptyStr = createLiteral("");
Builder.CreateStore(EmptyStr, Alloca);
NamedValues[Name] = Alloca;
}
Value *StringHandler::createLiteral(const std::string &Val) {
return Builder.CreateGlobalStringPtr(Val);
}
Value *StringHandler::emitLength(Value *Str) {
if (!Str) return nullptr;
return Builder.CreateCall(StrLenFunc, Str, "len");
}
Value *StringHandler::emitMid(Value *Str, Value *Start, Value *Len) {
Value *FullLen = emitLength(Str);
Value *One = ConstantInt::get(Context, APInt(64, 1));
Value *Zero = ConstantInt::get(Context, APInt(64, 0));
Value *StartZeroBased = Builder.CreateSub(Start, One, "start_idx");
Value *IsNeg = Builder.CreateICmpSLT(StartZeroBased, Zero);
StartZeroBased = Builder.CreateSelect(IsNeg, Zero, StartZeroBased);
Value *IsTooBig = Builder.CreateICmpSGT(StartZeroBased, FullLen);
StartZeroBased = Builder.CreateSelect(IsTooBig, FullLen, StartZeroBased);
Value *RemLen = Builder.CreateSub(FullLen, StartZeroBased);
Value *IsLenTooBig = Builder.CreateICmpSGT(Len, RemLen);
Value *ActualLen = Builder.CreateSelect(IsLenTooBig, RemLen, Len);
Value *IsLenNeg = Builder.CreateICmpSLT(ActualLen, Zero);
ActualLen = Builder.CreateSelect(IsLenNeg, Zero, ActualLen);
Value *AllocSize = Builder.CreateAdd(ActualLen, One);
Value *NewStrMem = Builder.CreateCall(MallocFunc, AllocSize, "mid_str_mem");
Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Str, StartZeroBased);
std::vector<Value*> Args = {NewStrMem, SrcPtr, 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::emitRight(Value *Str, Value *Len) {
Value *FullLen = emitLength(Str);
Value *StartIdx = Builder.CreateSub(FullLen, Len, "right_start");
Value *Zero = ConstantInt::get(Context, APInt(64, 0));
Value *IsNeg = Builder.CreateICmpSLT(StartIdx, Zero);
StartIdx = Builder.CreateSelect(IsNeg, Zero, StartIdx);
Value *ActualLen = Builder.CreateSub(FullLen, StartIdx);
Value *One = ConstantInt::get(Context, APInt(64, 1));
Value *AllocSize = Builder.CreateAdd(ActualLen, One);
Value *NewStrMem = Builder.CreateCall(MallocFunc, AllocSize, "right_str_mem");
Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Str, StartIdx);
std::vector<Value*> Args = {NewStrMem, SrcPtr, 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::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));
Value *AllocSize = Builder.CreateAdd(Len, One);
Value *NewStr = Builder.CreateCall(MallocFunc, AllocSize, "lcase_str");
Function *TheFunction = Builder.GetInsertBlock()->getParent();
BasicBlock *LoopBB = BasicBlock::Create(Context, "loop", TheFunction);
BasicBlock *AfterBB = BasicBlock::Create(Context, "afterloop", TheFunction);
IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
AllocaInst *IdxVar = TmpB.CreateAlloca(Type::getInt64Ty(Context), nullptr, "idx");
Builder.CreateStore(ConstantInt::get(Context, APInt(64, 0)), IdxVar);
Builder.CreateBr(LoopBB);
Builder.SetInsertPoint(LoopBB);
Value *CurIdx = Builder.CreateLoad(Type::getInt64Ty(Context), IdxVar);
Value *Cond = Builder.CreateICmpSLT(CurIdx, Len);
BasicBlock *BodyBB = BasicBlock::Create(Context, "body", TheFunction);
Builder.CreateCondBr(Cond, BodyBB, AfterBB);
Builder.SetInsertPoint(BodyBB);
Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Str, CurIdx);
Value *CharVal = Builder.CreateLoad(Type::getInt8Ty(Context), SrcPtr);
Value *ExtChar = Builder.CreateSExt(CharVal, Type::getInt32Ty(Context));
Value *LowerChar = Builder.CreateCall(ToLowerFunc, ExtChar);
Value *TruncChar = Builder.CreateTrunc(LowerChar, Type::getInt8Ty(Context));
Value *DestPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, CurIdx);
Builder.CreateStore(TruncChar, DestPtr);
Value *NextIdx = Builder.CreateAdd(CurIdx, One);
Builder.CreateStore(NextIdx, IdxVar);
Builder.CreateBr(LoopBB);
Builder.SetInsertPoint(AfterBB);
Value *NullPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, Len);
Builder.CreateStore(ConstantInt::get(Type::getInt8Ty(Context), 0), NullPtr);
return NewStr;
}
Value *StringHandler::emitUCase(Value *Str) {
Value *Len = emitLength(Str);
Value *One = ConstantInt::get(Context, APInt(64, 1));
Value *AllocSize = Builder.CreateAdd(Len, One);
Value *NewStr = Builder.CreateCall(MallocFunc, AllocSize, "ucase_str");
// Loop
Function *TheFunction = Builder.GetInsertBlock()->getParent();
BasicBlock *LoopBB = BasicBlock::Create(Context, "loop", TheFunction);
BasicBlock *AfterBB = BasicBlock::Create(Context, "afterloop", TheFunction);
// Init i = 0
IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
AllocaInst *IdxVar = TmpB.CreateAlloca(Type::getInt64Ty(Context), nullptr, "idx");
Builder.CreateStore(ConstantInt::get(Context, APInt(64, 0)), IdxVar);
Builder.CreateBr(LoopBB);
Builder.SetInsertPoint(LoopBB);
Value *CurIdx = Builder.CreateLoad(Type::getInt64Ty(Context), IdxVar);
Value *Cond = Builder.CreateICmpSLT(CurIdx, Len);
BasicBlock *BodyBB = BasicBlock::Create(Context, "body", TheFunction);
Builder.CreateCondBr(Cond, BodyBB, AfterBB);
Builder.SetInsertPoint(BodyBB);
Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Str, CurIdx);
Value *CharVal = Builder.CreateLoad(Type::getInt8Ty(Context), SrcPtr);
Value *ExtChar = Builder.CreateSExt(CharVal, Type::getInt32Ty(Context));
Value *UpperChar = Builder.CreateCall(ToUpperFunc, ExtChar);
Value *TruncChar = Builder.CreateTrunc(UpperChar, Type::getInt8Ty(Context));
Value *DestPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, CurIdx);
Builder.CreateStore(TruncChar, DestPtr);
Value *NextIdx = Builder.CreateAdd(CurIdx, One);
Builder.CreateStore(NextIdx, IdxVar);
Builder.CreateBr(LoopBB);
Builder.SetInsertPoint(AfterBB);
Value *NullPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, Len);
Builder.CreateStore(ConstantInt::get(Type::getInt8Ty(Context), 0), NullPtr);
return NewStr;
}
|