| ... | @@ -939,7 +939,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -939,7 +939,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 939 | /// Copies a value to a register without tracking the register. The register is not considered | 939 | /// Copies a value to a register without tracking the register. The register is not considered |
| 940 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 940 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 941 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 941 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 942 | fn copyToTmpRegister(self: *Self, src: usize, mcv: MCValue) !Register { | 942 | fn copyToTmpRegister(self: *Self, src: usize, ty: Type, mcv: MCValue) !Register { |
| 943 | const reg = self.findUnusedReg() orelse b: { | 943 | const reg = self.findUnusedReg() orelse b: { |
| 944 | // We'll take over the first register. Move the instruction that was previously | 944 | // We'll take over the first register. Move the instruction that was previously |
| 945 | // there to a stack allocation. | 945 | // there to a stack allocation. |
| ... | @@ -956,7 +956,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -956,7 +956,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 956 | | 956 | |
| 957 | break :b reg; | 957 | break :b reg; |
| 958 | }; | 958 | }; |
| 959 | try self.genSetReg(src, reg, mcv); | 959 | try self.genSetReg(src, ty, reg, mcv); |
| 960 | return reg; | 960 | return reg; |
| 961 | } | 961 | } |
| 962 | | 962 | |
| ... | @@ -983,7 +983,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -983,7 +983,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 983 | | 983 | |
| 984 | break :b reg; | 984 | break :b reg; |
| 985 | }; | 985 | }; |
| 986 | try self.genSetReg(reg_owner.src, reg, mcv); | 986 | try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv); |
| 987 | return MCValue{ .register = reg }; | 987 | return MCValue{ .register = reg }; |
| 988 | } | 988 | } |
| 989 | | 989 | |
| ... | @@ -1351,13 +1351,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1351,13 +1351,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1351 | // Load immediate into register if it doesn't fit | 1351 | // Load immediate into register if it doesn't fit |
| 1352 | // as an operand | 1352 | // as an operand |
| 1353 | break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse | 1353 | break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse |
| 1354 | Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none); | 1354 | Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none); |
| 1355 | }, | 1355 | }, |
| 1356 | .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none), | 1356 | .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none), |
| 1357 | .stack_offset, | 1357 | .stack_offset, |
| 1358 | .embedded_in_code, | 1358 | .embedded_in_code, |
| 1359 | .memory, | 1359 | .memory, |
| 1360 | => Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none), | 1360 | => Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none), |
| 1361 | }; | 1361 | }; |
| 1362 | | 1362 | |
| 1363 | switch (op) { | 1363 | switch (op) { |
| ... | @@ -1443,7 +1443,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1443,7 +1443,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1443 | switch (src_mcv) { | 1443 | switch (src_mcv) { |
| 1444 | .immediate => |imm| { | 1444 | .immediate => |imm| { |
| 1445 | if (imm > math.maxInt(u31)) { | 1445 | if (imm > math.maxInt(u31)) { |
| 1446 | src_mcv = MCValue{ .register = try self.copyToTmpRegister(src_inst.src, src_mcv) }; | 1446 | src_mcv = MCValue{ .register = try self.copyToTmpRegister(src_inst.src, Type.initTag(.u64), src_mcv) }; |
| 1447 | } | 1447 | } |
| 1448 | }, | 1448 | }, |
| 1449 | else => {}, | 1449 | else => {}, |
| ... | @@ -1474,7 +1474,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1474,7 +1474,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1474 | .register => |dst_reg| { | 1474 | .register => |dst_reg| { |
| 1475 | switch (src_mcv) { | 1475 | switch (src_mcv) { |
| 1476 | .none => unreachable, | 1476 | .none => unreachable, |
| 1477 | .undef => try self.genSetReg(src, dst_reg, .undef), | 1477 | .undef => try self.genSetReg(src, dst_ty, dst_reg, .undef), |
| 1478 | .dead, .unreach => unreachable, | 1478 | .dead, .unreach => unreachable, |
| 1479 | .ptr_stack_offset => unreachable, | 1479 | .ptr_stack_offset => unreachable, |
| 1480 | .ptr_embedded_in_code => unreachable, | 1480 | .ptr_embedded_in_code => unreachable, |
| ... | @@ -1684,7 +1684,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1684,7 +1684,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1684 | switch (mc_arg) { | 1684 | switch (mc_arg) { |
| 1685 | .none => continue, | 1685 | .none => continue, |
| 1686 | .register => |reg| { | 1686 | .register => |reg| { |
| 1687 | try self.genSetReg(arg.src, reg, arg_mcv); | 1687 | try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); |
| 1688 | // TODO interact with the register allocator to mark the instruction as moved. | 1688 | // TODO interact with the register allocator to mark the instruction as moved. |
| 1689 | }, | 1689 | }, |
| 1690 | .stack_offset => { | 1690 | .stack_offset => { |
| ... | @@ -1753,7 +1753,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1753,7 +1753,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1753 | else | 1753 | else |
| 1754 | unreachable; | 1754 | unreachable; |
| 1755 | | 1755 | |
| 1756 | try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); | 1756 | try self.genSetReg(inst.base.src, Type.initTag(.usize), .ra, .{ .memory = got_addr }); |
| 1757 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); | 1757 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); |
| 1758 | } else if (func_value.castTag(.extern_fn)) |_| { | 1758 | } else if (func_value.castTag(.extern_fn)) |_| { |
| 1759 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | 1759 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); |
| ... | @@ -1826,7 +1826,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1826,7 +1826,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1826 | .compare_flags_signed => unreachable, | 1826 | .compare_flags_signed => unreachable, |
| 1827 | .compare_flags_unsigned => unreachable, | 1827 | .compare_flags_unsigned => unreachable, |
| 1828 | .register => |reg| { | 1828 | .register => |reg| { |
| 1829 | try self.genSetReg(arg.src, reg, arg_mcv); | 1829 | try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); |
| 1830 | // TODO interact with the register allocator to mark the instruction as moved. | 1830 | // TODO interact with the register allocator to mark the instruction as moved. |
| 1831 | }, | 1831 | }, |
| 1832 | .stack_offset => { | 1832 | .stack_offset => { |
| ... | @@ -1854,7 +1854,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1854,7 +1854,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1854 | else | 1854 | else |
| 1855 | unreachable; | 1855 | unreachable; |
| 1856 | | 1856 | |
| 1857 | try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr }); | 1857 | try self.genSetReg(inst.base.src, Type.initTag(.usize), .lr, .{ .memory = got_addr }); |
| 1858 | | 1858 | |
| 1859 | // TODO: add Instruction.supportedOn | 1859 | // TODO: add Instruction.supportedOn |
| 1860 | // function for ARM | 1860 | // function for ARM |
| ... | @@ -1889,7 +1889,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1889,7 +1889,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1889 | .compare_flags_signed => unreachable, | 1889 | .compare_flags_signed => unreachable, |
| 1890 | .compare_flags_unsigned => unreachable, | 1890 | .compare_flags_unsigned => unreachable, |
| 1891 | .register => |reg| { | 1891 | .register => |reg| { |
| 1892 | try self.genSetReg(arg.src, reg, arg_mcv); | 1892 | try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); |
| 1893 | // TODO interact with the register allocator to mark the instruction as moved. | 1893 | // TODO interact with the register allocator to mark the instruction as moved. |
| 1894 | }, | 1894 | }, |
| 1895 | .stack_offset => { | 1895 | .stack_offset => { |
| ... | @@ -1917,7 +1917,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1917,7 +1917,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1917 | else | 1917 | else |
| 1918 | unreachable; | 1918 | unreachable; |
| 1919 | | 1919 | |
| 1920 | try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr }); | 1920 | try self.genSetReg(inst.base.src, Type.initTag(.usize), .x30, .{ .memory = got_addr }); |
| 1921 | | 1921 | |
| 1922 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); | 1922 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); |
| 1923 | } else if (func_value.castTag(.extern_fn)) |_| { | 1923 | } else if (func_value.castTag(.extern_fn)) |_| { |
| ... | @@ -1940,7 +1940,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1940,7 +1940,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1940 | switch (mc_arg) { | 1940 | switch (mc_arg) { |
| 1941 | .none => continue, | 1941 | .none => continue, |
| 1942 | .register => |reg| { | 1942 | .register => |reg| { |
| 1943 | try self.genSetReg(arg.src, reg, arg_mcv); | 1943 | try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); |
| 1944 | // TODO interact with the register allocator to mark the instruction as moved. | 1944 | // TODO interact with the register allocator to mark the instruction as moved. |
| 1945 | }, | 1945 | }, |
| 1946 | .stack_offset => { | 1946 | .stack_offset => { |
| ... | @@ -1973,12 +1973,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1973,12 +1973,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1973 | const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64); | 1973 | const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64); |
| 1974 | switch (arch) { | 1974 | switch (arch) { |
| 1975 | .x86_64 => { | 1975 | .x86_64 => { |
| 1976 | try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr }); | 1976 | try self.genSetReg(inst.base.src, Type.initTag(.u32), .rax, .{ .memory = got_addr }); |
| 1977 | // callq *%rax | 1977 | // callq *%rax |
| 1978 | self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 }); | 1978 | self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 }); |
| 1979 | }, | 1979 | }, |
| 1980 | .aarch64 => { | 1980 | .aarch64 => { |
| 1981 | try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr }); | 1981 | try self.genSetReg(inst.base.src, Type.initTag(.u32), .x30, .{ .memory = got_addr }); |
| 1982 | // blr x30 | 1982 | // blr x30 |
| 1983 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); | 1983 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); |
| 1984 | }, | 1984 | }, |
| ... | @@ -2579,7 +2579,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2579,7 +2579,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2579 | const reg = parseRegName(reg_name) orelse | 2579 | const reg = parseRegName(reg_name) orelse |
| 2580 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); | 2580 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); |
| 2581 | const arg = try self.resolveInst(inst.args[i]); | 2581 | const arg = try self.resolveInst(inst.args[i]); |
| 2582 | try self.genSetReg(inst.base.src, reg, arg); | 2582 | try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); |
| 2583 | } | 2583 | } |
| 2584 | | 2584 | |
| 2585 | if (mem.eql(u8, inst.asm_source, "svc #0")) { | 2585 | if (mem.eql(u8, inst.asm_source, "svc #0")) { |
| ... | @@ -2609,7 +2609,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2609,7 +2609,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2609 | const reg = parseRegName(reg_name) orelse | 2609 | const reg = parseRegName(reg_name) orelse |
| 2610 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); | 2610 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); |
| 2611 | const arg = try self.resolveInst(inst.args[i]); | 2611 | const arg = try self.resolveInst(inst.args[i]); |
| 2612 | try self.genSetReg(inst.base.src, reg, arg); | 2612 | try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); |
| 2613 | } | 2613 | } |
| 2614 | | 2614 | |
| 2615 | if (mem.eql(u8, inst.asm_source, "svc #0")) { | 2615 | if (mem.eql(u8, inst.asm_source, "svc #0")) { |
| ... | @@ -2641,7 +2641,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2641,7 +2641,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2641 | const reg = parseRegName(reg_name) orelse | 2641 | const reg = parseRegName(reg_name) orelse |
| 2642 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); | 2642 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); |
| 2643 | const arg = try self.resolveInst(inst.args[i]); | 2643 | const arg = try self.resolveInst(inst.args[i]); |
| 2644 | try self.genSetReg(inst.base.src, reg, arg); | 2644 | try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); |
| 2645 | } | 2645 | } |
| 2646 | | 2646 | |
| 2647 | if (mem.eql(u8, inst.asm_source, "ecall")) { | 2647 | if (mem.eql(u8, inst.asm_source, "ecall")) { |
| ... | @@ -2671,7 +2671,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2671,7 +2671,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2671 | const reg = parseRegName(reg_name) orelse | 2671 | const reg = parseRegName(reg_name) orelse |
| 2672 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); | 2672 | return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); |
| 2673 | const arg = try self.resolveInst(inst.args[i]); | 2673 | const arg = try self.resolveInst(inst.args[i]); |
| 2674 | try self.genSetReg(inst.base.src, reg, arg); | 2674 | try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); |
| 2675 | } | 2675 | } |
| 2676 | | 2676 | |
| 2677 | if (mem.eql(u8, inst.asm_source, "syscall")) { | 2677 | if (mem.eql(u8, inst.asm_source, "syscall")) { |
| ... | @@ -2733,7 +2733,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2733,7 +2733,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2733 | fn setRegOrMem(self: *Self, src: usize, ty: Type, loc: MCValue, val: MCValue) !void { | 2733 | fn setRegOrMem(self: *Self, src: usize, ty: Type, loc: MCValue, val: MCValue) !void { |
| 2734 | switch (loc) { | 2734 | switch (loc) { |
| 2735 | .none => return, | 2735 | .none => return, |
| 2736 | .register => |reg| return self.genSetReg(src, reg, val), | 2736 | .register => |reg| return self.genSetReg(src, ty, reg, val), |
| 2737 | .stack_offset => |off| return self.genSetStack(src, ty, off, val), | 2737 | .stack_offset => |off| return self.genSetStack(src, ty, off, val), |
| 2738 | .memory => { | 2738 | .memory => { |
| 2739 | return self.fail(src, "TODO implement setRegOrMem for memory", .{}); | 2739 | return self.fail(src, "TODO implement setRegOrMem for memory", .{}); |
| ... | @@ -2768,7 +2768,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2768,7 +2768,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2768 | return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{}); | 2768 | return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{}); |
| 2769 | }, | 2769 | }, |
| 2770 | .immediate => { | 2770 | .immediate => { |
| 2771 | const reg = try self.copyToTmpRegister(src, mcv); | 2771 | const reg = try self.copyToTmpRegister(src, ty, mcv); |
| 2772 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); | 2772 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 2773 | }, | 2773 | }, |
| 2774 | .embedded_in_code => |code_offset| { | 2774 | .embedded_in_code => |code_offset| { |
| ... | @@ -2782,7 +2782,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2782,7 +2782,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2782 | 1, 4 => { | 2782 | 1, 4 => { |
| 2783 | const offset = if (math.cast(u12, adj_off)) |imm| blk: { | 2783 | const offset = if (math.cast(u12, adj_off)) |imm| blk: { |
| 2784 | break :blk Instruction.Offset.imm(imm); | 2784 | break :blk Instruction.Offset.imm(imm); |
| 2785 | } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0); | 2785 | } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0); |
| 2786 | const str = switch (abi_size) { | 2786 | const str = switch (abi_size) { |
| 2787 | 1 => Instruction.strb, | 2787 | 1 => Instruction.strb, |
| 2788 | 4 => Instruction.str, | 2788 | 4 => Instruction.str, |
| ... | @@ -2797,7 +2797,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2797,7 +2797,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2797 | 2 => { | 2797 | 2 => { |
| 2798 | const offset = if (adj_off <= math.maxInt(u8)) blk: { | 2798 | const offset = if (adj_off <= math.maxInt(u8)) blk: { |
| 2799 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off)); | 2799 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off)); |
| 2800 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off })); | 2800 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off })); |
| 2801 | | 2801 | |
| 2802 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{ | 2802 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{ |
| 2803 | .offset = offset, | 2803 | .offset = offset, |
| ... | @@ -2814,7 +2814,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2814,7 +2814,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2814 | if (stack_offset == off) | 2814 | if (stack_offset == off) |
| 2815 | return; // Copy stack variable to itself; nothing to do. | 2815 | return; // Copy stack variable to itself; nothing to do. |
| 2816 | | 2816 | |
| 2817 | const reg = try self.copyToTmpRegister(src, mcv); | 2817 | const reg = try self.copyToTmpRegister(src, ty, mcv); |
| 2818 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); | 2818 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 2819 | }, | 2819 | }, |
| 2820 | }, | 2820 | }, |
| ... | @@ -2903,7 +2903,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2903,7 +2903,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2903 | if (stack_offset == off) | 2903 | if (stack_offset == off) |
| 2904 | return; // Copy stack variable to itself; nothing to do. | 2904 | return; // Copy stack variable to itself; nothing to do. |
| 2905 | | 2905 | |
| 2906 | const reg = try self.copyToTmpRegister(src, mcv); | 2906 | const reg = try self.copyToTmpRegister(src, ty, mcv); |
| 2907 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); | 2907 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 2908 | }, | 2908 | }, |
| 2909 | }, | 2909 | }, |
| ... | @@ -2931,7 +2931,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2931,7 +2931,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2931 | return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{}); | 2931 | return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{}); |
| 2932 | }, | 2932 | }, |
| 2933 | .immediate => { | 2933 | .immediate => { |
| 2934 | const reg = try self.copyToTmpRegister(src, mcv); | 2934 | const reg = try self.copyToTmpRegister(src, ty, mcv); |
| 2935 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); | 2935 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 2936 | }, | 2936 | }, |
| 2937 | .embedded_in_code => |code_offset| { | 2937 | .embedded_in_code => |code_offset| { |
| ... | @@ -2946,7 +2946,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2946,7 +2946,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2946 | const offset = if (math.cast(i9, adj_off)) |imm| | 2946 | const offset = if (math.cast(i9, adj_off)) |imm| |
| 2947 | Instruction.LoadStoreOffset.imm_post_index(-imm) | 2947 | Instruction.LoadStoreOffset.imm_post_index(-imm) |
| 2948 | else |_| | 2948 | else |_| |
| 2949 | Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off })); | 2949 | Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u64), MCValue{ .immediate = adj_off })); |
| 2950 | const rn: Register = switch (arch) { | 2950 | const rn: Register = switch (arch) { |
| 2951 | .aarch64, .aarch64_be => .x29, | 2951 | .aarch64, .aarch64_be => .x29, |
| 2952 | .aarch64_32 => .w29, | 2952 | .aarch64_32 => .w29, |
| ... | @@ -2967,7 +2967,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2967,7 +2967,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2967 | if (stack_offset == off) | 2967 | if (stack_offset == off) |
| 2968 | return; // Copy stack variable to itself; nothing to do. | 2968 | return; // Copy stack variable to itself; nothing to do. |
| 2969 | | 2969 | |
| 2970 | const reg = try self.copyToTmpRegister(src, mcv); | 2970 | const reg = try self.copyToTmpRegister(src, ty, mcv); |
| 2971 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); | 2971 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 2972 | }, | 2972 | }, |
| 2973 | }, | 2973 | }, |
| ... | @@ -2975,7 +2975,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2975,7 +2975,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2975 | } | 2975 | } |
| 2976 | } | 2976 | } |
| 2977 | | 2977 | |
| 2978 | fn genSetReg(self: *Self, src: usize, reg: Register, mcv: MCValue) InnerError!void { | 2978 | fn genSetReg(self: *Self, src: usize, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 2979 | switch (arch) { | 2979 | switch (arch) { |
| 2980 | .arm, .armeb => switch (mcv) { | 2980 | .arm, .armeb => switch (mcv) { |
| 2981 | .dead => unreachable, | 2981 | .dead => unreachable, |
| ... | @@ -2986,7 +2986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2986,7 +2986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2986 | if (!self.wantSafety()) | 2986 | if (!self.wantSafety()) |
| 2987 | return; // The already existing value will do just fine. | 2987 | return; // The already existing value will do just fine. |
| 2988 | // Write the debug undefined value. | 2988 | // Write the debug undefined value. |
| 2989 | return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa }); | 2989 | return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }); |
| 2990 | }, | 2990 | }, |
| 2991 | .compare_flags_unsigned, | 2991 | .compare_flags_unsigned, |
| 2992 | .compare_flags_signed, | 2992 | .compare_flags_signed, |
| ... | @@ -3051,21 +3051,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3051,21 +3051,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3051 | .memory => |addr| { | 3051 | .memory => |addr| { |
| 3052 | // The value is in memory at a hard-coded address. | 3052 | // The value is in memory at a hard-coded address. |
| 3053 | // If the type is a pointer, it means the pointer address is at this memory location. | 3053 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3054 | try self.genSetReg(src, reg, .{ .immediate = addr }); | 3054 | try self.genSetReg(src, ty, reg, .{ .immediate = addr }); |
| 3055 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32()); | 3055 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32()); |
| 3056 | }, | 3056 | }, |
| 3057 | .stack_offset => |unadjusted_off| { | 3057 | .stack_offset => |unadjusted_off| { |
| 3058 | // TODO: maybe addressing from sp instead of fp | 3058 | // TODO: maybe addressing from sp instead of fp |
| 3059 | // TODO: supply type information to genSetReg as we do to genSetStack | 3059 | const abi_size = ty.abiSize(self.target.*); |
| 3060 | // const abi_size = ty.abiSize(self.target.*); | | |
| 3061 | const abi_size = 4; | | |
| 3062 | const adj_off = unadjusted_off + abi_size; | 3060 | const adj_off = unadjusted_off + abi_size; |
| 3063 | | 3061 | |
| 3064 | switch (abi_size) { | 3062 | switch (abi_size) { |
| 3065 | 1, 4 => { | 3063 | 1, 4 => { |
| 3066 | const offset = if (adj_off <= math.maxInt(u12)) blk: { | 3064 | const offset = if (adj_off <= math.maxInt(u12)) blk: { |
| 3067 | break :blk Instruction.Offset.imm(@intCast(u12, adj_off)); | 3065 | break :blk Instruction.Offset.imm(@intCast(u12, adj_off)); |
| 3068 | } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0); | 3066 | } else Instruction.Offset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0); |
| 3069 | const ldr = switch (abi_size) { | 3067 | const ldr = switch (abi_size) { |
| 3070 | 1 => Instruction.ldrb, | 3068 | 1 => Instruction.ldrb, |
| 3071 | 4 => Instruction.ldr, | 3069 | 4 => Instruction.ldr, |
| ... | @@ -3080,7 +3078,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3080,7 +3078,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3080 | 2 => { | 3078 | 2 => { |
| 3081 | const offset = if (adj_off <= math.maxInt(u8)) blk: { | 3079 | const offset = if (adj_off <= math.maxInt(u8)) blk: { |
| 3082 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off)); | 3080 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off)); |
| 3083 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off })); | 3081 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off })); |
| 3084 | | 3082 | |
| 3085 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{ | 3083 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{ |
| 3086 | .offset = offset, | 3084 | .offset = offset, |
| ... | @@ -3102,8 +3100,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3102,8 +3100,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3102 | return; // The already existing value will do just fine. | 3100 | return; // The already existing value will do just fine. |
| 3103 | // Write the debug undefined value. | 3101 | // Write the debug undefined value. |
| 3104 | switch (reg.size()) { | 3102 | switch (reg.size()) { |
| 3105 | 32 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa }), | 3103 | 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }), |
| 3106 | 64 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), | 3104 | 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 3107 | else => unreachable, // unexpected register size | 3105 | else => unreachable, // unexpected register size |
| 3108 | } | 3106 | } |
| 3109 | }, | 3107 | }, |
| ... | @@ -3216,7 +3214,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3216,7 +3214,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3216 | } else { | 3214 | } else { |
| 3217 | // The value is in memory at a hard-coded address. | 3215 | // The value is in memory at a hard-coded address. |
| 3218 | // If the type is a pointer, it means the pointer address is at this memory location. | 3216 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3219 | try self.genSetReg(src, reg, .{ .immediate = addr }); | 3217 | try self.genSetReg(src, Type.initTag(.usize), reg, .{ .immediate = addr }); |
| 3220 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32()); | 3218 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32()); |
| 3221 | } | 3219 | } |
| 3222 | }, | 3220 | }, |
| ... | @@ -3231,7 +3229,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3231,7 +3229,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3231 | if (!self.wantSafety()) | 3229 | if (!self.wantSafety()) |
| 3232 | return; // The already existing value will do just fine. | 3230 | return; // The already existing value will do just fine. |
| 3233 | // Write the debug undefined value. | 3231 | // Write the debug undefined value. |
| 3234 | return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); | 3232 | return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); |
| 3235 | }, | 3233 | }, |
| 3236 | .immediate => |unsigned_x| { | 3234 | .immediate => |unsigned_x| { |
| 3237 | const x = @bitCast(i64, unsigned_x); | 3235 | const x = @bitCast(i64, unsigned_x); |
| ... | @@ -3256,7 +3254,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3256,7 +3254,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3256 | .memory => |addr| { | 3254 | .memory => |addr| { |
| 3257 | // The value is in memory at a hard-coded address. | 3255 | // The value is in memory at a hard-coded address. |
| 3258 | // If the type is a pointer, it means the pointer address is at this memory location. | 3256 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3259 | try self.genSetReg(src, reg, .{ .immediate = addr }); | 3257 | try self.genSetReg(src, ty, reg, .{ .immediate = addr }); |
| 3260 | | 3258 | |
| 3261 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ld(reg, 0, reg).toU32()); | 3259 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ld(reg, 0, reg).toU32()); |
| 3262 | // LOAD imm=[i12 offset = 0], rs1 = | 3260 | // LOAD imm=[i12 offset = 0], rs1 = |
| ... | @@ -3275,10 +3273,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3275,10 +3273,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3275 | return; // The already existing value will do just fine. | 3273 | return; // The already existing value will do just fine. |
| 3276 | // Write the debug undefined value. | 3274 | // Write the debug undefined value. |
| 3277 | switch (reg.size()) { | 3275 | switch (reg.size()) { |
| 3278 | 8 => return self.genSetReg(src, reg, .{ .immediate = 0xaa }), | 3276 | 8 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaa }), |
| 3279 | 16 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaa }), | 3277 | 16 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaa }), |
| 3280 | 32 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa }), | 3278 | 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }), |
| 3281 | 64 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), | 3279 | 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 3282 | else => unreachable, | 3280 | else => unreachable, |
| 3283 | } | 3281 | } |
| 3284 | }, | 3282 | }, |
| ... | @@ -3492,7 +3490,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3492,7 +3490,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3492 | assert(id3 != 4 and id3 != 5); | 3490 | assert(id3 != 4 and id3 != 5); |
| 3493 | | 3491 | |
| 3494 | // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue. | 3492 | // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue. |
| 3495 | try self.genSetReg(src, reg, MCValue{ .immediate = x }); | 3493 | try self.genSetReg(src, ty, reg, MCValue{ .immediate = x }); |
| 3496 | | 3494 | |
| 3497 | // Now, the register contains the address of the value to load into it | 3495 | // Now, the register contains the address of the value to load into it |
| 3498 | // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant. | 3496 | // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant. |
| ... | @@ -3591,7 +3589,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -3591,7 +3589,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3591 | // This immediate is unsigned. | 3589 | // This immediate is unsigned. |
| 3592 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); | 3590 | const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed)); |
| 3593 | if (imm >= math.maxInt(U)) { | 3591 | if (imm >= math.maxInt(U)) { |
| 3594 | return MCValue{ .register = try self.copyToTmpRegister(inst.src, mcv) }; | 3592 | return MCValue{ .register = try self.copyToTmpRegister(inst.src, Type.initTag(.usize), mcv) }; |
| 3595 | } | 3593 | } |
| 3596 | }, | 3594 | }, |
| 3597 | else => {}, | 3595 | else => {}, |