aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/CodeGen/MachineOperand.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-03 18:31:58 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-03 18:31:58 +0800
commit6580ac1c05bd1cbccd2dcd71fd9c2a384ae3db56 (patch)
tree3bea5331666575eb6a9cc7aa26842c7387cb372b /backend/lib/CodeGen/MachineOperand.cpp
parenta8a9d7d926202450645deae872d4d9dc11d63215 (diff)
downloadrcc-project-6580ac1c05bd1cbccd2dcd71fd9c2a384ae3db56.tar.gz
rcc-project-6580ac1c05bd1cbccd2dcd71fd9c2a384ae3db56.tar.xz
[CodeGen] Model complete MIR operands
Diffstat (limited to 'backend/lib/CodeGen/MachineOperand.cpp')
-rw-r--r--backend/lib/CodeGen/MachineOperand.cpp181
1 files changed, 181 insertions, 0 deletions
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 <algorithm>
#include <array>
#include <cstdint>
+#include <limits>
#include <memory>
#include <span>
#include <utility>
+#include <vector>
namespace rcc {
+namespace {
+
+[[nodiscard]] constexpr std::size_t integerWordCount(std::uint32_t BitWidth) noexcept {
+ return (static_cast<std::size_t>(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<std::uint64_t>::max();
+ return (std::uint64_t{1} << UsedBits) - 1U;
+}
+
+[[nodiscard]] Expected<void> verifyIntegerImmediate(std::uint32_t BitWidth,
+ std::span<const std::uint64_t> 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> IntegerImmediate::create(std::uint32_t BitWidth,
+ std::span<const std::uint64_t> Words) {
+ auto Verification = verifyIntegerImmediate(BitWidth, Words, ErrorCode::InvalidArgument);
+ if (!Verification)
+ return std::unexpected(Verification.error());
+ return IntegerImmediate(BitWidth, std::vector<std::uint64_t>(Words.begin(), Words.end()));
+}
+
+Expected<IntegerImmediate> 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<std::uint64_t> Words(integerWordCount(BitWidth), 0);
+ Words.front() = Value;
+ return create(BitWidth, Words);
+}
+
+Expected<IntegerImmediate> 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<std::uint64_t>::max() : std::uint64_t{0};
+ std::vector<std::uint64_t> Words(integerWordCount(BitWidth), Fill);
+ Words.front() = static_cast<std::uint64_t>(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<void> IntegerImmediate::verify() const {
+ return verifyIntegerImmediate(BitWidth, Words, ErrorCode::VerificationError);
+}
Expected<FloatingPointBits> FloatingPointBits::create(FloatSemantics Semantics,
std::span<const std::uint64_t> Words) {
@@ -45,6 +137,20 @@ RegisterOperandFlags::RegisterOperandFlags(
set(Flag);
}
+Expected<void> PredicateOperand::verify() const {
+ if (const auto *Integer = integerPredicate();
+ Integer != nullptr &&
+ static_cast<std::uint8_t>(*Integer) < static_cast<std::uint8_t>(IntegerPredicate::Count)) {
+ return {};
+ }
+ if (const auto *Floating = floatingPredicate();
+ Floating != nullptr &&
+ static_cast<std::uint8_t>(*Floating) < static_cast<std::uint8_t>(FloatingPredicate::Count)) {
+ return {};
+ }
+ return makeUnexpected(ErrorCode::VerificationError, "predicate operand contains an invalid kind");
+}
+
Expected<void> 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> MachineOperand::registerMask(std::shared_ptr<const Regi
return MachineOperand(Kind::RegisterMask, RegisterMaskOperand{std::move(Mask)}, TargetFlags);
}
+Expected<MachineOperand>
+MachineOperand::liveOutRegisterMask(std::shared_ptr<const RegisterMask> 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> MachineOperand::metadata(MachineMetadataValue Value,
std::uint32_t TargetFlags) {
if (!Value.isValid()) {
@@ -179,6 +301,65 @@ Expected<MachineOperand> 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> 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> 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> 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> MachineOperand::shuffleMask(std::vector<std::int32_t> 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> MachineOperand::debugInstrRef(std::uint64_t InstructionNumber,
+ std::uint64_t OperandNumber,
+ std::uint32_t TargetFlags) {
+ if (InstructionNumber > std::numeric_limits<std::uint32_t>::max()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "debug instruction reference instruction number must fit in uint32");
+ }
+ if (OperandNumber > std::numeric_limits<std::uint32_t>::max()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "debug instruction reference operand number must fit in uint32");
+ }
+ return MachineOperand(Kind::DebugInstrRef,
+ DebugInstrRefOperand{static_cast<std::uint32_t>(InstructionNumber),
+ static_cast<std::uint32_t>(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),