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 {
9090
9191test "xoroshiro sequence" {
9292 if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest;
93 if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
9493
9594 var r = Xoshiro256.init(0);
9695
lib/std/crypto/aes_ocb.zig-4
......@@ -262,7 +262,6 @@ const hexToBytes = std.fmt.hexToBytes;
262262
263263test "AesOcb test vector 1" {
264264 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
265 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
266265
267266 var k: [Aes128Ocb.key_length]u8 = undefined;
268267 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
......@@ -282,7 +281,6 @@ test "AesOcb test vector 1" {
282281
283282test "AesOcb test vector 2" {
284283 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
285 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
286284
287285 var k: [Aes128Ocb.key_length]u8 = undefined;
288286 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
......@@ -304,7 +302,6 @@ test "AesOcb test vector 2" {
304302
305303test "AesOcb test vector 3" {
306304 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
307 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
308305
309306 var k: [Aes128Ocb.key_length]u8 = undefined;
310307 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
......@@ -329,7 +326,6 @@ test "AesOcb test vector 3" {
329326
330327test "AesOcb test vector 4" {
331328 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
332 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
333329
334330 var k: [Aes128Ocb.key_length]u8 = undefined;
335331 var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
lib/std/crypto/ff.zig+1-2
......@@ -907,9 +907,8 @@ const ct_unprotected = struct {
907907 }
908908};
909909
910test {
910test "finite field arithmetic" {
911911 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
912 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
913912
914913 const M = Modulus(256);
915914 const m = try M.fromPrimitive(u256, 3429938563481314093726330772853735541133072814650493833233);
lib/std/crypto/pcurves/p384.zig-1
......@@ -479,7 +479,6 @@ pub const AffineCoordinates = struct {
479479
480480test {
481481 if (@import("builtin").zig_backend == .stage2_c) return error.SkipZigTest;
482 if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
483482
484483 _ = @import("tests/p384.zig");
485484}
lib/std/math/big/int_test.zig-3
......@@ -1698,7 +1698,6 @@ test "big.int div multi-multi (2 branch)" {
16981698
16991699test "big.int div multi-multi (3.1/3.3 branch)" {
17001700 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1701 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
17021701
17031702 var a = try Managed.initSet(testing.allocator, 0x11111111111111111111111111111111111111111111111111111111111111);
17041703 defer a.deinit();
......@@ -2187,7 +2186,6 @@ test "big.int bitNotWrap more than two limbs" {
21872186 // This test requires int sizes greater than 128 bits.
21882187 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
21892188 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2190 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
21912189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21922190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21932191 // LLVM: unexpected runtime library name: __umodei4
......@@ -2537,7 +2535,6 @@ test "big.int gcd non-one large" {
25372535
25382536test "big.int gcd large multi-limb result" {
25392537 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2540 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
25412538
25422539 var a = try Managed.initSet(testing.allocator, 0x12345678123456781234567812345678123456781234567812345678);
25432540 defer a.deinit();
lib/std/math/log10.zig+19-65
......@@ -1,10 +1,6 @@
11const std = @import("../std.zig");
22const builtin = @import("builtin");
3const math = std.math;
43const testing = std.testing;
5const maxInt = std.math.maxInt;
6const assert = std.debug.assert;
7const Log2Int = std.math.Log2Int;
84
95/// Returns the base-10 logarithm of x.
106///
......@@ -38,13 +34,13 @@ pub fn log10(x: anytype) @TypeOf(x) {
3834
3935/// Return the log base 10 of integer value x, rounding down to the
4036/// nearest integer.
41pub fn log10_int(x: anytype) Log2Int(@TypeOf(x)) {
37pub fn log10_int(x: anytype) std.math.Log2Int(@TypeOf(x)) {
4238 const T = @TypeOf(x);
43 const OutT = Log2Int(T);
39 const OutT = std.math.Log2Int(T);
4440 if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)
4541 @compileError("log10_int requires an unsigned integer, found " ++ @typeName(T));
4642
47 assert(x != 0);
43 std.debug.assert(x != 0);
4844
4945 const bit_size = @typeInfo(T).Int.bits;
5046
......@@ -133,18 +129,7 @@ inline fn less_than_5(x: u32) u32 {
133129 return (((x + C1) & (x + C2)) ^ ((x + C3) & (x + C4))) >> 17;
134130}
135131
136fn oldlog10(x: anytype) u8 {
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" {
132test log10_int {
148133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
149134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
150135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -152,53 +137,22 @@ test "log10_int vs old implementation" {
152137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
153138 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 };
156
157 inline for (int_types) |T| {
158 const last = @min(maxInt(T), 100_000);
159 for (1..last) |i| {
160 const x = @as(T, @intCast(i));
161 try testing.expectEqual(oldlog10(x), log10_int(x));
162 }
163
164 const max_int: T = maxInt(T);
165 try testing.expectEqual(oldlog10(max_int), log10_int(max_int));
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));
140 inline for (
141 .{ u8, u16, u32, u64, u128, u256, u512 },
142 .{ 2, 4, 9, 19, 38, 77, 154 },
143 ) |T, max_exponent| {
144 for (0..max_exponent + 1) |exponent_usize| {
145 const exponent: std.math.Log2Int(T) = @intCast(exponent_usize);
146 const power_of_ten = try std.math.powi(T, 10, exponent);
147
148 if (exponent > 0) {
149 try testing.expectEqual(exponent - 1, log10_int(power_of_ten - 9));
150 try testing.expectEqual(exponent - 1, log10_int(power_of_ten - 1));
201151 }
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));
202155 }
156 try testing.expectEqual(max_exponent, log10_int(@as(T, std.math.maxInt(T))));
203157 }
204158}
src/arch/x86_64/CodeGen.zig+496-142
......@@ -2986,6 +2986,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
29862986 .{ ._r, .sa },
29872987 Type.isize,
29882988 extend_mcv,
2989 Type.u8,
29892990 .{ .immediate = 63 },
29902991 );
29912992 break :extend extend_mcv;
......@@ -3500,10 +3501,22 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
35003501 const reg_extra_bits = self.regExtraBits(ty);
35013502 const cc: Condition = if (ty.isSignedInt(mod)) cc: {
35023503 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 );
35043511 }
35053512 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 );
35073520 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
35083521 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
35093522 });
......@@ -3517,6 +3530,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
35173530 .{ ._l, .sa },
35183531 ty,
35193532 shifted_rhs_mcv,
3533 Type.u8,
35203534 .{ .immediate = reg_extra_bits },
35213535 );
35223536 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv);
......@@ -3542,9 +3556,13 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
35423556 registerAlias(limit_reg, cmov_abi_size),
35433557 );
35443558
3545 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) {
3546 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
3547 }
3559 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) try self.genShiftBinOpMir(
3560 .{ ._r, .sa },
3561 ty,
3562 dst_mcv,
3563 Type.u8,
3564 .{ .immediate = reg_extra_bits },
3565 );
35483566
35493567 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
35503568}
......@@ -3583,10 +3601,22 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
35833601 const reg_extra_bits = self.regExtraBits(ty);
35843602 const cc: Condition = if (ty.isSignedInt(mod)) cc: {
35853603 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 );
35873611 }
35883612 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 );
35903620 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
35913621 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
35923622 });
......@@ -3600,6 +3630,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
36003630 .{ ._l, .sa },
36013631 ty,
36023632 shifted_rhs_mcv,
3633 Type.u8,
36033634 .{ .immediate = reg_extra_bits },
36043635 );
36053636 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv);
......@@ -3618,9 +3649,13 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
36183649 registerAlias(limit_reg, cmov_abi_size),
36193650 );
36203651
3621 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) {
3622 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
3623 }
3652 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) try self.genShiftBinOpMir(
3653 .{ ._r, .sa },
3654 ty,
3655 dst_mcv,
3656 Type.u8,
3657 .{ .immediate = reg_extra_bits },
3658 );
36243659
36253660 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
36263661}
......@@ -3741,7 +3776,13 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
37413776 const cc: Condition = if (ty.isSignedInt(mod)) cc: {
37423777 try self.genSetReg(limit_reg, ty, lhs_mcv, .{});
37433778 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 );
37453786 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
37463787 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
37473788 });
......@@ -4029,6 +4070,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
40294070 .size = .qword,
40304071 .index = temp_regs[0].to64(),
40314072 .scale = .@"8",
4073 .disp = rhs_mcv.load_frame.off,
40324074 } },
40334075 });
40344076 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 {
40474089 .size = .qword,
40484090 .index = temp_regs[3].to64(),
40494091 .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))),
40514094 } },
40524095 }, .rdx);
40534096 try self.asmSetccRegister(.c, .cl);
......@@ -4058,6 +4101,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
40584101 .size = .qword,
40594102 .index = temp_regs[2].to64(),
40604103 .scale = .@"8",
4104 .disp = lhs_mcv.load_frame.off,
40614105 } },
40624106 });
40634107 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());
......@@ -4069,7 +4113,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
40694113 .size = .qword,
40704114 .index = temp_regs[3].to64(),
40714115 .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))),
40734118 } },
40744119 }, .rax);
40754120 try self.asmSetccRegister(.c, .ch);
......@@ -4108,7 +4153,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
41084153 .size = .qword,
41094154 .index = temp_regs[2].to64(),
41104155 .scale = .@"8",
4111 .disp = -8,
4156 .disp = lhs_mcv.load_frame.off - 8,
41124157 } },
41134158 }, Immediate.u(0));
41144159 _ = try self.asmJccReloc(.z, overflow_loop);
......@@ -4117,7 +4162,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
41174162 .base = .{ .frame = dst_mcv.load_frame.index },
41184163 .mod = .{ .rm = .{
41194164 .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))),
41214167 } },
41224168 }, Immediate.u(1));
41234169 self.performReloc(no_overflow);
......@@ -4863,6 +4909,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
48634909 .{ ._r, .sh },
48644910 err_union_ty,
48654911 result,
4912 Type.u8,
48664913 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
48674914 ) else try self.truncateRegister(Type.anyerror, result.register);
48684915 break :result result;
......@@ -5020,6 +5067,7 @@ fn genUnwrapErrUnionPayloadMir(
50205067 .{ ._r, .sh },
50215068 err_union_ty,
50225069 result_mcv,
5070 Type.u8,
50235071 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
50245072 ) else try self.truncateRegister(payload_ty, result_mcv.register);
50255073 break :result if (payload_in_gp)
......@@ -5642,7 +5690,10 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
56425690 });
56435691 }
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 );
56465697 },
56475698 .register => {
56485699 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 {
56505701 else
56515702 0;
56525703 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 );
56545711 break :blk MCValue{
56555712 .register = registerAlias(result.register, @intCast(layout.tag_size)),
56565713 };
......@@ -6199,7 +6256,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
61996256 if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) {
62006257 .signed => .{ ._r, .sa },
62016258 .unsigned => .{ ._r, .sh },
6202 }, src_ty, dst_mcv, .{ .immediate = extra_bits });
6259 }, src_ty, dst_mcv, Type.u8, .{ .immediate = extra_bits });
62036260
62046261 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
62056262}
......@@ -6321,7 +6378,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
63216378 if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) {
63226379 .signed => .{ ._r, .sa },
63236380 .unsigned => .{ ._r, .sh },
6324 }, src_ty, dst_mcv, .{ .immediate = extra_bits });
6381 }, src_ty, dst_mcv, Type.u8, .{ .immediate = extra_bits });
63256382
63266383 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
63276384}
......@@ -6710,6 +6767,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
67106767 .size = .qword,
67116768 .index = tmp_regs[0].to64(),
67126769 .scale = .@"8",
6770 .disp = dst_mcv.load_frame.off,
67136771 } },
67146772 });
67156773 try self.asmSetccRegister(.c, tmp_regs[1].to8());
......@@ -6719,6 +6777,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
67196777 .size = .qword,
67206778 .index = tmp_regs[0].to64(),
67216779 .scale = .@"8",
6780 .disp = dst_mcv.load_frame.off,
67226781 } },
67236782 }, tmp_regs[2].to64());
67246783
......@@ -7303,12 +7362,14 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In
73037362 .{ ._l, .sh },
73047363 limb_ty,
73057364 tmp_mcv,
7365 Type.u8,
73067366 .{ .immediate = src_bit_off },
73077367 ),
73087368 1 => try self.genShiftBinOpMir(
73097369 .{ ._r, .sh },
73107370 limb_ty,
73117371 tmp_mcv,
7372 Type.u8,
73127373 .{ .immediate = limb_abi_bits - src_bit_off },
73137374 ),
73147375 else => unreachable,
......@@ -7497,6 +7558,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
74977558 .{ ._r, .sh },
74987559 Type.usize,
74997560 dst_mcv,
7561 Type.u8,
75007562 .{ .immediate = field_off },
75017563 );
75027564 }
......@@ -7540,6 +7602,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
75407602 .{ ._r, .sh },
75417603 Type.u128,
75427604 dst_mcv,
7605 Type.u8,
75437606 .{ .immediate = field_off },
75447607 );
75457608 }
......@@ -7576,6 +7639,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
75767639 .{ ._r, .sh },
75777640 Type.usize,
75787641 dst_mcv,
7642 Type.u8,
75797643 .{ .immediate = field_off % 64 },
75807644 );
75817645 }
......@@ -7890,117 +7954,350 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
78907954fn genShiftBinOpMir(
78917955 self: *Self,
78927956 tag: Mir.Inst.FixedTag,
7893 ty: Type,
7957 lhs_ty: Type,
78947958 lhs_mcv: MCValue,
7895 shift_mcv: MCValue,
7959 rhs_ty: Type,
7960 rhs_mcv: MCValue,
78967961) !void {
78977962 const mod = self.bin_file.comp.module.?;
7898 const rhs_mcv: MCValue = rhs: {
7899 switch (shift_mcv) {
7900 .immediate => |imm| switch (imm) {
7963 const abi_size: u32 = @intCast(lhs_ty.abiSize(mod));
7964 const shift_abi_size: u32 = @intCast(rhs_ty.abiSize(mod));
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) {
79017973 0 => return,
7902 else => break :rhs shift_mcv,
7974 else => null,
79037975 },
7904 .register => |shift_reg| if (shift_reg == .rcx) break :rhs shift_mcv,
7905 else => {},
7906 }
7907 self.register_manager.getRegAssumeFree(.rcx, null);
7908 try self.genSetReg(.cl, Type.u8, shift_mcv, .{});
7909 break :rhs .{ .register = .rcx };
7910 };
7976 else => lock: {
7977 if (switch (rhs_mcv) {
7978 .register => |rhs_reg| rhs_reg.id() != Register.rcx.id(),
7979 else => true,
7980 }) {
7981 self.register_manager.getRegAssumeFree(.rcx, null);
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));
7913 if (abi_size <= 8) {
7914 switch (lhs_mcv) {
7915 .register => |lhs_reg| switch (rhs_mcv) {
7916 .immediate => |rhs_imm| try self.asmRegisterImmediate(
7917 tag,
7918 registerAlias(lhs_reg, abi_size),
7919 Immediate.u(rhs_imm),
7920 ),
7921 .register => |rhs_reg| try self.asmRegisterRegister(
7922 tag,
7923 registerAlias(lhs_reg, abi_size),
7924 registerAlias(rhs_reg, 1),
7925 ),
7926 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
7927 @tagName(lhs_mcv),
7928 @tagName(rhs_mcv),
7929 }),
7989 const temp_regs = try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp);
7990 const temp_locks = self.register_manager.lockRegs(4, temp_regs);
7991 defer for (temp_locks) |temp_lock| if (temp_lock) |lock| self.register_manager.unlockReg(lock);
7992
7993 switch (tag[0]) {
7994 ._l => {
7995 try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), Immediate.u(limbs_len - 1));
7996 switch (rhs_mcv) {
7997 .immediate => |shift_imm| try self.asmRegisterImmediate(
7998 .{ ._, .mov },
7999 temp_regs[0].to32(),
8000 Immediate.u(limbs_len - (shift_imm >> 6) - 1),
8001 ),
8002 else => {
8003 try self.asmRegisterRegister(
8004 .{ ._, .movzx },
8005 temp_regs[2].to32(),
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 }
79308030 },
7931 .memory, .indirect, .load_frame => {
7932 const lhs_mem: Memory = switch (lhs_mcv) {
7933 .memory => |addr| .{
7934 .base = .{ .reg = .ds },
7935 .mod = .{ .rm = .{
7936 .size = Memory.Size.fromSize(abi_size),
7937 .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse
7938 return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
7939 @tagName(lhs_mcv),
7940 @tagName(rhs_mcv),
7941 }),
7942 } },
8031 ._r => {
8032 try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[1].to32(), temp_regs[1].to32());
8033 switch (rhs_mcv) {
8034 .immediate => |shift_imm| try self.asmRegisterImmediate(
8035 .{ ._, .mov },
8036 temp_regs[0].to32(),
8037 Immediate.u(shift_imm >> 6),
8038 ),
8039 else => {
8040 try self.asmRegisterRegister(
8041 .{ ._, .movzx },
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 );
79438055 },
7944 .indirect => |reg_off| .{
7945 .base = .{ .reg = reg_off.reg },
7946 .mod = .{ .rm = .{
7947 .size = Memory.Size.fromSize(abi_size),
7948 .disp = reg_off.off,
7949 } },
8056 }
8057 },
8058 else => unreachable,
8059 }
8060
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);
79508086 },
7951 .load_frame => |frame_addr| .{
7952 .base = .{ .frame = frame_addr.index },
7953 .mod = .{ .rm = .{
7954 .size = Memory.Size.fromSize(abi_size),
7955 .disp = frame_addr.off,
7956 } },
8087 else => unreachable,
8088 },
8089 };
8090 const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
8091 try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[3].to64(), .{
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,
79578101 },
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,
79588118 else => unreachable,
7959 };
7960 switch (rhs_mcv) {
7961 .immediate => |rhs_imm| try self.asmMemoryImmediate(
7962 tag,
7963 lhs_mem,
7964 Immediate.u(rhs_imm),
7965 ),
7966 .register => |rhs_reg| try self.asmMemoryRegister(
7967 tag,
7968 lhs_mem,
7969 registerAlias(rhs_reg, 1),
7970 ),
7971 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
7972 @tagName(lhs_mcv),
7973 @tagName(rhs_mcv),
7974 }),
7975 }
8119 }, .sh }, temp_regs[2].to64(), temp_regs[3].to64(), .cl),
8120 }
8121 try self.asmMemoryRegister(.{ ._, .mov }, .{
8122 .base = .{ .frame = lhs_mcv.load_frame.index },
8123 .mod = .{ .rm = .{
8124 .size = .qword,
8125 .index = temp_regs[1].to64(),
8126 .scale = .@"8",
8127 .disp = lhs_mcv.load_frame.off,
8128 } },
8129 }, temp_regs[2].to64());
8130 try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[2].to64(), temp_regs[3].to64());
8131 switch (tag[0]) {
8132 ._l => {
8133 if (slow_inc_dec) {
8134 try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1));
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,
79768269 },
7977 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
7978 @tagName(lhs_mcv),
7979 @tagName(rhs_mcv),
7980 }),
8270 .register => |rhs_reg| if (rhs_reg.id() == Register.rcx.id())
8271 break :shift rhs_mcv,
8272 else => {},
79818273 }
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) {
79838279 const info: struct { indices: [2]u31, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
79848280 ._l => .{ .indices = .{ 0, 1 }, .double_tag = .{ ._ld, .sh } },
79858281 ._r => .{ .indices = .{ 1, 0 }, .double_tag = .{ ._rd, .sh } },
79868282 else => unreachable,
79878283 };
79888284 switch (lhs_mcv) {
7989 .register_pair => |lhs_regs| switch (rhs_mcv) {
7990 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {
8285 .register_pair => |lhs_regs| switch (shift_mcv) {
8286 .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) {
79918287 try self.asmRegisterRegisterImmediate(
79928288 info.double_tag,
79938289 lhs_regs[info.indices[1]],
79948290 lhs_regs[info.indices[0]],
7995 Immediate.u(rhs_imm),
8291 Immediate.u(shift_imm),
79968292 );
79978293 try self.asmRegisterImmediate(
79988294 tag,
79998295 lhs_regs[info.indices[0]],
8000 Immediate.u(rhs_imm),
8296 Immediate.u(shift_imm),
80018297 );
8298 return;
80028299 } else {
8003 assert(rhs_imm < 128);
8300 assert(shift_imm < 128);
80048301 try self.asmRegisterRegister(
80058302 .{ ._, .mov },
80068303 lhs_regs[info.indices[1]],
......@@ -8015,13 +8312,14 @@ fn genShiftBinOpMir(
80158312 lhs_regs[info.indices[0]],
80168313 lhs_regs[info.indices[0]],
80178314 );
8018 if (rhs_imm > 64) try self.asmRegisterImmediate(
8315 if (shift_imm > 64) try self.asmRegisterImmediate(
80198316 tag,
80208317 lhs_regs[info.indices[1]],
8021 Immediate.u(rhs_imm - 64),
8318 Immediate.u(shift_imm - 64),
80228319 );
8320 return;
80238321 },
8024 .register => |rhs_reg| {
8322 .register => |shift_reg| {
80258323 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
80268324 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
80278325 defer self.register_manager.unlockReg(tmp_lock);
......@@ -8038,16 +8336,16 @@ fn genShiftBinOpMir(
80388336 info.double_tag,
80398337 lhs_regs[info.indices[1]],
80408338 lhs_regs[info.indices[0]],
8041 registerAlias(rhs_reg, 1),
8339 registerAlias(shift_reg, 1),
80428340 );
80438341 try self.asmRegisterRegister(
80448342 tag,
80458343 lhs_regs[info.indices[0]],
8046 registerAlias(rhs_reg, 1),
8344 registerAlias(shift_reg, 1),
80478345 );
80488346 try self.asmRegisterImmediate(
80498347 .{ ._, .cmp },
8050 registerAlias(rhs_reg, 1),
8348 registerAlias(shift_reg, 1),
80518349 Immediate.u(64),
80528350 );
80538351 try self.asmCmovccRegisterRegister(
......@@ -8056,19 +8354,17 @@ fn genShiftBinOpMir(
80568354 lhs_regs[info.indices[0]],
80578355 );
80588356 try self.asmCmovccRegisterRegister(.ae, lhs_regs[info.indices[0]], tmp_reg);
8357 return;
80598358 },
8060 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
8061 @tagName(lhs_mcv),
8062 @tagName(rhs_mcv),
8063 }),
8359 else => {},
80648360 },
80658361 .load_frame => |dst_frame_addr| {
80668362 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
80678363 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
80688364 defer self.register_manager.unlockReg(tmp_lock);
80698365
8070 switch (rhs_mcv) {
8071 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {
8366 switch (shift_mcv) {
8367 .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) {
80728368 try self.asmRegisterMemory(
80738369 .{ ._, .mov },
80748370 tmp_reg,
......@@ -8090,7 +8386,7 @@ fn genShiftBinOpMir(
80908386 } },
80918387 },
80928388 tmp_reg,
8093 Immediate.u(rhs_imm),
8389 Immediate.u(shift_imm),
80948390 );
80958391 try self.asmMemoryImmediate(
80968392 tag,
......@@ -8101,10 +8397,11 @@ fn genShiftBinOpMir(
81018397 .disp = dst_frame_addr.off + info.indices[0] * 8,
81028398 } },
81038399 },
8104 Immediate.u(rhs_imm),
8400 Immediate.u(shift_imm),
81058401 );
8402 return;
81068403 } else {
8107 assert(rhs_imm < 128);
8404 assert(shift_imm < 128);
81088405 try self.asmRegisterMemory(
81098406 .{ ._, .mov },
81108407 tmp_reg,
......@@ -8116,10 +8413,10 @@ fn genShiftBinOpMir(
81168413 } },
81178414 },
81188415 );
8119 if (rhs_imm > 64) try self.asmRegisterImmediate(
8416 if (shift_imm > 64) try self.asmRegisterImmediate(
81208417 tag,
81218418 tmp_reg,
8122 Immediate.u(rhs_imm - 64),
8419 Immediate.u(shift_imm - 64),
81238420 );
81248421 try self.asmMemoryRegister(
81258422 .{ ._, .mov },
......@@ -8156,8 +8453,9 @@ fn genShiftBinOpMir(
81568453 tmp_reg,
81578454 );
81588455 }
8456 return;
81598457 },
8160 .register => |rhs_reg| {
8458 .register => |shift_reg| {
81618459 const first_reg =
81628460 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
81638461 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
......@@ -8202,12 +8500,12 @@ fn genShiftBinOpMir(
82028500 info.double_tag,
82038501 second_reg,
82048502 first_reg,
8205 registerAlias(rhs_reg, 1),
8503 registerAlias(shift_reg, 1),
82068504 );
8207 try self.asmRegisterRegister(tag, first_reg, registerAlias(rhs_reg, 1));
8505 try self.asmRegisterRegister(tag, first_reg, registerAlias(shift_reg, 1));
82088506 try self.asmRegisterImmediate(
82098507 .{ ._, .cmp },
8210 registerAlias(rhs_reg, 1),
8508 registerAlias(shift_reg, 1),
82118509 Immediate.u(64),
82128510 );
82138511 try self.asmCmovccRegisterRegister(.ae, second_reg, first_reg);
......@@ -8234,21 +8532,75 @@ fn genShiftBinOpMir(
82348532 },
82358533 first_reg,
82368534 );
8535 return;
82378536 },
8238 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
8239 @tagName(lhs_mcv),
8240 @tagName(rhs_mcv),
8241 }),
8537 else => {},
82428538 }
82438539 },
8244 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
8245 @tagName(lhs_mcv),
8246 @tagName(rhs_mcv),
8247 }),
8540 else => {},
82488541 }
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}", .{
82508602 @tagName(lhs_mcv),
8251 @tagName(rhs_mcv),
8603 @tagName(shift_mcv),
82528604 });
82538605}
82548606
......@@ -8269,14 +8621,6 @@ fn genShiftBinOp(
82698621 lhs_ty.fmt(mod),
82708622 });
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
82808624 try self.register_manager.getReg(.rcx, null);
82818625 const rcx_lock = self.register_manager.lockReg(.rcx);
82828626 defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
......@@ -8314,7 +8658,7 @@ fn genShiftBinOp(
83148658 .unsigned => .{ ._r, .sh },
83158659 },
83168660 else => unreachable,
8317 }, lhs_ty, dst_mcv, rhs_mcv);
8661 }, lhs_ty, dst_mcv, rhs_ty, rhs_mcv);
83188662 return dst_mcv;
83198663}
83208664
......@@ -8446,6 +8790,7 @@ fn genMulDivBinOp(
84468790 .size = .qword,
84478791 .index = temp_regs[0].to64(),
84488792 .scale = .@"8",
8793 .disp = rhs_mcv.load_frame.off,
84498794 } },
84508795 });
84518796 try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64());
......@@ -8464,6 +8809,7 @@ fn genMulDivBinOp(
84648809 .size = .qword,
84658810 .index = temp_regs[3].to64(),
84668811 .scale = .@"8",
8812 .disp = dst_mcv.load_frame.off,
84678813 } },
84688814 }, .rdx);
84698815 try self.asmSetccRegister(.c, .cl);
......@@ -8474,6 +8820,7 @@ fn genMulDivBinOp(
84748820 .size = .qword,
84758821 .index = temp_regs[2].to64(),
84768822 .scale = .@"8",
8823 .disp = lhs_mcv.load_frame.off,
84778824 } },
84788825 });
84798826 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());
......@@ -8485,6 +8832,7 @@ fn genMulDivBinOp(
84858832 .size = .qword,
84868833 .index = temp_regs[3].to64(),
84878834 .scale = .@"8",
8835 .disp = dst_mcv.load_frame.off,
84888836 } },
84898837 }, .rax);
84908838 try self.asmSetccRegister(.c, .ch);
......@@ -8757,6 +9105,7 @@ fn genBinOp(
87579105 .div_float,
87589106 .div_trunc,
87599107 .div_floor,
9108 .div_exact,
87609109 => std.fmt.bufPrint(&callee_buf, "__{s}{c}f3", .{
87619110 @tagName(air_tag)[0..3],
87629111 floatCompilerRtAbiName(float_bits),
......@@ -8910,7 +9259,7 @@ fn genBinOp(
89109259 else => false,
89119260 .Float => true,
89129261 .Vector => switch (lhs_ty.childType(mod).toIntern()) {
8913 .bool_type => false,
9262 .bool_type, .u1_type => false,
89149263 else => true,
89159264 },
89169265 };
......@@ -12443,6 +12792,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)
1244312792 .{ ._r, .sh },
1244412793 eu_ty,
1244512794 .{ .register = tmp_reg },
12795 Type.u8,
1244612796 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
1244712797 );
1244812798 } else {
......@@ -16174,6 +16524,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1617416524 .{ ._l, .sh },
1617516525 elem_ty,
1617616526 .{ .register = elem_reg },
16527 Type.u8,
1617716528 .{ .immediate = elem_bit_off },
1617816529 );
1617916530 try self.genBinOpMir(
......@@ -16191,6 +16542,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1619116542 .{ ._r, .sh },
1619216543 elem_ty,
1619316544 .{ .register = reg },
16545 Type.u8,
1619416546 .{ .immediate = elem_abi_bits - elem_bit_off },
1619516547 );
1619616548 try self.genBinOpMir(
......@@ -17294,12 +17646,14 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
1729417646 .{ ._l, .sa },
1729517647 Type.isize,
1729617648 .{ .register = reg },
17649 Type.u8,
1729717650 .{ .immediate = shift },
1729817651 );
1729917652 try self.genShiftBinOpMir(
1730017653 .{ ._r, .sa },
1730117654 Type.isize,
1730217655 .{ .register = reg },
17656 Type.u8,
1730317657 .{ .immediate = shift },
1730417658 );
1730517659 },