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 }