llvm.org GIT mirror llvm / 060bb6b
Remove this from the main tree. I'll host it out of tree. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@112529 91177308-0d34-0410-b5e6-96231b3b80d8 Owen Anderson 8 years ago
8 changed file(s) with 0 addition(s) and 848 deletion(s). Raw diff Collapse all Expand all
+0
-77
examples/TracingBrainF/BrainF.h less more
None //===-- BrainF.h - BrainF compiler class ----------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8
9 #ifndef BRAINF_H
10 #define BRAINF_H
11
12 #include "llvm/LLVMContext.h"
13 #include "llvm/Module.h"
14 #include "llvm/ExecutionEngine/GenericValue.h"
15 #include "llvm/ExecutionEngine/JIT.h"
16 #include "llvm/PassManager.h"
17 #include "llvm/Support/IRBuilder.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/DenseSet.h"
20
21
22 using namespace llvm;
23
24 class BrainFTraceRecorder {
25 struct BrainFTraceNode {
26 uint8_t opcode;
27 size_t pc;
28 BrainFTraceNode(uint8_t o, size_t p)
29 : opcode(o), pc(p), left(0), right(0) { }
30 void dump(unsigned level);
31
32 // On an if, left is the x != 0 edge.
33 // A value of 0 indicates an un-traced edge.
34 // A value of ~0ULL indicates an edge to the trace head.
35 BrainFTraceNode *left, *right;
36 };
37
38 uint8_t prev_opcode;
39 uint8_t *iteration_count;
40 std::pair *trace_begin, *trace_end, *trace_tail;
41 DenseMap trace_map;
42 Module *module;
43 BasicBlock *Header;
44 Value *DataPtr;
45 PHINode *HeaderPHI;
46 ExecutionEngine *EE;
47
48 const IntegerType *int_type;
49 const FunctionType *op_type;
50 GlobalValue *bytecode_array, *executed_flag;
51 Value *getchar_func, *putchar_func;
52 FunctionPassManager *FPM;
53
54
55 void commit();
56 void initialize_module();
57 void compile(BrainFTraceNode* trace);
58 void compile_opcode(BrainFTraceNode *node, IRBuilder<>& builder);
59 void compile_plus(BrainFTraceNode *node, IRBuilder<>& builder);
60 void compile_minus(BrainFTraceNode *node, IRBuilder<>& builder);
61 void compile_left(BrainFTraceNode *node, IRBuilder<>& builder);
62 void compile_right(BrainFTraceNode *node, IRBuilder<>& builder);
63 void compile_put(BrainFTraceNode *node, IRBuilder<>& builder);
64 void compile_get(BrainFTraceNode *node, IRBuilder<>& builder);
65 void compile_if(BrainFTraceNode *node, IRBuilder<>& builder);
66 void compile_back(BrainFTraceNode *node, IRBuilder<>& builder);
67
68 public:
69 BrainFTraceRecorder();
70 ~BrainFTraceRecorder();
71
72 void record(size_t pc, uint8_t opcode);
73 void record_simple(size_t pc, uint8_t opcode);
74 };
75
76 #endif
+0
-351
examples/TracingBrainF/BrainFCodeGen.cpp less more
None //===-- BrainFCodeGen.cpp - BrainF trace compiler -----------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8
9 #include "BrainF.h"
10 #include "BrainFVM.h"
11 #include "llvm/Attributes.h"
12 #include "llvm/Support/StandardPasses.h"
13 #include "llvm/Target/TargetData.h"
14 #include "llvm/Target/TargetSelect.h"
15 #include "llvm/Transforms/Scalar.h"
16 #include "llvm/ADT/StringExtras.h"
17
18 /// initialize_module - perform setup of the LLVM code generation system.
19 void BrainFTraceRecorder::initialize_module() {
20 LLVMContext &Context = module->getContext();
21
22 // Initialize the code generator, and enable aggressive code generation.
23 InitializeNativeTarget();
24 EngineBuilder builder(module);
25 builder.setOptLevel(CodeGenOpt::Aggressive);
26 EE = builder.create();
27
28 // Create a FunctionPassManager to handle running optimization passes
29 // on our generated code. Setup a basic suite of optimizations for it.
30 FPM = new llvm::FunctionPassManager(module);
31 FPM->add(createInstructionCombiningPass());
32 FPM->add(createCFGSimplificationPass());
33 FPM->add(createScalarReplAggregatesPass());
34 FPM->add(createSimplifyLibCallsPass());
35 FPM->add(createInstructionCombiningPass());
36 FPM->add(createJumpThreadingPass());
37 FPM->add(createCFGSimplificationPass());
38 FPM->add(createInstructionCombiningPass());
39 FPM->add(createCFGSimplificationPass());
40 FPM->add(createReassociatePass());
41 FPM->add(createLoopRotatePass());
42 FPM->add(createLICMPass());
43 FPM->add(createLoopUnswitchPass(false));
44 FPM->add(createInstructionCombiningPass());
45 FPM->add(createIndVarSimplifyPass());
46 FPM->add(createLoopDeletionPass());
47 FPM->add(createLoopUnrollPass());
48 FPM->add(createInstructionCombiningPass());
49 FPM->add(createGVNPass());
50 FPM->add(createSCCPPass());
51 FPM->add(createInstructionCombiningPass());
52 FPM->add(createJumpThreadingPass());
53 FPM->add(createDeadStoreEliminationPass());
54 FPM->add(createAggressiveDCEPass());
55 FPM->add(createCFGSimplificationPass());
56
57 // Cache the LLVM type signature of an opcode function
58 int_type = sizeof(size_t) == 4 ?
59 IntegerType::getInt32Ty(Context) :
60 IntegerType::getInt64Ty(Context);
61 const Type *data_type =
62 PointerType::getUnqual(IntegerType::getInt8Ty(Context));
63 std::vector args;
64 args.push_back(int_type);
65 args.push_back(data_type);
66 op_type =
67 FunctionType::get(Type::getVoidTy(Context), args, false);
68
69 // Setup a global variable in the LLVM module to represent the bytecode
70 // array. Bind it to the actual bytecode array at JIT time.
71 const Type *bytecode_type = PointerType::getUnqual(op_type);
72 bytecode_array = cast(module->
73 getOrInsertGlobal("BytecodeArray", bytecode_type));
74 EE->addGlobalMapping(bytecode_array, BytecodeArray);
75
76 // Setup a similar mapping for the global executed flag.
77 const IntegerType *flag_type = IntegerType::get(Context, 8);
78 executed_flag =
79 cast(module->getOrInsertGlobal("executed", flag_type));
80 EE->addGlobalMapping(executed_flag, &executed);
81
82 // Cache LLVM declarations for putchar() and getchar().
83 const Type *int_type = sizeof(int) == 4 ? IntegerType::getInt32Ty(Context)
84 : IntegerType::getInt64Ty(Context);
85 putchar_func =
86 module->getOrInsertFunction("putchar", int_type, int_type, NULL);
87 getchar_func = module->getOrInsertFunction("getchar", int_type, NULL);
88 }
89
90 void BrainFTraceRecorder::compile(BrainFTraceNode* trace) {
91 LLVMContext &Context = module->getContext();
92
93 // Create a new function for the trace we're compiling.
94 Function *curr_func = cast(module->
95 getOrInsertFunction("trace_"+utostr(trace->pc), op_type));
96
97 // Create an entry block, which branches directly to a header block.
98 // This is necessary because the entry block cannot be the target of
99 // a loop.
100 BasicBlock *Entry = BasicBlock::Create(Context, "entry", curr_func);
101 Header = BasicBlock::Create(Context, utostr(trace->pc), curr_func);
102
103 // Mark the array pointer as noalias, and setup compiler state.
104 IRBuilder<> builder(Entry);
105 Argument *Arg1 = ++curr_func->arg_begin();
106 Arg1->addAttr(Attribute::NoAlias);
107 DataPtr = Arg1;
108
109 // Emit code to set the executed flag. This signals to the recorder
110 // that the preceding opcode was executed as a part of a compiled trace.
111 const IntegerType *flag_type = IntegerType::get(Context, 8);
112 ConstantInt *True = ConstantInt::get(flag_type, 1);
113 builder.CreateStore(True, executed_flag);
114 builder.CreateBr(Header);
115
116 // Header will be the root of our trace tree. As such, all loop back-edges
117 // will be targetting it. Setup a PHI node to merge together incoming values
118 // for the current array pointer as we loop.
119 builder.SetInsertPoint(Header);
120 HeaderPHI = builder.CreatePHI(DataPtr->getType());
121 HeaderPHI->addIncoming(DataPtr, Entry);
122 DataPtr = HeaderPHI;
123
124 // Recursively descend the trace tree, emitting code for the opcodes as we go.
125 compile_opcode(trace, builder);
126
127 // Run out optimization suite on our newly generated trace.
128 FPM->run(*curr_func);
129
130 // Compile our trace to machine code, and install function pointer to it
131 // into the bytecode array so that it will be executed every time the
132 // trace-head PC is reached.
133 void *code = EE->getPointerToFunction(curr_func);
134 BytecodeArray[trace->pc] =
135 (opcode_func_t)(intptr_t)code;
136 }
137
138 /// compile_plus - Emit code for '+'
139 void BrainFTraceRecorder::compile_plus(BrainFTraceNode *node,
140 IRBuilder<>& builder) {
141 Value *CellValue = builder.CreateLoad(DataPtr);
142 Constant *One =
143 ConstantInt::get(IntegerType::getInt8Ty(Header->getContext()), 1);
144 Value *UpdatedValue = builder.CreateAdd(CellValue, One);
145 builder.CreateStore(UpdatedValue, DataPtr);
146
147 if (node->left != (BrainFTraceNode*)~0ULL)
148 compile_opcode(node->left, builder);
149 else {
150 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
151 builder.CreateBr(Header);
152 }
153 }
154
155 /// compile_minus - Emit code for '-'
156 void BrainFTraceRecorder::compile_minus(BrainFTraceNode *node,
157 IRBuilder<>& builder) {
158 Value *CellValue = builder.CreateLoad(DataPtr);
159 Constant *One =
160 ConstantInt::get(IntegerType::getInt8Ty(Header->getContext()), 1);
161 Value *UpdatedValue = builder.CreateSub(CellValue, One);
162 builder.CreateStore(UpdatedValue, DataPtr);
163
164 if (node->left != (BrainFTraceNode*)~0ULL)
165 compile_opcode(node->left, builder);
166 else {
167 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
168 builder.CreateBr(Header);
169 }
170 }
171
172 /// compile_left - Emit code for '<'
173 void BrainFTraceRecorder::compile_left(BrainFTraceNode *node,
174 IRBuilder<>& builder) {
175 Value *OldPtr = DataPtr;
176 DataPtr = builder.CreateConstInBoundsGEP1_32(DataPtr, -1);
177 if (node->left != (BrainFTraceNode*)~0ULL)
178 compile_opcode(node->left, builder);
179 else {
180 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
181 builder.CreateBr(Header);
182 }
183 DataPtr = OldPtr;
184 }
185
186 /// compile_right - Emit code for '>'
187 void BrainFTraceRecorder::compile_right(BrainFTraceNode *node,
188 IRBuilder<>& builder) {
189 Value *OldPtr = DataPtr;
190 DataPtr = builder.CreateConstInBoundsGEP1_32(DataPtr, 1);
191 if (node->left != (BrainFTraceNode*)~0ULL)
192 compile_opcode(node->left, builder);
193 else {
194 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
195 builder.CreateBr(Header);
196 }
197 DataPtr = OldPtr;
198 }
199
200
201 /// compile_put - Emit code for '.'
202 void BrainFTraceRecorder::compile_put(BrainFTraceNode *node,
203 IRBuilder<>& builder) {
204 Value *Loaded = builder.CreateLoad(DataPtr);
205 Value *Print =
206 builder.CreateSExt(Loaded, IntegerType::get(Loaded->getContext(), 32));
207 builder.CreateCall(putchar_func, Print);
208 if (node->left != (BrainFTraceNode*)~0ULL)
209 compile_opcode(node->left, builder);
210 else {
211 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
212 builder.CreateBr(Header);
213 }
214 }
215
216 /// compile_get - Emit code for ','
217 void BrainFTraceRecorder::compile_get(BrainFTraceNode *node,
218 IRBuilder<>& builder) {
219 Value *Ret = builder.CreateCall(getchar_func);
220 Value *Trunc =
221 builder.CreateTrunc(Ret, IntegerType::get(Ret->getContext(), 8));
222 builder.CreateStore(Ret, Trunc);
223 if (node->left != (BrainFTraceNode*)~0ULL)
224 compile_opcode(node->left, builder);
225 else {
226 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
227 builder.CreateBr(Header);
228 }
229 }
230
231 /// compile_if - Emit code for '['
232 void BrainFTraceRecorder::compile_if(BrainFTraceNode *node,
233 IRBuilder<>& builder) {
234 BasicBlock *ZeroChild = 0;
235 BasicBlock *NonZeroChild = 0;
236
237 IRBuilder<> oldBuilder = builder;
238
239 LLVMContext &Context = Header->getContext();
240
241 // If both directions of the branch go back to the trace-head, just
242 // jump there directly.
243 if (node->left == (BrainFTraceNode*)~0ULL &&
244 node->right == (BrainFTraceNode*)~0ULL) {
245 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
246 builder.CreateBr(Header);
247 return;
248 }
249
250 // Otherwise, there are two cases to handle for each direction:
251 // ~0ULL - A branch back to the trace head
252 // 0 - A branch out of the trace
253 // * - A branch to a node we haven't compiled yet.
254 // Go ahead and generate code for both targets.
255
256 if (node->left == (BrainFTraceNode*)~0ULL) {
257 NonZeroChild = Header;
258 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
259 } else if (node->left == 0) {
260 NonZeroChild = BasicBlock::Create(Context,
261 "exit_left_"+utostr(node->pc),
262 Header->getParent());
263 builder.SetInsertPoint(NonZeroChild);
264 ConstantInt *NewPc = ConstantInt::get(int_type, node->pc+1);
265 Value *BytecodeIndex =
266 builder.CreateConstInBoundsGEP1_32(bytecode_array, node->pc+1);
267 Value *Target = builder.CreateLoad(BytecodeIndex);
268 CallInst *Call =cast(builder.CreateCall2(Target, NewPc, DataPtr));
269 Call->setTailCall();
270 builder.CreateRetVoid();
271 } else {
272 NonZeroChild = BasicBlock::Create(Context,
273 utostr(node->left->pc),
274 Header->getParent());
275 builder.SetInsertPoint(NonZeroChild);
276 compile_opcode(node->left, builder);
277 }
278
279 if (node->right == (BrainFTraceNode*)~0ULL) {
280 ZeroChild = Header;
281 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
282 } else if (node->right == 0) {
283 ZeroChild = BasicBlock::Create(Context,
284 "exit_right_"+utostr(node->pc),
285 Header->getParent());
286 builder.SetInsertPoint(ZeroChild);
287 ConstantInt *NewPc = ConstantInt::get(int_type, JumpMap[node->pc]+1);
288 Value *BytecodeIndex =
289 builder.CreateConstInBoundsGEP1_32(bytecode_array, JumpMap[node->pc]+1);
290 Value *Target = builder.CreateLoad(BytecodeIndex);
291 CallInst *Call =cast(builder.CreateCall2(Target, NewPc, DataPtr));
292 Call->setTailCall();
293 builder.CreateRetVoid();
294 } else {
295 ZeroChild = BasicBlock::Create(Context,
296 utostr(node->right->pc),
297 Header->getParent());
298 builder.SetInsertPoint(ZeroChild);
299 compile_opcode(node->right, builder);
300 }
301
302 // Generate the test and branch to select between the targets.
303 Value *Loaded = oldBuilder.CreateLoad(DataPtr);
304 Value *Cmp = oldBuilder.CreateICmpEQ(Loaded,
305 ConstantInt::get(Loaded->getType(), 0));
306 oldBuilder.CreateCondBr(Cmp, ZeroChild, NonZeroChild);
307 }
308
309 /// compile_back - Emit code for ']'
310 void BrainFTraceRecorder::compile_back(BrainFTraceNode *node,
311 IRBuilder<>& builder) {
312 if (node->right != (BrainFTraceNode*)~0ULL)
313 compile_opcode(node->right, builder);
314 else {
315 HeaderPHI->addIncoming(DataPtr, builder.GetInsertBlock());
316 builder.CreateBr(Header);
317 }
318 }
319
320 /// compile_opcode - Dispatch to a more specific compiler function based
321 /// on the opcode of the current node.
322 void BrainFTraceRecorder::compile_opcode(BrainFTraceNode *node,
323 IRBuilder<>& builder) {
324 switch (node->opcode) {
325 case '+':
326 compile_plus(node, builder);
327 break;
328 case '-':
329 compile_minus(node, builder);
330 break;
331 case '<':
332 compile_left(node, builder);
333 break;
334 case '>':
335 compile_right(node, builder);
336 break;
337 case '.':
338 compile_put(node, builder);
339 break;
340 case ',':
341 compile_get(node, builder);
342 break;
343 case '[':
344 compile_if(node, builder);
345 break;
346 case ']':
347 compile_back(node, builder);
348 break;
349 }
350 }
+0
-116
examples/TracingBrainF/BrainFInterpreter.cpp less more
None //===-- BrainFInterpreter.cpp - BrainF trace compiler interpreter -------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8
9 #include "BrainF.h"
10 #include "BrainFVM.h"
11 #include "llvm/Support/CommandLine.h"
12 #include "llvm/Support/MemoryBuffer.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include
15 using namespace llvm;
16
17 //Command line options
18
19 static cl::opt
20 InputFilename(cl::Positional, cl::desc(""));
21
22 int main(int argc, char **argv) {
23 cl::ParseCommandLineOptions(argc, argv, " BrainF compiler\n");
24
25 if (InputFilename == "") {
26 errs() << "Error: You must specify the filename of the program to "
27 "be compiled. Use --help to see the options.\n";
28 abort();
29 }
30
31 // Read the input file.
32 MemoryBuffer *Code = MemoryBuffer::getFileOrSTDIN(InputFilename);
33 const uint8_t *CodeBegin = (const uint8_t*)(Code->getBufferStart());
34
35 // Create a new buffer to hold the preprocessed code.
36 MemoryBuffer *ParsedCode =
37 MemoryBuffer::getNewMemBuffer(sizeof(opcode_func_t) *
38 (Code->getBufferSize()+1));
39 BytecodeArray = (opcode_func_t*)(ParsedCode->getBufferStart());
40 size_t BytecodeOffset = 0;
41
42 // Create JumpMap, a special on-the-side data array used to implement
43 // efficient jumps in the interpreter.
44 JumpMap = new size_t[Code->getBufferSize()];
45 memset(JumpMap, 0, sizeof(size_t) * Code->getBufferSize());
46 std::vector Stack;
47
48 // Preprocess the input source code, performing three tasks:
49 // 1 - Remove non-instruction characters
50 // 2 - Replace character literals with opcode function pointers
51 // 3 - Precompute the jump targets for [ and ] instructions in JumpMap
52 for (size_t i = 0; i < Code->getBufferSize(); ++i) {
53 uint8_t opcode = CodeBegin[i];
54 switch (opcode) {
55 case '>':
56 BytecodeArray[BytecodeOffset++] = &op_right;
57 break;
58 case '<':
59 BytecodeArray[BytecodeOffset++] = &op_left;
60 break;
61 case '+':
62 BytecodeArray[BytecodeOffset++] = &op_plus;
63 break;
64 case '-':
65 BytecodeArray[BytecodeOffset++] = &op_minus;
66 break;
67 case '.':
68 BytecodeArray[BytecodeOffset++] = &op_put;
69 break;
70 case ',':
71 BytecodeArray[BytecodeOffset++] = &op_get;
72 break;
73 case '[':
74 Stack.push_back(BytecodeOffset);
75 BytecodeArray[BytecodeOffset++] = &op_if;
76 break;
77 case ']':
78 JumpMap[Stack.back()] = BytecodeOffset;
79 JumpMap[BytecodeOffset] = Stack.back();
80 Stack.pop_back();
81 BytecodeArray[BytecodeOffset++] = &op_back;
82 break;
83 default:
84 continue;
85 }
86 }
87
88 // Fill in the suffix of the preprocessed source for op_exit.
89 // Thus, if we reach the end of the source, the program will terminate.
90 while (BytecodeOffset < Code->getBufferSize()+1) {
91 BytecodeArray[BytecodeOffset++] = &op_end;
92 }
93
94 // Setup the array.
95 uint8_t *BrainFArray = new uint8_t[32768];
96 memset(BrainFArray, 0, 32768);
97
98 // Setup the trace recorder.
99 Recorder = new BrainFTraceRecorder();
100
101 // Main interpreter loop.
102 // Note the lack of a explicit loop: every opcode is a tail-recursive
103 // function that calls its own successor by indexing into BytecodeArray.
104 uint8_t* data = BrainFArray;
105 BytecodeArray[0](0, data);
106
107 //Clean up
108 delete Recorder;
109 delete Code;
110 delete ParsedCode;
111 delete[] BrainFArray;
112 delete[] JumpMap;
113
114 return 0;
115 }
+0
-68
examples/TracingBrainF/BrainFOpcodes.cpp less more
None //===-- BrainFOpcodes.cpp - BrainF interpreter opcodes ------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8
9 #include "BrainFVM.h"
10 #include
11
12 opcode_func_t *BytecodeArray = 0;
13 size_t *JumpMap = 0;
14 uint8_t executed = 0;
15
16 BrainFTraceRecorder *Recorder = 0;
17
18 void op_plus(size_t pc, uint8_t *data) {
19 Recorder->record_simple(pc, '+');
20 *data += 1;
21 BytecodeArray[pc+1](pc+1, data);
22 }
23
24 void op_minus(size_t pc, uint8_t *data) {
25 Recorder->record_simple(pc, '-');
26 *data -= 1;
27 BytecodeArray[pc+1](pc+1, data);
28 }
29
30 void op_left(size_t pc, uint8_t *data) {
31 Recorder->record_simple(pc, '<');
32 BytecodeArray[pc+1](pc+1, data-1);
33 }
34
35 void op_right(size_t pc, uint8_t *data) {
36 Recorder->record_simple(pc, '>');
37 BytecodeArray[pc+1](pc+1, data+1);
38 }
39
40 void op_put(size_t pc, uint8_t *data) {
41 Recorder->record_simple(pc, '.');
42 putchar(*data);
43 BytecodeArray[pc+1](pc+1, data);
44 }
45
46 void op_get(size_t pc, uint8_t *data) {
47 Recorder->record_simple(pc, ',');
48 *data = getchar();
49 BytecodeArray[pc+1](pc+1, data);
50 }
51
52 void op_if(size_t pc, uint8_t *data) {
53 Recorder->record(pc, '[');
54 size_t new_pc = pc+1;
55 if (!*data) new_pc = JumpMap[pc]+1;
56 BytecodeArray[new_pc](new_pc, data);
57 }
58
59 void op_back(size_t pc, uint8_t *data) {
60 Recorder->record_simple(pc, ']');
61 size_t new_pc = JumpMap[pc];
62 BytecodeArray[new_pc](new_pc, data);
63 }
64
65 void op_end(size_t, uint8_t *) {
66 return;
67 }
+0
-155
examples/TracingBrainF/BrainFTraceRecorder.cpp less more
None //===-- BrainFTraceRecorder.cpp - BrainF trace recorder ------------------==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8 //
9 // This class observes the execution trace of the interpreter, identifying
10 // hot traces and eventually compiling them to native code.
11 //
12 // The operation of the recorder can be divided into four parts:
13 // 1) Interation Counting - To identify hot traces, we track the execution
14 // counts of all loop headers ('[' instructions). We use a fixed-size
15 // array of counters for this, since lack of precision does not affect
16 // correctness.
17 //
18 // 2) Trace Buffering - Once a header has passed a hotness threshold, we
19 // begin buffering the execution trace beginning from that header the
20 // next time it is executed. This buffer is of a fixed length, though
21 // that choice can be tuned for performance. If the end of the buffer
22 // is reached without execution returning to the header, we throw out
23 // the trace.
24 //
25 // 3) Trace Commit - If the buffered trace returns to the header before
26 // the buffer limit is reached, that trace is commited to form a trace
27 // tree. This tree aggregates all execution traces that have been
28 // observed originating from the header since it passed the hotness
29 // threshold. The buffer is then cleared to allow a new trace to be
30 // recorded.
31 //
32 // 4) Trace Compilation - Once a secondary hotness threshold is reached,
33 // trace recording is terminated and the set of observed traces encoded
34 // in the trace tree are compiled to native code, and a function pointer
35 // to that trace is installed into the bytecode array in place of one of
36 // the normal opcode functions. Details of this compilation are in
37 // BrainFCodeGen.cpp
38 //===--------------------------------------------------------------------===//
39
40 #include "BrainF.h"
41 #include "BrainFVM.h"
42 #include "llvm/Support/raw_ostream.h"
43
44 #define ITERATION_BUF_SIZE 1024
45 #define TRACE_BUF_SIZE 256
46 #define TRACE_THRESHOLD 50
47 #define COMPILE_THRESHOLD 200
48
49 void BrainFTraceRecorder::BrainFTraceNode::dump(unsigned lvl) {
50 for (unsigned i = 0; i < lvl; ++i)
51 outs() << '.';
52 outs() << opcode << " : " << pc << "\n";
53 if (left && left != (BrainFTraceNode*)~0ULL) left->dump(lvl+1);
54 if (right && right != (BrainFTraceNode*)~0ULL) right->dump(lvl+1);
55 }
56
57 BrainFTraceRecorder::BrainFTraceRecorder()
58 : prev_opcode('+'), iteration_count(new uint8_t[ITERATION_BUF_SIZE]),
59 trace_begin(new std::pair[TRACE_BUF_SIZE]),
60 trace_end(trace_begin + TRACE_BUF_SIZE),
61 trace_tail(trace_begin),
62 module(new Module("BrainF", getGlobalContext())) {
63 memset(iteration_count, 0, ITERATION_BUF_SIZE);
64 memset(trace_begin, 0, sizeof(std::pair) * TRACE_BUF_SIZE);
65
66 initialize_module();
67 }
68
69 BrainFTraceRecorder::~BrainFTraceRecorder() {
70 delete[] iteration_count;
71 delete[] trace_begin;
72 delete FPM;
73 delete EE;
74 }
75
76 void BrainFTraceRecorder::commit() {
77 BrainFTraceNode *&Head = trace_map[trace_begin->second];
78 if (!Head)
79 Head = new BrainFTraceNode(trace_begin->first, trace_begin->second);
80
81 BrainFTraceNode *Parent = Head;
82 std::pair *trace_iter = trace_begin+1;
83 while (trace_iter != trace_tail) {
84 BrainFTraceNode *Child = 0;
85
86 if (trace_iter->second == Parent->pc+1) {
87 if (Parent->left) Child = Parent->left;
88 else Child = Parent->left =
89 new BrainFTraceNode(trace_iter->first, trace_iter->second);
90 } else {
91 if (Parent->right) Child = Parent->right;
92 else Child = Parent->right =
93 new BrainFTraceNode(trace_iter->first, trace_iter->second);
94 }
95
96 Parent = Child;
97 ++trace_iter;
98 }
99
100 if (Parent->pc+1 == Head->pc)
101 Parent->left = (BrainFTraceNode*)~0ULL;
102 else
103 Parent->right = (BrainFTraceNode*)~0ULL;
104 }
105
106 void BrainFTraceRecorder::record_simple(size_t pc, uint8_t opcode) {
107 if (executed) {
108 executed = false;
109 trace_tail = trace_begin;
110 }
111
112 if (trace_tail != trace_begin) {
113 if (trace_tail == trace_end) {
114 trace_tail = trace_begin;
115 } else {
116 trace_tail->first = opcode;
117 trace_tail->second = pc;
118 ++trace_tail;
119 }
120 }
121 prev_opcode = opcode;
122 }
123
124 void BrainFTraceRecorder::record(size_t pc, uint8_t opcode) {
125 if (executed) {
126 executed = false;
127 trace_tail = trace_begin;
128 }
129
130 if (trace_tail != trace_begin) {
131 if (pc == trace_begin->second) {
132 commit();
133 trace_tail = trace_begin;
134 } else if (trace_tail == trace_end) {
135 trace_tail = trace_begin;
136 } else {
137 trace_tail->first = opcode;
138 trace_tail->second = pc;
139 ++trace_tail;
140 }
141 } else if (opcode == '[' && prev_opcode == ']'){
142 size_t hash = pc % ITERATION_BUF_SIZE;
143 if (iteration_count[hash] == 255) iteration_count[hash] = 254;
144 if (++iteration_count[hash] > COMPILE_THRESHOLD && trace_map.count(pc)) {
145 compile(trace_map[pc]);
146 } else if (++iteration_count[hash] > TRACE_THRESHOLD) {
147 trace_tail->first = opcode;
148 trace_tail->second = pc;
149 ++trace_tail;
150 }
151 }
152
153 prev_opcode = opcode;
154 }
+0
-63
examples/TracingBrainF/BrainFVM.h less more
None //===-- BrainFVM.h - BrainF interpreter header ----------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===--------------------------------------------------------------------===//
8
9 #ifndef BRAINF_VM_H
10 #define BRAINF_VM_H
11
12 #include "BrainF.h"
13 #include "stdint.h"
14 #include
15
16 /// opcode_func_t - A function pointer signature for all opcode functions.
17 typedef void(*opcode_func_t)(size_t pc, uint8_t* data);
18
19 /// BytecodeArray - An array of function pointers representing the
20 /// source program. Indexed by PC address.
21 extern opcode_func_t *BytecodeArray;
22
23 /// JumpMap - An array of on-the-side data used by the interpreter.
24 /// Indexed by PC address.
25 extern size_t *JumpMap;
26
27 /// executed - A flag indicating whether the preceding opcode was evaluated
28 /// within a compiled trace execution. Used by the trace recorder.
29 extern uint8_t executed;
30
31 /// Recorder - The trace recording engine.
32 extern BrainFTraceRecorder *Recorder;
33
34 /// op_plus - Implements the '+' instruction.
35 void op_plus(size_t, uint8_t*);
36
37 /// op_minus - Implements the '-' instruction.
38 void op_minus(size_t, uint8_t*);
39
40 // op_left - Implements the '<' instruction.
41 void op_left(size_t, uint8_t*);
42
43 // op_right - Implements the '>' instruction.
44 void op_right(size_t, uint8_t*);
45
46 // op_put - Implements the '.' instruction.
47 void op_put(size_t, uint8_t*);
48
49 // op_get - Implements the ',' instruction.
50 void op_get(size_t, uint8_t*);
51
52 // op_if - Implements the '[' instruction.
53 void op_if(size_t, uint8_t*);
54
55 // op_back - Implements the ']' instruction.
56 void op_back(size_t, uint8_t*);
57
58 // op_end - Terminates an execution.
59 void op_end(size_t, uint8_t*);
60
61
62 #endif
+0
-17
examples/TracingBrainF/Makefile less more
None ##===- examples/TracingBrainF/Makefile ------------------- -*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file is distributed under the University of Illinois Open Source
5 # License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8 LEVEL = ../..
9 TOOLNAME = TracingBrainF
10 EXAMPLE_TOOL = 1
11
12 CXXFLAGS += -foptimize-sibling-calls
13
14 LINK_COMPONENTS := scalaropts jit nativecodegen
15
16 include $(LEVEL)/Makefile.common
+0
-1
examples/TracingBrainF/README less more
None This is an example trace-based JIT for Brainfuck, using LLVM as its code generation engine. To compile it, simply drop this directory within llvm/examples in an LLVM source tree, and do `make` in that directory.