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(
22152215 self: *Module,
22162216 block: *Scope.Block,
22172217 src: usize,
2218 target_ptr: *Inst,
2218 target: *Inst,
22192219 cases: []Inst.SwitchBr.Case,
22202220 else_body: ir.Body,
22212221) !*Inst {
......@@ -2226,7 +2226,7 @@ pub fn addSwitchBr(
22262226 .ty = Type.initTag(.noreturn),
22272227 .src = src,
22282228 },
2229 .target_ptr = target_ptr,
2229 .target = target,
22302230 .cases = cases,
22312231 .else_body = else_body,
22322232 };
src/codegen/c.zig+35
......@@ -129,6 +129,9 @@ pub const DeclGen = struct {
129129 t: Type,
130130 val: Value,
131131 ) 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 }
132135 switch (t.zigTypeTag()) {
133136 .Int => {
134137 if (t.isSignedInt())
......@@ -196,6 +199,7 @@ pub const DeclGen = struct {
196199 },
197200 }
198201 },
202 .Bool => return writer.print("{}", .{val.toBool()}),
199203 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
200204 @tagName(e),
201205 }),
......@@ -409,6 +413,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
409413 .condbr => try genCondBr(o, inst.castTag(.condbr).?),
410414 .br => try genBr(o, inst.castTag(.br).?),
411415 .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).?, " | "),
412420 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
413421 };
414422 switch (result_value) {
......@@ -688,6 +696,33 @@ fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue {
688696 return CValue.none;
689697}
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
691726fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
692727 if (as.base.isUnused() and !as.is_volatile)
693728 return CValue.none;
src/ir.zig+2-2
......@@ -521,7 +521,7 @@ pub const Inst = struct {
521521 pub const base_tag = Tag.switchbr;
522522
523523 base: Inst,
524 target_ptr: *Inst,
524 target: *Inst,
525525 cases: []Case,
526526 /// Set of instructions whose lifetimes end at the start of one of the cases.
527527 /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... ].
......@@ -544,7 +544,7 @@ pub const Inst = struct {
544544 var i = index;
545545
546546 if (i < 1)
547 return self.target_ptr;
547 return self.target;
548548 i -= 1;
549549
550550 return null;
test/stage2/cbe.zig+39-39
......@@ -133,45 +133,6 @@ pub fn addCases(ctx: *TestContext) !void {
133133 \\}
134134 \\
135135 , "");
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 , "");
175136 }
176137
177138 {
......@@ -224,6 +185,45 @@ pub fn addCases(ctx: *TestContext) !void {
224185 \\}
225186 , "");
226187 }
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 }
227227 ctx.c("empty start function", linux_x64,
228228 \\export fn _start() noreturn {
229229 \\ unreachable;