authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-01-27 11:40:34+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-01 08:48:22+02:00
log106520329e5adc6cf5ef83595da6c9d5dd3c4b35
treeda0ceaa068638cd12ae91ce56795e88c8d7c367c
parent258f3ec5ecf8d2a165382d5837bed0dac2e0375b
signaturelock-open Commit is signed but in an unrecognized format.

stage2 cbe: implement switchbr


4 files changed, 78 insertions(+), 43 deletions(-)

src/Module.zig+2-2
...@@ -2215,7 +2215,7 @@ pub fn addSwitchBr(...@@ -2215,7 +2215,7 @@ pub fn addSwitchBr(
2215 self: *Module,2215 self: *Module,
2216 block: *Scope.Block,2216 block: *Scope.Block,
2217 src: usize,2217 src: usize,
2218 target_ptr: *Inst,2218 target: *Inst,
2219 cases: []Inst.SwitchBr.Case,2219 cases: []Inst.SwitchBr.Case,
2220 else_body: ir.Body,2220 else_body: ir.Body,
2221) !*Inst {2221) !*Inst {
...@@ -2226,7 +2226,7 @@ pub fn addSwitchBr(...@@ -2226,7 +2226,7 @@ pub fn addSwitchBr(
2226 .ty = Type.initTag(.noreturn),2226 .ty = Type.initTag(.noreturn),
2227 .src = src,2227 .src = src,
2228 },2228 },
2229 .target_ptr = target_ptr,2229 .target = target,
2230 .cases = cases,2230 .cases = cases,
2231 .else_body = else_body,2231 .else_body = else_body,
2232 };2232 };
src/codegen/c.zig+35
...@@ -129,6 +129,9 @@ pub const DeclGen = struct {...@@ -129,6 +129,9 @@ pub const DeclGen = struct {
129 t: Type,129 t: Type,
130 val: Value,130 val: Value,
131 ) error{ OutOfMemory, AnalysisFail }!void {131 ) error{ OutOfMemory, AnalysisFail }!void {
132 if (val.isUndef()) {
133 return dg.fail(dg.decl.src(), "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{});
134 }
132 switch (t.zigTypeTag()) {135 switch (t.zigTypeTag()) {
133 .Int => {136 .Int => {
134 if (t.isSignedInt())137 if (t.isSignedInt())
...@@ -196,6 +199,7 @@ pub const DeclGen = struct {...@@ -196,6 +199,7 @@ pub const DeclGen = struct {
196 },199 },
197 }200 }
198 },201 },
202 .Bool => return writer.print("{}", .{val.toBool()}),
199 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{203 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
200 @tagName(e),204 @tagName(e),
201 }),205 }),
...@@ -409,6 +413,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -409,6 +413,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
409 .condbr => try genCondBr(o, inst.castTag(.condbr).?),413 .condbr => try genCondBr(o, inst.castTag(.condbr).?),
410 .br => try genBr(o, inst.castTag(.br).?),414 .br => try genBr(o, inst.castTag(.br).?),
411 .brvoid => try genBrVoid(o, inst.castTag(.brvoid).?.block),415 .brvoid => try genBrVoid(o, inst.castTag(.brvoid).?.block),
416 .switchbr => try genSwitchBr(o, inst.castTag(.switchbr).?),
417 // booland and boolor are non-short-circuit operations
418 .booland => try genBinOp(o, inst.castTag(.booland).?, " & "),
419 .boolor => try genBinOp(o, inst.castTag(.boolor).?, " | "),
412 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),420 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
413 };421 };
414 switch (result_value) {422 switch (result_value) {
...@@ -688,6 +696,33 @@ fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue {...@@ -688,6 +696,33 @@ fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue {
688 return CValue.none;696 return CValue.none;
689}697}
690698
699fn genSwitchBr(o: *Object, inst: *Inst.SwitchBr) !CValue {
700 const target = try o.resolveInst(inst.target);
701 const writer = o.writer();
702
703 try writer.writeAll("switch (");
704 try o.writeCValue(writer, target);
705 try writer.writeAll(") {\n");
706 o.indent_writer.pushIndent();
707
708 for (inst.cases) |case| {
709 try writer.writeAll("case ");
710 try o.dg.renderValue(writer, inst.target.ty, case.item);
711 try writer.writeAll(": ");
712 // the case body must be noreturn so we don't need to insert a break
713 try genBody(o, case.body);
714 try o.indent_writer.insertNewline();
715 }
716
717 try writer.writeAll("default: ");
718 try genBody(o, inst.else_body);
719 try o.indent_writer.insertNewline();
720
721 o.indent_writer.popIndent();
722 try writer.writeAll("}\n");
723 return CValue.none;
724}
725
691fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {726fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
692 if (as.base.isUnused() and !as.is_volatile)727 if (as.base.isUnused() and !as.is_volatile)
693 return CValue.none;728 return CValue.none;
src/ir.zig+2-2
...@@ -521,7 +521,7 @@ pub const Inst = struct {...@@ -521,7 +521,7 @@ pub const Inst = struct {
521 pub const base_tag = Tag.switchbr;521 pub const base_tag = Tag.switchbr;
522522
523 base: Inst,523 base: Inst,
524 target_ptr: *Inst,524 target: *Inst,
525 cases: []Case,525 cases: []Case,
526 /// Set of instructions whose lifetimes end at the start of one of the cases.526 /// Set of instructions whose lifetimes end at the start of one of the cases.
527 /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... ].527 /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... ].
...@@ -544,7 +544,7 @@ pub const Inst = struct {...@@ -544,7 +544,7 @@ pub const Inst = struct {
544 var i = index;544 var i = index;
545545
546 if (i < 1)546 if (i < 1)
547 return self.target_ptr;547 return self.target;
548 i -= 1;548 i -= 1;
549549
550 return null;550 return null;
test/stage2/cbe.zig+39-39
...@@ -133,45 +133,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -133,45 +133,6 @@ pub fn addCases(ctx: *TestContext) !void {
133 \\}133 \\}
134 \\134 \\
135 , "");135 , "");
136
137 // Simple while loop
138 case.addCompareOutput(
139 \\export fn main() c_int {
140 \\ var a: c_int = 0;
141 \\ while (a < 5) : (a+=1) {}
142 \\ exit(a - 5);
143 \\}
144 \\
145 \\fn exit(code: usize) noreturn {
146 \\ asm volatile ("syscall"
147 \\ :
148 \\ : [number] "{rax}" (231),
149 \\ [arg1] "{rdi}" (code)
150 \\ );
151 \\ unreachable;
152 \\}
153 , "");
154
155 // If expression
156 case.addCompareOutput(
157 \\export fn main() c_int {
158 \\ var cond: c_int = 0;
159 \\ var a: c_int = @as(c_int, if (cond == 0)
160 \\ 2
161 \\ else
162 \\ 3) + 9;
163 \\ exit(a - 11);
164 \\}
165 \\
166 \\fn exit(code: usize) noreturn {
167 \\ asm volatile ("syscall"
168 \\ :
169 \\ : [number] "{rax}" (231),
170 \\ [arg1] "{rdi}" (code)
171 \\ );
172 \\ unreachable;
173 \\}
174 , "");
175 }136 }
176137
177 {138 {
...@@ -224,6 +185,45 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -224,6 +185,45 @@ pub fn addCases(ctx: *TestContext) !void {
224 \\}185 \\}
225 , "");186 , "");
226 }187 }
188 {
189 var case = ctx.exeFromCompiledC("control flow", .{});
190
191 // Simple while loop
192 case.addCompareOutput(
193 \\export fn main() c_int {
194 \\ var a: c_int = 0;
195 \\ while (a < 5) : (a+=1) {}
196 \\ return a - 5;
197 \\}
198 , "");
199
200 // If expression
201 case.addCompareOutput(
202 \\export fn main() c_int {
203 \\ var cond: c_int = 0;
204 \\ var a: c_int = @as(c_int, if (cond == 0)
205 \\ 2
206 \\ else
207 \\ 3) + 9;
208 \\ return a - 11;
209 \\}
210 , "");
211
212 // Switch expression
213 case.addCompareOutput(
214 \\export fn main() c_int {
215 \\ var cond: c_int = 0;
216 \\ var a: c_int = switch (cond) {
217 \\ 1 => 1,
218 \\ 2 => 2,
219 \\ 99...300, 12 => 3,
220 \\ 0 => 4,
221 \\ else => 5,
222 \\ };
223 \\ return a - 4;
224 \\}
225 , "");
226 }
227 ctx.c("empty start function", linux_x64,227 ctx.c("empty start function", linux_x64,
228 \\export fn _start() noreturn {228 \\export fn _start() noreturn {
229 \\ unreachable;229 \\ unreachable;