diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h index 98f1a1c5237..a1d6b1b830c 100644 --- a/runtime/platform/utils.h +++ b/runtime/platform/utils.h @@ -229,12 +229,22 @@ class Utils { return value <= limit; } - // Check whether the magnitude of value fits in N bits, i.e., whether an - // (N+1)-bit sign-magnitude representation can hold value. + // Check whether the magnitude of value fits in N bits. This differs from + // IsInt(N + 1, value) only in that this returns false for the minimum value + // of a N+1 bit two's complement value. + // + // Primarily used for testing whether a two's complement value can be used in + // a place where the sign is replaced with a marker that says whether the + // magnitude is added or subtracted, e.g., the U bit (bit 23) in some ARM7 + // instructions. template - static inline bool IsAbsoluteUint(intptr_t N, T value) { + static inline bool MagnitudeIsUint(intptr_t N, T value) { ASSERT(N >= 1); - return IsInt(N + 1, value); + if constexpr (std::is_signed::value) { + using Unsigned = typename std::make_unsigned::type; + if (value < 0) return IsUint(N, -value); + } + return IsUint(N, value); } static inline int32_t Low16Bits(int32_t value) { diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc index 7cf827213bf..d285792ed57 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.cc +++ b/runtime/vm/compiler/assembler/assembler_arm.cc @@ -2336,19 +2336,20 @@ bool Address::CanHoldLoadOffset(OperandSize size, case kUnsignedTwoBytes: case kWordPair: { *offset_mask = 0xff; - return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. + return Utils::MagnitudeIsUint(8, offset); // Addressing mode 3. } case kUnsignedByte: case kFourBytes: case kUnsignedFourBytes: { *offset_mask = 0xfff; - return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2. + return Utils::MagnitudeIsUint(12, offset); // Addressing mode 2. } case kSWord: case kDWord: { *offset_mask = 0x3fc; // Multiple of 4. // VFP addressing mode. - return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4)); + return (Utils::MagnitudeIsUint(10, offset) && + Utils::IsAligned(offset, 4)); } case kRegList: { *offset_mask = 0x0; @@ -2369,20 +2370,21 @@ bool Address::CanHoldStoreOffset(OperandSize size, case kUnsignedTwoBytes: case kWordPair: { *offset_mask = 0xff; - return Utils::IsAbsoluteUint(8, offset); // Addressing mode 3. + return Utils::MagnitudeIsUint(8, offset); // Addressing mode 3. } case kByte: case kUnsignedByte: case kFourBytes: case kUnsignedFourBytes: { *offset_mask = 0xfff; - return Utils::IsAbsoluteUint(12, offset); // Addressing mode 2. + return Utils::MagnitudeIsUint(12, offset); // Addressing mode 2. } case kSWord: case kDWord: { *offset_mask = 0x3fc; // Multiple of 4. // VFP addressing mode. - return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4)); + return (Utils::MagnitudeIsUint(10, offset) && + Utils::IsAligned(offset, 4)); } case kRegList: { *offset_mask = 0x0; diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h index 09162f4d442..c41b62d1bea 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.h +++ b/runtime/vm/compiler/assembler/assembler_arm.h @@ -238,7 +238,7 @@ class Address : public ValueObject { } explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) { - ASSERT(Utils::IsAbsoluteUint(12, offset)); + ASSERT(Utils::MagnitudeIsUint(12, offset)); kind_ = Immediate; if (offset < 0) { encoding_ = (am ^ (1 << kUShift)) | -offset; // Flip U to adjust sign. diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc index 979db7ea017..b71c7028604 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc @@ -712,7 +712,7 @@ void FlowGraphCompiler::EmitDispatchTableCall( } else { __ add(LR, DISPATCH_TABLE_REG, compiler::Operand(cid_reg, LSL, compiler::target::kWordSizeLog2)); - if (!Utils::IsAbsoluteUint(12, offset)) { + if (!Utils::MagnitudeIsUint(12, offset)) { const intptr_t adjust = offset & -(1 << 12); __ AddImmediate(LR, LR, adjust); offset -= adjust; diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc index 80aaa4759f3..0c07ad2fe29 100644 --- a/runtime/vm/compiler/backend/il_arm.cc +++ b/runtime/vm/compiler/backend/il_arm.cc @@ -1855,7 +1855,7 @@ static bool CanBeImmediateIndex(Value* value, const intptr_t base_offset = (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag)); const int64_t offset = index * scale + base_offset; - if (!Utils::IsAbsoluteUint(12, offset)) { + if (!Utils::MagnitudeIsUint(12, offset)) { return false; } if (compiler::Address::CanHoldImmediateOffset(is_load, cid, offset)) { diff --git a/runtime/vm/datastream.cc b/runtime/vm/datastream.cc index 6d398fe7597..2dde0cfa6c0 100644 --- a/runtime/vm/datastream.cc +++ b/runtime/vm/datastream.cc @@ -10,8 +10,7 @@ namespace dart { void BaseWriteStream::WriteTargetWord(word value) { - ASSERT(compiler::target::kBitsPerWord == kBitsPerWord || - Utils::IsAbsoluteUint(compiler::target::kBitsPerWord, value)); + ASSERT(Utils::BitLength(value) <= compiler::target::kBitsPerWord); WriteFixed(static_cast(value)); } diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc index 658892bd5f5..6be60de604b 100644 --- a/runtime/vm/image_snapshot.cc +++ b/runtime/vm/image_snapshot.cc @@ -1207,8 +1207,7 @@ void AssemblyImageWriter::ExitSection(ProgramSection name, } intptr_t AssemblyImageWriter::WriteTargetWord(word value) { - ASSERT(compiler::target::kBitsPerWord == kBitsPerWord || - Utils::IsAbsoluteUint(compiler::target::kBitsPerWord, value)); + ASSERT(Utils::BitLength(value) <= compiler::target::kBitsPerWord); // Padding is helpful for comparing the .S with --disassemble. assembly_stream_->Printf("%s 0x%.*" Px "\n", kWordDirective, 2 * compiler::target::kWordSize, value); diff --git a/runtime/vm/utils_test.cc b/runtime/vm/utils_test.cc index ba4e296cb7b..2b0369f530d 100644 --- a/runtime/vm/utils_test.cc +++ b/runtime/vm/utils_test.cc @@ -290,22 +290,26 @@ VM_UNIT_TEST_CASE(IsUint) { EXPECT(!Utils::IsUint(32, 4294967296LL)); } -VM_UNIT_TEST_CASE(IsAbsoluteUint) { - EXPECT(Utils::IsAbsoluteUint(8, 16)); - EXPECT(Utils::IsAbsoluteUint(8, 0)); - EXPECT(Utils::IsAbsoluteUint(8, -128)); - EXPECT(Utils::IsAbsoluteUint(8, 255)); - EXPECT(!Utils::IsAbsoluteUint(8, 256)); - EXPECT(Utils::IsAbsoluteUint(16, 16)); - EXPECT(Utils::IsAbsoluteUint(16, 0)); - EXPECT(Utils::IsAbsoluteUint(16, 65535)); - EXPECT(Utils::IsAbsoluteUint(16, -32768)); - EXPECT(!Utils::IsAbsoluteUint(16, 65536)); - EXPECT(Utils::IsAbsoluteUint(32, 16LL)); - EXPECT(Utils::IsAbsoluteUint(32, 0LL)); - EXPECT(Utils::IsAbsoluteUint(32, -2147483648LL)); - EXPECT(Utils::IsAbsoluteUint(32, 4294967295LL)); - EXPECT(!Utils::IsAbsoluteUint(32, 4294967296LL)); +VM_UNIT_TEST_CASE(MagnitudeIsUint) { + EXPECT(Utils::MagnitudeIsUint(8, 16)); + EXPECT(Utils::MagnitudeIsUint(8, 0)); + EXPECT(Utils::MagnitudeIsUint(8, -128)); + EXPECT(Utils::MagnitudeIsUint(8, 255)); + EXPECT(!Utils::MagnitudeIsUint(8, 256)); + EXPECT(Utils::MagnitudeIsUint(12, 4095)); + EXPECT(Utils::MagnitudeIsUint(12, -4095)); + EXPECT(!Utils::MagnitudeIsUint(12, 4096)); + EXPECT(!Utils::MagnitudeIsUint(12, -4096)); + EXPECT(Utils::MagnitudeIsUint(16, 16)); + EXPECT(Utils::MagnitudeIsUint(16, 0)); + EXPECT(Utils::MagnitudeIsUint(16, 65535)); + EXPECT(Utils::MagnitudeIsUint(16, -32768)); + EXPECT(!Utils::MagnitudeIsUint(16, 65536)); + EXPECT(Utils::MagnitudeIsUint(32, 16LL)); + EXPECT(Utils::MagnitudeIsUint(32, 0LL)); + EXPECT(Utils::MagnitudeIsUint(32, -2147483648LL)); + EXPECT(Utils::MagnitudeIsUint(32, 4294967295LL)); + EXPECT(!Utils::MagnitudeIsUint(32, 4294967296LL)); } VM_UNIT_TEST_CASE(LowBits) {