Commit e1d8073d2f

Timon Kruiper <timonkruiper@gmail.com>
2021-01-10 17:36:01
stage2: add support for loops in LLVM backend
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.
1 parent 2117489
Changed files (3)
src
test
stage2
src/codegen/llvm.zig
@@ -396,6 +396,7 @@ pub const LLVMIRModule = struct {
                 .condbr => try self.genCondBr(inst.castTag(.condbr).?),
                 .intcast => try self.genIntCast(inst.castTag(.intcast).?),
                 .load => try self.genLoad(inst.castTag(.load).?),
+                .loop => try self.genLoop(inst.castTag(.loop).?),
                 .not => try self.genNot(inst.castTag(.not).?),
                 .ret => try self.genRet(inst.castTag(.ret).?),
                 .retvoid => self.genRetVoid(inst.castTag(.retvoid).?),
@@ -559,6 +560,17 @@ pub const LLVMIRModule = struct {
         return null;
     }
 
+    fn genLoop(self: *LLVMIRModule, inst: *Inst.Loop) !?*const llvm.Value {
+        const loop_block = self.context.appendBasicBlock(self.llvm_func, "Loop");
+        _ = self.builder.buildBr(loop_block);
+
+        self.builder.positionBuilderAtEnd(loop_block);
+        try self.genBody(inst.body);
+
+        _ = self.builder.buildBr(loop_block);
+        return null;
+    }
+
     fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {
         return self.builder.buildNot(try self.resolveInst(inst.operand), "");
     }
src/zir.zig
@@ -2011,11 +2011,15 @@ const DumpTzir = struct {
                     try dtz.fetchInstsAndResolveConsts(condbr.else_body);
                 },
 
+                .loop => {
+                    const loop = inst.castTag(.loop).?;
+                    try dtz.fetchInstsAndResolveConsts(loop.body);
+                },
+
                 // TODO fill out this debug printing
                 .assembly,
                 .call,
                 .constant,
-                .loop,
                 .varptr,
                 .switchbr,
                 => {},
@@ -2229,11 +2233,24 @@ const DumpTzir = struct {
                     try writer.writeAll(")\n");
                 },
 
+                .loop => {
+                    const loop = inst.castTag(.loop).?;
+
+                    try writer.writeAll("\n");
+
+                    const old_indent = dtz.indent;
+                    dtz.indent += 2;
+                    try dtz.dumpBody(loop.body, writer);
+                    dtz.indent = old_indent;
+
+                    try writer.writeByteNTimes(' ', dtz.indent);
+                    try writer.writeAll(")\n");
+                },
+
                 // TODO fill out this debug printing
                 .assembly,
                 .call,
                 .constant,
-                .loop,
                 .varptr,
                 .switchbr,
                 => {
test/stage2/llvm.zig
@@ -111,4 +111,25 @@ pub fn addCases(ctx: *TestContext) !void {
             \\}
         , "");
     }
+
+    {
+        var case = ctx.exeUsingLlvmBackend("while loops", linux_x64);
+
+        case.addCompareOutput(
+            \\fn assert(ok: bool) void {
+            \\    if (!ok) unreachable;
+            \\}
+            \\
+            \\export fn main() c_int {
+            \\    var sum: u32 = 0;
+            \\    var i: u32 = 0;
+            \\    while (i < 5) : (i += 1) {
+            \\        sum += i;
+            \\    }
+            \\    assert(sum == 10);
+            \\    assert(i == 5);
+            \\    return 0;
+            \\}
+        , "");
+    }
 }