| ... | @@ -417,7 +417,6 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void { | ... | @@ -417,7 +417,6 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void { |
| 417 | } | 417 | } |
| 418 | | 418 | |
| 419 | fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void { | 419 | fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void { |
| 420 | // TODO imm64 | | |
| 421 | const ops: Mir.Inst.Ops = if (imm == .signed) .imm_s else .imm_u; | 420 | const ops: Mir.Inst.Ops = if (imm == .signed) .imm_s else .imm_u; |
| 422 | const data: Mir.Inst.Data = switch (ops) { | 421 | const data: Mir.Inst.Data = switch (ops) { |
| 423 | .imm_s => .{ .imm_s = imm.signed }, | 422 | .imm_s => .{ .imm_s = imm.signed }, |
| ... | @@ -443,7 +442,10 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Reg | ... | @@ -443,7 +442,10 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Reg |
| 443 | } | 442 | } |
| 444 | | 443 | |
| 445 | fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void { | 444 | fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void { |
| 446 | const ops: Mir.Inst.Ops = if (imm == .signed) .ri_s else .ri_u; | 445 | const ops: Mir.Inst.Ops = switch (imm) { |
| | 446 | .signed => .ri_s, |
| | 447 | .unsigned => |x| if (x <= math.maxInt(u32)) .ri_u else .ri64, |
| | 448 | }; |
| 447 | const data: Mir.Inst.Data = switch (ops) { | 449 | const data: Mir.Inst.Data = switch (ops) { |
| 448 | .ri_s => .{ .ri_s = .{ | 450 | .ri_s => .{ .ri_s = .{ |
| 449 | .r1 = reg, | 451 | .r1 = reg, |
| ... | @@ -453,6 +455,10 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme | ... | @@ -453,6 +455,10 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme |
| 453 | .r1 = reg, | 455 | .r1 = reg, |
| 454 | .imm = @intCast(u32, imm.unsigned), | 456 | .imm = @intCast(u32, imm.unsigned), |
| 455 | } }, | 457 | } }, |
| | 458 | .ri64 => .{ .rx = .{ |
| | 459 | .r1 = reg, |
| | 460 | .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)), |
| | 461 | } }, |
| 456 | else => unreachable, | 462 | else => unreachable, |
| 457 | }; | 463 | }; |
| 458 | _ = try self.addInst(.{ | 464 | _ = try self.addInst(.{ |
| ... | @@ -6118,32 +6124,23 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -6118,32 +6124,23 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6118 | // }); | 6124 | // }); |
| 6119 | }, | 6125 | }, |
| 6120 | .immediate => |x| { | 6126 | .immediate => |x| { |
| 6121 | // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit | | |
| 6122 | // register is the fastest way to zero a register. | | |
| 6123 | if (x == 0) { | 6127 | if (x == 0) { |
| | 6128 | // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit |
| | 6129 | // register is the fastest way to zero a register. |
| 6124 | return self.asmRegisterRegister(.xor, reg.to32(), reg.to32()); | 6130 | return self.asmRegisterRegister(.xor, reg.to32(), reg.to32()); |
| 6125 | } | 6131 | } |
| 6126 | if (x <= math.maxInt(i32)) { | 6132 | if (ty.isSignedInt() and x <= math.maxInt(i32)) { |
| 6127 | // Next best case: if we set the lower four bytes, the upper four will be zeroed. | | |
| 6128 | return self.asmRegisterImmediate( | 6133 | return self.asmRegisterImmediate( |
| 6129 | .mov, | 6134 | .mov, |
| 6130 | registerAlias(reg, abi_size), | 6135 | registerAlias(reg, abi_size), |
| 6131 | Immediate.u(@intCast(u32, x)), | 6136 | Immediate.s(@intCast(i32, @bitCast(i64, x))), |
| 6132 | ); | 6137 | ); |
| 6133 | } | 6138 | } |
| 6134 | // Worst case: we need to load the 64-bit register with the IMM. GNU's assemblers calls | 6139 | return self.asmRegisterImmediate( |
| 6135 | // this `movabs`, though this is officially just a different variant of the plain `mov` | 6140 | .mov, |
| 6136 | // instruction. | 6141 | registerAlias(reg, abi_size), |
| 6137 | // | 6142 | Immediate.u(x), |
| 6138 | // This encoding is, in fact, the *same* as the one used for 32-bit loads. The only | 6143 | ); |
| 6139 | // difference is that we set REX.W before the instruction, which extends the load to | | |
| 6140 | // 64-bit and uses the full bit-width of the register. | | |
| 6141 | // const payload = try self.addExtra(Mir.Imm64.encode(x)); | | |
| 6142 | // _ = try self.addInst(.{ | | |
| 6143 | // .tag = .movabs, | | |
| 6144 | // .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to64() }), | | |
| 6145 | // .data = .{ .payload = payload }, | | |
| 6146 | // }); | | |
| 6147 | }, | 6144 | }, |
| 6148 | .register => |src_reg| { | 6145 | .register => |src_reg| { |
| 6149 | // If the registers are the same, nothing to do. | 6146 | // If the registers are the same, nothing to do. |