authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 18:52:49+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 18:52:49+02:00
log9725205859517ce81e201b79b55f7a7c2cb87f20
treeb56d00e0b9eb8280ab5a479d10a60d1088bba7de
parenta9514ae1732df1fdc142b602e62ab0d12f693afa

x64: consolidate shifts into single MIR helper fn


1 files changed, 81 insertions(+), 120 deletions(-)

src/arch/x86_64/CodeGen.zig+81-120
......@@ -1708,7 +1708,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
17081708 // TODO reuse the operand
17091709 const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand);
17101710 const shift = @intCast(u8, offset * @sizeOf(usize));
1711 try self.shiftRegisterRightUnsigned(result.register, @intCast(u8, shift));
1711 try self.genShiftBinOpMir(optional_ty, result.register, .{ .immediate = @intCast(u8, shift) }, .right);
17121712 break :result result;
17131713 },
17141714 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 {
17951795 // TODO reuse operand
17961796 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));
17971797 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1798 try self.shiftRegisterRightUnsigned(result.register.to64(), shift);
1798 try self.genShiftBinOpMir(Type.usize, result.register, .{ .immediate = shift }, .right);
17991799 break :result MCValue{
18001800 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
18011801 };
......@@ -2307,7 +2307,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
23072307 else
23082308 0;
23092309 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
2310 try self.shiftRegisterRightUnsigned(result.register.to64(), shift);
2310 try self.genShiftBinOpMir(Type.usize, result.register, .{ .immediate = shift }, .right);
23112311 break :blk MCValue{
23122312 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
23132313 };
......@@ -2906,7 +2906,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
29062906
29072907 // Shift by struct_field_offset.
29082908 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
2909 try self.shiftRegisterRightUnsigned(dst_mcv.register, shift);
2909 try self.genShiftBinOpMir(Type.usize, dst_mcv.register, .{ .immediate = shift }, .right);
29102910
29112911 // Mask with reg.size() - struct_field_size
29122912 const max_reg_bit_width = Register.rax.size();
......@@ -2982,6 +2982,74 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
29822982 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
29832983}
29842984
2985/// Clobbers .rcx for non-immediate shift value.
2986fn genShiftBinOpMir(self: *Self, ty: Type, reg: Register, shift: MCValue, direction: enum { left, right }) !void {
2987 assert(reg.to64() != .rcx);
2988
2989 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
2990 const signedness: std.builtin.Signedness = blk: {
2991 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
2992 break :blk ty.intInfo(self.target.*).signedness;
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 };
3005
3006 blk: {
3007 switch (shift) {
3008 .immediate => |imm| switch (imm) {
3009 0 => return,
3010 1 => {
3011 _ = try self.addInst(.{
3012 .tag = tag,
3013 .ops = (Mir.Ops{
3014 .reg1 = registerAlias(reg, abi_size),
3015 .flags = 0b00,
3016 }).encode(),
3017 .data = undefined,
3018 });
3019 return;
3020 },
3021 else => {
3022 _ = try self.addInst(.{
3023 .tag = tag,
3024 .ops = (Mir.Ops{
3025 .reg1 = registerAlias(reg, abi_size),
3026 .flags = 0b10,
3027 }).encode(),
3028 .data = .{ .imm = @intCast(u8, imm) },
3029 });
3030 return;
3031 },
3032 },
3033 .register => |shift_reg| {
3034 if (shift_reg == .rcx) break :blk;
3035 },
3036 else => {},
3037 }
3038 assert(self.register_manager.isRegFree(.rcx));
3039 try self.register_manager.getReg(.rcx, null);
3040 try self.genSetReg(Type.u8, .rcx, shift);
3041 }
3042
3043 _ = try self.addInst(.{
3044 .tag = tag,
3045 .ops = (Mir.Ops{
3046 .reg1 = registerAlias(reg, abi_size),
3047 .flags = 0b01,
3048 }).encode(),
3049 .data = undefined,
3050 });
3051}
3052
29853053/// Result is always a register.
29863054/// Clobbers .rcx for non-immediate rhs, therefore care is needed to spill .rcx upfront.
29873055/// Asserts .rcx is free.
......@@ -3003,9 +3071,6 @@ fn genShiftBinOp(
30033071
30043072 assert(rhs_ty.abiSize(self.target.*) == 1);
30053073
3006 const int_info = lhs_ty.intInfo(self.target.*);
3007 const signedness = int_info.signedness;
3008
30093074 const lhs_lock: ?RegisterLock = switch (lhs) {
30103075 .register => |reg| self.register_manager.lockReg(reg),
30113076 else => null,
......@@ -3018,28 +3083,10 @@ fn genShiftBinOp(
30183083 };
30193084 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
30203085
3021 const flags: u2 = blk: {
3022 if (rhs.isImmediate()) {
3023 const flags: u2 = switch (rhs.immediate) {
3024 0 => unreachable, // TODO is this valid?
3025 1 => 0b00,
3026 else => 0b10,
3027 };
3028 break :blk flags;
3029 }
3030
3031 assert(self.register_manager.isRegFree(.rcx));
3032
3033 try self.register_manager.getReg(.rcx, null);
3034 try self.genSetReg(rhs_ty, .rcx, rhs);
3035 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
3036 defer self.register_manager.unlockReg(rcx_lock);
3037
3038 break :blk 0b01;
3039 };
3040 const data: Mir.Inst.Data = if (rhs.isImmediate()) .{
3041 .imm = @intCast(u8, rhs.immediate),
3042 } else undefined;
3086 assert(self.register_manager.isRegFree(.rcx));
3087 try self.register_manager.getReg(.rcx, null);
3088 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
3089 defer self.register_manager.unlockReg(rcx_lock);
30433090
30443091 const dst: MCValue = blk: {
30453092 if (maybe_inst) |inst| {
......@@ -3054,50 +3101,8 @@ fn genShiftBinOp(
30543101 };
30553102
30563103 switch (tag) {
3057 .shl => switch (signedness) {
3058 .signed => {
3059 _ = try self.addInst(.{
3060 .tag = .sal,
3061 .ops = (Mir.Ops{
3062 .reg1 = dst.register,
3063 .flags = flags,
3064 }).encode(),
3065 .data = data,
3066 });
3067 },
3068 .unsigned => {
3069 _ = try self.addInst(.{
3070 .tag = .shl,
3071 .ops = (Mir.Ops{
3072 .reg1 = dst.register,
3073 .flags = flags,
3074 }).encode(),
3075 .data = data,
3076 });
3077 },
3078 },
3079 .shr => switch (signedness) {
3080 .signed => {
3081 _ = try self.addInst(.{
3082 .tag = .sar,
3083 .ops = (Mir.Ops{
3084 .reg1 = dst.register,
3085 .flags = flags,
3086 }).encode(),
3087 .data = data,
3088 });
3089 },
3090 .unsigned => {
3091 _ = try self.addInst(.{
3092 .tag = .shr,
3093 .ops = (Mir.Ops{
3094 .reg1 = dst.register,
3095 .flags = flags,
3096 }).encode(),
3097 .data = data,
3098 });
3099 },
3100 },
3104 .shl => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .left),
3105 .shr => try self.genShiftBinOpMir(lhs_ty, dst.register, rhs, .right),
31013106 else => unreachable,
31023107 }
31033108
......@@ -5422,14 +5427,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
54225427 });
54235428
54245429 if (nearest_power_of_two > 1) {
5425 _ = try self.addInst(.{
5426 .tag = .shr,
5427 .ops = (Mir.Ops{
5428 .reg1 = tmp_reg,
5429 .flags = 0b10,
5430 }).encode(),
5431 .data = .{ .imm = nearest_power_of_two * 8 },
5432 });
5430 try self.genShiftBinOpMir(ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }, .right);
54335431 }
54345432
54355433 remainder -= nearest_power_of_two;
......@@ -6798,29 +6796,6 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
67986796 }
67996797}
68006798
6801/// Shifts register right without sign-extension.
6802fn shiftRegisterRightUnsigned(self: *Self, reg: Register, shift: u8) !void {
6803 if (shift == 0) return;
6804 if (shift == 1) {
6805 _ = try self.addInst(.{
6806 .tag = .shr,
6807 .ops = (Mir.Ops{
6808 .reg1 = reg,
6809 }).encode(),
6810 .data = undefined,
6811 });
6812 } else {
6813 _ = try self.addInst(.{
6814 .tag = .shr,
6815 .ops = (Mir.Ops{
6816 .reg1 = reg,
6817 .flags = 0b10,
6818 }).encode(),
6819 .data = .{ .imm = shift },
6820 });
6821 }
6822}
6823
68246799/// Truncates the value in the register in place.
68256800/// Clobbers any remaining bits.
68266801fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
......@@ -6829,22 +6804,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
68296804 switch (int_info.signedness) {
68306805 .signed => {
68316806 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
6832 _ = try self.addInst(.{
6833 .tag = .sal,
6834 .ops = (Mir.Ops{
6835 .reg1 = reg.to64(),
6836 .flags = 0b10,
6837 }).encode(),
6838 .data = .{ .imm = shift },
6839 });
6840 _ = try self.addInst(.{
6841 .tag = .sar,
6842 .ops = (Mir.Ops{
6843 .reg1 = reg.to64(),
6844 .flags = 0b10,
6845 }).encode(),
6846 .data = .{ .imm = shift },
6847 });
6807 try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .left);
6808 try self.genShiftBinOpMir(Type.isize, reg, .{ .immediate = shift }, .right);
68486809 },
68496810 .unsigned => {
68506811 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);