authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-01-26 21:09:40+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-01 08:47:25+02:00
logbdfe3aeab8310a64cc9c2f5fac194a609aa0f13d
treee85db06e6da871ead6feb649214da512854253bf
parent6ca0ff90b63cea79d8d63519a3c133cfde111884
signaturelock-open Commit is signed but in an unrecognized format.

stage2 cbe: condbr and breaks


2 files changed, 68 insertions(+), 6 deletions(-)

src/codegen/c.zig+50-6
...@@ -41,6 +41,7 @@ pub const Object = struct {...@@ -41,6 +41,7 @@ pub const Object = struct {
41 value_map: CValueMap,41 value_map: CValueMap,
42 next_arg_index: usize = 0,42 next_arg_index: usize = 0,
43 next_local_index: usize = 0,43 next_local_index: usize = 0,
44 next_block_index: usize = 0,
44 indent_writer: std.io.AutoIndentingStream(std.ArrayList(u8).Writer),45 indent_writer: std.io.AutoIndentingStream(std.ArrayList(u8).Writer),
4546
46 fn resolveInst(o: *Object, inst: *Inst) !CValue {47 fn resolveInst(o: *Object, inst: *Inst) !CValue {
...@@ -255,8 +256,8 @@ pub const DeclGen = struct {...@@ -255,8 +256,8 @@ pub const DeclGen = struct {
255 .int_signed, .int_unsigned => {256 .int_signed, .int_unsigned => {
256 const info = t.intInfo(dg.module.getTarget());257 const info = t.intInfo(dg.module.getTarget());
257 const sign_prefix = switch (info.signedness) {258 const sign_prefix = switch (info.signedness) {
258 .signed => "i",259 .signed => "",
259 .unsigned => "",260 .unsigned => "u",
260 };261 };
261 inline for (.{ 8, 16, 32, 64, 128 }) |nbits| {262 inline for (.{ 8, 16, 32, 64, 128 }) |nbits| {
262 if (info.bits <= nbits) {263 if (info.bits <= nbits) {
...@@ -325,6 +326,7 @@ pub fn genDecl(o: *Object) !void {...@@ -325,6 +326,7 @@ pub fn genDecl(o: *Object) !void {
325 try o.indent_writer.insertNewline();326 try o.indent_writer.insertNewline();
326 try o.dg.renderFunctionSignature(o.writer(), is_global);327 try o.dg.renderFunctionSignature(o.writer(), is_global);
327 328
329 try o.writer().writeByte(' ');
328 try genBody(o, func.body);330 try genBody(o, func.body);
329331
330 try o.indent_writer.insertNewline();332 try o.indent_writer.insertNewline();
...@@ -372,11 +374,11 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -372,11 +374,11 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
372pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!void {374pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!void {
373 const writer = o.writer();375 const writer = o.writer();
374 if (body.instructions.len == 0) {376 if (body.instructions.len == 0) {
375 try writer.writeAll(" {}");377 try writer.writeAll("{}");
376 return;378 return;
377 }379 }
378380
379 try writer.writeAll(" {\n");381 try writer.writeAll("{\n");
380 o.indent_writer.pushIndent();382 o.indent_writer.pushIndent();
381383
382 for (body.instructions) |inst| {384 for (body.instructions) |inst| {
...@@ -404,6 +406,9 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -404,6 +406,9 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
404 .sub => try genBinOp(o, inst.castTag(.sub).?, " - "),406 .sub => try genBinOp(o, inst.castTag(.sub).?, " - "),
405 .unreach => try genUnreach(o, inst.castTag(.unreach).?),407 .unreach => try genUnreach(o, inst.castTag(.unreach).?),
406 .loop => try genLoop(o, inst.castTag(.loop).?),408 .loop => try genLoop(o, inst.castTag(.loop).?),
409 .condbr => try genCondBr(o, inst.castTag(.condbr).?),
410 .br => try genBr(o, inst.castTag(.br).?),
411 .brvoid => try genBrVoid(o, inst.castTag(.brvoid).?.block),
407 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),412 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
408 };413 };
409 switch (result_value) {414 switch (result_value) {
...@@ -579,7 +584,31 @@ fn genDbgStmt(o: *Object, inst: *Inst.NoOp) !CValue {...@@ -579,7 +584,31 @@ fn genDbgStmt(o: *Object, inst: *Inst.NoOp) !CValue {
579}584}
580585
581fn genBlock(o: *Object, inst: *Inst.Block) !CValue {586fn genBlock(o: *Object, inst: *Inst.Block) !CValue {
582 return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement blocks", .{});587 const block_id: usize = o.next_block_index;
588 o.next_block_index += 1;
589 // abuse codegen.msv to store the block's id
590 inst.codegen.mcv.a = block_id;
591 try genBody(o, inst.body);
592 try o.indent_writer.insertNewline();
593 // label must be followed by an expression, add an empty one.
594 try o.writer().print("zig_block_{d}:;\n", .{block_id});
595
596 // blocks in C cannot result in values
597 // TODO we need some other way to pass the result of the block
598 return CValue.none;
599}
600
601fn genBr(o: *Object, inst: *Inst.Br) !CValue {
602 if (inst.operand.ty.tag() != .void) {
603 return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement block return values", .{});
604 }
605
606 return genBrVoid(o, inst.block);
607}
608
609fn genBrVoid(o: *Object, block: *Inst.Block) !CValue {
610 try o.writer().print("goto zig_block_{d};\n", .{block.codegen.mcv.a});
611 return CValue.none;
583}612}
584613
585fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue {614fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue {
...@@ -622,12 +651,27 @@ fn genUnreach(o: *Object, inst: *Inst.NoOp) !CValue {...@@ -622,12 +651,27 @@ fn genUnreach(o: *Object, inst: *Inst.NoOp) !CValue {
622}651}
623652
624fn genLoop(o: *Object, inst: *Inst.Loop) !CValue {653fn genLoop(o: *Object, inst: *Inst.Loop) !CValue {
625 try o.writer().writeAll("while (true)");654 try o.writer().writeAll("while (true) ");
626 try genBody(o, inst.body);655 try genBody(o, inst.body);
627 try o.indent_writer.insertNewline();656 try o.indent_writer.insertNewline();
628 return CValue.none;657 return CValue.none;
629}658}
630659
660fn genCondBr(o: *Object, inst: *Inst.CondBr) !CValue {
661 const cond = try o.resolveInst(inst.condition);
662 const writer = o.writer();
663
664 try writer.writeAll("if (");
665 try o.writeCValue(writer, cond);
666 try writer.writeAll(") ");
667 try genBody(o, inst.then_body);
668 try writer.writeAll(" else ");
669 try genBody(o, inst.else_body);
670 try o.indent_writer.insertNewline();
671
672 return CValue.none;
673}
674
631fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {675fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
632 if (as.base.isUnused() and !as.is_volatile)676 if (as.base.isUnused() and !as.is_volatile)
633 return CValue.none;677 return CValue.none;
test/stage2/cbe.zig+18
...@@ -133,6 +133,24 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -133,6 +133,24 @@ 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 , "");
136 }154 }
137155
138 {156 {