| ... | ... | @@ -521,8 +521,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 521 | 521 | => try self.airDbgBlock(inst), |
| 522 | 522 | |
| 523 | 523 | .call => try self.airCall(inst, .auto), |
| 524 | | .call_always_tail => @panic("TODO try self.airCall(inst, .always_tail)"), |
| 525 | | .call_never_tail => @panic("TODO try self.airCall(inst, .never_tail)"), |
| 524 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 525 | .call_never_tail => try self.airCall(inst, .never_tail), |
| 526 | 526 | .call_never_inline => try self.airCall(inst, .never_inline), |
| 527 | 527 | |
| 528 | 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 | 586 | const is_volatile = (extra.data.flags & 0x80000000) != 0; |
| 587 | 587 | const clobbers_len = @truncate(u31, extra.data.flags); |
| 588 | 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 | 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 | 592 | extra_i += inputs.len; |
| 593 | 593 | |
| 594 | 594 | const dead = !is_volatile and self.liveness.isUnused(inst); |
| 595 | | _ = dead; |
| 596 | | _ = clobbers_len; |
| 595 | const result: MCValue = if (dead) .dead else result: { |
| 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 | 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 | 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 | 864 | fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -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 | 1325 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 1222 | 1326 | const tag = self.mir_instructions.items(.tag)[inst]; |
| 1223 | 1327 | switch (tag) { |