authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-02-11 04:35:32+01:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-02-12 05:25:07+01:00
logbcbd49b2a6e6a4dd84a5516bf6d1a6fd1e2af3ae
tree9a4ac458271d05e4375574cc0d49d7334aea4afb
parent9023ff04d0dff0c5eff761c5aa1f8611106767d6

x86_64: implement shifts of big integers


7 files changed, 516 insertions(+), 218 deletions(-)

lib/std/Random/Xoshiro256.zig-1
...@@ -90,7 +90,6 @@ pub fn fill(self: *Xoshiro256, buf: []u8) void {...@@ -90,7 +90,6 @@ pub fn fill(self: *Xoshiro256, buf: []u8) void {
9090
91test "xoroshiro sequence" {91test "xoroshiro sequence" {
92 if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest;92 if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest;
93 if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
9493
95 var r = Xoshiro256.init(0);94 var r = Xoshiro256.init(0);
9695
lib/std/crypto/aes_ocb.zig-4
...@@ -262,7 +262,6 @@ const hexToBytes = std.fmt.hexToBytes;...@@ -262,7 +262,6 @@ const hexToBytes = std.fmt.hexToBytes;
262262
263test "AesOcb test vector 1" {263test "AesOcb test vector 1" {
264 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;264 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
265 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
266265
267 var k: [Aes128Ocb.key_length]u8 = undefined;266 var k: [Aes128Ocb.key_length]u8 = undefined;
268 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;267 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
...@@ -282,7 +281,6 @@ test "AesOcb test vector 1" {...@@ -282,7 +281,6 @@ test "AesOcb test vector 1" {
282281
283test "AesOcb test vector 2" {282test "AesOcb test vector 2" {
284 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;283 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
285 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
286284
287 var k: [Aes128Ocb.key_length]u8 = undefined;285 var k: [Aes128Ocb.key_length]u8 = undefined;
288 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;286 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
...@@ -304,7 +302,6 @@ test "AesOcb test vector 2" {...@@ -304,7 +302,6 @@ test "AesOcb test vector 2" {
304302
305test "AesOcb test vector 3" {303test "AesOcb test vector 3" {
306 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;304 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
307 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
308305
309 var k: [Aes128Ocb.key_length]u8 = undefined;306 var k: [Aes128Ocb.key_length]u8 = undefined;
310 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;307 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
...@@ -329,7 +326,6 @@ test "AesOcb test vector 3" {...@@ -329,7 +326,6 @@ test "AesOcb test vector 3" {
329326
330test "AesOcb test vector 4" {327test "AesOcb test vector 4" {
331 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;328 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
332 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
333329
334 var k: [Aes128Ocb.key_length]u8 = undefined;330 var k: [Aes128Ocb.key_length]u8 = undefined;
335 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;331 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
lib/std/crypto/ff.zig+1-2
...@@ -907,9 +907,8 @@ const ct_unprotected = struct {...@@ -907,9 +907,8 @@ const ct_unprotected = struct {
907 }907 }
908};908};
909909
910test {910test "finite field arithmetic" {
911 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;911 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
912 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
913912
914 const M = Modulus(256);913 const M = Modulus(256);
915 const m = try M.fromPrimitive(u256, 3429938563481314093726330772853735541133072814650493833233);914 const m = try M.fromPrimitive(u256, 3429938563481314093726330772853735541133072814650493833233);
lib/std/crypto/pcurves/p384.zig-1
...@@ -479,7 +479,6 @@ pub const AffineCoordinates = struct {...@@ -479,7 +479,6 @@ pub const AffineCoordinates = struct {
479479
480test {480test {
481 if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest;481 if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest;
482 if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
483482
484 _ = @import("tests/p384.zig");483 _ = @import("tests/p384.zig");
485}484}
lib/std/math/big/int_test.zig-3
...@@ -1698,7 +1698,6 @@ test "big.int div multi-multi (2 branch)" {...@@ -1698,7 +1698,6 @@ test "big.int div multi-multi (2 branch)" {
16981698
1699test "big.int div multi-multi (3.1/3.3 branch)" {1699test "big.int div multi-multi (3.1/3.3 branch)" {
1700 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1700 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1701 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
17021701
1703 var a = try Managed.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111);1702 var a = try Managed.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111);
1704 defer a.deinit();1703 defer a.deinit();
...@@ -2187,7 +2186,6 @@ test "big.int bitNotWrap more than two limbs" {...@@ -2187,7 +2186,6 @@ test "big.int bitNotWrap more than two limbs" {
2187 // This test requires int sizes greater than 128 bits.2186 // This test requires int sizes greater than 128 bits.
2188 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2187 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2189 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO2188 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2190 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2191 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2193 // LLVM: unexpected runtime library name: __umodei42191 // LLVM: unexpected runtime library name: __umodei4
...@@ -2537,7 +2535,6 @@ test "big.int gcd non-one large" {...@@ -2537,7 +2535,6 @@ test "big.int gcd non-one large" {
25372535
2538test "big.int gcd large multi-limb result" {2536test "big.int gcd large multi-limb result" {
2539 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;2537 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2540 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
25412538
2542 var a = try Managed.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678);2539 var a = try Managed.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678);
2543 defer a.deinit();2540 defer a.deinit();
lib/std/math/log10.zig+19-65
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const math = std.math;
4const testing = std.testing;3const testing = std.testing;
5const maxInt = std.math.maxInt;
6const assert = std.debug.assert;
7const Log2Int = std.math.Log2Int;
84
9/// Returns the base-10 logarithm of x.5/// Returns the base-10 logarithm of x.
10///6///
...@@ -38,13 +34,13 @@ pub fn log10(x: anytype) @TypeOf(x) {...@@ -38,13 +34,13 @@ pub fn log10(x: anytype) @TypeOf(x) {
3834
39/// Return the log base 10 of integer value x, rounding down to the35/// Return the log base 10 of integer value x, rounding down to the
40/// nearest integer.36/// nearest integer.
41pub fn log10_int(x: anytype) Log2Int(@TypeOf(x)) {37pub fn log10_int(x: anytype) std.math.Log2Int(@TypeOf(x)) {
42 const T = @TypeOf(x);38 const T = @TypeOf(x);
43 const OutT = Log2Int(T);39 const OutT = std.math.Log2Int(T);
44 if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)40 if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)
45 @compileError("log10_int requires an unsigned integer, found " ++ @typeName(T));41 @compileError("log10_int requires an unsigned integer, found " ++ @typeName(T));
4642
47 assert(x != 0);43 std.debug.assert(x != 0);
4844
49 const bit_size = @typeInfo(T).Int.bits;45 const bit_size = @typeInfo(T).Int.bits;
5046
...@@ -133,18 +129,7 @@ inline fn less_than_5(x: u32) u32 {...@@ -133,18 +129,7 @@ inline fn less_than_5(x: u32) u32 {
133 return (((x + C1) & (x + C2)) ^ ((x + C3) & (x + C4))) >> 17;129 return (((x + C1) & (x + C2)) ^ ((x + C3) & (x + C4))) >> 17;
134}130}
135131
136fn oldlog10(x: anytype) u8 {132test log10_int {
137 return @as(u8, @intFromFloat(@log10(@as(f64, @floatFromInt(x)))));
138}
139
140test "oldlog10 doesn't work" {
141 try testing.expect(14 != oldlog10(pow10(15) - 1));
142
143 // log10(10**15 -1) should indeed be 14
144 try testing.expect(14 == log10_int(@as(u64, pow10(15) - 1)));
145}
146
147test "log10_int vs old implementation" {
148 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
149 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
150 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -152,53 +137,22 @@ test "log10_int vs old implementation" {...@@ -152,53 +137,22 @@ test "log10_int vs old implementation" {
152 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
153 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.isWasm()) return error.SkipZigTest; // TODO138 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.isWasm()) return error.SkipZigTest; // TODO
154139
155 const int_types = .{ u8, u16, u32, u64, u128 };140 inline for (
156141 .{ u8, u16, u32, u64, u128, u256, u512 },
157 inline for (int_types) |T| {142 .{ 2, 4, 9, 19, 38, 77, 154 },
158 const last = @min(maxInt(T), 100_000);143 ) |T, max_exponent| {
159 for (1..last) |i| {144 for (0..max_exponent + 1) |exponent_usize| {
160 const x = @as(T, @intCast(i));145 const exponent: std.math.Log2Int(T) = @intCast(exponent_usize);
161 try testing.expectEqual(oldlog10(x), log10_int(x));146 const power_of_ten = try std.math.powi(T, 10, exponent);
162 }147
163148 if (exponent > 0) {
164 const max_int: T = maxInt(T);149 try testing.expectEqual(exponent - 1, log10_int(power_of_ten - 9));
165 try testing.expectEqual(oldlog10(max_int), log10_int(max_int));150 try testing.expectEqual(exponent - 1, log10_int(power_of_ten - 1));
166 }
167}
168
169test "log10_int close to powers of 10" {
170 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
174 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.isWasm()) return error.SkipZigTest; // TODO
176 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
177
178 const int_types = .{ u8, u16, u32, u64, u128, u256, u512 };
179 const max_log_values: [7]usize = .{ 2, 4, 9, 19, 38, 77, 154 };
180
181 inline for (int_types, max_log_values) |T, expected_max_ilog| {
182 const max_val: T = maxInt(T);
183
184 try testing.expectEqual(expected_max_ilog, log10_int(max_val));
185
186 for (0..(expected_max_ilog + 1)) |idx| {
187 const i = @as(T, @intCast(idx));
188 const p: T = try math.powi(T, 10, i);
189
190 const b = @as(Log2Int(T), @intCast(i));
191
192 if (p >= 10) {
193 try testing.expectEqual(b - 1, log10_int(p - 9));
194 try testing.expectEqual(b - 1, log10_int(p - 1));
195 }
196
197 try testing.expectEqual(b, log10_int(p));
198 try testing.expectEqual(b, log10_int(p + 1));
199 if (p >= 10) {
200 try testing.expectEqual(b, log10_int(p + 9));
201 }151 }
152 try testing.expectEqual(exponent, log10_int(power_of_ten));
153 try testing.expectEqual(exponent, log10_int(power_of_ten + 1));
154 try testing.expectEqual(exponent, log10_int(power_of_ten + 8));
202 }155 }
156 try testing.expectEqual(max_exponent, log10_int(@as(T, std.math.maxInt(T))));
203 }157 }
204}158}
src/arch/x86_64/CodeGen.zig+496-142
...@@ -2986,6 +2986,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -2986,6 +2986,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
2986 .{ ._r, .sa },2986 .{ ._r, .sa },
2987 Type.isize,2987 Type.isize,
2988 extend_mcv,2988 extend_mcv,
2989 Type.u8,
2989 .{ .immediate = 63 },2990 .{ .immediate = 63 },
2990 );2991 );
2991 break :extend extend_mcv;2992 break :extend extend_mcv;
...@@ -3500,10 +3501,22 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3500,10 +3501,22 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
3500 const reg_extra_bits = self.regExtraBits(ty);3501 const reg_extra_bits = self.regExtraBits(ty);
3501 const cc: Condition = if (ty.isSignedInt(mod)) cc: {3502 const cc: Condition = if (ty.isSignedInt(mod)) cc: {
3502 if (reg_extra_bits > 0) {3503 if (reg_extra_bits > 0) {
3503 try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });3504 try self.genShiftBinOpMir(
3505 .{ ._l, .sa },
3506 ty,
3507 dst_mcv,
3508 Type.u8,
3509 .{ .immediate = reg_extra_bits },
3510 );
3504 }3511 }
3505 try self.genSetReg(limit_reg, ty, dst_mcv, .{});3512 try self.genSetReg(limit_reg, ty, dst_mcv, .{});
3506 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });3513 try self.genShiftBinOpMir(
3514 .{ ._r, .sa },
3515 ty,
3516 limit_mcv,
3517 Type.u8,
3518 .{ .immediate = reg_bits - 1 },
3519 );
3507 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{3520 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
3508 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,3521 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
3509 });3522 });
...@@ -3517,6 +3530,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3517,6 +3530,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
3517 .{ ._l, .sa },3530 .{ ._l, .sa },
3518 ty,3531 ty,
3519 shifted_rhs_mcv,3532 shifted_rhs_mcv,
3533 Type.u8,
3520 .{ .immediate = reg_extra_bits },3534 .{ .immediate = reg_extra_bits },
3521 );3535 );
3522 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv);3536 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv);
...@@ -3542,9 +3556,13 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3542,9 +3556,13 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
3542 registerAlias(limit_reg, cmov_abi_size),3556 registerAlias(limit_reg, cmov_abi_size),
3543 );3557 );
35443558
3545 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) {3559 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) try self.genShiftBinOpMir(
3546 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });3560 .{ ._r, .sa },
3547 }3561 ty,
3562 dst_mcv,
3563 Type.u8,
3564 .{ .immediate = reg_extra_bits },
3565 );
35483566
3549 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });3567 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
3550}3568}
...@@ -3583,10 +3601,22 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3583,10 +3601,22 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
3583 const reg_extra_bits = self.regExtraBits(ty);3601 const reg_extra_bits = self.regExtraBits(ty);
3584 const cc: Condition = if (ty.isSignedInt(mod)) cc: {3602 const cc: Condition = if (ty.isSignedInt(mod)) cc: {
3585 if (reg_extra_bits > 0) {3603 if (reg_extra_bits > 0) {
3586 try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });3604 try self.genShiftBinOpMir(
3605 .{ ._l, .sa },
3606 ty,
3607 dst_mcv,
3608 Type.u8,
3609 .{ .immediate = reg_extra_bits },
3610 );
3587 }3611 }
3588 try self.genSetReg(limit_reg, ty, dst_mcv, .{});3612 try self.genSetReg(limit_reg, ty, dst_mcv, .{});
3589 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });3613 try self.genShiftBinOpMir(
3614 .{ ._r, .sa },
3615 ty,
3616 limit_mcv,
3617 Type.u8,
3618 .{ .immediate = reg_bits - 1 },
3619 );
3590 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{3620 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
3591 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,3621 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
3592 });3622 });
...@@ -3600,6 +3630,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3600,6 +3630,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
3600 .{ ._l, .sa },3630 .{ ._l, .sa },
3601 ty,3631 ty,
3602 shifted_rhs_mcv,3632 shifted_rhs_mcv,
3633 Type.u8,
3603 .{ .immediate = reg_extra_bits },3634 .{ .immediate = reg_extra_bits },
3604 );3635 );
3605 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv);3636 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv);
...@@ -3618,9 +3649,13 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3618,9 +3649,13 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
3618 registerAlias(limit_reg, cmov_abi_size),3649 registerAlias(limit_reg, cmov_abi_size),
3619 );3650 );
36203651
3621 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) {3652 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) try self.genShiftBinOpMir(
3622 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });3653 .{ ._r, .sa },
3623 }3654 ty,
3655 dst_mcv,
3656 Type.u8,
3657 .{ .immediate = reg_extra_bits },
3658 );
36243659
3625 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });3660 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
3626}3661}
...@@ -3741,7 +3776,13 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3741,7 +3776,13 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
3741 const cc: Condition = if (ty.isSignedInt(mod)) cc: {3776 const cc: Condition = if (ty.isSignedInt(mod)) cc: {
3742 try self.genSetReg(limit_reg, ty, lhs_mcv, .{});3777 try self.genSetReg(limit_reg, ty, lhs_mcv, .{});
3743 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv);3778 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv);
3744 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });3779 try self.genShiftBinOpMir(
3780 .{ ._r, .sa },
3781 ty,
3782 limit_mcv,
3783 Type.u8,
3784 .{ .immediate = reg_bits - 1 },
3785 );
3745 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{3786 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
3746 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,3787 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
3747 });3788 });
...@@ -4029,6 +4070,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4029,6 +4070,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
4029 .size = .qword,4070 .size = .qword,
4030 .index = temp_regs[0].to64(),4071 .index = temp_regs[0].to64(),
4031 .scale = .@"8",4072 .scale = .@"8",
4073 .disp = rhs_mcv.load_frame.off,
4032 } },4074 } },
4033 });4075 });
4034 try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64());4076 try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64());
...@@ -4047,7 +4089,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4047,7 +4089,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
4047 .size = .qword,4089 .size = .qword,
4048 .index = temp_regs[3].to64(),4090 .index = temp_regs[3].to64(),
4049 .scale = .@"8",4091 .scale = .@"8",
4050 .disp = @intCast(tuple_ty.structFieldOffset(0, mod)),4092 .disp = dst_mcv.load_frame.off +
4093 @as(i32, @intCast(tuple_ty.structFieldOffset(0, mod))),
4051 } },4094 } },
4052 }, .rdx);4095 }, .rdx);
4053 try self.asmSetccRegister(.c, .cl);4096 try self.asmSetccRegister(.c, .cl);
...@@ -4058,6 +4101,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4058,6 +4101,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
4058 .size = .qword,4101 .size = .qword,
4059 .index = temp_regs[2].to64(),4102 .index = temp_regs[2].to64(),
4060 .scale = .@"8",4103 .scale = .@"8",
4104 .disp = lhs_mcv.load_frame.off,
4061 } },4105 } },
4062 });4106 });
4063 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());4107 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());
...@@ -4069,7 +4113,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4069,7 +4113,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
4069 .size = .qword,4113 .size = .qword,
4070 .index = temp_regs[3].to64(),4114 .index = temp_regs[3].to64(),
4071 .scale = .@"8",4115 .scale = .@"8",
4072 .disp = @intCast(tuple_ty.structFieldOffset(0, mod)),4116 .disp = dst_mcv.load_frame.off +
4117 @as(i32, @intCast(tuple_ty.structFieldOffset(0, mod))),
4073 } },4118 } },
4074 }, .rax);4119 }, .rax);
4075 try self.asmSetccRegister(.c, .ch);4120 try self.asmSetccRegister(.c, .ch);
...@@ -4108,7 +4153,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4108,7 +4153,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
4108 .size = .qword,4153 .size = .qword,
4109 .index = temp_regs[2].to64(),4154 .index = temp_regs[2].to64(),
4110 .scale = .@"8",4155 .scale = .@"8",
4111 .disp = -8,4156 .disp = lhs_mcv.load_frame.off - 8,
4112 } },4157 } },
4113 }, Immediate.u(0));4158 }, Immediate.u(0));
4114 _ = try self.asmJccReloc(.z, overflow_loop);4159 _ = try self.asmJccReloc(.z, overflow_loop);
...@@ -4117,7 +4162,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4117,7 +4162,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
4117 .base = .{ .frame = dst_mcv.load_frame.index },4162 .base = .{ .frame = dst_mcv.load_frame.index },
4118 .mod = .{ .rm = .{4163 .mod = .{ .rm = .{
4119 .size = .byte,4164 .size = .byte,
4120 .disp = @intCast(tuple_ty.structFieldOffset(1, mod)),4165 .disp = dst_mcv.load_frame.off +
4166 @as(i32, @intCast(tuple_ty.structFieldOffset(1, mod))),
4121 } },4167 } },
4122 }, Immediate.u(1));4168 }, Immediate.u(1));
4123 self.performReloc(no_overflow);4169 self.performReloc(no_overflow);
...@@ -4863,6 +4909,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4863,6 +4909,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
4863 .{ ._r, .sh },4909 .{ ._r, .sh },
4864 err_union_ty,4910 err_union_ty,
4865 result,4911 result,
4912 Type.u8,
4866 .{ .immediate = @as(u6, @intCast(err_off * 8)) },4913 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
4867 ) else try self.truncateRegister(Type.anyerror, result.register);4914 ) else try self.truncateRegister(Type.anyerror, result.register);
4868 break :result result;4915 break :result result;
...@@ -5020,6 +5067,7 @@ fn genUnwrapErrUnionPayloadMir(...@@ -5020,6 +5067,7 @@ fn genUnwrapErrUnionPayloadMir(
5020 .{ ._r, .sh },5067 .{ ._r, .sh },
5021 err_union_ty,5068 err_union_ty,
5022 result_mcv,5069 result_mcv,
5070 Type.u8,
5023 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },5071 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
5024 ) else try self.truncateRegister(payload_ty, result_mcv.register);5072 ) else try self.truncateRegister(payload_ty, result_mcv.register);
5025 break :result if (payload_in_gp)5073 break :result if (payload_in_gp)
...@@ -5642,7 +5690,10 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -5642,7 +5690,10 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
5642 });5690 });
5643 }5691 }
56445692
5645 return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand});5693 return self.fail(
5694 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}",
5695 .{operand},
5696 );
5646 },5697 },
5647 .register => {5698 .register => {
5648 const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align))5699 const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align))
...@@ -5650,7 +5701,13 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -5650,7 +5701,13 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
5650 else5701 else
5651 0;5702 0;
5652 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);5703 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
5653 try self.genShiftBinOpMir(.{ ._r, .sh }, Type.usize, result, .{ .immediate = shift });5704 try self.genShiftBinOpMir(
5705 .{ ._r, .sh },
5706 Type.usize,
5707 result,
5708 Type.u8,
5709 .{ .immediate = shift },
5710 );
5654 break :blk MCValue{5711 break :blk MCValue{
5655 .register = registerAlias(result.register, @intCast(layout.tag_size)),5712 .register = registerAlias(result.register, @intCast(layout.tag_size)),
5656 };5713 };
...@@ -6199,7 +6256,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -6199,7 +6256,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
6199 if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) {6256 if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) {
6200 .signed => .{ ._r, .sa },6257 .signed => .{ ._r, .sa },
6201 .unsigned => .{ ._r, .sh },6258 .unsigned => .{ ._r, .sh },
6202 }, src_ty, dst_mcv, .{ .immediate = extra_bits });6259 }, src_ty, dst_mcv, Type.u8, .{ .immediate = extra_bits });
62036260
6204 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });6261 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
6205}6262}
...@@ -6321,7 +6378,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -6321,7 +6378,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
6321 if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) {6378 if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) {
6322 .signed => .{ ._r, .sa },6379 .signed => .{ ._r, .sa },
6323 .unsigned => .{ ._r, .sh },6380 .unsigned => .{ ._r, .sh },
6324 }, src_ty, dst_mcv, .{ .immediate = extra_bits });6381 }, src_ty, dst_mcv, Type.u8, .{ .immediate = extra_bits });
63256382
6326 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });6383 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
6327}6384}
...@@ -6710,6 +6767,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {...@@ -6710,6 +6767,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
6710 .size = .qword,6767 .size = .qword,
6711 .index = tmp_regs[0].to64(),6768 .index = tmp_regs[0].to64(),
6712 .scale = .@"8",6769 .scale = .@"8",
6770 .disp = dst_mcv.load_frame.off,
6713 } },6771 } },
6714 });6772 });
6715 try self.asmSetccRegister(.c, tmp_regs[1].to8());6773 try self.asmSetccRegister(.c, tmp_regs[1].to8());
...@@ -6719,6 +6777,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {...@@ -6719,6 +6777,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
6719 .size = .qword,6777 .size = .qword,
6720 .index = tmp_regs[0].to64(),6778 .index = tmp_regs[0].to64(),
6721 .scale = .@"8",6779 .scale = .@"8",
6780 .disp = dst_mcv.load_frame.off,
6722 } },6781 } },
6723 }, tmp_regs[2].to64());6782 }, tmp_regs[2].to64());
67246783
...@@ -7303,12 +7362,14 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In...@@ -7303,12 +7362,14 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
7303 .{ ._l, .sh },7362 .{ ._l, .sh },
7304 limb_ty,7363 limb_ty,
7305 tmp_mcv,7364 tmp_mcv,
7365 Type.u8,
7306 .{ .immediate = src_bit_off },7366 .{ .immediate = src_bit_off },
7307 ),7367 ),
7308 1 => try self.genShiftBinOpMir(7368 1 => try self.genShiftBinOpMir(
7309 .{ ._r, .sh },7369 .{ ._r, .sh },
7310 limb_ty,7370 limb_ty,
7311 tmp_mcv,7371 tmp_mcv,
7372 Type.u8,
7312 .{ .immediate = limb_abi_bits - src_bit_off },7373 .{ .immediate = limb_abi_bits - src_bit_off },
7313 ),7374 ),
7314 else => unreachable,7375 else => unreachable,
...@@ -7497,6 +7558,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7497,6 +7558,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7497 .{ ._r, .sh },7558 .{ ._r, .sh },
7498 Type.usize,7559 Type.usize,
7499 dst_mcv,7560 dst_mcv,
7561 Type.u8,
7500 .{ .immediate = field_off },7562 .{ .immediate = field_off },
7501 );7563 );
7502 }7564 }
...@@ -7540,6 +7602,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7540,6 +7602,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7540 .{ ._r, .sh },7602 .{ ._r, .sh },
7541 Type.u128,7603 Type.u128,
7542 dst_mcv,7604 dst_mcv,
7605 Type.u8,
7543 .{ .immediate = field_off },7606 .{ .immediate = field_off },
7544 );7607 );
7545 }7608 }
...@@ -7576,6 +7639,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -7576,6 +7639,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
7576 .{ ._r, .sh },7639 .{ ._r, .sh },
7577 Type.usize,7640 Type.usize,
7578 dst_mcv,7641 dst_mcv,
7642 Type.u8,
7579 .{ .immediate = field_off % 64 },7643 .{ .immediate = field_off % 64 },
7580 );7644 );
7581 }7645 }
...@@ -7890,117 +7954,350 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC...@@ -7890,117 +7954,350 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
7890fn genShiftBinOpMir(7954fn genShiftBinOpMir(
7891 self: *Self,7955 self: *Self,
7892 tag: Mir.Inst.FixedTag,7956 tag: Mir.Inst.FixedTag,
7893 ty: Type,7957 lhs_ty: Type,
7894 lhs_mcv: MCValue,7958 lhs_mcv: MCValue,
7895 shift_mcv: MCValue,7959 rhs_ty: Type,
7960 rhs_mcv: MCValue,
7896) !void {7961) !void {
7897 const mod = self.bin_file.comp.module.?;7962 const mod = self.bin_file.comp.module.?;
7898 const rhs_mcv: MCValue = rhs: {7963 const abi_size: u32 = @intCast(lhs_ty.abiSize(mod));
7899 switch (shift_mcv) {7964 const shift_abi_size: u32 = @intCast(rhs_ty.abiSize(mod));
7900 .immediate => |imm| switch (imm) {7965 try self.spillEflagsIfOccupied();
7966
7967 if (abi_size > 16) {
7968 const limbs_len = math.divCeil(u32, abi_size, 8) catch unreachable;
7969 assert(shift_abi_size >= 1 and shift_abi_size <= 2);
7970
7971 const rcx_lock: ?RegisterLock = switch (rhs_mcv) {
7972 .immediate => |shift_imm| switch (shift_imm) {
7901 0 => return,7973 0 => return,
7902 else => break :rhs shift_mcv,7974 else => null,
7903 },7975 },
7904 .register => |shift_reg| if (shift_reg == .rcx) break :rhs shift_mcv,7976 else => lock: {
7905 else => {},7977 if (switch (rhs_mcv) {
7906 }7978 .register => |rhs_reg| rhs_reg.id() != Register.rcx.id(),
7907 self.register_manager.getRegAssumeFree(.rcx, null);7979 else => true,
7908 try self.genSetReg(.cl, Type.u8, shift_mcv, .{});7980 }) {
7909 break :rhs .{ .register = .rcx };7981 self.register_manager.getRegAssumeFree(.rcx, null);
7910 };7982 try self.genSetReg(.rcx, rhs_ty, rhs_mcv, .{});
7983 }
7984 break :lock self.register_manager.lockReg(.rcx);
7985 },
7986 };
7987 defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
79117988
7912 const abi_size: u32 = @intCast(ty.abiSize(mod));7989 const temp_regs = try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp);
7913 if (abi_size <= 8) {7990 const temp_locks = self.register_manager.lockRegs(4, temp_regs);
7914 switch (lhs_mcv) {7991 defer for (temp_locks) |temp_lock| if (temp_lock) |lock| self.register_manager.unlockReg(lock);
7915 .register => |lhs_reg| switch (rhs_mcv) {7992
7916 .immediate => |rhs_imm| try self.asmRegisterImmediate(7993 switch (tag[0]) {
7917 tag,7994 ._l => {
7918 registerAlias(lhs_reg, abi_size),7995 try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), Immediate.u(limbs_len - 1));
7919 Immediate.u(rhs_imm),7996 switch (rhs_mcv) {
7920 ),7997 .immediate => |shift_imm| try self.asmRegisterImmediate(
7921 .register => |rhs_reg| try self.asmRegisterRegister(7998 .{ ._, .mov },
7922 tag,7999 temp_regs[0].to32(),
7923 registerAlias(lhs_reg, abi_size),8000 Immediate.u(limbs_len - (shift_imm >> 6) - 1),
7924 registerAlias(rhs_reg, 1),8001 ),
7925 ),8002 else => {
7926 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8003 try self.asmRegisterRegister(
7927 @tagName(lhs_mcv),8004 .{ ._, .movzx },
7928 @tagName(rhs_mcv),8005 temp_regs[2].to32(),
7929 }),8006 registerAlias(.rcx, shift_abi_size),
8007 );
8008 try self.asmRegisterImmediate(
8009 .{ ._, .@"and" },
8010 .cl,
8011 Immediate.u(std.math.maxInt(u6)),
8012 );
8013 try self.asmRegisterImmediate(
8014 .{ ._r, .sh },
8015 temp_regs[2].to32(),
8016 Immediate.u(6),
8017 );
8018 try self.asmRegisterRegister(
8019 .{ ._, .mov },
8020 temp_regs[0].to32(),
8021 temp_regs[1].to32(),
8022 );
8023 try self.asmRegisterRegister(
8024 .{ ._, .sub },
8025 temp_regs[0].to32(),
8026 temp_regs[2].to32(),
8027 );
8028 },
8029 }
7930 },8030 },
7931 .memory, .indirect, .load_frame => {8031 ._r => {
7932 const lhs_mem: Memory = switch (lhs_mcv) {8032 try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[1].to32(), temp_regs[1].to32());
7933 .memory => |addr| .{8033 switch (rhs_mcv) {
7934 .base = .{ .reg = .ds },8034 .immediate => |shift_imm| try self.asmRegisterImmediate(
7935 .mod = .{ .rm = .{8035 .{ ._, .mov },
7936 .size = Memory.Size.fromSize(abi_size),8036 temp_regs[0].to32(),
7937 .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse8037 Immediate.u(shift_imm >> 6),
7938 return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8038 ),
7939 @tagName(lhs_mcv),8039 else => {
7940 @tagName(rhs_mcv),8040 try self.asmRegisterRegister(
7941 }),8041 .{ ._, .movzx },
7942 } },8042 temp_regs[0].to32(),
8043 registerAlias(.rcx, shift_abi_size),
8044 );
8045 try self.asmRegisterImmediate(
8046 .{ ._, .@"and" },
8047 .cl,
8048 Immediate.u(std.math.maxInt(u6)),
8049 );
8050 try self.asmRegisterImmediate(
8051 .{ ._r, .sh },
8052 temp_regs[0].to32(),
8053 Immediate.u(6),
8054 );
7943 },8055 },
7944 .indirect => |reg_off| .{8056 }
7945 .base = .{ .reg = reg_off.reg },8057 },
7946 .mod = .{ .rm = .{8058 else => unreachable,
7947 .size = Memory.Size.fromSize(abi_size),8059 }
7948 .disp = reg_off.off,8060
7949 } },8061 const slow_inc_dec = self.hasFeature(.slow_incdec);
8062 if (switch (rhs_mcv) {
8063 .immediate => |shift_imm| shift_imm >> 6 < limbs_len - 1,
8064 else => true,
8065 }) {
8066 try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[2].to64(), .{
8067 .base = .{ .frame = lhs_mcv.load_frame.index },
8068 .mod = .{ .rm = .{
8069 .size = .qword,
8070 .index = temp_regs[0].to64(),
8071 .scale = .@"8",
8072 .disp = lhs_mcv.load_frame.off,
8073 } },
8074 });
8075 const skip = switch (rhs_mcv) {
8076 .immediate => undefined,
8077 else => switch (tag[0]) {
8078 ._l => try self.asmJccReloc(.z, undefined),
8079 ._r => skip: {
8080 try self.asmRegisterImmediate(
8081 .{ ._, .cmp },
8082 temp_regs[0].to32(),
8083 Immediate.u(limbs_len - 1),
8084 );
8085 break :skip try self.asmJccReloc(.nb, undefined);
7950 },8086 },
7951 .load_frame => |frame_addr| .{8087 else => unreachable,
7952 .base = .{ .frame = frame_addr.index },8088 },
7953 .mod = .{ .rm = .{8089 };
7954 .size = Memory.Size.fromSize(abi_size),8090 const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
7955 .disp = frame_addr.off,8091 try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[3].to64(), .{
7956 } },8092 .base = .{ .frame = lhs_mcv.load_frame.index },
8093 .mod = .{ .rm = .{
8094 .size = .qword,
8095 .index = temp_regs[0].to64(),
8096 .scale = .@"8",
8097 .disp = switch (tag[0]) {
8098 ._l => lhs_mcv.load_frame.off - 8,
8099 ._r => lhs_mcv.load_frame.off + 8,
8100 else => unreachable,
7957 },8101 },
8102 } },
8103 });
8104 switch (rhs_mcv) {
8105 .immediate => |shift_imm| try self.asmRegisterRegisterImmediate(
8106 .{ switch (tag[0]) {
8107 ._l => ._ld,
8108 ._r => ._rd,
8109 else => unreachable,
8110 }, .sh },
8111 temp_regs[2].to64(),
8112 temp_regs[3].to64(),
8113 Immediate.u(shift_imm & std.math.maxInt(u6)),
8114 ),
8115 else => try self.asmRegisterRegisterRegister(.{ switch (tag[0]) {
8116 ._l => ._ld,
8117 ._r => ._rd,
7958 else => unreachable,8118 else => unreachable,
7959 };8119 }, .sh }, temp_regs[2].to64(), temp_regs[3].to64(), .cl),
7960 switch (rhs_mcv) {8120 }
7961 .immediate => |rhs_imm| try self.asmMemoryImmediate(8121 try self.asmMemoryRegister(.{ ._, .mov }, .{
7962 tag,8122 .base = .{ .frame = lhs_mcv.load_frame.index },
7963 lhs_mem,8123 .mod = .{ .rm = .{
7964 Immediate.u(rhs_imm),8124 .size = .qword,
7965 ),8125 .index = temp_regs[1].to64(),
7966 .register => |rhs_reg| try self.asmMemoryRegister(8126 .scale = .@"8",
7967 tag,8127 .disp = lhs_mcv.load_frame.off,
7968 lhs_mem,8128 } },
7969 registerAlias(rhs_reg, 1),8129 }, temp_regs[2].to64());
7970 ),8130 try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[2].to64(), temp_regs[3].to64());
7971 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8131 switch (tag[0]) {
7972 @tagName(lhs_mcv),8132 ._l => {
7973 @tagName(rhs_mcv),8133 if (slow_inc_dec) {
7974 }),8134 try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1));
7975 }8135 try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[0].to32(), Immediate.u(1));
8136 } else {
8137 try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32());
8138 try self.asmRegister(.{ ._, .dec }, temp_regs[0].to32());
8139 }
8140 _ = try self.asmJccReloc(.nz, loop);
8141 },
8142 ._r => {
8143 if (slow_inc_dec) {
8144 try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), Immediate.u(1));
8145 try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1));
8146 } else {
8147 try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32());
8148 try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32());
8149 }
8150 try self.asmRegisterImmediate(
8151 .{ ._, .cmp },
8152 temp_regs[0].to32(),
8153 Immediate.u(limbs_len - 1),
8154 );
8155 _ = try self.asmJccReloc(.b, loop);
8156 },
8157 else => unreachable,
8158 }
8159 switch (rhs_mcv) {
8160 .immediate => {},
8161 else => self.performReloc(skip),
8162 }
8163 }
8164 switch (rhs_mcv) {
8165 .immediate => |shift_imm| try self.asmRegisterImmediate(
8166 tag,
8167 temp_regs[2].to64(),
8168 Immediate.u(shift_imm & std.math.maxInt(u6)),
8169 ),
8170 else => try self.asmRegisterRegister(tag, temp_regs[2].to64(), .cl),
8171 }
8172 try self.asmMemoryRegister(.{ ._, .mov }, .{
8173 .base = .{ .frame = lhs_mcv.load_frame.index },
8174 .mod = .{ .rm = .{
8175 .size = .qword,
8176 .index = temp_regs[1].to64(),
8177 .scale = .@"8",
8178 .disp = lhs_mcv.load_frame.off,
8179 } },
8180 }, temp_regs[2].to64());
8181 if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate(
8182 tag,
8183 temp_regs[2].to64(),
8184 Immediate.u(63),
8185 );
8186 if (switch (rhs_mcv) {
8187 .immediate => |shift_imm| shift_imm >> 6 > 0,
8188 else => true,
8189 }) {
8190 const skip = switch (rhs_mcv) {
8191 .immediate => undefined,
8192 else => switch (tag[0]) {
8193 ._l => skip: {
8194 try self.asmRegisterRegister(
8195 .{ ._, .@"test" },
8196 temp_regs[1].to32(),
8197 temp_regs[1].to32(),
8198 );
8199 break :skip try self.asmJccReloc(.z, undefined);
8200 },
8201 ._r => skip: {
8202 try self.asmRegisterImmediate(
8203 .{ ._, .cmp },
8204 temp_regs[1].to32(),
8205 Immediate.u(limbs_len - 1),
8206 );
8207 break :skip try self.asmJccReloc(.nb, undefined);
8208 },
8209 else => unreachable,
8210 },
8211 };
8212 const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
8213 switch (tag[0]) {
8214 ._l => if (slow_inc_dec) {
8215 try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1));
8216 } else {
8217 try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32());
8218 },
8219 ._r => if (slow_inc_dec) {
8220 try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), Immediate.u(1));
8221 } else {
8222 try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32());
8223 },
8224 else => unreachable,
8225 }
8226 if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryRegister(.{ ._, .mov }, .{
8227 .base = .{ .frame = lhs_mcv.load_frame.index },
8228 .mod = .{ .rm = .{
8229 .size = .qword,
8230 .index = temp_regs[1].to64(),
8231 .scale = .@"8",
8232 .disp = lhs_mcv.load_frame.off,
8233 } },
8234 }, temp_regs[2].to64()) else try self.asmMemoryImmediate(.{ ._, .mov }, .{
8235 .base = .{ .frame = lhs_mcv.load_frame.index },
8236 .mod = .{ .rm = .{
8237 .size = .qword,
8238 .index = temp_regs[1].to64(),
8239 .scale = .@"8",
8240 .disp = lhs_mcv.load_frame.off,
8241 } },
8242 }, Immediate.u(0));
8243 switch (tag[0]) {
8244 ._l => _ = try self.asmJccReloc(.nz, loop),
8245 ._r => {
8246 try self.asmRegisterImmediate(
8247 .{ ._, .cmp },
8248 temp_regs[1].to32(),
8249 Immediate.u(limbs_len - 1),
8250 );
8251 _ = try self.asmJccReloc(.b, loop);
8252 },
8253 else => unreachable,
8254 }
8255 switch (rhs_mcv) {
8256 .immediate => {},
8257 else => self.performReloc(skip),
8258 }
8259 }
8260 return;
8261 }
8262
8263 assert(shift_abi_size == 1);
8264 const shift_mcv: MCValue = shift: {
8265 switch (rhs_mcv) {
8266 .immediate => |shift_imm| switch (shift_imm) {
8267 0 => return,
8268 else => break :shift rhs_mcv,
7976 },8269 },
7977 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8270 .register => |rhs_reg| if (rhs_reg.id() == Register.rcx.id())
7978 @tagName(lhs_mcv),8271 break :shift rhs_mcv,
7979 @tagName(rhs_mcv),8272 else => {},
7980 }),
7981 }8273 }
7982 } else if (abi_size <= 16) {8274 self.register_manager.getRegAssumeFree(.rcx, null);
8275 try self.genSetReg(.cl, rhs_ty, rhs_mcv, .{});
8276 break :shift .{ .register = .rcx };
8277 };
8278 if (abi_size > 8) {
7983 const info: struct { indices: [2]u31, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {8279 const info: struct { indices: [2]u31, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
7984 ._l => .{ .indices = .{ 0, 1 }, .double_tag = .{ ._ld, .sh } },8280 ._l => .{ .indices = .{ 0, 1 }, .double_tag = .{ ._ld, .sh } },
7985 ._r => .{ .indices = .{ 1, 0 }, .double_tag = .{ ._rd, .sh } },8281 ._r => .{ .indices = .{ 1, 0 }, .double_tag = .{ ._rd, .sh } },
7986 else => unreachable,8282 else => unreachable,
7987 };8283 };
7988 switch (lhs_mcv) {8284 switch (lhs_mcv) {
7989 .register_pair => |lhs_regs| switch (rhs_mcv) {8285 .register_pair => |lhs_regs| switch (shift_mcv) {
7990 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {8286 .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) {
7991 try self.asmRegisterRegisterImmediate(8287 try self.asmRegisterRegisterImmediate(
7992 info.double_tag,8288 info.double_tag,
7993 lhs_regs[info.indices[1]],8289 lhs_regs[info.indices[1]],
7994 lhs_regs[info.indices[0]],8290 lhs_regs[info.indices[0]],
7995 Immediate.u(rhs_imm),8291 Immediate.u(shift_imm),
7996 );8292 );
7997 try self.asmRegisterImmediate(8293 try self.asmRegisterImmediate(
7998 tag,8294 tag,
7999 lhs_regs[info.indices[0]],8295 lhs_regs[info.indices[0]],
8000 Immediate.u(rhs_imm),8296 Immediate.u(shift_imm),
8001 );8297 );
8298 return;
8002 } else {8299 } else {
8003 assert(rhs_imm < 128);8300 assert(shift_imm < 128);
8004 try self.asmRegisterRegister(8301 try self.asmRegisterRegister(
8005 .{ ._, .mov },8302 .{ ._, .mov },
8006 lhs_regs[info.indices[1]],8303 lhs_regs[info.indices[1]],
...@@ -8015,13 +8312,14 @@ fn genShiftBinOpMir(...@@ -8015,13 +8312,14 @@ fn genShiftBinOpMir(
8015 lhs_regs[info.indices[0]],8312 lhs_regs[info.indices[0]],
8016 lhs_regs[info.indices[0]],8313 lhs_regs[info.indices[0]],
8017 );8314 );
8018 if (rhs_imm > 64) try self.asmRegisterImmediate(8315 if (shift_imm > 64) try self.asmRegisterImmediate(
8019 tag,8316 tag,
8020 lhs_regs[info.indices[1]],8317 lhs_regs[info.indices[1]],
8021 Immediate.u(rhs_imm - 64),8318 Immediate.u(shift_imm - 64),
8022 );8319 );
8320 return;
8023 },8321 },
8024 .register => |rhs_reg| {8322 .register => |shift_reg| {
8025 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);8323 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
8026 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);8324 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
8027 defer self.register_manager.unlockReg(tmp_lock);8325 defer self.register_manager.unlockReg(tmp_lock);
...@@ -8038,16 +8336,16 @@ fn genShiftBinOpMir(...@@ -8038,16 +8336,16 @@ fn genShiftBinOpMir(
8038 info.double_tag,8336 info.double_tag,
8039 lhs_regs[info.indices[1]],8337 lhs_regs[info.indices[1]],
8040 lhs_regs[info.indices[0]],8338 lhs_regs[info.indices[0]],
8041 registerAlias(rhs_reg, 1),8339 registerAlias(shift_reg, 1),
8042 );8340 );
8043 try self.asmRegisterRegister(8341 try self.asmRegisterRegister(
8044 tag,8342 tag,
8045 lhs_regs[info.indices[0]],8343 lhs_regs[info.indices[0]],
8046 registerAlias(rhs_reg, 1),8344 registerAlias(shift_reg, 1),
8047 );8345 );
8048 try self.asmRegisterImmediate(8346 try self.asmRegisterImmediate(
8049 .{ ._, .cmp },8347 .{ ._, .cmp },
8050 registerAlias(rhs_reg, 1),8348 registerAlias(shift_reg, 1),
8051 Immediate.u(64),8349 Immediate.u(64),
8052 );8350 );
8053 try self.asmCmovccRegisterRegister(8351 try self.asmCmovccRegisterRegister(
...@@ -8056,19 +8354,17 @@ fn genShiftBinOpMir(...@@ -8056,19 +8354,17 @@ fn genShiftBinOpMir(
8056 lhs_regs[info.indices[0]],8354 lhs_regs[info.indices[0]],
8057 );8355 );
8058 try self.asmCmovccRegisterRegister(.ae, lhs_regs[info.indices[0]], tmp_reg);8356 try self.asmCmovccRegisterRegister(.ae, lhs_regs[info.indices[0]], tmp_reg);
8357 return;
8059 },8358 },
8060 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8359 else => {},
8061 @tagName(lhs_mcv),
8062 @tagName(rhs_mcv),
8063 }),
8064 },8360 },
8065 .load_frame => |dst_frame_addr| {8361 .load_frame => |dst_frame_addr| {
8066 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);8362 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
8067 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);8363 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
8068 defer self.register_manager.unlockReg(tmp_lock);8364 defer self.register_manager.unlockReg(tmp_lock);
80698365
8070 switch (rhs_mcv) {8366 switch (shift_mcv) {
8071 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {8367 .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) {
8072 try self.asmRegisterMemory(8368 try self.asmRegisterMemory(
8073 .{ ._, .mov },8369 .{ ._, .mov },
8074 tmp_reg,8370 tmp_reg,
...@@ -8090,7 +8386,7 @@ fn genShiftBinOpMir(...@@ -8090,7 +8386,7 @@ fn genShiftBinOpMir(
8090 } },8386 } },
8091 },8387 },
8092 tmp_reg,8388 tmp_reg,
8093 Immediate.u(rhs_imm),8389 Immediate.u(shift_imm),
8094 );8390 );
8095 try self.asmMemoryImmediate(8391 try self.asmMemoryImmediate(
8096 tag,8392 tag,
...@@ -8101,10 +8397,11 @@ fn genShiftBinOpMir(...@@ -8101,10 +8397,11 @@ fn genShiftBinOpMir(
8101 .disp = dst_frame_addr.off + info.indices[0] * 8,8397 .disp = dst_frame_addr.off + info.indices[0] * 8,
8102 } },8398 } },
8103 },8399 },
8104 Immediate.u(rhs_imm),8400 Immediate.u(shift_imm),
8105 );8401 );
8402 return;
8106 } else {8403 } else {
8107 assert(rhs_imm < 128);8404 assert(shift_imm < 128);
8108 try self.asmRegisterMemory(8405 try self.asmRegisterMemory(
8109 .{ ._, .mov },8406 .{ ._, .mov },
8110 tmp_reg,8407 tmp_reg,
...@@ -8116,10 +8413,10 @@ fn genShiftBinOpMir(...@@ -8116,10 +8413,10 @@ fn genShiftBinOpMir(
8116 } },8413 } },
8117 },8414 },
8118 );8415 );
8119 if (rhs_imm > 64) try self.asmRegisterImmediate(8416 if (shift_imm > 64) try self.asmRegisterImmediate(
8120 tag,8417 tag,
8121 tmp_reg,8418 tmp_reg,
8122 Immediate.u(rhs_imm - 64),8419 Immediate.u(shift_imm - 64),
8123 );8420 );
8124 try self.asmMemoryRegister(8421 try self.asmMemoryRegister(
8125 .{ ._, .mov },8422 .{ ._, .mov },
...@@ -8156,8 +8453,9 @@ fn genShiftBinOpMir(...@@ -8156,8 +8453,9 @@ fn genShiftBinOpMir(
8156 tmp_reg,8453 tmp_reg,
8157 );8454 );
8158 }8455 }
8456 return;
8159 },8457 },
8160 .register => |rhs_reg| {8458 .register => |shift_reg| {
8161 const first_reg =8459 const first_reg =
8162 try self.register_manager.allocReg(null, abi.RegisterClass.gp);8460 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
8163 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);8461 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
...@@ -8202,12 +8500,12 @@ fn genShiftBinOpMir(...@@ -8202,12 +8500,12 @@ fn genShiftBinOpMir(
8202 info.double_tag,8500 info.double_tag,
8203 second_reg,8501 second_reg,
8204 first_reg,8502 first_reg,
8205 registerAlias(rhs_reg, 1),8503 registerAlias(shift_reg, 1),
8206 );8504 );
8207 try self.asmRegisterRegister(tag, first_reg, registerAlias(rhs_reg, 1));8505 try self.asmRegisterRegister(tag, first_reg, registerAlias(shift_reg, 1));
8208 try self.asmRegisterImmediate(8506 try self.asmRegisterImmediate(
8209 .{ ._, .cmp },8507 .{ ._, .cmp },
8210 registerAlias(rhs_reg, 1),8508 registerAlias(shift_reg, 1),
8211 Immediate.u(64),8509 Immediate.u(64),
8212 );8510 );
8213 try self.asmCmovccRegisterRegister(.ae, second_reg, first_reg);8511 try self.asmCmovccRegisterRegister(.ae, second_reg, first_reg);
...@@ -8234,21 +8532,75 @@ fn genShiftBinOpMir(...@@ -8234,21 +8532,75 @@ fn genShiftBinOpMir(
8234 },8532 },
8235 first_reg,8533 first_reg,
8236 );8534 );
8535 return;
8237 },8536 },
8238 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8537 else => {},
8239 @tagName(lhs_mcv),
8240 @tagName(rhs_mcv),
8241 }),
8242 }8538 }
8243 },8539 },
8244 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8540 else => {},
8245 @tagName(lhs_mcv),
8246 @tagName(rhs_mcv),
8247 }),
8248 }8541 }
8249 } else return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{8542 } else switch (lhs_mcv) {
8543 .register => |lhs_reg| switch (shift_mcv) {
8544 .immediate => |shift_imm| return self.asmRegisterImmediate(
8545 tag,
8546 registerAlias(lhs_reg, abi_size),
8547 Immediate.u(shift_imm),
8548 ),
8549 .register => |shift_reg| return self.asmRegisterRegister(
8550 tag,
8551 registerAlias(lhs_reg, abi_size),
8552 registerAlias(shift_reg, 1),
8553 ),
8554 else => {},
8555 },
8556 .memory, .indirect, .load_frame => {
8557 const lhs_mem: Memory = switch (lhs_mcv) {
8558 .memory => |addr| .{
8559 .base = .{ .reg = .ds },
8560 .mod = .{ .rm = .{
8561 .size = Memory.Size.fromSize(abi_size),
8562 .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse
8563 return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
8564 @tagName(lhs_mcv),
8565 @tagName(shift_mcv),
8566 }),
8567 } },
8568 },
8569 .indirect => |reg_off| .{
8570 .base = .{ .reg = reg_off.reg },
8571 .mod = .{ .rm = .{
8572 .size = Memory.Size.fromSize(abi_size),
8573 .disp = reg_off.off,
8574 } },
8575 },
8576 .load_frame => |frame_addr| .{
8577 .base = .{ .frame = frame_addr.index },
8578 .mod = .{ .rm = .{
8579 .size = Memory.Size.fromSize(abi_size),
8580 .disp = frame_addr.off,
8581 } },
8582 },
8583 else => unreachable,
8584 };
8585 switch (shift_mcv) {
8586 .immediate => |shift_imm| return self.asmMemoryImmediate(
8587 tag,
8588 lhs_mem,
8589 Immediate.u(shift_imm),
8590 ),
8591 .register => |shift_reg| return self.asmMemoryRegister(
8592 tag,
8593 lhs_mem,
8594 registerAlias(shift_reg, 1),
8595 ),
8596 else => {},
8597 }
8598 },
8599 else => {},
8600 }
8601 return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
8250 @tagName(lhs_mcv),8602 @tagName(lhs_mcv),
8251 @tagName(rhs_mcv),8603 @tagName(shift_mcv),
8252 });8604 });
8253}8605}
82548606
...@@ -8269,14 +8621,6 @@ fn genShiftBinOp(...@@ -8269,14 +8621,6 @@ fn genShiftBinOp(
8269 lhs_ty.fmt(mod),8621 lhs_ty.fmt(mod),
8270 });8622 });
82718623
8272 try self.spillEflagsIfOccupied();
8273
8274 const lhs_abi_size = lhs_ty.abiSize(mod);
8275 if (lhs_abi_size > 16) return self.fail("TODO implement genShiftBinOp for {}", .{
8276 lhs_ty.fmt(mod),
8277 });
8278 assert(rhs_ty.abiSize(mod) == 1);
8279
8280 try self.register_manager.getReg(.rcx, null);8624 try self.register_manager.getReg(.rcx, null);
8281 const rcx_lock = self.register_manager.lockReg(.rcx);8625 const rcx_lock = self.register_manager.lockReg(.rcx);
8282 defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);8626 defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -8314,7 +8658,7 @@ fn genShiftBinOp(...@@ -8314,7 +8658,7 @@ fn genShiftBinOp(
8314 .unsigned => .{ ._r, .sh },8658 .unsigned => .{ ._r, .sh },
8315 },8659 },
8316 else => unreachable,8660 else => unreachable,
8317 }, lhs_ty, dst_mcv, rhs_mcv);8661 }, lhs_ty, dst_mcv, rhs_ty, rhs_mcv);
8318 return dst_mcv;8662 return dst_mcv;
8319}8663}
83208664
...@@ -8446,6 +8790,7 @@ fn genMulDivBinOp(...@@ -8446,6 +8790,7 @@ fn genMulDivBinOp(
8446 .size = .qword,8790 .size = .qword,
8447 .index = temp_regs[0].to64(),8791 .index = temp_regs[0].to64(),
8448 .scale = .@"8",8792 .scale = .@"8",
8793 .disp = rhs_mcv.load_frame.off,
8449 } },8794 } },
8450 });8795 });
8451 try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64());8796 try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64());
...@@ -8464,6 +8809,7 @@ fn genMulDivBinOp(...@@ -8464,6 +8809,7 @@ fn genMulDivBinOp(
8464 .size = .qword,8809 .size = .qword,
8465 .index = temp_regs[3].to64(),8810 .index = temp_regs[3].to64(),
8466 .scale = .@"8",8811 .scale = .@"8",
8812 .disp = dst_mcv.load_frame.off,
8467 } },8813 } },
8468 }, .rdx);8814 }, .rdx);
8469 try self.asmSetccRegister(.c, .cl);8815 try self.asmSetccRegister(.c, .cl);
...@@ -8474,6 +8820,7 @@ fn genMulDivBinOp(...@@ -8474,6 +8820,7 @@ fn genMulDivBinOp(
8474 .size = .qword,8820 .size = .qword,
8475 .index = temp_regs[2].to64(),8821 .index = temp_regs[2].to64(),
8476 .scale = .@"8",8822 .scale = .@"8",
8823 .disp = lhs_mcv.load_frame.off,
8477 } },8824 } },
8478 });8825 });
8479 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());8826 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());
...@@ -8485,6 +8832,7 @@ fn genMulDivBinOp(...@@ -8485,6 +8832,7 @@ fn genMulDivBinOp(
8485 .size = .qword,8832 .size = .qword,
8486 .index = temp_regs[3].to64(),8833 .index = temp_regs[3].to64(),
8487 .scale = .@"8",8834 .scale = .@"8",
8835 .disp = dst_mcv.load_frame.off,
8488 } },8836 } },
8489 }, .rax);8837 }, .rax);
8490 try self.asmSetccRegister(.c, .ch);8838 try self.asmSetccRegister(.c, .ch);
...@@ -8757,6 +9105,7 @@ fn genBinOp(...@@ -8757,6 +9105,7 @@ fn genBinOp(
8757 .div_float,9105 .div_float,
8758 .div_trunc,9106 .div_trunc,
8759 .div_floor,9107 .div_floor,
9108 .div_exact,
8760 => std.fmt.bufPrint(&callee_buf, "__{s}{c}f3", .{9109 => std.fmt.bufPrint(&callee_buf, "__{s}{c}f3", .{
8761 @tagName(air_tag)[0..3],9110 @tagName(air_tag)[0..3],
8762 floatCompilerRtAbiName(float_bits),9111 floatCompilerRtAbiName(float_bits),
...@@ -8910,7 +9259,7 @@ fn genBinOp(...@@ -8910,7 +9259,7 @@ fn genBinOp(
8910 else => false,9259 else => false,
8911 .Float => true,9260 .Float => true,
8912 .Vector => switch (lhs_ty.childType(mod).toIntern()) {9261 .Vector => switch (lhs_ty.childType(mod).toIntern()) {
8913 .bool_type => false,9262 .bool_type, .u1_type => false,
8914 else => true,9263 else => true,
8915 },9264 },
8916 };9265 };
...@@ -12443,6 +12792,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)...@@ -12443,6 +12792,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)
12443 .{ ._r, .sh },12792 .{ ._r, .sh },
12444 eu_ty,12793 eu_ty,
12445 .{ .register = tmp_reg },12794 .{ .register = tmp_reg },
12795 Type.u8,
12446 .{ .immediate = @as(u6, @intCast(err_off * 8)) },12796 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
12447 );12797 );
12448 } else {12798 } else {
...@@ -16174,6 +16524,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -16174,6 +16524,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
16174 .{ ._l, .sh },16524 .{ ._l, .sh },
16175 elem_ty,16525 elem_ty,
16176 .{ .register = elem_reg },16526 .{ .register = elem_reg },
16527 Type.u8,
16177 .{ .immediate = elem_bit_off },16528 .{ .immediate = elem_bit_off },
16178 );16529 );
16179 try self.genBinOpMir(16530 try self.genBinOpMir(
...@@ -16191,6 +16542,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -16191,6 +16542,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
16191 .{ ._r, .sh },16542 .{ ._r, .sh },
16192 elem_ty,16543 elem_ty,
16193 .{ .register = reg },16544 .{ .register = reg },
16545 Type.u8,
16194 .{ .immediate = elem_abi_bits - elem_bit_off },16546 .{ .immediate = elem_abi_bits - elem_bit_off },
16195 );16547 );
16196 try self.genBinOpMir(16548 try self.genBinOpMir(
...@@ -17294,12 +17646,14 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {...@@ -17294,12 +17646,14 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
17294 .{ ._l, .sa },17646 .{ ._l, .sa },
17295 Type.isize,17647 Type.isize,
17296 .{ .register = reg },17648 .{ .register = reg },
17649 Type.u8,
17297 .{ .immediate = shift },17650 .{ .immediate = shift },
17298 );17651 );
17299 try self.genShiftBinOpMir(17652 try self.genShiftBinOpMir(
17300 .{ ._r, .sa },17653 .{ ._r, .sa },
17301 Type.isize,17654 Type.isize,
17302 .{ .register = reg },17655 .{ .register = reg },
17656 Type.u8,
17303 .{ .immediate = shift },17657 .{ .immediate = shift },
17304 );17658 );
17305 },17659 },