return false;
}
+ template <unsigned RHSBits, bool RHSSign>
+ static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,
+ unsigned OpBits, Integral *R) {
+ *R = Integral::from(A.V << B.V, OpBits);
+ }
+
+ template <unsigned RHSBits, bool RHSSign>
+ static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,
+ unsigned OpBits, Integral *R) {
+ *R = Integral::from(A.V >> B.V, OpBits);
+ }
+
private:
template <typename T> static bool CheckAddUB(T A, T B, T &R) {
if constexpr (std::is_signed_v<T>) {
if (!CheckShift<RT>(S, OpPC, RHS, Bits))
return false;
- unsigned URHS = static_cast<unsigned>(RHS);
- S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth()));
+ Integral<LT::bitWidth(), false> R;
+ Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
+ S.Stk.push<LT>(R);
return true;
}
if (!CheckShift<RT>(S, OpPC, RHS, Bits))
return false;
- unsigned URHS = static_cast<unsigned>(RHS);
- S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth()));
-
+ Integral<LT::bitWidth(), false> R;
+ Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
+ S.Stk.push<LT>(R);
return true;
}
constexpr char c2 = 1;
constexpr int i3 = c2 << (__CHAR_BIT__ + 1); // Not ill-formed
+
+ /// The purpose of these few lines is to test that we can shift more bits
+ /// than an unsigned *of the host* has. There was a bug where we casted
+ /// to host-unsigned. However, we cannot query what a host-unsigned even is
+ /// here, so only test this on platforms where `sizeof(long long) > sizeof(unsigned)`.
+ constexpr long long int L = 1;
+ constexpr signed int R = (sizeof(unsigned) * 8) + 1;
+ constexpr decltype(L) M = (R > 32 && R < 64) ? L << R : 0;
+ constexpr decltype(L) M2 = (R > 32 && R < 64) ? L >> R : 0;
};