1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 From the LLVM source code, llvm/IR/BasicBlock.h
7 
8 # LLVM Basic Block Representation
9 
10 This represents a single basic block in LLVM. A basic block is simply a
11 container of instructions that execute sequentially. Basic blocks are Values
12 because they are referenced by instructions such as branches and switch tables.
13 The type of a BasicBlock is "Type::LabelTy" because the basic block represents
14 a label to which a branch can jump.
15 
16 A well formed basic block is formed of a list of non-terminating instructions
17 followed by a single TerminatorInst instruction.  TerminatorInst's may not
18 occur in the middle of basic blocks, and must terminate the blocks. The
19 BasicBlock class allows malformed basic blocks to occur because it may be
20 useful in the intermediate stage of constructing or modifying a program.
21 However, the verifier will ensure that basic blocks are "well formed".
22 */
23 module llvm_hiwrap.value.basic_block;
24 
25 import std.typecons : Nullable;
26 
27 import llvm_hiwrap.types;
28 import llvm_hiwrap.value.function_;
29 import llvm_hiwrap.value.value;
30 
31 /// Note that isTerminator and isCall overlap.
32 bool isTerminator(LxOpcode op) {
33     switch (op) with (LxOpcode) {
34     case Ret:
35         goto case;
36     case Br:
37         goto case;
38     case Switch:
39         goto case;
40     case IndirectBr:
41         goto case;
42     case Invoke:
43         return true;
44     default:
45         return false;
46     }
47 }
48 
49 bool isAlloca(LxOpcode op) {
50     return op == LxOpcode.Alloca;
51 }
52 
53 bool isElementPtr(LxOpcode op) {
54     return op == LxOpcode.GetElementPtr;
55 }
56 
57 bool isCall(LxOpcode op) {
58     switch (op) with (LxOpcode) {
59     case Invoke:
60         goto case;
61     case Call:
62         return true;
63     default:
64         return false;
65     }
66 }
67 
68 /** A basic block represents a single entry single exit section of code.
69  *
70  * Basic blocks contain a list of instructions which form the body of
71  * the block.
72  *
73  * Basic blocks belong to functions. They have the type of label.
74  *
75  * Basic blocks are themselves values. However, the C API models them as
76  * LLVMBasicBlockRef.
77  *
78  * See: llvm::BasicBlock
79  */
80 struct BasicBlock {
81     import llvm;
82     import llvm_hiwrap.value.instruction;
83 
84     LxBasicBlock lx;
85     alias lx this;
86 
87     /// Uses the pointer as a unique identifier.
88     size_t id() {
89         return cast(size_t) lx;
90     }
91 
92     /// Convert a basic block instance to a value type.
93     Value asValue() {
94         auto v = LLVMBasicBlockAsValue(lx);
95         return LxValue(v).Value;
96     }
97 
98     /**
99      * Obtain the string name of a basic block.
100      */
101     @property const(char)[] name() {
102         import std..string : fromStringz;
103         import llvm : LLVMGetBasicBlockName;
104 
105         auto s = LLVMGetBasicBlockName(lx);
106         return s.fromStringz;
107     }
108 
109     /** Obtain the function to which a basic block belongs.
110      *
111      * See: llvm::BasicBlock::getParent()
112      *
113      * TODO assuming that the base type is always a function.
114      */
115     FunctionValue parent() {
116         auto raw = LLVMGetBasicBlockParent(lx);
117         return raw.LxValue.LxUserValue.LxFunctionValue.FunctionValue;
118     }
119 
120     /// A range over the instructions in the block
121     InstructionRange instructions() {
122         return InstructionRange(this);
123     }
124 
125     /**
126      * Obtain the terminator instruction for a basic block.
127      *
128      * If the basic block does not have a terminator (it is not well-formed
129      * if it doesn't), then NULL is returned.
130      *
131      * The returned LLVMValueRef corresponds to a llvm::TerminatorInst.
132      *
133      * @see llvm::BasicBlock::getTerminator()
134      */
135     Nullable!InstructionTerminatorValue terminator() {
136         auto raw = LLVMGetBasicBlockTerminator(lx);
137         return typeof(return)(
138                 raw.LxValue.LxInstructionValue.LxInstructionTerminatorValue
139                 .InstructionTerminatorValue);
140     }
141 
142     /**
143      * Move a basic block to before another one.
144      *
145      * @see llvm::BasicBlock::moveBefore()
146      */
147     //void LLVMMoveBasicBlockBefore(LLVMBasicBlockRef BB, LLVMBasicBlockRef MovePos);
148 
149     /**
150      * Move a basic block to after another one.
151      *
152      * @see llvm::BasicBlock::moveAfter()
153      */
154     //void LLVMMoveBasicBlockAfter(LLVMBasicBlockRef BB, LLVMBasicBlockRef MovePos);
155 
156     /** Obtain the first instruction in a basic block.
157      *
158      * The returned LLVMValueRef corresponds to a llvm::Instruction
159      * instance.
160      */
161     InstructionValue firstInstr() {
162         return LLVMGetFirstInstruction(this).LxValue.LxInstructionValue.InstructionValue;
163     }
164 
165     /** Obtain the last instruction in a basic block.
166      *
167      * The returned LLVMValueRef corresponds to an LLVM:Instruction.
168      *
169      * TODO I assume this is the last instruction and not _end_.
170      */
171     InstructionValue lastInstr() {
172         return LLVMGetLastInstruction(this).LxValue.LxInstructionValue.InstructionValue;
173     }
174 
175     /**
176      * Remove a basic block from a function and delete it.
177      *
178      * This deletes the basic block from its containing function and deletes
179      * the basic block itself.
180      *
181      * @see llvm::BasicBlock::eraseFromParent()
182      */
183     //void LLVMDeleteBasicBlock(LLVMBasicBlockRef BB);
184 
185     /**
186      * Remove a basic block from a function.
187      *
188      * This deletes the basic block from its containing function but keep
189      * the basic block alive.
190      *
191      * @see llvm::BasicBlock::removeFromParent()
192      */
193     //void LLVMRemoveBasicBlockFromParent(LLVMBasicBlockRef BB);
194 }
195 
196 struct EntryBasicBlock {
197     import llvm;
198     import llvm_hiwrap.value.instruction;
199 
200     LxEntryBasicBlock lx;
201     alias lx this;
202 
203     BasicBlock asBasicBlock() {
204         return lx.BasicBlock;
205     }
206 }
207 
208 struct InstructionRange {
209     import std.typecons : Nullable;
210     import llvm_hiwrap.value.instruction;
211 
212     private Nullable!InstructionValue cur;
213 
214     this(BasicBlock bb) {
215         cur = bb.firstInstr;
216     }
217 
218     InstructionValue front() {
219         assert(!empty, "Can't get front of an empty range");
220         return cur;
221     }
222 
223     void popFront() {
224         assert(!empty, "Can't pop front of an empty range");
225         cur = cur.nextInstr;
226     }
227 
228     bool empty() {
229         return cur.isNull;
230     }
231 }
232 
233 mixin template BasicBlockAccept(VisitorT, UserT) {
234     import llvm_hiwrap.value.basic_block;
235 
236     void implAccept(ref EntryBasicBlock entry) {
237         import llvm_hiwrap.ast.tree : maybeCallVisit;
238 
239         {
240             auto bb = entry.asBasicBlock;
241             implAcceptInstructions(bb);
242         }
243 
244         auto term = entry.asBasicBlock.terminator;
245         if (term.isNull) {
246             return;
247         }
248 
249         foreach (b; term.successors) {
250             maybeCallVisit(this, user, b);
251         }
252     }
253 
254     void implAccept(ref BasicBlock n) {
255         import llvm_hiwrap.ast.tree : maybeCallVisit;
256 
257         implAcceptInstructions(n);
258 
259         auto term = n.terminator;
260         if (term.isNull) {
261             return;
262         }
263 
264         foreach (b; term.successors) {
265             maybeCallVisit(this, user, b);
266         }
267     }
268 
269     private void implAcceptInstructions(ref BasicBlock n) {
270         import llvm_hiwrap.ast.tree : maybeCallVisit;
271         import llvm_hiwrap.value.instruction;
272         import llvm_hiwrap.types;
273 
274         static void fallback(T)(ref VisitorT!UserT self, ref UserT user, ref T node) {
275             auto n = node.value.LxInstructionValue.InstructionValue;
276             maybeCallVisit(self, user, n);
277         }
278 
279         foreach (instr; n.instructions) {
280             if (instr.opcode.isAlloca) {
281                 auto nn = instr.LxInstructionAllocaValue.InstructionAllocaValue;
282                 maybeCallVisit(this, user, nn, &fallback!InstructionAllocaValue);
283             } else if (instr.opcode.isCall) {
284                 auto nn = instr.LxInstructionCallValue.InstructionCallValue;
285                 maybeCallVisit(this, user, nn, &fallback!InstructionCallValue);
286             } else if (instr.opcode.isElementPtr) {
287                 auto nn = instr.LxInstructionElementPtrValue.InstructionElementPtrValue;
288                 maybeCallVisit(this, user, nn, &fallback!InstructionElementPtrValue);
289             } else if (instr.opcode.isTerminator) {
290                 auto nn = instr.LxInstructionTerminatorValue.InstructionTerminatorValue;
291                 maybeCallVisit(this, user, nn, &fallback!InstructionTerminatorValue);
292             } else {
293                 maybeCallVisit(this, user, instr);
294             }
295         }
296     }
297 }
298 
299 /** A depth-first visitor.
300  *
301  * See: llvm_hiwrap.ast.tree
302  *
303  * Accepted node types are:
304  *  - InstructionValue
305  *  - InstructionCallValue
306  *  - InstructionTerminatorValue
307  *  - InstructionAllocaValue
308  *  - InstructionElementPtrValue
309  */
310 struct BasicBlockVisitor(UserT) {
311     UserT user;
312 
313     void visit(ref BasicBlock n) {
314         import llvm_hiwrap.ast.tree;
315 
316         static void fallback(T)(ref this self, ref UserT user, ref T node) {
317             accept(n, self);
318         }
319 
320         maybeCallVisit(this, user, n);
321     }
322 
323     mixin BasicBlockAccept!(BasicBlockVisitor, UserT);
324 }
325 
326 @("shall be an instance of BasicBlockVisitor")
327 unittest {
328     import llvm_hiwrap.ast.tree;
329 
330     struct Null {
331     }
332 
333     BasicBlockVisitor!Null v;
334 }