| ... | @@ -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), |
| 45 | | 46 | |
| 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); |
| 329 | | 331 | |
| 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 { |
| 372 | pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!void { | 374 | pub 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 | } |
| 378 | | 380 | |
| 379 | try writer.writeAll(" {\n"); | 381 | try writer.writeAll("{\n"); |
| 380 | o.indent_writer.pushIndent(); | 382 | o.indent_writer.pushIndent(); |
| 381 | | 383 | |
| 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 | } |
| 580 | | 585 | |
| 581 | fn genBlock(o: *Object, inst: *Inst.Block) !CValue { | 586 | fn 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 | |
| | 601 | fn 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 | |
| | 609 | fn 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 | } |
| 584 | | 613 | |
| 585 | fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue { | 614 | fn 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 | } |
| 623 | | 652 | |
| 624 | fn genLoop(o: *Object, inst: *Inst.Loop) !CValue { | 653 | fn 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 | } |
| 630 | | 659 | |
| | 660 | fn 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 | |
| 631 | fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { | 675 | fn 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; |