| ... | ... | @@ -41,6 +41,7 @@ pub const Object = struct { |
| 41 | 41 | value_map: CValueMap, |
| 42 | 42 | next_arg_index: usize = 0, |
| 43 | 43 | next_local_index: usize = 0, |
| 44 | next_block_index: usize = 0, |
| 44 | 45 | indent_writer: std.io.AutoIndentingStream(std.ArrayList(u8).Writer), |
| 45 | 46 | |
| 46 | 47 | fn resolveInst(o: *Object, inst: *Inst) !CValue { |
| ... | ... | @@ -255,8 +256,8 @@ pub const DeclGen = struct { |
| 255 | 256 | .int_signed, .int_unsigned => { |
| 256 | 257 | const info = t.intInfo(dg.module.getTarget()); |
| 257 | 258 | const sign_prefix = switch (info.signedness) { |
| 258 | | .signed => "i", |
| 259 | | .unsigned => "", |
| 259 | .signed => "", |
| 260 | .unsigned => "u", |
| 260 | 261 | }; |
| 261 | 262 | inline for (.{ 8, 16, 32, 64, 128 }) |nbits| { |
| 262 | 263 | if (info.bits <= nbits) { |
| ... | ... | @@ -325,6 +326,7 @@ pub fn genDecl(o: *Object) !void { |
| 325 | 326 | try o.indent_writer.insertNewline(); |
| 326 | 327 | try o.dg.renderFunctionSignature(o.writer(), is_global); |
| 327 | 328 | |
| 329 | try o.writer().writeByte(' '); |
| 328 | 330 | try genBody(o, func.body); |
| 329 | 331 | |
| 330 | 332 | try o.indent_writer.insertNewline(); |
| ... | ... | @@ -372,11 +374,11 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 372 | 374 | pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!void { |
| 373 | 375 | const writer = o.writer(); |
| 374 | 376 | if (body.instructions.len == 0) { |
| 375 | | try writer.writeAll(" {}"); |
| 377 | try writer.writeAll("{}"); |
| 376 | 378 | return; |
| 377 | 379 | } |
| 378 | 380 | |
| 379 | | try writer.writeAll(" {\n"); |
| 381 | try writer.writeAll("{\n"); |
| 380 | 382 | o.indent_writer.pushIndent(); |
| 381 | 383 | |
| 382 | 384 | for (body.instructions) |inst| { |
| ... | ... | @@ -404,6 +406,9 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi |
| 404 | 406 | .sub => try genBinOp(o, inst.castTag(.sub).?, " - "), |
| 405 | 407 | .unreach => try genUnreach(o, inst.castTag(.unreach).?), |
| 406 | 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 | 412 | else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}), |
| 408 | 413 | }; |
| 409 | 414 | switch (result_value) { |
| ... | ... | @@ -579,7 +584,31 @@ fn genDbgStmt(o: *Object, inst: *Inst.NoOp) !CValue { |
| 579 | 584 | } |
| 580 | 585 | |
| 581 | 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 | 614 | fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue { |
| ... | ... | @@ -622,12 +651,27 @@ fn genUnreach(o: *Object, inst: *Inst.NoOp) !CValue { |
| 622 | 651 | } |
| 623 | 652 | |
| 624 | 653 | fn genLoop(o: *Object, inst: *Inst.Loop) !CValue { |
| 625 | | try o.writer().writeAll("while (true)"); |
| 654 | try o.writer().writeAll("while (true) "); |
| 626 | 655 | try genBody(o, inst.body); |
| 627 | 656 | try o.indent_writer.insertNewline(); |
| 628 | 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 | 675 | fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { |
| 632 | 676 | if (as.base.isUnused() and !as.is_volatile) |
| 633 | 677 | return CValue.none; |