authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 19:34:20+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 19:34:20+02:00
logf131e41db9f8b1b1bbd678b52ef377821d83bddc
treecea3ed7aabb22c3decdc7934fa1019b5799b3e92
parent9725205859517ce81e201b79b55f7a7c2cb87f20

x64: implement shl_exact and shr_exact


2 files changed, 28 insertions(+), 30 deletions(-)

src/arch/x86_64/CodeGen.zig+28-26
...@@ -1708,7 +1708,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1708,7 +1708,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1708 // TODO reuse the operand1708 // TODO reuse the operand
1709 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);1709 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);
1710 const shift = @intCast(u8, offset * @sizeOf(usize));1710 const shift = @intCast(u8, offset * @sizeOf(usize));
1711 try self.genShiftBinOpMir(optional_ty, result.register, .{ .immediate = @intCast(u8, shift) }, .right);1711 try self.genShiftBinOpMir(.shr, optional_ty, result.register, .{ .immediate = @intCast(u8, shift) });
1712 break :result result;1712 break :result result;
1713 },1713 },
1714 else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}),1714 else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}),
...@@ -1795,7 +1795,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1795,7 +1795,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1795 // TODO reuse operand1795 // TODO reuse operand
1796 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));1796 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));
1797 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);1797 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1798 try self.genShiftBinOpMir(Type.usize, result.register, .{ .immediate = shift }, .right);1798 try self.genShiftBinOpMir(.shr, Type.usize, result.register, .{ .immediate = shift });
1799 break :result MCValue{1799 break :result MCValue{
1800 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),1800 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
1801 };1801 };
...@@ -2307,7 +2307,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -2307,7 +2307,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
2307 else2307 else
2308 0;2308 0;
2309 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);2309 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
2310 try self.genShiftBinOpMir(Type.usize, result.register, .{ .immediate = shift }, .right);2310 try self.genShiftBinOpMir(.shr, Type.usize, result.register, .{ .immediate = shift });
2311 break :blk MCValue{2311 break :blk MCValue{
2312 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),2312 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
2313 };2313 };
...@@ -2906,7 +2906,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2906,7 +2906,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
29062906
2907 // Shift by struct_field_offset.2907 // Shift by struct_field_offset.
2908 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));2908 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
2909 try self.genShiftBinOpMir(Type.usize, dst_mcv.register, .{ .immediate = shift }, .right);2909 try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift });
29102910
2911 // Mask with reg.size() - struct_field_size2911 // Mask with reg.size() - struct_field_size
2912 const max_reg_bit_width = Register.rax.size();2912 const max_reg_bit_width = Register.rax.size();
...@@ -2983,26 +2983,15 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2983,26 +2983,15 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2983}2983}
29842984
2985/// Clobbers .rcx for non-immediate shift value.2985/// Clobbers .rcx for non-immediate shift value.
2986fn genShiftBinOpMir(self: *Self, ty: Type, reg: Register, shift: MCValue, direction: enum { left, right }) !void {2986fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {
2987 assert(reg.to64() != .rcx);2987 assert(reg.to64() != .rcx);
29882988
2989 const abi_size = @intCast(u32, ty.abiSize(self.target.*));2989 switch (tag) {
2990 const signedness: std.builtin.Signedness = blk: {2990 .sal, .sar, .shl, .shr => {},
2991 if (ty.zigTypeTag() != .Int) break :blk .unsigned;2991 else => unreachable,
2992 break :blk ty.intInfo(self.target.*).signedness;2992 }
2993 };
2994
2995 const tag: Mir.Inst.Tag = switch (signedness) {
2996 .signed => switch (direction) {
2997 .left => Mir.Inst.Tag.sal,
2998 .right => Mir.Inst.Tag.sar,
2999 },
3000 .unsigned => switch (direction) {
3001 .left => Mir.Inst.Tag.shl,
3002 .right => Mir.Inst.Tag.shr,
3003 },
3004 };
30052993
2994 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3006 blk: {2995 blk: {
3007 switch (shift) {2996 switch (shift) {
3008 .immediate => |imm| switch (imm) {2997 .immediate => |imm| switch (imm) {
...@@ -3100,9 +3089,22 @@ fn genShiftBinOp(...@@ -3100,9 +3089,22 @@ fn genShiftBinOp(
3100 break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };3089 break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
3101 };3090 };
31023091
3092 const signedness = lhs_ty.intInfo(self.target.*).signedness;
3103 switch (tag) {3093 switch (tag) {
3104 .shl => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .left),3094 .shl => try self.genShiftBinOpMir(switch (signedness) {
3105 .shr => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .right),3095 .signed => .sal,
3096 .unsigned => .shl,
3097 }, lhs_ty, dst.register, rhs),
3098
3099 .shl_exact => try self.genShiftBinOpMir(.shl, lhs_ty, dst.register, rhs),
3100
3101 .shr,
3102 .shr_exact,
3103 => try self.genShiftBinOpMir(switch (signedness) {
3104 .signed => .sar,
3105 .unsigned => .shr,
3106 }, lhs_ty, dst.register, rhs),
3107
3106 else => unreachable,3108 else => unreachable,
3107 }3109 }
31083110
...@@ -5427,7 +5429,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5427,7 +5429,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5427 });5429 });
54285430
5429 if (nearest_power_of_two > 1) {5431 if (nearest_power_of_two > 1) {
5430 try self.genShiftBinOpMir(ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }, .right);5432 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 });
5431 }5433 }
54325434
5433 remainder -= nearest_power_of_two;5435 remainder -= nearest_power_of_two;
...@@ -6804,8 +6806,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {...@@ -6804,8 +6806,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
6804 switch (int_info.signedness) {6806 switch (int_info.signedness) {
6805 .signed => {6807 .signed => {
6806 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);6808 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
6807 try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .left);6809 try self.genShiftBinOpMir(.sal, Type.isize, reg, .{ .immediate = shift });
6808 try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .right);6810 try self.genShiftBinOpMir(.sar, Type.isize, reg, .{ .immediate = shift });
6809 },6811 },
6810 .unsigned => {6812 .unsigned => {
6811 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);6813 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
test/behavior/math.zig-4
...@@ -1065,8 +1065,6 @@ fn testShlTrunc(x: u16) !void {...@@ -1065,8 +1065,6 @@ fn testShlTrunc(x: u16) !void {
1065}1065}
10661066
1067test "exact shift left" {1067test "exact shift left" {
1068 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1069
1070 try testShlExact(0b00110101);1068 try testShlExact(0b00110101);
1071 comptime try testShlExact(0b00110101);1069 comptime try testShlExact(0b00110101);
1072}1070}
...@@ -1076,8 +1074,6 @@ fn testShlExact(x: u8) !void {...@@ -1076,8 +1074,6 @@ fn testShlExact(x: u8) !void {
1076}1074}
10771075
1078test "exact shift right" {1076test "exact shift right" {
1079 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1080
1081 try testShrExact(0b10110100);1077 try testShrExact(0b10110100);
1082 comptime try testShrExact(0b10110100);1078 comptime try testShrExact(0b10110100);
1083}1079}