1 module d.llvm.statement; 2 3 import d.llvm.local; 4 5 import d.ir.expression; 6 import d.ir.instruction; 7 8 import source.location; 9 10 import util.visitor; 11 12 import llvm.c.core; 13 14 struct StatementGenData { 15 private: 16 LLVMValueRef llvmEhTypeIdFor; 17 } 18 19 struct StatementGen { 20 private LocalPass pass; 21 alias pass this; 22 23 LLVMValueRef fun; 24 25 LLVMBasicBlockRef[] basicBlocks; 26 LLVMBasicBlockRef[] landingPads; 27 28 Body fbody; 29 30 this(LocalPass pass) { 31 this.pass = pass; 32 } 33 34 void visit(Body fbody) in { 35 assert(fbody, "Empty body"); 36 } do { 37 basicBlocks.length = fbody.length; 38 landingPads.length = fbody.length; 39 40 auto allocaBB = LLVMGetInsertBlock(builder); 41 fun = LLVMGetBasicBlockParent(allocaBB); 42 scope(success) { 43 // Branch from alloca block to function body. 44 LLVMPositionBuilderAtEnd(builder, allocaBB); 45 LLVMBuildBr(builder, basicBlocks[0]); 46 } 47 48 this.fbody = fbody; 49 foreach (b; range(fbody)) { 50 visit(b); 51 } 52 } 53 54 void visit(BasicBlockRef b) { 55 auto llvmBB = genBasicBlock(b); 56 LLVMMoveBasicBlockAfter(llvmBB, LLVMGetInsertBlock(builder)); 57 LLVMPositionBuilderAtEnd(builder, llvmBB); 58 59 lpBB = genLandingPad(b); 60 61 foreach(i; range(fbody, b)) { 62 final switch(i.op) with(OpCode) { 63 case Alloca: 64 define(i.var); 65 break; 66 67 case Destroy: 68 auto v = i.var; 69 auto s = v.type.getCanonical().dstruct; 70 assert(!s.isPod, "struct is not a pod"); 71 72 import source.name; 73 auto dsym = s.resolve(i.location, BuiltinName!"__dtor"); 74 75 import d.ir.symbol; 76 auto dtor = cast(Function) dsym; 77 if (dtor is null) { 78 auto os = cast(OverloadSet) dsym; 79 assert(os, "__dtor must be an overload set"); 80 dtor = cast(Function) os.set[0]; 81 } 82 83 assert(dtor, "Cannot find dtor"); 84 genCall(declare(dtor), [declare(v)]); 85 break; 86 87 case Evaluate: 88 genExpression(i.expr); 89 break; 90 91 // FIXME: Delete this, we can generate these upon use. 92 case Declare: 93 define(i.sym); 94 break; 95 } 96 } 97 98 auto bb = &fbody[b]; 99 final switch(bb.terminator) with(Terminator) { 100 case None: 101 assert(0, "Unterminated block"); 102 103 case Branch: 104 if (bb.value) { 105 LLVMBuildCondBr( 106 builder, 107 genExpression(bb.value), 108 genBasicBlock(fbody[b].successors[0]), 109 genBasicBlock(fbody[b].successors[1]), 110 ); 111 } else { 112 LLVMBuildBr( 113 builder, 114 genBasicBlock(fbody[b].successors[0]), 115 ); 116 } 117 118 break; 119 120 case Switch: 121 auto switchTable = bb.switchTable; 122 auto e = genExpression(bb.value); 123 auto switchInstr = LLVMBuildSwitch( 124 builder, 125 e, 126 genBasicBlock(switchTable.defaultBlock), 127 switchTable.entryCount, 128 ); 129 130 auto t = LLVMTypeOf(e); 131 foreach(c; switchTable.cases) { 132 LLVMAddCase( 133 switchInstr, 134 LLVMConstInt(t, c.value, false), 135 genBasicBlock(c.block), 136 ); 137 } 138 139 break; 140 141 case Return: 142 if (bb.value) { 143 auto ret = genExpression(bb.value); 144 LLVMBuildRet(builder, ret); 145 } else { 146 LLVMBuildRetVoid(builder); 147 } 148 149 break; 150 151 case Throw: 152 if (bb.value) { 153 genCall( 154 declare(pass.object.getThrow()), 155 [genExpression(bb.value)], 156 ); 157 LLVMBuildUnreachable(builder); 158 break; 159 } 160 161 // Create an alloca for the landing pad results. 162 if (!lpContext) { 163 auto currentBB = LLVMGetInsertBlock(builder); 164 LLVMPositionBuilderAtEnd(builder, LLVMGetFirstBasicBlock(fun)); 165 lpContext = LLVMBuildAlloca(builder, getLpType(), "lpContext"); 166 LLVMPositionBuilderAtEnd(builder, currentBB); 167 LLVMSetPersonalityFn(fun, declare(pass.object.getPersonality())); 168 } 169 170 auto catchTable = fbody[b].catchTable; 171 if (catchTable is null) { 172 Resume: 173 if (auto lpBlock = fbody[b].landingpad) { 174 LLVMBuildBr(builder, genBasicBlock(lpBlock)); 175 } else { 176 auto lp = LLVMBuildLoad(builder, lpContext, ""); 177 LLVMBuildResume(builder, lp); 178 } 179 180 break; 181 } 182 183 auto i32 = LLVMInt32TypeInContext(llvmCtx); 184 LLVMValueRef[2] gepIdx = [ 185 LLVMConstInt(i32, 0, false), 186 LLVMConstInt(i32, 1, false), 187 ]; 188 189 auto ptr = LLVMBuildInBoundsGEP( 190 builder, 191 lpContext, 192 gepIdx.ptr, 193 gepIdx.length, 194 "", 195 ); 196 197 auto actionid = LLVMBuildLoad(builder, ptr, "actionid"); 198 auto i8 = LLVMInt8TypeInContext(llvmCtx); 199 auto voidstar = LLVMPointerType(i8, 0); 200 foreach(c; catchTable.catches) { 201 auto nextUnwindBB = 202 LLVMAppendBasicBlockInContext(llvmCtx, fun, ""); 203 204 import d.llvm.type; 205 auto typeinfo = LLVMBuildBitCast( 206 builder, 207 TypeGen(pass.pass).getTypeInfo(c.type), 208 voidstar, 209 "", 210 ); 211 212 LLVMBuildCondBr( 213 builder, 214 LLVMBuildICmp( 215 builder, 216 LLVMIntPredicate.EQ, 217 genCall(getEhTypeidFor(), [typeinfo]), 218 actionid, 219 "", 220 ), 221 genBasicBlock(c.block), 222 nextUnwindBB, 223 ); 224 225 LLVMPositionBuilderAtEnd(builder, nextUnwindBB); 226 } 227 228 auto lpBlock = fbody[b].landingpad; 229 if (lpBlock) { 230 LLVMBuildBr(builder, genBasicBlock(lpBlock)); 231 break; 232 } 233 234 goto Resume; 235 236 case Halt: 237 genHalt(bb.location, bb.value); 238 break; 239 } 240 } 241 242 private auto getEhTypeidFor() { 243 if (pass.statementGenData.llvmEhTypeIdFor !is null) { 244 return pass.statementGenData.llvmEhTypeIdFor; 245 } 246 247 auto i32 = LLVMInt32TypeInContext(llvmCtx); 248 auto arg = LLVMPointerType(LLVMInt8TypeInContext(llvmCtx), 0); 249 250 pass.statementGenData.llvmEhTypeIdFor = LLVMAddFunction( 251 dmodule, 252 "llvm.eh.typeid.for".ptr, 253 LLVMFunctionType(i32, &arg, 1, false), 254 ); 255 256 return pass.statementGenData.llvmEhTypeIdFor; 257 } 258 259 private auto genExpression(Expression e) { 260 import d.llvm.expression; 261 return ExpressionGen(pass).visit(e); 262 } 263 264 private auto getLpType() { 265 LLVMTypeRef[2] lpTypes = [ 266 LLVMPointerType(LLVMInt8TypeInContext(llvmCtx), 0), 267 LLVMInt32TypeInContext(llvmCtx), 268 ]; 269 270 return LLVMStructTypeInContext( 271 llvmCtx, 272 lpTypes.ptr, 273 lpTypes.length, 274 false, 275 ); 276 } 277 278 private LLVMBasicBlockRef genLandingPad(BasicBlockRef srcBlock) { 279 auto b = fbody[srcBlock].landingpad; 280 if (!b) { 281 return null; 282 } 283 284 auto i = *(cast(uint*) &b) - 1; 285 if (landingPads[i] !is null) { 286 return landingPads[i]; 287 } 288 289 // We have a failure case. 290 auto currentBB = LLVMGetInsertBlock(builder); 291 scope(exit) LLVMPositionBuilderAtEnd(builder, currentBB); 292 293 auto lpType = getLpType(); 294 295 // Create an alloca for the landing pad results. 296 if (!lpContext) { 297 LLVMPositionBuilderAtEnd(builder, LLVMGetFirstBasicBlock(fun)); 298 lpContext = LLVMBuildAlloca(builder, lpType, "lpContext"); 299 LLVMSetPersonalityFn(fun, declare(pass.object.getPersonality())); 300 } 301 302 auto lpBB = landingPads[i] = LLVMAppendBasicBlockInContext( 303 llvmCtx, 304 fun, 305 "landingPad", 306 ); 307 308 auto instrs = range(fbody, b); 309 auto terminator = fbody[b].terminator; 310 bool cleanup = instrs.length > 0 || terminator != Terminator.Throw; 311 312 LLVMValueRef[] clauses; 313 if (terminator == Terminator.Throw && !fbody[b].value) { 314 if (auto catchTable = fbody[b].catchTable) { 315 foreach(c; catchTable.catches) { 316 import d.llvm.type; 317 clauses ~= TypeGen(pass.pass).getTypeInfo(c.type); 318 } 319 } 320 } 321 322 if (auto nextLpBB = genLandingPad(b)) { 323 auto nextLp = LLVMGetFirstInstruction(nextLpBB); 324 cleanup = cleanup || LLVMIsCleanup(nextLp); 325 326 clauses.length = LLVMGetNumClauses(nextLp); 327 foreach (n, ref c; clauses) { 328 c = LLVMGetClause(nextLp, cast(uint) n); 329 } 330 } 331 332 LLVMPositionBuilderAtEnd(builder, lpBB); 333 auto landingPad = LLVMBuildLandingPad( 334 builder, 335 lpType, 336 null, 337 cast(uint) clauses.length, 338 "", 339 ); 340 341 LLVMSetCleanup(landingPad, cleanup); 342 foreach (c; clauses) { 343 LLVMAddClause(landingPad, c); 344 } 345 346 LLVMBuildStore(builder, landingPad, lpContext); 347 LLVMBuildBr(builder, genBasicBlock(b)); 348 349 return lpBB; 350 } 351 352 private LLVMBasicBlockRef genBasicBlock(BasicBlockRef b) { 353 auto i = *(cast(uint*) &b) - 1; 354 if (basicBlocks[i] !is null) { 355 return basicBlocks[i]; 356 } 357 358 // Make sure we have the landign pad ready. 359 genLandingPad(b); 360 361 return basicBlocks[i] = LLVMAppendBasicBlockInContext( 362 llvmCtx, 363 fun, 364 fbody[b].name.toStringz(context), 365 ); 366 } 367 368 private auto genCall(LLVMValueRef callee, LLVMValueRef[] args) { 369 import d.llvm.expression; 370 return ExpressionGen(pass).buildCall(callee, args); 371 } 372 373 void genHalt(Location location, Expression msg) { 374 auto floc = location.getFullLocation(context); 375 376 LLVMValueRef[3] args; 377 args[1] = buildDString(floc.getSource().getFileName().toString()); 378 args[2] = LLVMConstInt( 379 LLVMInt32TypeInContext(llvmCtx), 380 floc.getStartLineNumber(), 381 false, 382 ); 383 384 if (msg) { 385 args[0] = genExpression(msg); 386 genCall(declare(pass.object.getAssertFailMsg()), args[]); 387 } else { 388 genCall(declare(pass.object.getAssertFail()), args[1 .. $]); 389 } 390 391 // Conclude that block. 392 LLVMBuildUnreachable(builder); 393 } 394 }