@@ -12868,10 +12868,85 @@ fn airShlShrBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
12868
12868
}
12869
12869
12870
12870
fn airShlSat(self: *CodeGen, inst: Air.Inst.Index) !void {
12871
+ const zcu = self.pt.zcu;
12871
12872
const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
12872
- _ = bin_op;
12873
- return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
12874
- //return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12873
+ const lhs_ty = self.typeOf(bin_op.lhs);
12874
+ const rhs_ty = self.typeOf(bin_op.rhs);
12875
+
12876
+ const result: MCValue = result: {
12877
+ switch (lhs_ty.zigTypeTag(zcu)) {
12878
+ .int => {
12879
+ try self.spillRegisters(&.{.rcx});
12880
+ try self.register_manager.getKnownReg(.rcx, null);
12881
+ const lhs_mcv = try self.resolveInst(bin_op.lhs);
12882
+ const rhs_mcv = try self.resolveInst(bin_op.rhs);
12883
+
12884
+ // 1. shift left
12885
+ const dst_mcv = try self.genShiftBinOp(Air.Inst.Tag.shl, null, lhs_mcv, rhs_mcv, lhs_ty, rhs_ty);
12886
+ switch (dst_mcv) {
12887
+ .register => |dst_reg| try self.truncateRegister(lhs_ty, dst_reg),
12888
+ .register_pair => |dst_regs| try self.truncateRegister(lhs_ty, dst_regs[1]),
12889
+ .load_frame => |frame_addr| {
12890
+ const tmp_reg =
12891
+ try self.register_manager.allocReg(null, abi.RegisterClass.gp);
12892
+ const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
12893
+ defer self.register_manager.unlockReg(tmp_lock);
12894
+
12895
+ const lhs_bits: u31 = @intCast(lhs_ty.bitSize(zcu));
12896
+ const tmp_ty: Type = if (lhs_bits > 64) .usize else lhs_ty;
12897
+ const off = frame_addr.off + (lhs_bits - 1) / 64 * 8;
12898
+ try self.genSetReg(
12899
+ tmp_reg,
12900
+ tmp_ty,
12901
+ .{ .load_frame = .{ .index = frame_addr.index, .off = off } },
12902
+ .{},
12903
+ );
12904
+ try self.truncateRegister(lhs_ty, tmp_reg);
12905
+ try self.genSetMem(
12906
+ .{ .frame = frame_addr.index },
12907
+ off,
12908
+ tmp_ty,
12909
+ .{ .register = tmp_reg },
12910
+ .{},
12911
+ );
12912
+ },
12913
+ else => {},
12914
+ }
12915
+ const dst_lock = switch (dst_mcv) {
12916
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
12917
+ else => null,
12918
+ };
12919
+ defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
12920
+
12921
+ // 2. shift right
12922
+ const tmp_mcv = try self.genShiftBinOp(Air.Inst.Tag.shr, null, dst_mcv, rhs_mcv, lhs_ty, rhs_ty);
12923
+ const tmp_lock = switch (tmp_mcv) {
12924
+ .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
12925
+ else => null,
12926
+ };
12927
+ defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
12928
+
12929
+ // 3. check if overflow happens
12930
+ try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, tmp_mcv, lhs_mcv);
12931
+ const reloc = try self.genCondBrMir(lhs_ty, .{ .eflags = Condition.ne });
12932
+
12933
+ // 4. if overflow, set the value to upper limit
12934
+ const bound_val = try lhs_ty.maxIntScalar(self.pt, lhs_ty);
12935
+ const bound_mcv = try self.genTypedValue(bound_val);
12936
+ switch (dst_mcv) {
12937
+ .register, .register_pair, .load_frame, .memory => try self.genCopy(lhs_ty, dst_mcv, bound_mcv, CopyOptions{}),
12938
+ else => return self.fail("TODO implement shl_sat for {} dest type {}", .{ self.target.cpu.arch, lhs_ty.zigTypeTag(zcu) }),
12939
+ }
12940
+
12941
+ self.performReloc(reloc);
12942
+ break :result dst_mcv;
12943
+ },
12944
+ else => {
12945
+ return self.fail("TODO implement shl_sat for {} op type {}", .{ self.target.cpu.arch, lhs_ty.zigTypeTag(zcu) });
12946
+ },
12947
+ }
12948
+ };
12949
+ return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12875
12950
}
12876
12951
12877
12952
fn airOptionalPayload(self: *CodeGen, inst: Air.Inst.Index) !void {
0 commit comments