stage2 cbe: implement switchbr
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user