stage2 cbe: implement switchbr

This commit is contained in:
Veikka Tuominen
2021-01-27 11:40:34 +02:00
parent 258f3ec5ec
commit 106520329e
4 changed files with 78 additions and 43 deletions

View File

@@ -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,
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;