From 6580ac1c05bd1cbccd2dcd71fd9c2a384ae3db56 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Mon, 3 Aug 2026 18:31:58 +0800 Subject: [CodeGen] Model complete MIR operands --- backend/lib/CodeGen/MachineOperand.cpp | 181 +++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) (limited to 'backend/lib/CodeGen/MachineOperand.cpp') diff --git a/backend/lib/CodeGen/MachineOperand.cpp b/backend/lib/CodeGen/MachineOperand.cpp index cd2d217..6cce188 100644 --- a/backend/lib/CodeGen/MachineOperand.cpp +++ b/backend/lib/CodeGen/MachineOperand.cpp @@ -9,11 +9,103 @@ #include #include #include +#include #include #include #include +#include namespace rcc { +namespace { + +[[nodiscard]] constexpr std::size_t integerWordCount(std::uint32_t BitWidth) noexcept { + return (static_cast(BitWidth) + 63U) / 64U; +} + +[[nodiscard]] constexpr std::uint64_t integerHighWordMask(std::uint32_t BitWidth) noexcept { + const std::uint32_t UsedBits = BitWidth % 64U; + if (UsedBits == 0) + return std::numeric_limits::max(); + return (std::uint64_t{1} << UsedBits) - 1U; +} + +[[nodiscard]] Expected verifyIntegerImmediate(std::uint32_t BitWidth, + std::span Words, + ErrorCode Code) { + if (BitWidth == 0 || BitWidth > IntegerImmediate::MaxBitWidth) { + return makeUnexpected(Code, "integer immediate bit width is outside the supported range"); + } + if (Words.size() != integerWordCount(BitWidth)) { + return makeUnexpected(Code, "integer immediate bit pattern has the wrong word count"); + } + if ((Words.back() & ~integerHighWordMask(BitWidth)) != 0) { + return makeUnexpected(Code, "integer immediate has nonzero bits above its declared width"); + } + return {}; +} + +} // namespace + +Expected IntegerImmediate::create(std::uint32_t BitWidth, + std::span Words) { + auto Verification = verifyIntegerImmediate(BitWidth, Words, ErrorCode::InvalidArgument); + if (!Verification) + return std::unexpected(Verification.error()); + return IntegerImmediate(BitWidth, std::vector(Words.begin(), Words.end())); +} + +Expected IntegerImmediate::fromUnsigned(std::uint32_t BitWidth, + std::uint64_t Value) { + if (BitWidth == 0 || BitWidth > MaxBitWidth) { + return makeUnexpected(ErrorCode::InvalidArgument, + "integer immediate bit width is outside the supported range"); + } + if (BitWidth < 64U && (Value >> BitWidth) != 0) { + return makeUnexpected(ErrorCode::InvalidArgument, + "unsigned value does not fit the integer immediate bit width"); + } + + std::vector Words(integerWordCount(BitWidth), 0); + Words.front() = Value; + return create(BitWidth, Words); +} + +Expected IntegerImmediate::fromSigned(std::uint32_t BitWidth, + std::int64_t Value) { + if (BitWidth == 0 || BitWidth > MaxBitWidth) { + return makeUnexpected(ErrorCode::InvalidArgument, + "integer immediate bit width is outside the supported range"); + } + if (BitWidth < 64U) { + const std::uint32_t MagnitudeBits = BitWidth - 1U; + const std::int64_t Minimum = -(std::int64_t{1} << MagnitudeBits); + const std::int64_t Maximum = (std::int64_t{1} << MagnitudeBits) - 1; + if (Value < Minimum || Value > Maximum) { + return makeUnexpected(ErrorCode::InvalidArgument, + "signed value does not fit the integer immediate bit width"); + } + } + + const std::uint64_t Fill = + Value < 0 ? std::numeric_limits::max() : std::uint64_t{0}; + std::vector Words(integerWordCount(BitWidth), Fill); + Words.front() = static_cast(Value); + Words.back() &= integerHighWordMask(BitWidth); + return create(BitWidth, Words); +} + +bool IntegerImmediate::isZero() const noexcept { + return std::ranges::all_of(Words, [](std::uint64_t Word) { return Word == 0; }); +} + +bool IntegerImmediate::isNegative() const noexcept { + const std::uint32_t SignBit = BitWidth - 1U; + return (Words[SignBit / 64U] & (std::uint64_t{1} << (SignBit % 64U))) != 0; +} + +Expected IntegerImmediate::verify() const { + return verifyIntegerImmediate(BitWidth, Words, ErrorCode::VerificationError); +} Expected FloatingPointBits::create(FloatSemantics Semantics, std::span Words) { @@ -45,6 +137,20 @@ RegisterOperandFlags::RegisterOperandFlags( set(Flag); } +Expected PredicateOperand::verify() const { + if (const auto *Integer = integerPredicate(); + Integer != nullptr && + static_cast(*Integer) < static_cast(IntegerPredicate::Count)) { + return {}; + } + if (const auto *Floating = floatingPredicate(); + Floating != nullptr && + static_cast(*Floating) < static_cast(FloatingPredicate::Count)) { + return {}; + } + return makeUnexpected(ErrorCode::VerificationError, "predicate operand contains an invalid kind"); +} + Expected MachineOperand::verifyRegisterFlags(RegisterOperandFlags Flags) { const bool IsDef = Flags.has(RegisterOperandFlag::Define); const bool IsUse = Flags.has(RegisterOperandFlag::Use); @@ -96,6 +202,11 @@ MachineOperand MachineOperand::immediate(std::int64_t Value, std::uint32_t Targe return MachineOperand(Kind::Immediate, Value, TargetFlags); } +MachineOperand MachineOperand::integerImmediate(IntegerImmediate Value, std::uint32_t TargetFlags) { + return MachineOperand(Kind::IntegerImmediate, IntegerImmediateOperand{std::move(Value)}, + TargetFlags); +} + MachineOperand MachineOperand::floatingImmediate(FloatingPointBits Bits, std::uint32_t TargetFlags) { return MachineOperand(Kind::FloatingImmediate, FloatingImmediateOperand{Bits}, TargetFlags); @@ -158,6 +269,17 @@ Expected MachineOperand::registerMask(std::shared_ptr +MachineOperand::liveOutRegisterMask(std::shared_ptr Mask, + std::uint32_t TargetFlags) { + if (!Mask) { + return makeUnexpected(ErrorCode::InvalidArgument, + "live-out register-mask operand cannot be null"); + } + return MachineOperand(Kind::LiveOutRegisterMask, LiveOutRegisterMaskOperand{std::move(Mask)}, + TargetFlags); +} + Expected MachineOperand::metadata(MachineMetadataValue Value, std::uint32_t TargetFlags) { if (!Value.isValid()) { @@ -179,6 +301,65 @@ Expected MachineOperand::mcSymbol(std::string Name, std::int64_t return MachineOperand(Kind::MCSymbol, MCSymbolOperand{std::move(Name), Offset}, TargetFlags); } +MachineOperand MachineOperand::cfiIndex(CFIInstructionIndex Index, std::uint32_t TargetFlags) { + return MachineOperand(Kind::CFIIndex, CFIIndexOperand{Index}, TargetFlags); +} + +Expected MachineOperand::intrinsic(IntrinsicID ID, std::uint32_t TargetFlags) { + if (ID.value() == 0) { + return makeUnexpected(ErrorCode::InvalidArgument, "intrinsic operand ID must be nonzero"); + } + return MachineOperand(Kind::Intrinsic, IntrinsicOperand{ID}, TargetFlags); +} + +Expected MachineOperand::integerPredicate(IntegerPredicate Predicate, + std::uint32_t TargetFlags) { + PredicateOperand Value(Predicate); + auto Verification = Value.verify(); + if (!Verification) + return makeUnexpected(ErrorCode::InvalidArgument, "integer predicate operand is invalid"); + return MachineOperand(Kind::Predicate, Value, TargetFlags); +} + +Expected MachineOperand::floatingPredicate(FloatingPredicate Predicate, + std::uint32_t TargetFlags) { + PredicateOperand Value(Predicate); + auto Verification = Value.verify(); + if (!Verification) + return makeUnexpected(ErrorCode::InvalidArgument, "floating predicate operand is invalid"); + return MachineOperand(Kind::Predicate, Value, TargetFlags); +} + +Expected MachineOperand::shuffleMask(std::vector Elements, + std::uint32_t TargetFlags) { + if (Elements.size() < 2) { + return makeUnexpected(ErrorCode::InvalidArgument, + "shuffle-mask operand requires at least two elements"); + } + return MachineOperand(Kind::ShuffleMask, ShuffleMaskOperand{std::move(Elements)}, TargetFlags); +} + +Expected MachineOperand::debugInstrRef(std::uint64_t InstructionNumber, + std::uint64_t OperandNumber, + std::uint32_t TargetFlags) { + if (InstructionNumber > std::numeric_limits::max()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "debug instruction reference instruction number must fit in uint32"); + } + if (OperandNumber > std::numeric_limits::max()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "debug instruction reference operand number must fit in uint32"); + } + return MachineOperand(Kind::DebugInstrRef, + DebugInstrRefOperand{static_cast(InstructionNumber), + static_cast(OperandNumber)}, + TargetFlags); +} + +MachineOperand MachineOperand::laneMask(LaneMask Mask, std::uint32_t TargetFlags) { + return MachineOperand(Kind::LaneMask, LaneMaskOperand{Mask}, TargetFlags); +} + MachineOperand::MachineOperand(MachineOperand &&Other) noexcept : OperandKind(Other.OperandKind), Storage(std::move(Other.Storage)), RegFlags(Other.RegFlags), RegSubReg(Other.RegSubReg), TiedOperandIndex(Other.TiedOperandIndex), -- cgit v1.2.3