diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index ee472eeac8..28de88ff86 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2052,11 +2052,76 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { fn airShr(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) - .dead - else - return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); + + if (self.liveness.isUnused(inst)) { + return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); + } + + const ty = self.air.typeOfIndex(inst); + const tag = self.air.instructions.items(.tag)[inst]; + switch (tag) { + .shr_exact => return self.fail("TODO implement shr_exact for type {}", .{ty.fmtDebug()}), + .shr => {}, + else => unreachable, + } + + if (ty.zigTypeTag() != .Int) { + return self.fail("TODO implement shr for type {}", .{ty.fmtDebug()}); + } + if (ty.abiSize(self.target.*) > 8) { + return self.fail("TODO implement shr for integers larger than 8 bytes", .{}); + } + + // TODO look into reusing the operands + // TODO audit register allocation mechanics + const shift = try self.resolveInst(bin_op.rhs); + const shift_ty = self.air.typeOf(bin_op.rhs); + + blk: { + switch (shift) { + .register => |reg| { + if (reg.to64() == .rcx) break :blk; + }, + else => {}, + } + try self.register_manager.getReg(.rcx, null); + try self.genSetReg(shift_ty, .rcx, shift); + } + const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx); + defer self.register_manager.unlockReg(rcx_lock); + + const value = try self.resolveInst(bin_op.lhs); + const value_lock: ?RegisterLock = switch (value) { + .register => |reg| self.register_manager.lockRegAssumeUnused(reg), + else => null, + }; + defer if (value_lock) |lock| self.register_manager.unlockReg(lock); + + const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value); + switch (ty.intInfo(self.target.*).signedness) { + .signed => { + _ = try self.addInst(.{ + .tag = .sar, + .ops = (Mir.Ops{ + .reg1 = dst_mcv.register, + .flags = 0b01, + }).encode(), + .data = undefined, + }); + }, + .unsigned => { + _ = try self.addInst(.{ + .tag = .shr, + .ops = (Mir.Ops{ + .reg1 = dst_mcv.register, + .flags = 0b01, + }).encode(), + .data = undefined, + }); + }, + } + + return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); } fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 42f2635afd..dd609c9b08 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -570,8 +570,6 @@ test "bit shift a u1" { } test "truncating shift right" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - try testShrTrunc(maxInt(u16)); comptime try testShrTrunc(maxInt(u16)); }