| author | |
| committer | |
| log | e1d8073d2fc0df6fbc5ce983312e3da374a9889b |
| tree | 11d8c5aa24c3c09dfec529c2d9f150511623c7b9 |
| parent | 2117489e05ddf7cc4653feecbf47b3637276d6b6 |
A simple `while(true) {}` loop generates the following LLVMIR:
```
define i32 @main() {
Entry:
br label %Loop
Loop: ; preds = %Loop, %Entry
br label %Loop
}
```
Also implement TZIR printing for loops and add a corresponding test.3 files changed, 52 insertions(+), 2 deletions(-)
src/codegen/llvm.zig+12| ... | @@ -396,6 +396,7 @@ pub const LLVMIRModule = struct { | ... | @@ -396,6 +396,7 @@ pub const LLVMIRModule = struct { |
| 396 | .condbr => try self.genCondBr(inst.castTag(.condbr).?), | 396 | .condbr => try self.genCondBr(inst.castTag(.condbr).?), |
| 397 | .intcast => try self.genIntCast(inst.castTag(.intcast).?), | 397 | .intcast => try self.genIntCast(inst.castTag(.intcast).?), |
| 398 | .load => try self.genLoad(inst.castTag(.load).?), | 398 | .load => try self.genLoad(inst.castTag(.load).?), |
| 399 | .loop => try self.genLoop(inst.castTag(.loop).?), | ||
| 399 | .not => try self.genNot(inst.castTag(.not).?), | 400 | .not => try self.genNot(inst.castTag(.not).?), |
| 400 | .ret => try self.genRet(inst.castTag(.ret).?), | 401 | .ret => try self.genRet(inst.castTag(.ret).?), |
| 401 | .retvoid => self.genRetVoid(inst.castTag(.retvoid).?), | 402 | .retvoid => self.genRetVoid(inst.castTag(.retvoid).?), |
| ... | @@ -559,6 +560,17 @@ pub const LLVMIRModule = struct { | ... | @@ -559,6 +560,17 @@ pub const LLVMIRModule = struct { |
| 559 | return null; | 560 | return null; |
| 560 | } | 561 | } |
| 561 | 562 | ||
| 563 | fn genLoop(self: *LLVMIRModule, inst: *Inst.Loop) !?*const llvm.Value { | ||
| 564 | const loop_block = self.context.appendBasicBlock(self.llvm_func, "Loop"); | ||
| 565 | _ = self.builder.buildBr(loop_block); | ||
| 566 | |||
| 567 | self.builder.positionBuilderAtEnd(loop_block); | ||
| 568 | try self.genBody(inst.body); | ||
| 569 | |||
| 570 | _ = self.builder.buildBr(loop_block); | ||
| 571 | return null; | ||
| 572 | } | ||
| 573 | |||
| 562 | fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value { | 574 | fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value { |
| 563 | return self.builder.buildNot(try self.resolveInst(inst.operand), ""); | 575 | return self.builder.buildNot(try self.resolveInst(inst.operand), ""); |
| 564 | } | 576 | } |
src/zir.zig+19-2| ... | @@ -2011,11 +2011,15 @@ const DumpTzir = struct { | ... | @@ -2011,11 +2011,15 @@ const DumpTzir = struct { |
| 2011 | try dtz.fetchInstsAndResolveConsts(condbr.else_body); | 2011 | try dtz.fetchInstsAndResolveConsts(condbr.else_body); |
| 2012 | }, | 2012 | }, |
| 2013 | 2013 | ||
| 2014 | .loop => { | ||
| 2015 | const loop = inst.castTag(.loop).?; | ||
| 2016 | try dtz.fetchInstsAndResolveConsts(loop.body); | ||
| 2017 | }, | ||
| 2018 | |||
| 2014 | // TODO fill out this debug printing | 2019 | // TODO fill out this debug printing |
| 2015 | .assembly, | 2020 | .assembly, |
| 2016 | .call, | 2021 | .call, |
| 2017 | .constant, | 2022 | .constant, |
| 2018 | .loop, | ||
| 2019 | .varptr, | 2023 | .varptr, |
| 2020 | .switchbr, | 2024 | .switchbr, |
| 2021 | => {}, | 2025 | => {}, |
| ... | @@ -2229,11 +2233,24 @@ const DumpTzir = struct { | ... | @@ -2229,11 +2233,24 @@ const DumpTzir = struct { |
| 2229 | try writer.writeAll(")\n"); | 2233 | try writer.writeAll(")\n"); |
| 2230 | }, | 2234 | }, |
| 2231 | 2235 | ||
| 2236 | .loop => { | ||
| 2237 | const loop = inst.castTag(.loop).?; | ||
| 2238 | |||
| 2239 | try writer.writeAll("\n"); | ||
| 2240 | |||
| 2241 | const old_indent = dtz.indent; | ||
| 2242 | dtz.indent += 2; | ||
| 2243 | try dtz.dumpBody(loop.body, writer); | ||
| 2244 | dtz.indent = old_indent; | ||
| 2245 | |||
| 2246 | try writer.writeByteNTimes(' ', dtz.indent); | ||
| 2247 | try writer.writeAll(")\n"); | ||
| 2248 | }, | ||
| 2249 | |||
| 2232 | // TODO fill out this debug printing | 2250 | // TODO fill out this debug printing |
| 2233 | .assembly, | 2251 | .assembly, |
| 2234 | .call, | 2252 | .call, |
| 2235 | .constant, | 2253 | .constant, |
| 2236 | .loop, | ||
| 2237 | .varptr, | 2254 | .varptr, |
| 2238 | .switchbr, | 2255 | .switchbr, |
| 2239 | => { | 2256 | => { |
test/stage2/llvm.zig+21| ... | @@ -111,4 +111,25 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -111,4 +111,25 @@ pub fn addCases(ctx: *TestContext) !void { |
| 111 | \\} | 111 | \\} |
| 112 | , ""); | 112 | , ""); |
| 113 | } | 113 | } |
| 114 | |||
| 115 | { | ||
| 116 | var case = ctx.exeUsingLlvmBackend("while loops", linux_x64); | ||
| 117 | |||
| 118 | case.addCompareOutput( | ||
| 119 | \\fn assert(ok: bool) void { | ||
| 120 | \\ if (!ok) unreachable; | ||
| 121 | \\} | ||
| 122 | \\ | ||
| 123 | \\export fn main() c_int { | ||
| 124 | \\ var sum: u32 = 0; | ||
| 125 | \\ var i: u32 = 0; | ||
| 126 | \\ while (i < 5) : (i += 1) { | ||
| 127 | \\ sum += i; | ||
| 128 | \\ } | ||
| 129 | \\ assert(sum == 10); | ||
| 130 | \\ assert(i == 5); | ||
| 131 | \\ return 0; | ||
| 132 | \\} | ||
| 133 | , ""); | ||
| 134 | } | ||
| 114 | } | 135 | } |