diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-27 17:13:36 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-27 17:13:36 +0800 |
| commit | 3b14bd4d5324b5a280c1ee5567b5526b59e60c5b (patch) | |
| tree | 1881fc10785a8c195c9b1cdb2ddde6c310f63ab7 /backend | |
| parent | dd477bc887546b00144ea6c0a3e03ad366661636 (diff) | |
| download | rcc-project-3b14bd4d5324b5a280c1ee5567b5526b59e60c5b.tar.gz rcc-project-3b14bd4d5324b5a280c1ee5567b5526b59e60c5b.tar.xz | |
[GlobalISel] Generate floating memory selection
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h | 1 | ||||
| -rw-r--r-- | backend/include/rcc/TableGen/Record.h | 3 | ||||
| -rw-r--r-- | backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp | 101 | ||||
| -rw-r--r-- | backend/lib/TableGen/Parser.cpp | 29 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp | 95 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc | 56 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenSelection.cpp | 38 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenTarget.h | 3 | ||||
| -rw-r--r-- | backend/utils/TableGen/GlobalISelEmitter.cpp | 12 |
9 files changed, 179 insertions, 159 deletions
diff --git a/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h b/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h index d8bdc1a..f191db2 100644 --- a/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h +++ b/backend/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h @@ -49,6 +49,7 @@ enum class GIMatchTableOpcode : std::uint8_t { CheckOperandDefOperandConstantRanges, CaptureDefOperand, CreateTemporary, + CreateTemporaryType, MutateOpcode, BuildInstruction, RenderOperand, diff --git a/backend/include/rcc/TableGen/Record.h b/backend/include/rcc/TableGen/Record.h index f3c7d12..525d63f 100644 --- a/backend/include/rcc/TableGen/Record.h +++ b/backend/include/rcc/TableGen/Record.h @@ -348,7 +348,8 @@ struct SourceSelectionDefUsePredicate final { struct SourceSelectionTemporary final { std::string Symbol; - std::uint32_t TypeFromOperand = 0; + std::optional<std::uint32_t> TypeFromOperand; + std::optional<SourceSelectionTypePredicate> Type; TextRange Range; }; diff --git a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp index 39699c2..88fcc24 100644 --- a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp +++ b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp @@ -17,6 +17,7 @@ #include <charconv> #include <cstddef> #include <cstdint> +#include <iterator> #include <limits> #include <optional> #include <ranges> @@ -293,7 +294,7 @@ struct MatchedRule final { struct Temporary final { std::uint32_t ID = 0; - std::uint32_t TypeFromOperand = 0; + LowLevelType Type; }; struct RenderedOperand final { @@ -342,6 +343,10 @@ struct MatchedRule final { [ID](const MatchedRule::CapturedOperand &Capture) { return Capture.ID == ID; }); } +[[nodiscard]] bool hasRootInstruction(const MatchedRule &Rule) { + return std::ranges::any_of(Rule.Instructions, &MatchedRule::Instruction::ReplacesRoot); +} + [[nodiscard]] const MatchedRule::CapturedOperand * findCapturedOperand(const std::vector<MatchedRule::CapturedOperand> &Captures, std::uint32_t ID) { const auto Position = std::ranges::find(Captures, ID, &MatchedRule::CapturedOperand::ID); @@ -565,12 +570,28 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine Applying = true; Result.Temporaries.push_back({ .ID = Step.Value, - .TypeFromOperand = Step.OperandIndex, + .Type = **Type, }); break; } + case GIMatchTableOpcode::CreateTemporaryType: { + if (Complete || Step.Value == 0 || hasTemporary(Result, Step.Value) || + Step.Auxiliary != static_cast<std::uint32_t>(GIMatchTypeKind::Scalar) || + Step.Immediate <= 0 || + static_cast<std::uint64_t>(Step.Immediate) > LowLevelType::MaxBitWidth) { + return makeUnexpected(ErrorCode::VerificationError, + "generated match table has an invalid explicit temporary type"); + } + auto Type = + LowLevelType::makeCategoryNeutralScalar(static_cast<std::uint64_t>(Step.Immediate)); + if (!Type) + return std::unexpected(Type.error()); + Applying = true; + Result.Temporaries.push_back({.ID = Step.Value, .Type = *Type}); + break; + } case GIMatchTableOpcode::MutateOpcode: - if (Complete || Step.Value == 0 || !Result.Instructions.empty()) { + if (Complete || Step.Value == 0 || hasRootInstruction(Result)) { return makeUnexpected(ErrorCode::VerificationError, "generated match table has an invalid root mutation"); } @@ -582,7 +603,7 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine }); break; case GIMatchTableOpcode::BuildInstruction: - if (Complete || Step.Value == 0 || Result.Instructions.empty()) { + if (Complete || Step.Value == 0) { return makeUnexpected(ErrorCode::VerificationError, "generated match table has an invalid instruction action"); } @@ -736,7 +757,7 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine if (!Complete || (Table.Kind == GIMatchTableKind::Selection && - (Result.Instructions.empty() || !Result.Instructions.front().ReplacesRoot)) || + (Result.Instructions.empty() || !hasRootInstruction(Result))) || (Table.Kind == GIMatchTableKind::Combiner && Result.Instructions.empty() && !Result.ReplaceRootCapture) || (Table.Kind == GIMatchTableKind::Combiner && !Result.Instructions.empty() && @@ -1134,6 +1155,13 @@ template <typename Finalizer, typename ComplexRenderer> } return {}; } + const auto RootPosition = + std::ranges::find(Rule.Instructions, true, &MatchedRule::Instruction::ReplacesRoot); + if (RootPosition == Rule.Instructions.end()) + return makeUnexpected(ErrorCode::VerificationError, + "generated match table selection has no root instruction"); + const std::size_t RootIndex = + static_cast<std::size_t>(std::distance(Rule.Instructions.begin(), RootPosition)); const MachineInstrFlags InputFlags = Instruction.flags(); const bool InputMayRaiseFPException = InputDescriptor->Flags.has(InstructionFlag::MayRaiseFPException); @@ -1156,31 +1184,7 @@ template <typename Finalizer, typename ComplexRenderer> std::vector<MaterializedTemporary> Temporaries; Temporaries.reserve(Rule.Temporaries.size()); for (const MatchedRule::Temporary &Temporary : Rule.Temporaries) { - const MachineOperand *SourceOperand = Instruction.operandAt(Temporary.TypeFromOperand); - const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>(); - if (Source == nullptr || !Source->isVirtual()) { - auto Cleanup = eraseTemporaries(Function.registerInfo(), Temporaries); - if (!Cleanup) - return std::unexpected(Cleanup.error()); - return makeUnexpected(ErrorCode::VerificationError, - "generated match table temporary has an invalid type source"); - } - auto SourceInfo = Function.registerInfo().virtualRegisterInfo(*Source); - if (!SourceInfo) { - auto Cleanup = eraseTemporaries(Function.registerInfo(), Temporaries); - if (!Cleanup) - return std::unexpected(Cleanup.error()); - return std::unexpected(SourceInfo.error()); - } - const std::optional<LowLevelType> Type = SourceInfo->get().Type; - if (!Type) { - auto Cleanup = eraseTemporaries(Function.registerInfo(), Temporaries); - if (!Cleanup) - return std::unexpected(Cleanup.error()); - return makeUnexpected(ErrorCode::VerificationError, - "generated match table temporary type source has no type"); - } - auto Reg = Function.registerInfo().createVirtualRegister(*Type); + auto Reg = Function.registerInfo().createVirtualRegister(Temporary.Type); if (!Reg) { auto Cleanup = eraseTemporaries(Function.registerInfo(), Temporaries); if (!Cleanup) @@ -1272,7 +1276,7 @@ template <typename Finalizer, typename ComplexRenderer> return std::unexpected(Cleanup.error()); return std::unexpected(Operand.error()); } - if (InstructionIndex == 0 && + if (InstructionIndex == RootIndex && Rendered.SourceKind == MatchedRule::RenderedOperand::Kind::RootOperand) { if (SourceToOutput[Rendered.Value] && Instruction.operandAt(Rendered.Value)->tiedOperandIndex()) { @@ -1365,30 +1369,38 @@ template <typename Finalizer, typename ComplexRenderer> ComplexAnchor = *Complete; } - MachineInstr *Anchor = &Instruction; - for (std::size_t Index = 1; Index < Rule.Instructions.size(); ++Index) { - auto Point = Builder.setInsertPointAfter(*Anchor); + const auto BuildAction = [&](std::size_t Index, MachineInstr *&Anchor) -> Expected<void> { + auto Point = Anchor == nullptr ? Builder.setInsertPointBefore(Instruction) + : Builder.setInsertPointAfter(*Anchor); if (!Point) - return Rollback(Point.error()); + return std::unexpected(Point.error()); auto Pending = Builder.buildInstr(Rule.Instructions[Index].ResultOpcode); if (!Pending) - return Rollback(Pending.error()); + return std::unexpected(Pending.error()); for (MachineOperand &Operand : RenderedInstructions[Index]) { auto Added = Pending->addOperand(std::move(Operand)); if (!Added) - return Rollback(Added.error()); + return std::unexpected(Added.error()); } auto Built = Pending->build(); if (!Built) - return Rollback(Built.error()); + return std::unexpected(Built.error()); AddedInstructions.push_back(*Built); auto Finalized = Finalize(**Built, InputFlags, InputMayRaiseFPException); if (!Finalized) - return Rollback(Finalized.error()); + return std::unexpected(Finalized.error()); Anchor = *Built; + return {}; + }; + + MachineInstr *BeforeAnchor = ComplexAnchor; + for (std::size_t Index = 0; Index < RootIndex; ++Index) { + auto Built = BuildAction(Index, BeforeAnchor); + if (!Built) + return Rollback(Built.error()); } - const MatchedRule::Instruction &RootAction = Rule.Instructions.front(); + const MatchedRule::Instruction &RootAction = Rule.Instructions[RootIndex]; RootModified = true; auto SetOpcode = Instruction.setOpcode(RootAction.ResultOpcode); if (!SetOpcode) @@ -1398,7 +1410,7 @@ template <typename Finalizer, typename ComplexRenderer> if (!Erased) return Rollback(Erased.error()); } - for (MachineOperand &Operand : RenderedInstructions.front()) { + for (MachineOperand &Operand : RenderedInstructions[RootIndex]) { auto Added = Instruction.addOperand(std::move(Operand)); if (!Added) return Rollback(Added.error()); @@ -1419,6 +1431,13 @@ template <typename Finalizer, typename ComplexRenderer> return Rollback(Tied.error()); } + MachineInstr *AfterAnchor = &Instruction; + for (std::size_t Index = RootIndex + 1U; Index < Rule.Instructions.size(); ++Index) { + auto Built = BuildAction(Index, AfterAnchor); + if (!Built) + return Rollback(Built.error()); + } + for (const Register Reg : Rule.EraseOperandDefinitions) { MachineInstr *Definition = Function.registerInfo().getVRegDef(Reg); if (Definition == nullptr || Definition == &Instruction || diff --git a/backend/lib/TableGen/Parser.cpp b/backend/lib/TableGen/Parser.cpp index 67c7a43..a4e2dfe 100644 --- a/backend/lib/TableGen/Parser.cpp +++ b/backend/lib/TableGen/Parser.cpp @@ -1553,20 +1553,35 @@ private: for (const yaml::NodeID ElementID : Node.sequence()) { const yaml::Node *Element = Input.node(ElementID); if (!requireMapping(Element, "selection temporary") || - !checkKeys(*Element, {"id", "type_from_operand"}, "selection temporary")) { + !checkKeys(*Element, {"id", "type_from_operand", "type"}, "selection temporary")) { return false; } const auto Symbol = requiredScalar(*Element, "id", "selection temporary"); - const yaml::Node *TypeNode = - requiredNode(*Element, "type_from_operand", "selection temporary"); - if (!Symbol || TypeNode == nullptr) + const yaml::Node *TypeFromOperandNode = optionalNode(*Element, "type_from_operand"); + const yaml::Node *TypeNode = optionalNode(*Element, "type"); + if (!Symbol) return false; - const auto TypeFromOperand = unsignedInteger32(*TypeNode, "selection temporary type operand"); - if (!TypeFromOperand) + if ((TypeFromOperandNode == nullptr) == (TypeNode == nullptr)) { + fail(Element->range(), + "selection temporary requires exactly one of type_from_operand and type"); return false; + } + std::optional<std::uint32_t> TypeFromOperand; + std::optional<SourceSelectionTypePredicate> Type; + if (TypeFromOperandNode != nullptr) { + TypeFromOperand = + unsignedInteger32(*TypeFromOperandNode, "selection temporary type operand"); + if (!TypeFromOperand) + return false; + } else { + Type = parseSelectionTypePredicate(*TypeNode, "selection temporary type"); + if (!Type) + return false; + } Result.push_back({ .Symbol = *Symbol, - .TypeFromOperand = *TypeFromOperand, + .TypeFromOperand = TypeFromOperand, + .Type = std::move(Type), .Range = Element->range(), }); } diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index 6486f5c..f87bb78 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -146,14 +146,6 @@ operandType(const MachineFunction &Function, const MachineInstr &Instruction, st (Type.isPointer() && Type.scalarBitWidth() == 64); } -[[nodiscard]] constexpr RegisterBankID fprBank() noexcept { - return RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::FPR)); -} - -[[nodiscard]] Expected<void> appendImmediate(MachineInstr &Instruction, std::int64_t Value) { - return Instruction.addOperand(MachineOperand::immediate(Value)); -} - [[nodiscard]] Expected<void> insertPhysicalRegister(MachineInstr &Instruction, std::size_t Index, PhysicalRegister Reg, RegisterOperandFlag Flag) { @@ -577,10 +569,6 @@ public: const std::optional<LowLevelType> Type = resultType(Function, Instruction); switch (Generic) { - case GenericOpcode::G_FPEXTLOAD: - return selectFloatExtLoad(Instruction, Function, Target); - case GenericOpcode::G_FPTRUNCSTORE: - return selectFloatTruncStore(Instruction, Function, Target); case GenericOpcode::G_CONSTANT: return selectIntegerConstant(Instruction, Function, Target, Type); case GenericOpcode::G_FCONSTANT: @@ -1158,89 +1146,6 @@ private: return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FENCE)); } - [[nodiscard]] Expected<void> selectFloatExtLoad(MachineInstr &Instruction, - MachineFunction &Function, - const TargetDescription &Target) const { - const MachineOperand *DestinationOperand = Instruction.operandAt(0); - const Register *Destination = - DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); - if (Destination == nullptr) - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V floating extension load has no destination register"); - const Register DestinationRegister = *Destination; - auto F32 = LowLevelType::makeCategoryNeutralScalar(32); - if (!F32) - return std::unexpected(F32.error()); - auto Temporary = createTemporary(Function, *F32, Target, fprBank()); - if (!Temporary) - return std::unexpected(Temporary.error()); - auto SetDestination = Instruction.operandAt(0)->setRegister(*Temporary); - if (!SetDestination) - return std::unexpected(SetDestination.error()); - auto Immediate = appendImmediate(Instruction, 0); - if (!Immediate) - return std::unexpected(Immediate.error()); - auto SetOpcode = Instruction.setOpcode(instructionOpcode(InstructionOpcode::FLW)); - if (!SetOpcode) - return std::unexpected(SetOpcode.error()); - MachineIRBuilder Builder(Function, Target); - auto Conversion = buildImmediateAfter(Builder, Instruction, InstructionOpcode::FCVT_D_S, - DestinationRegister, *Temporary, 0); - if (!Conversion) - return std::unexpected(Conversion.error()); - return {}; - } - - [[nodiscard]] Expected<void> selectFloatTruncStore(MachineInstr &Instruction, - MachineFunction &Function, - const TargetDescription &Target) const { - const MachineOperand *ValueOperand = Instruction.operandAt(0); - const Register *Value = ValueOperand == nullptr ? nullptr : ValueOperand->getIf<Register>(); - if (Value == nullptr) - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V floating truncation store has no value register"); - const Register ValueRegister = *Value; - auto F32 = LowLevelType::makeCategoryNeutralScalar(32); - if (!F32) - return std::unexpected(F32.error()); - auto Temporary = createTemporary(Function, *F32, Target, fprBank()); - if (!Temporary) - return std::unexpected(Temporary.error()); - MachineIRBuilder Builder(Function, Target); - auto Point = Builder.setInsertPointBefore(Instruction); - if (!Point) - return std::unexpected(Point.error()); - auto RegisterConstraints = - constrainBuilderRegisters(Function, Target, {*Temporary, ValueRegister}); - if (!RegisterConstraints) - return std::unexpected(RegisterConstraints.error()); - auto Conversion = Builder.buildInstr(instructionOpcode(InstructionOpcode::FCVT_S_D)); - if (!Conversion) - return std::unexpected(Conversion.error()); - auto Def = Conversion->addDef(*Temporary); - if (!Def) - return std::unexpected(Def.error()); - auto Use = Conversion->addUse(ValueRegister); - if (!Use) - return std::unexpected(Use.error()); - auto Rounding = Conversion->addImmediate(0); - if (!Rounding) - return std::unexpected(Rounding.error()); - auto Built = Conversion->build(); - if (!Built) - return std::unexpected(Built.error()); - auto Constraint = constrainSelectedInstruction(**Built, Function, Target); - if (!Constraint) - return std::unexpected(Constraint.error()); - auto SetValue = Instruction.operandAt(0)->setRegister(*Temporary); - if (!SetValue) - return std::unexpected(SetValue.error()); - auto Immediate = appendImmediate(Instruction, 0); - if (!Immediate) - return std::unexpected(Immediate.error()); - return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FSW)); - } - [[nodiscard]] Expected<void> selectIntegerConstant(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, diff --git a/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc b/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc index a5d9107..940da64 100644 --- a/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc +++ b/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc @@ -795,3 +795,59 @@ selection_rules: - { complex: select_condition_code, operand: 1 } - { operand: 2 } - { operand: 3 } + - + id: select_g_fpextload_s32_to_s64 + priority: 300 + match: + opcode: G_FPEXTLOAD + result_type: { kind: scalar, bits: 64 } + memory: { index: 0, bytes: 4 } + operand_types: + - { index: 1, kind: pointer, bits: 64 } + operand_banks: + - { index: 0, bank: FPR } + - { index: 1, bank: GPR } + apply: + temporaries: + - { id: loaded, type: { kind: scalar, bits: 32 } } + instructions: + - opcode: FLW + root: true + operands: + - { temporary: loaded, flags: [define] } + - { complex: addr_reg_imm_base, operand: 1 } + - { complex: addr_reg_imm_offset, operand: 1 } + - opcode: FCVT_D_S + root: false + operands: + - { operand: 0 } + - { temporary: loaded, flags: [use] } + - { immediate: 0 } + - + id: select_g_fptruncstore_s64_to_s32 + priority: 300 + match: + opcode: G_FPTRUNCSTORE + memory: { index: 0, bytes: 4 } + operand_types: + - { index: 0, kind: scalar, bits: 64 } + - { index: 1, kind: pointer, bits: 64 } + operand_banks: + - { index: 0, bank: FPR } + - { index: 1, bank: GPR } + apply: + temporaries: + - { id: rounded, type: { kind: scalar, bits: 32 } } + instructions: + - opcode: FCVT_S_D + root: false + operands: + - { temporary: rounded, flags: [define] } + - { operand: 0 } + - { immediate: 7 } + - opcode: FSW + root: true + operands: + - { temporary: rounded, flags: [use] } + - { complex: addr_reg_imm_base, operand: 1 } + - { complex: addr_reg_imm_offset, operand: 1 } diff --git a/backend/utils/TableGen/Common/CodeGenSelection.cpp b/backend/utils/TableGen/Common/CodeGenSelection.cpp index 5093f67..077a95f 100644 --- a/backend/utils/TableGen/Common/CodeGenSelection.cpp +++ b/backend/utils/TableGen/Common/CodeGenSelection.cpp @@ -481,21 +481,36 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { for (const SourceSelectionTemporary &Temporary : Rule.Temporaries) { if (!isIdentifier(Temporary.Symbol) || !TemporaryIDs.emplace(Temporary.Symbol, TemporaryIDs.size() + 1U).second || - (MatchInstruction != nullptr && - !isRegisterOperand(*MatchInstruction, Temporary.TypeFromOperand))) { - fail(Temporary.Range, - "selection temporary requires a unique identifier and a register type source"); + (Temporary.TypeFromOperand.has_value() == Temporary.Type.has_value())) { + fail(Temporary.Range, "selection temporary requires a unique identifier and one type"); return false; } - Normalized.Temporaries.push_back({ + NormalizedSelectionTemporary NormalizedTemporary{ .ID = TemporaryIDs.at(Temporary.Symbol), - .TypeFromOperand = Temporary.TypeFromOperand, - }); + .TypeFromOperand = std::nullopt, + .Type = std::nullopt, + }; + if (Temporary.TypeFromOperand) { + if (MatchInstruction != nullptr && + !isRegisterOperand(*MatchInstruction, *Temporary.TypeFromOperand)) { + fail(Temporary.Range, + "selection temporary type source must be a matched register operand"); + return false; + } + NormalizedTemporary.TypeFromOperand = *Temporary.TypeFromOperand; + } else { + auto Type = NormalizeType(*Temporary.Type); + if (!Type || Type->Kind != NormalizedSelectionTypeKind::Scalar) { + fail(Temporary.Range, "selection temporary explicit type must be a scalar"); + return false; + } + NormalizedTemporary.Type = *Type; + } + Normalized.Temporaries.push_back(std::move(NormalizedTemporary)); } bool HasRootAction = false; - for (std::size_t ActionIndex = 0; ActionIndex < Rule.Actions.size(); ++ActionIndex) { - const SourceSelectionAction &Action = Rule.Actions[ActionIndex]; + for (const SourceSelectionAction &Action : Rule.Actions) { const auto ResultOpcode = resolveOpcode(Result, Action.ResultOpcodeSymbol); const NormalizedInstruction *ResultInstruction = findInstructionBySymbol(Result, Action.ResultOpcodeSymbol); @@ -509,9 +524,8 @@ bool CodeGenTarget::normalizeSelectionRules(NormalizedTargetModel &Result) { "selection instruction opcode must name a declared target instruction or core pseudo"); return false; } - if (Action.ReplacesRoot == HasRootAction || (Action.ReplacesRoot && ActionIndex != 0)) { - fail(Action.Range, - "selection instructions require exactly one root replacement as their first action"); + if (Action.ReplacesRoot && HasRootAction) { + fail(Action.Range, "selection instructions require exactly one root replacement"); return false; } HasRootAction |= Action.ReplacesRoot; diff --git a/backend/utils/TableGen/Common/CodeGenTarget.h b/backend/utils/TableGen/Common/CodeGenTarget.h index 43c7383..2ab6db1 100644 --- a/backend/utils/TableGen/Common/CodeGenTarget.h +++ b/backend/utils/TableGen/Common/CodeGenTarget.h @@ -298,7 +298,8 @@ struct NormalizedSelectionDefUsePredicate final { struct NormalizedSelectionTemporary final { std::uint32_t ID = 0; - std::uint32_t TypeFromOperand = 0; + std::optional<std::uint32_t> TypeFromOperand; + std::optional<NormalizedSelectionTypePredicate> Type; }; enum class NormalizedSelectionImmediateTransform : std::uint8_t { diff --git a/backend/utils/TableGen/GlobalISelEmitter.cpp b/backend/utils/TableGen/GlobalISelEmitter.cpp index 092969d..3ce9411 100644 --- a/backend/utils/TableGen/GlobalISelEmitter.cpp +++ b/backend/utils/TableGen/GlobalISelEmitter.cpp @@ -162,8 +162,16 @@ std::string emitGlobalISel(const NormalizedTargetModel &Model, std::string_view emitInstruction(Output, "CaptureDefOperand", DefUse.RootOperandIndex, Capture.ID, std::to_string(Capture.OperandIndex)); } - for (const NormalizedSelectionTemporary &Temporary : Rule.Temporaries) - emitInstruction(Output, "CreateTemporary", Temporary.TypeFromOperand, Temporary.ID); + for (const NormalizedSelectionTemporary &Temporary : Rule.Temporaries) { + if (Temporary.TypeFromOperand) { + emitInstruction(Output, "CreateTemporary", *Temporary.TypeFromOperand, Temporary.ID); + continue; + } + emitInstruction(Output, "CreateTemporaryType", 0, Temporary.ID, + "static_cast<std::uint32_t>(GIMatchTypeKind::" + + std::string(typeKindName(Temporary.Type->Kind)) + ")", + Temporary.Type->Bits); + } for (const NormalizedSelectionAction &Action : Rule.Actions) { emitInstruction(Output, Action.ReplacesRoot ? "MutateOpcode" : "BuildInstruction", 0, Action.ResultOpcode); |
