| ... | @@ -521,8 +521,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -521,8 +521,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 521 | => try self.airDbgBlock(inst), | 521 | => try self.airDbgBlock(inst), |
| 522 | | 522 | |
| 523 | .call => try self.airCall(inst, .auto), | 523 | .call => try self.airCall(inst, .auto), |
| 524 | .call_always_tail => @panic("TODO try self.airCall(inst, .always_tail)"), | 524 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 525 | .call_never_tail => @panic("TODO try self.airCall(inst, .never_tail)"), | 525 | .call_never_tail => try self.airCall(inst, .never_tail), |
| 526 | .call_never_inline => try self.airCall(inst, .never_inline), | 526 | .call_never_inline => try self.airCall(inst, .never_inline), |
| 527 | | 527 | |
| 528 | .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"), | 528 | .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"), |
| ... | @@ -586,16 +586,106 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -586,16 +586,106 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 586 | const is_volatile = (extra.data.flags & 0x80000000) != 0; | 586 | const is_volatile = (extra.data.flags & 0x80000000) != 0; |
| 587 | const clobbers_len = @truncate(u31, extra.data.flags); | 587 | const clobbers_len = @truncate(u31, extra.data.flags); |
| 588 | var extra_i: usize = extra.end; | 588 | var extra_i: usize = extra.end; |
| 589 | const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); | 589 | const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..extra_i+extra.data.outputs_len]); |
| 590 | extra_i += outputs.len; | 590 | extra_i += outputs.len; |
| 591 | const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); | 591 | const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..extra_i+extra.data.inputs_len]); |
| 592 | extra_i += inputs.len; | 592 | extra_i += inputs.len; |
| 593 | | 593 | |
| 594 | const dead = !is_volatile and self.liveness.isUnused(inst); | 594 | const dead = !is_volatile and self.liveness.isUnused(inst); |
| 595 | _ = dead; | 595 | const result: MCValue = if (dead) .dead else result: { |
| 596 | _ = clobbers_len; | 596 | if (outputs.len > 1) { |
| | 597 | return self.fail("TODO implement codegen for asm with more than 1 output", .{}); |
| | 598 | } |
| | 599 | |
| | 600 | const output_constraint: ?[]const u8 = for (outputs) |output| { |
| | 601 | if (output != .none) { |
| | 602 | return self.fail("TODO implement codegen for non-expr asm", .{}); |
| | 603 | } |
| | 604 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| | 605 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| | 606 | // for the string, we still use the next u32 for the null terminator. |
| | 607 | extra_i += constraint.len / 4 + 1; |
| | 608 | |
| | 609 | break constraint; |
| | 610 | } else null; |
| | 611 | |
| | 612 | for (inputs) |input| { |
| | 613 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| | 614 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| | 615 | // for the string, we still use the next u32 for the null terminator. |
| | 616 | extra_i += constraint.len / 4 + 1; |
| | 617 | |
| | 618 | if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { |
| | 619 | return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); |
| | 620 | } |
| | 621 | const reg_name = constraint[1 .. constraint.len - 1]; |
| | 622 | const reg = parseRegName(reg_name) orelse |
| | 623 | return self.fail("unrecognized register: '{s}'", .{reg_name}); |
| | 624 | |
| | 625 | const arg_mcv = try self.resolveInst(input); |
| | 626 | try self.register_manager.getReg(reg, null); |
| | 627 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); |
| | 628 | } |
| | 629 | |
| | 630 | { |
| | 631 | var clobber_i: u32 = 0; |
| | 632 | while (clobber_i < clobbers_len) : (clobber_i += 1) { |
| | 633 | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| | 634 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| | 635 | // for the string, we still use the next u32 for the null terminator. |
| | 636 | extra_i += clobber.len / 4 + 1; |
| | 637 | |
| | 638 | // TODO honor these |
| | 639 | } |
| | 640 | } |
| | 641 | |
| | 642 | const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| | 643 | |
| | 644 | if (mem.eql(u8, asm_source, "ta 0x6d")) { |
| | 645 | _ = try self.addInst(.{ |
| | 646 | .tag = .tcc, |
| | 647 | .data = .{ |
| | 648 | .trap = .{ |
| | 649 | .is_imm = true, |
| | 650 | .cond = 0b1000, // TODO need to look into changing this into an enum |
| | 651 | .rs2_or_imm = .{ .imm = 0x6d }, |
| | 652 | }, |
| | 653 | }, |
| | 654 | }); |
| | 655 | } else { |
| | 656 | return self.fail("TODO implement a full SPARCv9 assembly parsing", .{}); |
| | 657 | } |
| | 658 | |
| | 659 | if (output_constraint) |output| { |
| | 660 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| | 661 | return self.fail("unrecognized asm output constraint: '{s}'", .{output}); |
| | 662 | } |
| | 663 | const reg_name = output[2 .. output.len - 1]; |
| | 664 | const reg = parseRegName(reg_name) orelse |
| | 665 | return self.fail("unrecognized register: '{s}'", .{reg_name}); |
| | 666 | break :result MCValue{ .register = reg }; |
| | 667 | } else { |
| | 668 | break :result MCValue{ .none = {} }; |
| | 669 | } |
| | 670 | }; |
| | 671 | |
| | 672 | simple: { |
| | 673 | var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); |
| | 674 | var buf_index: usize = 0; |
| | 675 | for (outputs) |output| { |
| | 676 | if (output == .none) continue; |
| 597 | | 677 | |
| 598 | return self.fail("TODO implement asm for {}", .{self.target.cpu.arch}); | 678 | if (buf_index >= buf.len) break :simple; |
| | 679 | buf[buf_index] = output; |
| | 680 | buf_index += 1; |
| | 681 | } |
| | 682 | if (buf_index + inputs.len > buf.len) break :simple; |
| | 683 | std.mem.copy(Air.Inst.Ref, buf[buf_index..], inputs); |
| | 684 | return self.finishAir(inst, result, buf); |
| | 685 | } |
| | 686 | |
| | 687 | @panic("TODO implement asm return"); |
| | 688 | //return self.fail("TODO implement asm return for {}", .{self.target.cpu.arch}); |
| 599 | } | 689 | } |
| 600 | | 690 | |
| 601 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { | 691 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -759,9 +849,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -759,9 +849,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 759 | }); | 849 | }); |
| 760 | } | 850 | } |
| 761 | | 851 | |
| 762 | // TODO handle return value | 852 | const result = info.return_value; |
| | 853 | |
| | 854 | if (args.len + 1 <= Liveness.bpi - 1) { |
| | 855 | var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); |
| | 856 | buf[0] = callee; |
| | 857 | std.mem.copy(Air.Inst.Ref, buf[1..], args); |
| | 858 | return self.finishAir(inst, result, buf); |
| | 859 | } |
| 763 | | 860 | |
| 764 | return self.fail("TODO implement call for {}", .{self.target.cpu.arch}); | 861 | @panic("TODO handle return value with BigTomb"); |
| 765 | } | 862 | } |
| 766 | | 863 | |
| 767 | fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { | 864 | fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1218,6 +1315,13 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -1218,6 +1315,13 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 1218 | } | 1315 | } |
| 1219 | } | 1316 | } |
| 1220 | | 1317 | |
| | 1318 | fn parseRegName(name: []const u8) ?Register { |
| | 1319 | if (@hasDecl(Register, "parseRegName")) { |
| | 1320 | return Register.parseRegName(name); |
| | 1321 | } |
| | 1322 | return std.meta.stringToEnum(Register, name); |
| | 1323 | } |
| | 1324 | |
| 1221 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { | 1325 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 1222 | const tag = self.mir_instructions.items(.tag)[inst]; | 1326 | const tag = self.mir_instructions.items(.tag)[inst]; |
| 1223 | switch (tag) { | 1327 | switch (tag) { |