diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-17 02:22:27 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-17 02:22:27 +0800 |
| commit | f6a3a06de3d32eaeba1f3c8bbc5faa5ffaeb1128 (patch) | |
| tree | 709c80bac56fb9c18f795ab77185da6132d35ff8 | |
| parent | fb5c47bd2cb9ba5b201dfaa8d4918d122c4a624d (diff) | |
| download | rcc-project-f6a3a06de3d32eaeba1f3c8bbc5faa5ffaeb1128.tar.gz rcc-project-f6a3a06de3d32eaeba1f3c8bbc5faa5ffaeb1128.tar.xz | |
[RISCV][GlobalISel] Generate integer extension selections
| -rw-r--r-- | backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h | 6 | ||||
| -rw-r--r-- | backend/include/rcc/TableGen/Record.h | 27 | ||||
| -rw-r--r-- | backend/include/rcc/Target/RISCV/RISCVSubtarget.h | 1 | ||||
| -rw-r--r-- | backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp | 107 | ||||
| -rw-r--r-- | backend/lib/TableGen/Parser.cpp | 129 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp | 137 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc | 193 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVSubtarget.cpp | 1 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenSelection.cpp | 134 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenTarget.h | 19 | ||||
| -rw-r--r-- | backend/utils/TableGen/GlobalISelEmitter.cpp | 24 |
11 files changed, 516 insertions, 262 deletions
diff --git a/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h b/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h index fbbf68f..098f9d6 100644 --- a/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h +++ b/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h @@ -37,6 +37,8 @@ enum class GIMatchTableOpcode : std::uint8_t { CheckOperandBank, CheckOperandClass, CheckIntegerPredicate, + CheckTargetPredicate, + CheckOperandImmediateRanges, CheckOperandDefConstantRanges, CheckOperandDefOpcode, CheckOperandDefOperandConstantRanges, @@ -108,6 +110,10 @@ public: const TargetDescription &Target) const; protected: + [[nodiscard]] virtual Expected<bool> + matchesTargetPredicate(std::string_view Name, const MachineInstr &Instruction, + const MachineFunction &Function, const TargetDescription &Target) const; + [[nodiscard]] virtual Expected<std::optional<GIMatchComplexOperand>> renderComplexOperand(std::string_view Name, const MachineInstr &Instruction, const MachineFunction &Function, const TargetDescription &Target, diff --git a/backend/include/rcc/TableGen/Record.h b/backend/include/rcc/TableGen/Record.h index 6575b82..1f9dea9 100644 --- a/backend/include/rcc/TableGen/Record.h +++ b/backend/include/rcc/TableGen/Record.h @@ -235,15 +235,26 @@ struct SourceSelectionIntegerPredicate final { TextRange Range; }; -struct SourceSelectionOperandDefConstantPredicate final { +struct SourceSelectionTargetPredicate final { + std::string Symbol; + TextRange Range; +}; + +struct SourceSelectionConstantRange final { + std::int64_t Minimum = 0; + std::int64_t Maximum = 0; + TextRange SourceRange; +}; + +struct SourceSelectionOperandImmediatePredicate final { std::uint32_t OperandIndex = 0; - struct ConstantRange final { - std::int64_t Minimum = 0; - std::int64_t Maximum = 0; - TextRange SourceRange; - }; + std::vector<SourceSelectionConstantRange> Ranges; + TextRange Range; +}; - std::vector<ConstantRange> Ranges; +struct SourceSelectionOperandDefConstantPredicate final { + std::uint32_t OperandIndex = 0; + std::vector<SourceSelectionConstantRange> Ranges; TextRange Range; }; @@ -294,9 +305,11 @@ struct SourceSelectionRule final { std::string MatchOpcodeSymbol; std::optional<SourceSelectionTypePredicate> ResultType; std::optional<SourceSelectionIntegerPredicate> IntegerPredicate; + std::vector<SourceSelectionTargetPredicate> TargetPredicates; std::vector<SourceSelectionOperandTypePredicate> OperandTypes; std::vector<SourceSelectionOperandBankPredicate> OperandBanks; std::vector<SourceSelectionOperandClassPredicate> OperandClasses; + std::vector<SourceSelectionOperandImmediatePredicate> OperandImmediates; std::vector<SourceSelectionOperandDefConstantPredicate> OperandDefConstants; std::vector<SourceSelectionDefUsePredicate> DefUsePredicates; std::vector<SourceSelectionTemporary> Temporaries; diff --git a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h index 34ed4bd..c590be6 100644 --- a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h +++ b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h @@ -27,6 +27,7 @@ enum class RISCVExtension : std::uint8_t { F, D, C, + Zba, Zbb, Zicsr, Zifencei, diff --git a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp index 97b6cfe..739f12b 100644 --- a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp +++ b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp @@ -146,21 +146,15 @@ operandOrDefConstantValue(const MachineInstr &Instruction, const MachineFunction return operandDefConstantValue(Instruction, Function, OperandIndex); } -[[nodiscard]] Expected<bool> matchesOperandDefConstantRanges(const GIMatchTable &Table, - const MachineInstr &Instruction, - const MachineFunction &Function, - const GIMatchTableInstruction &Step) { - const std::size_t First = Step.Value; - const std::size_t Count = Step.Auxiliary; +[[nodiscard]] Expected<bool> matchesConstantRanges(const GIMatchTable &Table, std::size_t First, + std::size_t Count, + std::optional<std::int64_t> Value) { if (Count == 0 || First > Table.ConstantRanges.size() || Count > Table.ConstantRanges.size() - First) { return makeUnexpected(ErrorCode::VerificationError, "generated match table has an invalid constant range"); } - auto Value = operandDefConstantValue(Instruction, Function, Step.OperandIndex); if (!Value) - return std::unexpected(Value.error()); - if (!*Value) return false; for (std::size_t Index = First; Index < First + Count; ++Index) { const GIMatchTableConstantRange &Range = Table.ConstantRanges[Index]; @@ -168,12 +162,31 @@ operandOrDefConstantValue(const MachineInstr &Instruction, const MachineFunction return makeUnexpected(ErrorCode::VerificationError, "generated match table has an inverted constant range"); } - if (**Value >= Range.Minimum && **Value <= Range.Maximum) + if (*Value >= Range.Minimum && *Value <= Range.Maximum) return true; } return false; } +[[nodiscard]] Expected<bool> matchesOperandImmediateRanges(const GIMatchTable &Table, + const MachineInstr &Instruction, + const GIMatchTableInstruction &Step) { + const MachineOperand *Operand = Instruction.operandAt(Step.OperandIndex); + const std::optional<std::int64_t> Value = + Operand == nullptr ? std::optional<std::int64_t>{} : immediateValue(*Operand); + return matchesConstantRanges(Table, Step.Value, Step.Auxiliary, Value); +} + +[[nodiscard]] Expected<bool> matchesOperandDefConstantRanges(const GIMatchTable &Table, + const MachineInstr &Instruction, + const MachineFunction &Function, + const GIMatchTableInstruction &Step) { + auto Value = operandDefConstantValue(Instruction, Function, Step.OperandIndex); + if (!Value) + return std::unexpected(Value.error()); + return matchesConstantRanges(Table, Step.Value, Step.Auxiliary, *Value); +} + [[nodiscard]] const MachineInstr *operandDefinition(const MachineInstr &Instruction, const MachineFunction &Function, std::size_t OperandIndex) { @@ -201,30 +214,14 @@ matchesOperandDefOperandConstantRanges(const GIMatchTable &Table, const MachineI return makeUnexpected(ErrorCode::VerificationError, "generated match table has an invalid def-use constant range count"); } - const std::size_t First = Step.Value; const std::size_t Count = static_cast<std::size_t>(Step.Immediate); - if (First > Table.ConstantRanges.size() || Count > Table.ConstantRanges.size() - First) { - return makeUnexpected(ErrorCode::VerificationError, - "generated match table has an invalid def-use constant range"); - } const MachineInstr *Definition = operandDefinition(Instruction, Function, Step.OperandIndex); if (Definition == nullptr) return false; auto Value = operandOrDefConstantValue(*Definition, Function, Step.Auxiliary); if (!Value) return std::unexpected(Value.error()); - if (!*Value) - return false; - for (std::size_t Index = First; Index < First + Count; ++Index) { - const GIMatchTableConstantRange &Range = Table.ConstantRanges[Index]; - if (Range.Minimum > Range.Maximum) { - return makeUnexpected(ErrorCode::VerificationError, - "generated match table has an inverted def-use constant range"); - } - if (**Value >= Range.Minimum && **Value <= Range.Maximum) - return true; - } - return false; + return matchesConstantRanges(Table, Step.Value, Count, *Value); } [[nodiscard]] Expected<RegisterOperandFlags> registerFlagsFromRaw(std::uint32_t Raw) { @@ -303,10 +300,11 @@ findCapturedOperand(const std::vector<MatchedRule::CapturedOperand> &Captures, s return Position == Captures.end() ? nullptr : &*Position; } -[[nodiscard]] Expected<std::optional<MatchedRule>> matchRule(const GIMatchTable &Table, - const GIMatchTableRule &Rule, - const MachineInstr &Instruction, - const MachineFunction &Function) { +template <typename TargetPredicateMatcher> +[[nodiscard]] Expected<std::optional<MatchedRule>> +matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const MachineInstr &Instruction, + const MachineFunction &Function, const TargetDescription &Target, + TargetPredicateMatcher &&MatchesTargetPredicate) { const std::size_t First = Rule.FirstInstruction; const std::size_t Count = Rule.InstructionCount; if (First > Table.Instructions.size() || Count > Table.Instructions.size() - First) { @@ -376,6 +374,30 @@ findCapturedOperand(const std::vector<MatchedRule::CapturedOperand> &Captures, s return std::optional<MatchedRule>{}; break; } + case GIMatchTableOpcode::CheckTargetPredicate: { + if (Applying || Step.Symbol.empty()) { + return makeUnexpected(ErrorCode::VerificationError, + "generated match table has an invalid target predicate"); + } + auto Matched = MatchesTargetPredicate(Step.Symbol, Instruction, Function, Target); + if (!Matched) + return std::unexpected(Matched.error()); + if (!*Matched) + return std::optional<MatchedRule>{}; + break; + } + case GIMatchTableOpcode::CheckOperandImmediateRanges: { + if (Applying) { + return makeUnexpected(ErrorCode::VerificationError, + "generated match table performs a predicate after an action"); + } + auto Matched = matchesOperandImmediateRanges(Table, Instruction, Step); + if (!Matched) + return std::unexpected(Matched.error()); + if (!*Matched) + return std::optional<MatchedRule>{}; + break; + } case GIMatchTableOpcode::CheckOperandDefConstantRanges: { if (Applying) { return makeUnexpected(ErrorCode::VerificationError, @@ -1175,6 +1197,15 @@ Expected<void> GIMatchTableExecutor::finalizeGeneratedInstruction(MachineInstr & return {}; } +Expected<bool> GIMatchTableExecutor::matchesTargetPredicate(std::string_view Name, + const MachineInstr &, + const MachineFunction &, + const TargetDescription &) const { + return makeUnexpected(ErrorCode::VerificationError, + "generated match table uses unknown target predicate '" + + std::string(Name) + "'"); +} + Expected<std::optional<GIMatchComplexOperand>> GIMatchTableExecutor::renderComplexOperand(std::string_view, const MachineInstr &, const MachineFunction &, const TargetDescription &, @@ -1187,7 +1218,12 @@ Expected<bool> GIMatchTableExecutor::match(const GIMatchTable &Table, const MachineFunction &Function, const TargetDescription &Target) const { for (const GIMatchTableRule &Rule : Table.Rules) { - auto Match = matchRule(Table, Rule, Instruction, Function); + auto Match = matchRule(Table, Rule, Instruction, Function, Target, + [this](std::string_view Name, const MachineInstr &Input, + const MachineFunction &InputFunction, + const TargetDescription &InputTarget) { + return matchesTargetPredicate(Name, Input, InputFunction, InputTarget); + }); if (!Match) return std::unexpected(Match.error()); if (!*Match) @@ -1218,7 +1254,12 @@ Expected<bool> GIMatchTableExecutor::select(const GIMatchTable &Table, MachineIn MachineFunction &Function, const TargetDescription &Target) const { for (const GIMatchTableRule &Rule : Table.Rules) { - auto Match = matchRule(Table, Rule, Instruction, Function); + auto Match = matchRule(Table, Rule, Instruction, Function, Target, + [this](std::string_view Name, const MachineInstr &Input, + const MachineFunction &InputFunction, + const TargetDescription &InputTarget) { + return matchesTargetPredicate(Name, Input, InputFunction, InputTarget); + }); if (!Match) return std::unexpected(Match.error()); if (!*Match) diff --git a/backend/lib/TableGen/Parser.cpp b/backend/lib/TableGen/Parser.cpp index b4ff73c..7c6a8de 100644 --- a/backend/lib/TableGen/Parser.cpp +++ b/backend/lib/TableGen/Parser.cpp @@ -1173,6 +1173,92 @@ private: return true; } + [[nodiscard]] bool + parseSelectionTargetPredicates(const yaml::Node &Node, + std::vector<SourceSelectionTargetPredicate> &Result) { + if (!requireSequence(&Node, "selection target predicates")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (Element == nullptr) + return false; + const auto Symbol = scalar(*Element, "selection target predicate"); + if (!Symbol) + return false; + Result.push_back({ + .Symbol = *Symbol, + .Range = Element->range(), + }); + } + return true; + } + + [[nodiscard]] bool parseSelectionConstantRanges(const yaml::Node &Node, + std::vector<SourceSelectionConstantRange> &Result, + std::string_view Context) { + if (!requireSequence(&Node, Context) || Node.sequence().empty()) + return false; + for (const yaml::NodeID RangeID : Node.sequence()) { + const yaml::Node *Range = Input.node(RangeID); + const std::string RangeContext = std::string(Context) + " range"; + if (!requireMapping(Range, RangeContext) || + !checkKeys(*Range, {"min", "max"}, RangeContext)) { + return false; + } + const yaml::Node *MinimumNode = requiredNode(*Range, "min", RangeContext); + const yaml::Node *MaximumNode = requiredNode(*Range, "max", RangeContext); + if (MinimumNode == nullptr || MaximumNode == nullptr) + return false; + const auto Minimum = signedInteger(*MinimumNode, "selection constant range minimum"); + const auto Maximum = signedInteger(*MaximumNode, "selection constant range maximum"); + if (!Minimum || !Maximum || *Minimum > *Maximum) { + if (Minimum && Maximum) + fail(Range->range(), "selection constant range is invalid"); + return false; + } + Result.push_back({ + .Minimum = *Minimum, + .Maximum = *Maximum, + .SourceRange = Range->range(), + }); + } + return true; + } + + [[nodiscard]] bool + parseSelectionOperandImmediates(const yaml::Node &Node, + std::vector<SourceSelectionOperandImmediatePredicate> &Result) { + if (!requireSequence(&Node, "selection operand immediates")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "selection operand immediate") || + !checkKeys(*Element, {"index", "ranges"}, "selection operand immediate")) { + return false; + } + const yaml::Node *IndexNode = requiredNode(*Element, "index", "selection operand immediate"); + const yaml::Node *RangesNode = + requiredNode(*Element, "ranges", "selection operand immediate"); + if (IndexNode == nullptr || RangesNode == nullptr) + return false; + const auto Index = unsignedInteger32(*IndexNode, "selection operand immediate index"); + if (!Index) + return false; + + SourceSelectionOperandImmediatePredicate Predicate{ + .OperandIndex = *Index, + .Ranges = {}, + .Range = Element->range(), + }; + if (!parseSelectionConstantRanges(*RangesNode, Predicate.Ranges, + "selection operand immediate ranges")) { + return false; + } + Result.push_back(std::move(Predicate)); + } + return true; + } + [[nodiscard]] bool parseSelectionOperandDefConstants( const yaml::Node &Node, std::vector<SourceSelectionOperandDefConstantPredicate> &Result) { if (!requireSequence(&Node, "selection operand definition constants")) @@ -1191,8 +1277,7 @@ private: return false; const auto Index = unsignedInteger32(*IndexNode, "selection operand definition constant index"); - if (!Index || !requireSequence(RangesNode, "selection operand definition constant ranges") || - RangesNode->sequence().empty()) { + if (!Index) { return false; } @@ -1201,30 +1286,9 @@ private: .Ranges = {}, .Range = Element->range(), }; - for (const yaml::NodeID RangeID : RangesNode->sequence()) { - const yaml::Node *Range = Input.node(RangeID); - if (!requireMapping(Range, "selection operand definition constant range") || - !checkKeys(*Range, {"min", "max"}, "selection operand definition constant range")) { - return false; - } - const yaml::Node *MinimumNode = - requiredNode(*Range, "min", "selection operand definition constant range"); - const yaml::Node *MaximumNode = - requiredNode(*Range, "max", "selection operand definition constant range"); - if (MinimumNode == nullptr || MaximumNode == nullptr) - return false; - const auto Minimum = signedInteger(*MinimumNode, "selection constant range minimum"); - const auto Maximum = signedInteger(*MaximumNode, "selection constant range maximum"); - if (!Minimum || !Maximum || *Minimum > *Maximum) { - if (Minimum && Maximum) - fail(Range->range(), "selection operand definition constant range is invalid"); - return false; - } - Predicate.Ranges.push_back({ - .Minimum = *Minimum, - .Maximum = *Maximum, - .SourceRange = Range->range(), - }); + if (!parseSelectionConstantRanges(*RangesNode, Predicate.Ranges, + "selection operand definition constant ranges")) { + return false; } Result.push_back(std::move(Predicate)); } @@ -1472,8 +1536,9 @@ private: [[nodiscard]] bool parseSelectionRuleMatch(const yaml::Node &Node, SourceSelectionRule &Result) { if (!requireMapping(&Node, "selection rule match") || !checkKeys(Node, - {"opcode", "result_type", "integer_predicate", "operand_types", "operand_banks", - "operand_classes", "operand_def_constants", "def_use"}, + {"opcode", "result_type", "integer_predicate", "target_predicates", + "operand_types", "operand_banks", "operand_classes", "operand_immediates", + "operand_def_constants", "def_use"}, "selection rule match")) { return false; } @@ -1491,6 +1556,10 @@ private: if (!parseSelectionIntegerPredicate(*Predicate, Result)) return false; } + if (const yaml::Node *TargetPredicates = optionalNode(Node, "target_predicates")) { + if (!parseSelectionTargetPredicates(*TargetPredicates, Result.TargetPredicates)) + return false; + } if (const yaml::Node *OperandTypes = optionalNode(Node, "operand_types")) { if (!parseSelectionOperandTypes(*OperandTypes, Result.OperandTypes)) return false; @@ -1503,6 +1572,10 @@ private: if (!parseSelectionOperandClasses(*OperandClasses, Result.OperandClasses)) return false; } + if (const yaml::Node *OperandImmediates = optionalNode(Node, "operand_immediates")) { + if (!parseSelectionOperandImmediates(*OperandImmediates, Result.OperandImmediates)) + return false; + } if (const yaml::Node *OperandDefConstants = optionalNode(Node, "operand_def_constants")) { if (!parseSelectionOperandDefConstants(*OperandDefConstants, Result.OperandDefConstants)) return false; diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index 64cbf47..898b366 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -147,6 +147,16 @@ public: const RISCVRegisterBankInfo &RegisterBanks) : Subtarget(Subtarget), RegisterBanks(RegisterBanks) {} + [[nodiscard]] Expected<bool> matchesTargetPredicate(std::string_view Name, const MachineInstr &, + const MachineFunction &, + const TargetDescription &) const override { + if (Name == "zba") + return Subtarget.features().has(RISCVExtension::Zba); + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V generated GlobalISel rule uses unknown target predicate '" + + std::string(Name) + "'"); + } + [[nodiscard]] Expected<void> constrainSelectedInstruction(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) const override { @@ -375,9 +385,6 @@ public: case GenericOpcode::G_PTRTOINT: case GenericOpcode::G_INTTOPTR: case GenericOpcode::G_TRUNC: - case GenericOpcode::G_SEXT: - case GenericOpcode::G_SEXT_INREG: - case GenericOpcode::G_ZEXT: case GenericOpcode::G_FCMP: case GenericOpcode::G_SMULH: case GenericOpcode::G_UMULH: @@ -456,13 +463,9 @@ public: case GenericOpcode::G_INTTOPTR: return Instruction.setOpcode(opcode(GenericOpcode::COPY)); case GenericOpcode::G_ANYEXT: - case GenericOpcode::G_SEXT: - case GenericOpcode::G_ZEXT: - return selectIntegerExtension(Instruction, Function, Target, Generic, Type); + return Instruction.setOpcode(opcode(GenericOpcode::COPY)); case GenericOpcode::G_TRUNC: return Instruction.setOpcode(opcode(GenericOpcode::COPY)); - case GenericOpcode::G_SEXT_INREG: - return selectSignExtendInRegister(Instruction, Function, Target, Type); case GenericOpcode::G_FCMP: return selectFloatingCompare(Instruction, Function, Target); case GenericOpcode::G_SELECT: @@ -890,7 +893,6 @@ private: return {}; } - [[nodiscard]] Expected<void> selectAtomicRMW(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, std::optional<LowLevelType> Type, @@ -975,123 +977,6 @@ private: return Instruction.setOpcode(instructionOpcode(Selected)); } - [[nodiscard]] Expected<void> selectIntegerExtension(MachineInstr &Instruction, - MachineFunction &Function, - const TargetDescription &Target, - GenericOpcode Generic, - std::optional<LowLevelType> Type) const { - const std::optional<LowLevelType> SourceType = operandType(Function, Instruction, 1); - const MachineOperand *DestinationOperand = Instruction.operandAt(0); - const MachineOperand *SourceOperand = Instruction.operandAt(1); - const Register *Destination = - DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); - const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>(); - if (!Type || !SourceType || Destination == nullptr || Source == nullptr) - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V integer extension has invalid register operands"); - const Register DestinationRegister = *Destination; - if (Generic == GenericOpcode::G_ANYEXT) - return Instruction.setOpcode(opcode(GenericOpcode::COPY)); - - const std::uint32_t DestinationBits = Type->scalarBitWidth(); - const std::uint32_t SourceBits = SourceType->scalarBitWidth(); - if (Generic == GenericOpcode::G_SEXT && DestinationBits == 64 && SourceBits == 32) { - auto ImmediateResult = appendImmediate(Instruction, 0); - if (!ImmediateResult) - return std::unexpected(ImmediateResult.error()); - return Instruction.setOpcode(instructionOpcode(InstructionOpcode::ADDIW)); - } - - const std::uint32_t ContainerBits = DestinationBits <= 32 ? 32 : 64; - const std::int64_t Shift = static_cast<std::int64_t>(ContainerBits - SourceBits); - const InstructionOpcode ShiftLeft = - ContainerBits == 32 ? InstructionOpcode::SLLIW : InstructionOpcode::SLLI; - const InstructionOpcode ShiftRight = - Generic == GenericOpcode::G_SEXT - ? (ContainerBits == 32 ? InstructionOpcode::SRAIW : InstructionOpcode::SRAI) - : (ContainerBits == 32 ? InstructionOpcode::SRLIW : InstructionOpcode::SRLI); - auto Temporary = createTemporary(Function, *Type, Target); - if (!Temporary) - return std::unexpected(Temporary.error()); - auto SetDestination = Instruction.operandAt(0)->setRegister(*Temporary); - if (!SetDestination) - return std::unexpected(SetDestination.error()); - auto SetOpcode = Instruction.setOpcode(instructionOpcode(ShiftLeft)); - if (!SetOpcode) - return std::unexpected(SetOpcode.error()); - auto ShiftImmediate = appendImmediate(Instruction, Shift); - if (!ShiftImmediate) - return std::unexpected(ShiftImmediate.error()); - - MachineIRBuilder Builder(Function, Target); - auto Shifted = buildImmediateAfter(Builder, Instruction, ShiftRight, DestinationRegister, - *Temporary, Shift); - if (!Shifted) - return std::unexpected(Shifted.error()); - return {}; - } - - [[nodiscard]] Expected<void> selectSignExtendInRegister(MachineInstr &Instruction, - MachineFunction &Function, - const TargetDescription &Target, - std::optional<LowLevelType> Type) const { - const MachineOperand *DestinationOperand = Instruction.operandAt(0); - const MachineOperand *SourceOperand = Instruction.operandAt(1); - const Register *Destination = - DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); - const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>(); - std::optional<std::int64_t> Width; - if (const MachineOperand *WidthOperand = Instruction.operandAt(2); WidthOperand != nullptr) { - auto ParsedWidth = signedImmediate(*WidthOperand); - if (ParsedWidth) - Width = *ParsedWidth; - } - if (!Type || Destination == nullptr || Source == nullptr || !Width || *Width <= 0 || - static_cast<std::uint64_t>(*Width) > Type->scalarBitWidth()) - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V sign-extension-in-register has invalid operands"); - const Register DestinationRegister = *Destination; - if (static_cast<std::uint64_t>(*Width) == Type->scalarBitWidth()) { - auto EraseWidth = Instruction.eraseOperand(2); - if (!EraseWidth) - return std::unexpected(EraseWidth.error()); - return Instruction.setOpcode(opcode(GenericOpcode::COPY)); - } - - const std::uint32_t TypeBits = Type->scalarBitWidth(); - if (TypeBits == 64 && *Width == 32) { - auto ImmediateResult = replaceImmediate(Instruction, 2, 0); - if (!ImmediateResult) - return std::unexpected(ImmediateResult.error()); - return Instruction.setOpcode(instructionOpcode(InstructionOpcode::ADDIW)); - } - const std::uint32_t ContainerBits = TypeBits <= 32 ? 32 : 64; - const std::int64_t Shift = static_cast<std::int64_t>(ContainerBits) - *Width; - const InstructionOpcode ShiftLeft = - ContainerBits == 32 ? InstructionOpcode::SLLIW : InstructionOpcode::SLLI; - const InstructionOpcode ShiftRight = - ContainerBits == 32 ? InstructionOpcode::SRAIW : InstructionOpcode::SRAI; - auto Temporary = createTemporary(Function, *Type, Target); - if (!Temporary) - return std::unexpected(Temporary.error()); - auto SetDestination = Instruction.operandAt(0)->setRegister(*Temporary); - if (!SetDestination) - return std::unexpected(SetDestination.error()); - auto SetOpcode = Instruction.setOpcode(instructionOpcode(ShiftLeft)); - if (!SetOpcode) - return std::unexpected(SetOpcode.error()); - auto ShiftImmediate = replaceImmediate(Instruction, 2, Shift); - if (!ShiftImmediate) - return std::unexpected(ShiftImmediate.error()); - - MachineIRBuilder Builder(Function, Target); - auto Shifted = buildImmediateAfter(Builder, Instruction, ShiftRight, DestinationRegister, - *Temporary, Shift); - if (!Shifted) - return std::unexpected(Shifted.error()); - return {}; - } - [[nodiscard]] Expected<void> selectFloatingCompare(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) const { diff --git a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc index e096993..1667f66 100644 --- a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc +++ b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc @@ -1,5 +1,198 @@ selection_rules: - + id: select_g_sext_s64_s32 + priority: 500 + match: + opcode: G_SEXT + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 32 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + apply: + instructions: + - opcode: ADDIW + root: true + operands: [{ operand: 0 }, { operand: 1 }, { immediate: 0 }] + - + id: select_g_sext_s64_s16 + priority: 400 + match: + opcode: G_SEXT + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 16 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + apply: + temporaries: + - { id: extended, type_from_operand: 0 } + instructions: + - opcode: SLLI + root: true + operands: + - { temporary: extended, flags: [define] } + - { operand: 1 } + - { immediate: 48 } + - opcode: SRAI + root: false + operands: + - { operand: 0 } + - { temporary: extended, flags: [use] } + - { immediate: 48 } + - + id: select_g_sext_s32_s16 + priority: 400 + match: + opcode: G_SEXT + result_type: { kind: scalar, bits: 32 } + operand_types: + - { index: 1, kind: scalar, bits: 16 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + apply: + temporaries: + - { id: extended, type_from_operand: 0 } + instructions: + - opcode: SLLIW + root: true + operands: + - { temporary: extended, flags: [define] } + - { operand: 1 } + - { immediate: 16 } + - opcode: SRAIW + root: false + operands: + - { operand: 0 } + - { temporary: extended, flags: [use] } + - { immediate: 16 } + - + id: select_g_zext_s64_s32_zba + priority: 500 + match: + opcode: G_ZEXT + result_type: { kind: scalar, bits: 64 } + target_predicates: [zba] + operand_types: + - { index: 1, kind: scalar, bits: 32 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + apply: + instructions: + - opcode: ADD_UW + root: true + operands: + - { operand: 0 } + - { operand: 1 } + - { physical_register: X0, flags: [use] } + - + id: select_g_zext_s64_s32 + priority: 400 + match: + opcode: G_ZEXT + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 32 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + apply: + temporaries: + - { id: extended, type_from_operand: 0 } + instructions: + - opcode: SLLI + root: true + operands: + - { temporary: extended, flags: [define] } + - { operand: 1 } + - { immediate: 32 } + - opcode: SRLI + root: false + operands: + - { operand: 0 } + - { temporary: extended, flags: [use] } + - { immediate: 32 } + - + id: select_g_zext_s64_s16 + priority: 400 + match: + opcode: G_ZEXT + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 16 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + apply: + temporaries: + - { id: extended, type_from_operand: 0 } + instructions: + - opcode: SLLI + root: true + operands: + - { temporary: extended, flags: [define] } + - { operand: 1 } + - { immediate: 48 } + - opcode: SRLI + root: false + operands: + - { operand: 0 } + - { temporary: extended, flags: [use] } + - { immediate: 48 } + - + id: select_g_zext_s32_s16 + priority: 400 + match: + opcode: G_ZEXT + result_type: { kind: scalar, bits: 32 } + operand_types: + - { index: 1, kind: scalar, bits: 16 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + apply: + temporaries: + - { id: extended, type_from_operand: 0 } + instructions: + - opcode: SLLIW + root: true + operands: + - { temporary: extended, flags: [define] } + - { operand: 1 } + - { immediate: 16 } + - opcode: SRLIW + root: false + operands: + - { operand: 0 } + - { temporary: extended, flags: [use] } + - { immediate: 16 } + - + id: select_g_sext_inreg_s64_32 + priority: 500 + match: + opcode: G_SEXT_INREG + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + operand_immediates: + - index: 2 + ranges: [{ min: 32, max: 32 }] + apply: + instructions: + - opcode: ADDIW + root: true + operands: + - { operand: 0 } + - { operand: 1 } + - { immediate: 0 } + - id: select_g_ptr_add_immediate priority: 400 match: diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp index e38a574..b6370fd 100644 --- a/backend/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp @@ -32,6 +32,7 @@ constexpr std::array ExtensionNames{ ExtensionName{"f", RISCVExtension::F}, ExtensionName{"d", RISCVExtension::D}, ExtensionName{"c", RISCVExtension::C}, + ExtensionName{"zba", RISCVExtension::Zba}, ExtensionName{"zbb", RISCVExtension::Zbb}, ExtensionName{"zicsr", RISCVExtension::Zicsr}, ExtensionName{"zifencei", RISCVExtension::Zifencei}, diff --git a/backend/utils/TableGen/Common/CodeGenSelection.cpp b/backend/utils/TableGen/Common/CodeGenSelection.cpp index 88f85f7..d3bc299 100644 --- a/backend/utils/TableGen/Common/CodeGenSelection.cpp +++ b/backend/utils/TableGen/Common/CodeGenSelection.cpp @@ -170,6 +170,36 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { } return NormalizedSelectionTypePredicate{.Kind = Kind, .Bits = Source.Bits}; }; + const auto NormalizeRanges = [this](const std::vector<SourceSelectionConstantRange> &Ranges, + TextRange PredicateRange, std::string_view PredicateName) + -> std::optional<std::vector<NormalizedSelectionConstantRange>> { + if (Ranges.empty()) { + fail(PredicateRange, std::string(PredicateName) + " requires at least one range"); + return std::nullopt; + } + std::vector<NormalizedSelectionConstantRange> NormalizedRanges; + NormalizedRanges.reserve(Ranges.size()); + for (const SourceSelectionConstantRange &Range : Ranges) { + if (Range.Minimum > Range.Maximum) { + fail(Range.SourceRange, std::string(PredicateName) + " range is invalid"); + return std::nullopt; + } + NormalizedRanges.push_back({ + .Minimum = Range.Minimum, + .Maximum = Range.Maximum, + }); + } + std::ranges::sort(NormalizedRanges, {}, &NormalizedSelectionConstantRange::Minimum); + for (std::size_t Index = 1; Index < NormalizedRanges.size(); ++Index) { + const auto &Previous = NormalizedRanges[Index - 1]; + const auto &Current = NormalizedRanges[Index]; + if (Current.Minimum <= Previous.Maximum) { + fail(PredicateRange, std::string(PredicateName) + " ranges overlap"); + return std::nullopt; + } + } + return NormalizedRanges; + }; NormalizedSelectionRule Normalized; Normalized.Symbol = Rule.Symbol; @@ -213,6 +243,17 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { ++Normalized.Specificity; } + std::unordered_set<std::string> TargetPredicateSymbols; + for (const SourceSelectionTargetPredicate &Predicate : Rule.TargetPredicates) { + if (!isIdentifier(Predicate.Symbol) || + !TargetPredicateSymbols.insert(Predicate.Symbol).second) { + fail(Predicate.Range, "selection target predicates require distinct identifiers"); + return false; + } + Normalized.TargetPredicates.push_back(Predicate.Symbol); + ++Normalized.Specificity; + } + std::unordered_set<std::uint32_t> TypeOperands; for (const SourceSelectionOperandTypePredicate &Predicate : Rule.OperandTypes) { auto Type = NormalizeType(Predicate.Type); @@ -261,43 +302,40 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { ++Normalized.Specificity; } + std::unordered_set<std::uint32_t> ImmediateOperands; + for (const SourceSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) { + if (!ImmediateOperands.insert(Predicate.OperandIndex).second) { + fail(Predicate.Range, "selection operand immediate predicates require distinct operands"); + return false; + } + auto Ranges = NormalizeRanges(Predicate.Ranges, Predicate.Range, + "selection operand immediate predicate"); + if (!Ranges) + return false; + Normalized.OperandImmediates.push_back({ + .OperandIndex = Predicate.OperandIndex, + .Ranges = std::move(*Ranges), + }); + ++Normalized.Specificity; + } + std::unordered_set<std::uint32_t> ConstantOperands; for (const SourceSelectionOperandDefConstantPredicate &Predicate : Rule.OperandDefConstants) { if (!ConstantOperands.insert(Predicate.OperandIndex).second || (MatchInstruction != nullptr && - !isRegisterOperand(*MatchInstruction, Predicate.OperandIndex)) || - Predicate.Ranges.empty()) { + !isRegisterOperand(*MatchInstruction, Predicate.OperandIndex))) { fail(Predicate.Range, - "selection operand definition constant predicates require distinct register " - "operands and at least one range"); + "selection operand definition constant predicates require distinct register operands"); return false; } - NormalizedSelectionOperandDefConstantPredicate NormalizedPredicate{ + auto Ranges = NormalizeRanges(Predicate.Ranges, Predicate.Range, + "selection operand definition constant predicate"); + if (!Ranges) + return false; + Normalized.OperandDefConstants.push_back({ .OperandIndex = Predicate.OperandIndex, - .Ranges = {}, - }; - for (const SourceSelectionOperandDefConstantPredicate::ConstantRange &Range : - Predicate.Ranges) { - if (Range.Minimum > Range.Maximum) { - fail(Range.SourceRange, "selection operand definition constant range is invalid"); - return false; - } - NormalizedPredicate.Ranges.push_back({ - .Minimum = Range.Minimum, - .Maximum = Range.Maximum, - }); - } - std::ranges::sort(NormalizedPredicate.Ranges, {}, - &NormalizedSelectionOperandDefConstantPredicate::Range::Minimum); - for (std::size_t Index = 1; Index < NormalizedPredicate.Ranges.size(); ++Index) { - const auto &Previous = NormalizedPredicate.Ranges[Index - 1]; - const auto &Current = NormalizedPredicate.Ranges[Index]; - if (Current.Minimum <= Previous.Maximum) { - fail(Predicate.Range, "selection operand definition constant ranges overlap"); - return false; - } - } - Normalized.OperandDefConstants.push_back(std::move(NormalizedPredicate)); + .Ranges = std::move(*Ranges), + }); ++Normalized.Specificity; } @@ -338,38 +376,18 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { std::unordered_set<std::uint32_t> ConstantOperandsInDef; for (const SourceSelectionOperandDefConstantPredicate &Constant : Predicate.OperandDefConstants) { - if (!ConstantOperandsInDef.insert(Constant.OperandIndex).second || - Constant.Ranges.empty()) { - fail(Constant.Range, "selection def-use constant predicates require distinct operands " - "and at least one range"); + if (!ConstantOperandsInDef.insert(Constant.OperandIndex).second) { + fail(Constant.Range, "selection def-use constant predicates require distinct operands"); return false; } - NormalizedSelectionOperandDefConstantPredicate NormalizedConstant{ + auto Ranges = NormalizeRanges(Constant.Ranges, Constant.Range, + "selection def-use constant predicate"); + if (!Ranges) + return false; + NormalizedPredicate.OperandDefConstants.push_back({ .OperandIndex = Constant.OperandIndex, - .Ranges = {}, - }; - for (const SourceSelectionOperandDefConstantPredicate::ConstantRange &Range : - Constant.Ranges) { - if (Range.Minimum > Range.Maximum) { - fail(Range.SourceRange, "selection def-use constant range is invalid"); - return false; - } - NormalizedConstant.Ranges.push_back({ - .Minimum = Range.Minimum, - .Maximum = Range.Maximum, - }); - } - std::ranges::sort(NormalizedConstant.Ranges, {}, - &NormalizedSelectionOperandDefConstantPredicate::Range::Minimum); - for (std::size_t Index = 1; Index < NormalizedConstant.Ranges.size(); ++Index) { - const auto &Previous = NormalizedConstant.Ranges[Index - 1]; - const auto &Current = NormalizedConstant.Ranges[Index]; - if (Current.Minimum <= Previous.Maximum) { - fail(Constant.Range, "selection def-use constant ranges overlap"); - return false; - } - } - NormalizedPredicate.OperandDefConstants.push_back(std::move(NormalizedConstant)); + .Ranges = std::move(*Ranges), + }); } Normalized.DefUsePredicates.push_back(std::move(NormalizedPredicate)); Normalized.Specificity += 1U + static_cast<std::uint32_t>(Predicate.Captures.size()) + diff --git a/backend/utils/TableGen/Common/CodeGenTarget.h b/backend/utils/TableGen/Common/CodeGenTarget.h index 47dd598..d66cfee 100644 --- a/backend/utils/TableGen/Common/CodeGenTarget.h +++ b/backend/utils/TableGen/Common/CodeGenTarget.h @@ -194,14 +194,19 @@ struct NormalizedSelectionIntegerPredicate final { std::uint32_t Predicate = 0; }; -struct NormalizedSelectionOperandDefConstantPredicate final { - struct Range final { - std::int64_t Minimum = 0; - std::int64_t Maximum = 0; - }; +struct NormalizedSelectionConstantRange final { + std::int64_t Minimum = 0; + std::int64_t Maximum = 0; +}; +struct NormalizedSelectionOperandImmediatePredicate final { + std::uint32_t OperandIndex = 0; + std::vector<NormalizedSelectionConstantRange> Ranges; +}; + +struct NormalizedSelectionOperandDefConstantPredicate final { std::uint32_t OperandIndex = 0; - std::vector<Range> Ranges; + std::vector<NormalizedSelectionConstantRange> Ranges; }; struct NormalizedSelectionDefUseCapture final { @@ -259,9 +264,11 @@ struct NormalizedSelectionRule final { std::uint32_t MatchOpcode = 0; std::optional<NormalizedSelectionTypePredicate> ResultType; std::optional<NormalizedSelectionIntegerPredicate> IntegerPredicate; + std::vector<std::string> TargetPredicates; std::vector<NormalizedSelectionOperandTypePredicate> OperandTypes; std::vector<NormalizedSelectionOperandBankPredicate> OperandBanks; std::vector<NormalizedSelectionOperandClassPredicate> OperandClasses; + std::vector<NormalizedSelectionOperandImmediatePredicate> OperandImmediates; std::vector<NormalizedSelectionOperandDefConstantPredicate> OperandDefConstants; std::vector<NormalizedSelectionDefUsePredicate> DefUsePredicates; std::vector<NormalizedSelectionTemporary> Temporaries; diff --git a/backend/utils/TableGen/GlobalISelEmitter.cpp b/backend/utils/TableGen/GlobalISelEmitter.cpp index 562ff7c..98568b1 100644 --- a/backend/utils/TableGen/GlobalISelEmitter.cpp +++ b/backend/utils/TableGen/GlobalISelEmitter.cpp @@ -42,8 +42,9 @@ void emitTypePredicate(std::ostream &Output, std::uint32_t OperandIndex, [[nodiscard]] std::size_t instructionCount(const NormalizedSelectionRule &Rule) noexcept { std::size_t Count = 2U + (Rule.ResultType ? 1U : 0U) + (Rule.IntegerPredicate ? 1U : 0U) + - Rule.OperandTypes.size() + Rule.OperandBanks.size() + - Rule.OperandClasses.size() + Rule.OperandDefConstants.size() + + Rule.TargetPredicates.size() + Rule.OperandTypes.size() + + Rule.OperandBanks.size() + Rule.OperandClasses.size() + + Rule.OperandImmediates.size() + Rule.OperandDefConstants.size() + Rule.Temporaries.size() + Rule.EraseOperandDefinitions.size(); for (const NormalizedSelectionDefUsePredicate &Predicate : Rule.DefUsePredicates) Count += 1U + Predicate.Captures.size() + Predicate.OperandDefConstants.size(); @@ -60,6 +61,9 @@ std::string emitGlobalISel(const NormalizedTargetModel &Model, std::string_view for (const NormalizedSelectionRule &Rule : Model.SelectionRules) InstructionCount += instructionCount(Rule); for (const NormalizedSelectionRule &Rule : Model.SelectionRules) { + for (const NormalizedSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) { + ConstantRangeCount += Predicate.Ranges.size(); + } for (const NormalizedSelectionOperandDefConstantPredicate &Predicate : Rule.OperandDefConstants) { ConstantRangeCount += Predicate.Ranges.size(); @@ -81,15 +85,19 @@ std::string emitGlobalISel(const NormalizedTargetModel &Model, std::string_view Output << "constexpr std::array<GIMatchTableConstantRange, " << ConstantRangeCount << "> GeneratedGlobalISelConstantRanges = {{\n"; for (const NormalizedSelectionRule &Rule : Model.SelectionRules) { + for (const NormalizedSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) { + for (const NormalizedSelectionConstantRange &Range : Predicate.Ranges) + Output << " {" << Range.Minimum << ", " << Range.Maximum << "},\n"; + } for (const NormalizedSelectionOperandDefConstantPredicate &Predicate : Rule.OperandDefConstants) { - for (const NormalizedSelectionOperandDefConstantPredicate::Range &Range : Predicate.Ranges) + for (const NormalizedSelectionConstantRange &Range : Predicate.Ranges) Output << " {" << Range.Minimum << ", " << Range.Maximum << "},\n"; } for (const NormalizedSelectionDefUsePredicate &DefUse : Rule.DefUsePredicates) { for (const NormalizedSelectionOperandDefConstantPredicate &Predicate : DefUse.OperandDefConstants) { - for (const NormalizedSelectionOperandDefConstantPredicate::Range &Range : Predicate.Ranges) + for (const NormalizedSelectionConstantRange &Range : Predicate.Ranges) Output << " {" << Range.Minimum << ", " << Range.Maximum << "},\n"; } } @@ -106,12 +114,20 @@ std::string emitGlobalISel(const NormalizedTargetModel &Model, std::string_view if (Rule.IntegerPredicate) emitInstruction(Output, "CheckIntegerPredicate", Rule.IntegerPredicate->OperandIndex, Rule.IntegerPredicate->Predicate); + for (const std::string &Predicate : Rule.TargetPredicates) + emitInstruction(Output, "CheckTargetPredicate", 0, 0, "0", 0, Predicate); for (const NormalizedSelectionOperandTypePredicate &Predicate : Rule.OperandTypes) emitTypePredicate(Output, Predicate.OperandIndex, Predicate.Type); for (const NormalizedSelectionOperandBankPredicate &Predicate : Rule.OperandBanks) emitInstruction(Output, "CheckOperandBank", Predicate.OperandIndex, Predicate.Bank); for (const NormalizedSelectionOperandClassPredicate &Predicate : Rule.OperandClasses) emitInstruction(Output, "CheckOperandClass", Predicate.OperandIndex, Predicate.RegClass); + for (const NormalizedSelectionOperandImmediatePredicate &Predicate : Rule.OperandImmediates) { + emitInstruction(Output, "CheckOperandImmediateRanges", Predicate.OperandIndex, + static_cast<std::uint32_t>(FirstConstantRange), + std::to_string(Predicate.Ranges.size())); + FirstConstantRange += Predicate.Ranges.size(); + } for (const NormalizedSelectionOperandDefConstantPredicate &Predicate : Rule.OperandDefConstants) { emitInstruction(Output, "CheckOperandDefConstantRanges", Predicate.OperandIndex, |
