Commit 106520329e
Changed files (4)
src
test
stage2
src/codegen/c.zig
@@ -129,6 +129,9 @@ pub const DeclGen = struct {
t: Type,
val: Value,
) error{ OutOfMemory, AnalysisFail }!void {
+ if (val.isUndef()) {
+ return dg.fail(dg.decl.src(), "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{});
+ }
switch (t.zigTypeTag()) {
.Int => {
if (t.isSignedInt())
@@ -196,6 +199,7 @@ pub const DeclGen = struct {
},
}
},
+ .Bool => return writer.print("{}", .{val.toBool()}),
else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
@tagName(e),
}),
@@ -409,6 +413,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
.condbr => try genCondBr(o, inst.castTag(.condbr).?),
.br => try genBr(o, inst.castTag(.br).?),
.brvoid => try genBrVoid(o, inst.castTag(.brvoid).?.block),
+ .switchbr => try genSwitchBr(o, inst.castTag(.switchbr).?),
+ // booland and boolor are non-short-circuit operations
+ .booland => try genBinOp(o, inst.castTag(.booland).?, " & "),
+ .boolor => try genBinOp(o, inst.castTag(.boolor).?, " | "),
else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
};
switch (result_value) {
@@ -688,6 +696,33 @@ fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue {
return CValue.none;
}
+fn genSwitchBr(o: *Object, inst: *Inst.SwitchBr) !CValue {
+ const target = try o.resolveInst(inst.target);
+ const writer = o.writer();
+
+ try writer.writeAll("switch (");
+ try o.writeCValue(writer, target);
+ try writer.writeAll(") {\n");
+ o.indent_writer.pushIndent();
+
+ for (inst.cases) |case| {
+ try writer.writeAll("case ");
+ try o.dg.renderValue(writer, inst.target.ty, case.item);
+ try writer.writeAll(": ");
+ // the case body must be noreturn so we don't need to insert a break
+ try genBody(o, case.body);
+ try o.indent_writer.insertNewline();
+ }
+
+ try writer.writeAll("default: ");
+ try genBody(o, inst.else_body);
+ try o.indent_writer.insertNewline();
+
+ o.indent_writer.popIndent();
+ try writer.writeAll("}\n");
+ return CValue.none;
+}
+
fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
if (as.base.isUnused() and !as.is_volatile)
return CValue.none;
src/ir.zig
@@ -521,7 +521,7 @@ pub const Inst = struct {
pub const base_tag = Tag.switchbr;
base: Inst,
- target_ptr: *Inst,
+ target: *Inst,
cases: []Case,
/// Set of instructions whose lifetimes end at the start of one of the cases.
/// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... ].
@@ -544,7 +544,7 @@ pub const Inst = struct {
var i = index;
if (i < 1)
- return self.target_ptr;
+ return self.target;
i -= 1;
return null;
src/Module.zig
@@ -2215,7 +2215,7 @@ pub fn addSwitchBr(
self: *Module,
block: *Scope.Block,
src: usize,
- target_ptr: *Inst,
+ target: *Inst,
cases: []Inst.SwitchBr.Case,
else_body: ir.Body,
) !*Inst {
@@ -2226,7 +2226,7 @@ pub fn addSwitchBr(
.ty = Type.initTag(.noreturn),
.src = src,
},
- .target_ptr = target_ptr,
+ .target = target,
.cases = cases,
.else_body = else_body,
};
test/stage2/cbe.zig
@@ -133,45 +133,6 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
\\
, "");
-
- // Simple while loop
- case.addCompareOutput(
- \\export fn main() c_int {
- \\ var a: c_int = 0;
- \\ while (a < 5) : (a+=1) {}
- \\ exit(a - 5);
- \\}
- \\
- \\fn exit(code: usize) noreturn {
- \\ asm volatile ("syscall"
- \\ :
- \\ : [number] "{rax}" (231),
- \\ [arg1] "{rdi}" (code)
- \\ );
- \\ unreachable;
- \\}
- , "");
-
- // If expression
- case.addCompareOutput(
- \\export fn main() c_int {
- \\ var cond: c_int = 0;
- \\ var a: c_int = @as(c_int, if (cond == 0)
- \\ 2
- \\ else
- \\ 3) + 9;
- \\ exit(a - 11);
- \\}
- \\
- \\fn exit(code: usize) noreturn {
- \\ asm volatile ("syscall"
- \\ :
- \\ : [number] "{rax}" (231),
- \\ [arg1] "{rdi}" (code)
- \\ );
- \\ unreachable;
- \\}
- , "");
}
{
@@ -224,6 +185,45 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, "");
}
+ {
+ var case = ctx.exeFromCompiledC("control flow", .{});
+
+ // Simple while loop
+ case.addCompareOutput(
+ \\export fn main() c_int {
+ \\ var a: c_int = 0;
+ \\ while (a < 5) : (a+=1) {}
+ \\ return a - 5;
+ \\}
+ , "");
+
+ // If expression
+ case.addCompareOutput(
+ \\export fn main() c_int {
+ \\ var cond: c_int = 0;
+ \\ var a: c_int = @as(c_int, if (cond == 0)
+ \\ 2
+ \\ else
+ \\ 3) + 9;
+ \\ return a - 11;
+ \\}
+ , "");
+
+ // Switch expression
+ case.addCompareOutput(
+ \\export fn main() c_int {
+ \\ var cond: c_int = 0;
+ \\ var a: c_int = switch (cond) {
+ \\ 1 => 1,
+ \\ 2 => 2,
+ \\ 99...300, 12 => 3,
+ \\ 0 => 4,
+ \\ else => 5,
+ \\ };
+ \\ return a - 4;
+ \\}
+ , "");
+ }
ctx.c("empty start function", linux_x64,
\\export fn _start() noreturn {
\\ unreachable;