diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 254a81fe57ec22..e372086a46ecc0 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -2595,20 +2595,9 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) { assert(width <= 64); - UINT64 result = ~value; - - if (width < 64) - { - // Check that 'value' fits in 'width' bits. Don't consider "sign" bits above width. - UINT64 maxVal = 1ULL << width; - UINT64 lowBitsMask = maxVal - 1; - UINT64 signBitsMask = ~lowBitsMask | (1ULL << (width - 1)); // The high bits must be set, and the top bit - // (sign bit) must be set. - assert((value < maxVal) || ((value & signBitsMask) == signBitsMask)); - - // mask off any extra bits that we got from the complement operation - result &= lowBitsMask; - } + // Mask for zero'ing bits above width. + UINT64 mask = UINT64_MAX >> (64 - width); + UINT64 result = ~value & mask; return result; } diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index dd85dcf67691bc..2e0b10c9392258 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -19671,6 +19671,15 @@ bool GenTreeIntConCommon::ImmedValCanBeFolded(Compiler* comp, genTreeOps op) return !ImmedValNeedsReloc(comp) || (op == GT_EQ) || (op == GT_NE); } +UINT64 GenTreeIntConCommon::UnsignedIntegralValue() const +{ + uint64_t mask = (UINT64_MAX >> (64 - (genTypeSize(this) * BITS_PER_BYTE))); + + INT64 signExtended = IntegralValue(); + UINT64 zeroExtended = signExtended & mask; + return zeroExtended; +} + #if defined(TARGET_AMD64) || defined(TARGET_RISCV64) // Returns true if this absolute address fits within the base of an addr mode. // On Amd64 this effectively means, whether an absolute indirect address can diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index c9c965960083ea..8b506a174f3ab2 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -3337,6 +3337,7 @@ struct GenTreeIntConCommon : public GenTree inline ssize_t IconValue() const; inline void SetIconValue(ssize_t val); inline INT64 IntegralValue() const; + UINT64 UnsignedIntegralValue() const; inline void SetIntegralValue(int64_t value); template @@ -3536,7 +3537,7 @@ inline INT64 GenTreeIntConCommon::IntegralValue() const #ifdef TARGET_64BIT return LngValue(); #else - return OperIs(GT_CNS_LNG) ? LngValue() : (INT64)IconValue(); + return OperIs(GT_CNS_LNG) ? LngValue() : static_cast(IconValue()); #endif // TARGET_64BIT } @@ -10473,7 +10474,7 @@ inline bool GenTree::IsIntegralConstUnsignedPow2() const { if (IsIntegralConst()) { - return isPow2((UINT64)AsIntConCommon()->IntegralValue()); + return isPow2(AsIntConCommon()->UnsignedIntegralValue()); } return false; @@ -10491,9 +10492,7 @@ inline bool GenTree::IsIntegralConstAbsPow2() const { if (IsIntegralConst()) { - INT64 svalue = AsIntConCommon()->IntegralValue(); - size_t value = (svalue == SSIZE_T_MIN) ? static_cast(svalue) : static_cast(abs(svalue)); - return isPow2(value); + return isAbsPow2(AsIntConCommon()->IntegralValue()); } return false; diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 5f8f8166f57fa9..46f41c76e359af 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -4326,8 +4326,8 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp) #ifdef TARGET_RISCV64 if (bitOp->IsIntegralConstUnsignedPow2()) { - INT64 bit = bitOp->AsIntConCommon()->IntegralValue(); - int log2 = BitOperations::Log2((UINT64)bit); + UINT64 bit = bitOp->AsIntConCommon()->UnsignedIntegralValue(); + int log2 = BitOperations::Log2(bit); bitOp->AsIntConCommon()->SetIntegralValue(log2); return true; } diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index fe982668bce51c..aa99e56359ced6 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -12094,8 +12094,8 @@ GenTree* Compiler::fgMorphUModToAndSub(GenTreeOp* tree) const var_types type = tree->TypeGet(); - const size_t cnsValue = (static_cast(tree->gtOp2->AsIntConCommon()->IntegralValue())) - 1; - GenTree* const newTree = gtNewOperNode(GT_AND, type, tree->gtOp1, gtNewIconNodeWithVN(this, cnsValue, type)); + const UINT64 mask = tree->gtOp2->AsIntConCommon()->UnsignedIntegralValue() - 1; + GenTree* const newTree = gtNewOperNode(GT_AND, type, tree->gtOp1, gtNewIconNodeWithVN(this, mask, type)); newTree->SetMorphed(this); DEBUG_DESTROY_NODE(tree->gtOp2); diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index 38c819e0672896..06b72fc33cd71e 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -67,6 +67,14 @@ inline bool isPow2(T i) return (i > 0 && ((i - 1) & i) == 0); } +// return true if abs(arg) is a power of 2 +template +inline bool isAbsPow2(T i) +{ + static_assert(std::numeric_limits::is_signed); + return (i == std::numeric_limits::min()) || isPow2(std::abs(i)); +} + template constexpr bool AreContiguous(T val1, T val2) {