| ... | @@ -1454,6 +1454,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1454,6 +1454,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1454 | .rem => self.airBinOp(inst, .rem), | 1454 | .rem => self.airBinOp(inst, .rem), |
| 1455 | .shl => self.airWrapBinOp(inst, .shl), | 1455 | .shl => self.airWrapBinOp(inst, .shl), |
| 1456 | .shl_exact => self.airBinOp(inst, .shl), | 1456 | .shl_exact => self.airBinOp(inst, .shl), |
| | 1457 | .shl_sat => self.airShlSat(inst), |
| 1457 | .shr, .shr_exact => self.airBinOp(inst, .shr), | 1458 | .shr, .shr_exact => self.airBinOp(inst, .shr), |
| 1458 | .xor => self.airBinOp(inst, .xor), | 1459 | .xor => self.airBinOp(inst, .xor), |
| 1459 | .max => self.airMaxMin(inst, .max), | 1460 | .max => self.airMaxMin(inst, .max), |
| ... | @@ -1588,7 +1589,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1588,7 +1589,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1588 | .mul_sat, | 1589 | .mul_sat, |
| 1589 | .mod, | 1590 | .mod, |
| 1590 | .assembly, | 1591 | .assembly, |
| 1591 | .shl_sat, | | |
| 1592 | .ret_addr, | 1592 | .ret_addr, |
| 1593 | .frame_addr, | 1593 | .frame_addr, |
| 1594 | .bit_reverse, | 1594 | .bit_reverse, |
| ... | @@ -4988,3 +4988,57 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op | ... | @@ -4988,3 +4988,57 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 4988 | return bin_result; | 4988 | return bin_result; |
| 4989 | } | 4989 | } |
| 4990 | } | 4990 | } |
| | 4991 | |
| | 4992 | fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| | 4993 | if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; |
| | 4994 | |
| | 4995 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 4996 | const ty = self.air.typeOfIndex(inst); |
| | 4997 | const int_info = ty.intInfo(self.target); |
| | 4998 | if (int_info.bits > 64) { |
| | 4999 | return self.fail("TODO: Saturating shifting left for integers with bitsize '{d}'", .{int_info.bits}); |
| | 5000 | } |
| | 5001 | |
| | 5002 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 5003 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 5004 | if (int_info.signedness == .signed) {} |
| | 5005 | const wasm_bits = toWasmBits(int_info.bits).?; |
| | 5006 | const result = try self.allocLocal(ty); |
| | 5007 | |
| | 5008 | if (wasm_bits == int_info.bits) { |
| | 5009 | const shl = try self.binOp(lhs, rhs, ty, .shl); |
| | 5010 | const shr = try self.binOp(shl, rhs, ty, .shr); |
| | 5011 | const cmp_result = try self.cmp(lhs, shr, ty, .neq); |
| | 5012 | if (wasm_bits == 32) |
| | 5013 | try self.addImm32(-1) |
| | 5014 | else |
| | 5015 | try self.addImm64(@bitCast(u64, @as(i64, -1))); |
| | 5016 | try self.emitWValue(shl); |
| | 5017 | try self.emitWValue(cmp_result); |
| | 5018 | try self.addTag(.select); |
| | 5019 | try self.addLabel(.local_set, result.local); |
| | 5020 | return result; |
| | 5021 | } else { |
| | 5022 | const shift_size = wasm_bits - int_info.bits; |
| | 5023 | const shift_value = switch (wasm_bits) { |
| | 5024 | 32 => WValue{ .imm32 = shift_size }, |
| | 5025 | 64 => WValue{ .imm64 = shift_size }, |
| | 5026 | else => unreachable, |
| | 5027 | }; |
| | 5028 | |
| | 5029 | const shl_res = try self.binOp(lhs, shift_value, ty, .shl); |
| | 5030 | const shl = try self.binOp(shl_res, rhs, ty, .shl); |
| | 5031 | const shr = try self.binOp(shl, rhs, ty, .shr); |
| | 5032 | |
| | 5033 | const cmp_result = try self.cmp(shl_res, shr, ty, .neq); |
| | 5034 | if (wasm_bits == 32) |
| | 5035 | try self.addImm32(-1) |
| | 5036 | else |
| | 5037 | try self.addImm64(@bitCast(u64, @as(i64, -1))); |
| | 5038 | try self.emitWValue(shl); |
| | 5039 | try self.emitWValue(cmp_result); |
| | 5040 | try self.addTag(.select); |
| | 5041 | try self.addLabel(.local_set, result.local); |
| | 5042 | return self.binOp(result, shift_value, ty, .shr); |
| | 5043 | } |
| | 5044 | } |