22 #define LLVM_BEFORE(major,minor)\
23 ((LLVM_MAJOR < major) || ((LLVM_MAJOR == major) && (LLVM_MINOR < minor)))
24 #define LLVM_AFTER(major,minor)\
25 ((LLVM_MAJOR > major) || ((LLVM_MAJOR == major) && (LLVM_MINOR > minor)))
27 #include <llvm/Analysis/Passes.h>
28 #include <llvm/Bitcode/ReaderWriter.h>
29 #include <llvm/ExecutionEngine/ExecutionEngine.h>
30 #include <llvm/ExecutionEngine/GenericValue.h>
31 #include <llvm/IR/Constants.h>
32 #include <llvm/IR/DataLayout.h>
33 #include <llvm/IR/DerivedTypes.h>
34 #include <llvm/IR/GlobalVariable.h>
35 #include <llvm/IR/IRBuilder.h>
36 #include <llvm/IR/LLVMContext.h>
37 #include <llvm/IR/Module.h>
39 #include <llvm/Support/system_error.h>
40 #include <llvm/Analysis/Verifier.h>
41 #include <llvm/Linker.h>
43 #include <llvm/IR/Verifier.h>
44 #include <llvm/Linker/Linker.h>
46 #include <llvm/PassManager.h>
47 #include <llvm/Support/MemoryBuffer.h>
48 #include <llvm/Support/TargetSelect.h>
49 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
50 #include <llvm/Transforms/IPO.h>
98 State() : C(getGlobalContext()), B(C)
102 OwningPtr<MemoryBuffer> buffer;
103 error_code ec = MemoryBuffer::getFile(
"runtime.bc", buffer);
106 std::cerr <<
"Failed to open runtime.bc: " << ec.message() <<
"\n";
109 Mod = ParseBitcodeFile(buffer.get(), C);
111 auto buffer = MemoryBuffer::getFile(
"runtime.bc");
113 if ((ec = buffer.getError()))
115 std::cerr <<
"Failed to open runtime.bc: " << ec.message() <<
"\n";
118 ErrorOr<Module*> e = parseBitcodeFile(buffer.get().get(), C);
119 if ((ec = e.getError()))
121 std::cerr <<
"Failed to parse runtime.bc: " << ec.message() <<
"\n";
127 F = Mod->getFunction(
"cell");
130 F->setLinkage(GlobalValue::PrivateLinkage);
132 BasicBlock *entry = BasicBlock::Create(C,
"entry", F);
133 B.SetInsertPoint(entry);
135 regTy = Type::getInt16Ty(C);
138 auto args = F->arg_begin();
147 for (
int i=0 ; i<10 ; i++)
149 a[i] = B.CreateAlloca(regTy);
154 v = B.CreateAlloca(regTy);
155 B.CreateStore(args++, v);
159 for (
int i=0 ; i<10 ; i++)
161 B.CreateStore(ConstantInt::get(regTy, 0), a[i]);
162 g[i] = B.CreateConstGEP1_32(gArg, i);
174 B.CreateRet(B.CreateLoad(v));
183 PassManagerBuilder PMBuilder;
186 PMBuilder.OptLevel = optimiseLevel;
189 PMBuilder.Inliner = createFunctionInliningPass(275);
192 FunctionPassManager *PerFunctionPasses=
new FunctionPassManager(Mod);
193 PMBuilder.populateFunctionPassManager(*PerFunctionPasses);
198 if (!I.isDeclaration())
200 PerFunctionPasses->run(I);
204 PerFunctionPasses->doFinalization();
205 delete PerFunctionPasses;
207 PassManager *PerModulePasses =
new PassManager();
208 PMBuilder.populateModulePassManager(*PerModulePasses);
209 PerModulePasses->run(*Mod);
210 delete PerModulePasses;
215 ExecutionEngine *EE = ExecutionEngine::create(Mod,
false, &error);
218 fprintf(stderr,
"Error: %s\n", error.c_str());
222 return (automaton)EE->getPointerToFunction(Mod->getFunction(
"automaton"));
231 InitializeNativeTarget();
237 return s.getAutomaton(optimiseLevel);
247 return ConstantInt::get(s.
regTy, value);
251 assert(registerNumber >= 0 && registerNumber < 10);
252 return s.
B.CreateLoad(s.
a[registerNumber]);
256 assert(registerNumber >= 0 && registerNumber < 10);
257 s.
B.CreateStore(val, s.
a[registerNumber]);
261 assert(registerNumber >= 0 && registerNumber < 10);
262 return s.
B.CreateLoad(s.
g[registerNumber]);
266 assert(registerNumber >= 0 && registerNumber < 10);
267 s.
B.CreateStore(val, s.
g[registerNumber]);
271 return s.
B.CreateLoad(s.
v);
275 s.
B.CreateStore(val, s.
v);
281 IRBuilder<> &B = s.
B;
282 Value *v = value->compile(s);
283 Value *o = target->compile(s);
290 result = B.CreateAdd(v, o);
296 result = B.CreateSub(o, v);
299 result = B.CreateMul(o, v);
302 result = B.CreateSDiv(o, v);
306 Value *gt = B.CreateICmpSGT(o, v);
307 result = B.CreateSelect(gt, v, o);
312 Value *gt = B.CreateICmpSGT(o, v);
313 result = B.CreateSelect(gt, o, v);
317 target->assign(s, result);
318 return target->compile(s);
324 IRBuilder<> &B = s.
B;
325 LLVMContext &C = s.
C;
328 Value *reg = value->compile(s);
331 BasicBlock *cont = BasicBlock::Create(s.
C,
"range_continue", s.
F);
333 PHINode *phi = PHINode::Create(s.
regTy, ranges.objects().size(),
334 "range_result", cont);
336 BasicBlock *current = B.GetInsertBlock();
337 for (
const auto &re : ranges.objects())
342 if (re->start.get() ==
nullptr)
344 Value *val = re->end->compile(s);
345 match = B.CreateICmpEQ(reg, val);
352 Value *min = re->start->compile(s);
353 Value *max = re->end->compile(s);
354 match = B.CreateAnd(B.CreateICmpSGE(reg, min),
355 B.CreateICmpSLE(reg, max));
361 BasicBlock *expr = BasicBlock::Create(C,
"range_result", F);
362 BasicBlock *next = BasicBlock::Create(C,
"range_next", F);
364 B.CreateCondBr(match, expr, next);
366 B.SetInsertPoint(expr);
372 Value *output = re->value->compile(s);
373 phi->addIncoming(output, B.GetInsertBlock());
380 B.SetInsertPoint(current);
385 phi->addIncoming(ConstantInt::get(s.
regTy, 0), B.GetInsertBlock());
386 B.SetInsertPoint(cont);
393 IRBuilder<> &B = s.
B;
396 Value *width = s.
width;
398 Type *regTy = s.
regTy;
399 LLVMContext &C = s.
C;
402 Value *Zero = ConstantInt::get(regTy, 0);
403 Value *One = ConstantInt::get(regTy, 1);
405 Value *XMin = B.CreateSub(x, One);
406 Value *XMax = B.CreateAdd(x, One);
407 Value *YMin = B.CreateSub(y, One);
408 Value *YMax = B.CreateAdd(y, One);
410 XMin = B.CreateSelect(B.CreateICmpSLT(XMin, Zero), x, XMin);
411 YMin = B.CreateSelect(B.CreateICmpSLT(YMin, Zero), y, YMin);
412 XMax = B.CreateSelect(B.CreateICmpSGE(XMax, width), x, XMax);
413 YMax = B.CreateSelect(B.CreateICmpSGE(YMax, height), y, YMax);
417 BasicBlock *start = B.GetInsertBlock();
419 BasicBlock *xLoopStart = BasicBlock::Create(C,
"x_loop_start", F);
420 BasicBlock *yLoopStart = BasicBlock::Create(C,
"y_loop_start", F);
422 B.CreateBr(xLoopStart);
423 B.SetInsertPoint(xLoopStart);
427 PHINode *XPhi = B.CreatePHI(regTy, 2);
428 XPhi->addIncoming(XMin, start);
430 B.CreateBr(yLoopStart);
431 B.SetInsertPoint(yLoopStart);
432 PHINode *YPhi = B.CreatePHI(regTy, 2);
433 YPhi->addIncoming(YMin, xLoopStart);
436 BasicBlock *endY = BasicBlock::Create(C,
"y_loop_end", F);
437 BasicBlock *body = BasicBlock::Create(C,
"body", F);
441 B.CreateCondBr(B.CreateAnd(B.CreateICmpEQ(x, XPhi),
442 B.CreateICmpEQ(y, YPhi)),
445 B.SetInsertPoint(body);
449 IntegerType *i32 = IntegerType::get(C, 32);
450 Value *x32 = B.CreateZExt(XPhi, i32);
451 Value *y32 = B.CreateZExt(YPhi, i32);
452 Value *height32 = B.CreateZExt(height, i32);
454 Value *idx = B.CreateAdd(y32, B.CreateMul(x32, height32));
457 B.CreateStore(B.CreateLoad(B.CreateGEP(s.
oldGrid, idx)), s.
a[0]);
460 statements->compile(s);
464 B.SetInsertPoint(endY);
465 BasicBlock *endX = BasicBlock::Create(C,
"x_loop_end", F);
466 BasicBlock *cont = BasicBlock::Create(C,
"continue", F);
468 YPhi->addIncoming(B.CreateAdd(YPhi, ConstantInt::get(regTy, 1)), endY);
469 B.CreateCondBr(B.CreateICmpEQ(YPhi, YMax), endX, yLoopStart);
471 B.SetInsertPoint(endX);
472 XPhi->addIncoming(B.CreateAdd(XPhi, ConstantInt::get(regTy, 1)), endX);
473 B.CreateCondBr(B.CreateICmpEQ(XPhi, XMax), cont, xLoopStart);
474 B.SetInsertPoint(cont);
480 for (
auto &s: statements.objects())
Value * height
The height of the grid (passed as an argument)
LLVMContext & C
LLVM uses a context object to allow multiple threads.
Value * oldGrid
The input grid (passed as an argument)
Type * regTy
The type of our registers (currently i16)
A list of statements that will be executed sequentially.
Function * F
The function representing the program.
Value * x
The x coordinate of the current cell (passed as an argument)
Value * a[10]
The 10 local registers in the source language.
Value * width
The width of the grid (passed as an argument)
Value * g[10]
The 10 global registers in the source language.
IRBuilder B
A helper class for generating instructions.
Value * y
The y coordinate of the current cell (passed as an argument)
Value * newGrid
The output grid (passed as an argument)
Value * v
The value of the current cell (passed as an argument, returned at the end)
Module * Mod
The compilation unit that we are generating.
automaton getAutomaton(int optimiseLevel)
Returns a function pointer for the automaton at the specified optimisation level. ...
State()
Construct the compiler state object.
virtual llvm::Value * compile(Compiler::State &) override
Compile this node, returning the LLVM value representing the result, if there is one.