aboutsummaryrefslogtreecommitdiff
path: root/backend/lib
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib')
-rw-r--r--backend/lib/CodeGen/GlobalISel/CMakeLists.txt4
-rw-r--r--backend/lib/CodeGen/GlobalISel/Combiner.cpp103
-rw-r--r--backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp225
-rw-r--r--backend/lib/TableGen/Parser.cpp183
-rw-r--r--backend/lib/Target/RISCV/CMakeLists.txt13
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVGISelCombiner.cpp56
-rw-r--r--backend/lib/Target/RISCV/RISCV.h3
-rw-r--r--backend/lib/Target/RISCV/RISCVGISelCombiner.rccdesc173
-rw-r--r--backend/lib/Target/RISCV/RISCVPipeline.cpp10
9 files changed, 760 insertions, 10 deletions
diff --git a/backend/lib/CodeGen/GlobalISel/CMakeLists.txt b/backend/lib/CodeGen/GlobalISel/CMakeLists.txt
index 5e3c33f..4a96d3a 100644
--- a/backend/lib/CodeGen/GlobalISel/CMakeLists.txt
+++ b/backend/lib/CodeGen/GlobalISel/CMakeLists.txt
@@ -4,6 +4,7 @@ set(
RCCBackendGlobalISelSources
CSEInfo.cpp
CSEMIRBuilder.cpp
+ Combiner.cpp
GIMatchTableExecutor.cpp
GISelChangeObserver.cpp
GISelValueTracking.cpp
@@ -19,6 +20,7 @@ set(
RCCBackendGlobalISelHeaders
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GlobalISel/CSEInfo.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GlobalISel/CSEMIRBuilder.h"
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GlobalISel/Combiner.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GlobalISel/GISelChangeObserver.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/GlobalISel/GISelValueTracking.h"
@@ -39,6 +41,7 @@ target_sources(RCCBackendCodeGen PRIVATE ${RCCBackendGlobalISelSources})
rcc_backend_register_format_files(
"${CMAKE_CURRENT_SOURCE_DIR}/CSEInfo.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/CSEMIRBuilder.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/Combiner.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GIMatchTableExecutor.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISelChangeObserver.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISelValueTracking.cpp"
@@ -54,6 +57,7 @@ rcc_backend_register_format_files(
rcc_backend_register_tidy_files(
"${CMAKE_CURRENT_SOURCE_DIR}/CSEInfo.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/CSEMIRBuilder.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/Combiner.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GIMatchTableExecutor.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISelChangeObserver.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISelValueTracking.cpp"
diff --git a/backend/lib/CodeGen/GlobalISel/Combiner.cpp b/backend/lib/CodeGen/GlobalISel/Combiner.cpp
new file mode 100644
index 0000000..6d65a50
--- /dev/null
+++ b/backend/lib/CodeGen/GlobalISel/Combiner.cpp
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/CodeGen/GlobalISel/Combiner.h"
+
+#include "rcc/CodeGen/GlobalISel/Utils.h"
+#include "rcc/CodeGen/LiveVariables.h"
+#include "rcc/CodeGen/MachineBasicBlock.h"
+#include "rcc/CodeGen/MachineFunction.h"
+#include "rcc/CodeGen/MachineFunctionCloner.h"
+#include "rcc/CodeGen/MachineInstr.h"
+
+#include <optional>
+#include <string>
+
+namespace rcc {
+
+const MachinePassContract &GlobalISelCombinerPass::contract() const noexcept {
+ return Contract;
+}
+
+Expected<MachinePassResult> GlobalISelCombinerPass::run(MachineFunction &Function,
+ const TargetDescription &Target,
+ MachineFunctionAnalysisManager &Analyses) {
+ if (!Function.properties().containsAll(contract().Requires))
+ return makeUnexpected(ErrorCode::VerificationError,
+ "GlobalISel combiner input does not satisfy its stage contract");
+ auto Trial = cloneMachineFunction(
+ Function, Target,
+ MachineFunctionCloneOptions{.NewStableID = Function.stableID(), .NewName = std::nullopt});
+ if (!Trial)
+ return std::unexpected(withErrorContext(Trial.error(), "GlobalISel combiner clone failed: "));
+
+ MachineActionReplay Actions(Analyses, Trial->InstructionStableIDs);
+ auto TrialResult = runImplementation(*Trial->ClonedFunction, Target, Actions);
+ if (!TrialResult)
+ return std::unexpected(TrialResult.error());
+ Actions.beginReplay();
+ auto Result = runImplementation(Function, Target, Actions);
+ if (!Result)
+ return std::unexpected(
+ withErrorContext(Result.error(), "GlobalISel combiner replay diverged: "));
+ auto Replayed = Actions.finishReplay();
+ if (!Replayed)
+ return std::unexpected(Replayed.error());
+ return Result;
+}
+
+Expected<MachinePassResult>
+GlobalISelCombinerPass::runImplementation(MachineFunction &Function,
+ const TargetDescription &Target,
+ MachineActionReplay &Actions) const {
+ if (MaximumRewrites == 0 || MaximumIterations == 0)
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "GlobalISel combiner iteration limits must be nonzero");
+ MachinePassResult Result;
+ std::size_t Rewrites = 0;
+ for (std::size_t Iteration = 0; Iteration < MaximumIterations; ++Iteration) {
+ bool IterationChanged = false;
+ for (MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr;
+ Block = Block->next()) {
+ for (MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;) {
+ MachineInstr *Next = Instruction->next();
+ auto Matches = Executor->match(*Table, *Instruction, Function, Target);
+ if (!Matches)
+ return std::unexpected(Matches.error());
+ if (*Matches && Rewrites < MaximumRewrites) {
+ auto Accepted = Actions.request("gisel-combiner", Function, Instruction->stableID());
+ if (!Accepted)
+ return std::unexpected(Accepted.error());
+ if (*Accepted) {
+ auto Combined = Executor->combine(*Table, *Instruction, Function, Target);
+ if (!Combined)
+ return std::unexpected(Combined.error());
+ if (*Combined) {
+ ++Rewrites;
+ IterationChanged = true;
+ Result.Changed = true;
+ }
+ }
+ }
+ Instruction = Next;
+ }
+ }
+ if (!IterationChanged || Rewrites == MaximumRewrites)
+ break;
+ }
+
+ if (!Result.Changed) {
+ Result.Preserved = PreservedAnalyses::all();
+ return Result;
+ }
+ if (Function.properties().has(MachineFunctionProperty::TracksLiveness)) {
+ auto Rebuilt = rebuildMachineLiveness(Function, Target);
+ if (!Rebuilt)
+ return std::unexpected(Rebuilt.error());
+ }
+ Result.Changes = {MachinePassChange::Instructions, MachinePassChange::Operands,
+ MachinePassChange::Registers};
+ Result.Preserved = PreservedAnalyses::none();
+ return Result;
+}
+
+} // namespace rcc
diff --git a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
index dd8d920..39699c2 100644
--- a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
+++ b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
@@ -62,6 +62,11 @@ namespace {
"generated match table has an invalid type predicate");
}
+[[nodiscard]] bool matchesInstructionFlags(const MachineInstr &Instruction,
+ const GIMatchTableInstruction &Step) noexcept {
+ return (Instruction.flags().rawValue() & Step.Value) == Step.Value;
+}
+
[[nodiscard]] Expected<bool> matchesMemorySize(const MachineInstr &Instruction,
const GIMatchTableInstruction &Step) {
if (Step.Value == 0) {
@@ -299,6 +304,7 @@ struct MatchedRule final {
PhysicalRegister,
Temporary,
CapturedImmediate,
+ CapturedTypeBits,
Immediate,
};
@@ -320,6 +326,8 @@ struct MatchedRule final {
std::vector<CapturedOperand> CapturedOperands;
std::vector<Instruction> Instructions;
std::vector<Register> EraseOperandDefinitions;
+ std::optional<std::uint32_t> ReplaceRootCapture;
+ std::uint32_t ClearInstructionFlags = 0;
};
[[nodiscard]] bool hasTemporary(const MatchedRule &Rule, std::uint32_t ID) {
@@ -378,6 +386,22 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine
return std::optional<MatchedRule>{};
break;
}
+ case GIMatchTableOpcode::CheckInstructionFlag:
+ if (Applying || Step.Value == 0)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table has an invalid instruction flag predicate");
+ if (!matchesInstructionFlags(Instruction, Step))
+ return std::optional<MatchedRule>{};
+ break;
+ case GIMatchTableOpcode::ClearInstructionFlags:
+ if (!Applying || Complete || Step.Value == 0)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table has an invalid flag clear action");
+ if (Result.ClearInstructionFlags != 0)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table clears instruction flags twice");
+ Result.ClearInstructionFlags = Step.Value;
+ break;
case GIMatchTableOpcode::CheckOperandBank: {
if (Applying) {
return makeUnexpected(ErrorCode::VerificationError,
@@ -607,6 +631,18 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine
.ComplexRenderer = {},
});
break;
+ case GIMatchTableOpcode::RenderCapturedTypeBits:
+ if (Complete || Result.Instructions.empty() || Step.Value == 0 ||
+ !hasCapturedOperand(Result, Step.Value)) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table has an invalid captured type renderer");
+ }
+ Result.Instructions.back().Operands.push_back({
+ .SourceKind = MatchedRule::RenderedOperand::Kind::CapturedTypeBits,
+ .Value = Step.Value,
+ .ComplexRenderer = {},
+ });
+ break;
case GIMatchTableOpcode::RenderPhysicalRegister:
if (Complete || Result.Instructions.empty() || Step.Value == 0) {
return makeUnexpected(ErrorCode::VerificationError,
@@ -663,8 +699,18 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine
.Immediate = Step.Immediate,
});
break;
+ case GIMatchTableOpcode::ReplaceRootWithCapturedOperand:
+ if (Table.Kind != GIMatchTableKind::Combiner || Complete || Applying ||
+ !Result.Instructions.empty() || Step.Value == 0 ||
+ !hasCapturedOperand(Result, Step.Value) || Result.ReplaceRootCapture) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table has an invalid root replacement action");
+ }
+ Applying = true;
+ Result.ReplaceRootCapture = Step.Value;
+ break;
case GIMatchTableOpcode::EraseOperandDefinition: {
- if (Complete || Result.Instructions.empty()) {
+ if (Complete || (Result.Instructions.empty() && !Result.ReplaceRootCapture)) {
return makeUnexpected(ErrorCode::VerificationError,
"generated match table has an invalid erased definition");
}
@@ -678,7 +724,8 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine
break;
}
case GIMatchTableOpcode::Complete:
- if (Complete || Result.Instructions.empty() || Index + 1 != First + Count) {
+ if (Complete || (Result.Instructions.empty() && !Result.ReplaceRootCapture) ||
+ Index + 1 != First + Count) {
return makeUnexpected(ErrorCode::VerificationError,
"generated match table has an invalid completion action");
}
@@ -687,7 +734,13 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine
}
}
- if (!Complete || Result.Instructions.empty() || !Result.Instructions.front().ReplacesRoot) {
+ if (!Complete ||
+ (Table.Kind == GIMatchTableKind::Selection &&
+ (Result.Instructions.empty() || !Result.Instructions.front().ReplacesRoot)) ||
+ (Table.Kind == GIMatchTableKind::Combiner && Result.Instructions.empty() &&
+ !Result.ReplaceRootCapture) ||
+ (Table.Kind == GIMatchTableKind::Combiner && !Result.Instructions.empty() &&
+ Result.ReplaceRootCapture)) {
return makeUnexpected(ErrorCode::VerificationError,
"generated match table rule does not complete rendering");
}
@@ -900,6 +953,24 @@ renderOperand(const MatchedRule::RenderedOperand &Rendered, const MachineInstr &
}
return Captured->Operand.cloneDetached();
}
+ case MatchedRule::RenderedOperand::Kind::CapturedTypeBits: {
+ const MatchedRule::CapturedOperand *Captured =
+ findCapturedOperand(CapturedOperands, Rendered.Value);
+ if (Captured == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table renders an unknown captured type");
+ const Register *Reg = Captured->Operand.getIf<Register>();
+ if (Reg == nullptr || !Reg->isVirtual())
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table captured type is not a virtual register");
+ auto Type = Function.registerInfo().getType(*Reg);
+ if (!Type)
+ return std::unexpected(Type.error());
+ if (!Type->isCategoryNeutralScalar())
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated match table captured type is not scalar");
+ return MachineOperand::immediate(static_cast<std::int64_t>(Type->scalarBitWidth()));
+ }
case MatchedRule::RenderedOperand::Kind::PhysicalRegister: {
auto Physical = PhysicalRegister::create(Rendered.Value);
if (!Physical || Target.registers().physicalRegister(*Physical) == nullptr) {
@@ -958,6 +1029,76 @@ renderOperand(const MatchedRule::RenderedOperand &Rendered, const MachineInstr &
"generated match table has an invalid operand renderer");
}
+[[nodiscard]] bool compatibleReplacement(Register Destination, Register Source,
+ const MachineFunction &Function,
+ const TargetDescription &Target) {
+ if (!Destination.isVirtual() || Source.isNoRegister())
+ return false;
+ auto DestinationInfo = Function.registerInfo().virtualRegisterInfo(Destination);
+ if (!DestinationInfo)
+ return false;
+ const VirtualRegisterInfo &DestinationValue = DestinationInfo->get();
+ if (Source.isPhysical()) {
+ const std::optional<PhysicalRegister> Physical = Source.physicalRegister();
+ if (!Physical)
+ return false;
+ if (DestinationValue.RegClass &&
+ !Target.registers().registerClassContains(*DestinationValue.RegClass, *Physical))
+ return false;
+ return !DestinationValue.Bank ||
+ Target.registers().bankContainsRegister(*DestinationValue.Bank, *Physical);
+ }
+ auto SourceInfo = Function.registerInfo().virtualRegisterInfo(Source);
+ if (!SourceInfo)
+ return false;
+ const VirtualRegisterInfo &SourceValue = SourceInfo->get();
+ if (DestinationValue.Type != SourceValue.Type)
+ return false;
+ if (DestinationValue.Bank &&
+ (!SourceValue.Bank ||
+ !Target.registers().registerBanksOverlap(*DestinationValue.Bank, *SourceValue.Bank)))
+ return false;
+ if (DestinationValue.RegClass &&
+ (!SourceValue.RegClass || !Target.registers().registerClassesOverlap(
+ *DestinationValue.RegClass, *SourceValue.RegClass)))
+ return false;
+ return true;
+}
+
+[[nodiscard]] Expected<bool> replaceRootWithCapturedOperand(const MatchedRule &Rule,
+ MachineInstr &Instruction,
+ MachineFunction &Function,
+ const TargetDescription &Target) {
+ if (!Rule.ReplaceRootCapture)
+ return false;
+ const MatchedRule::CapturedOperand *Captured =
+ findCapturedOperand(Rule.CapturedOperands, *Rule.ReplaceRootCapture);
+ const MachineOperand *Definition = Instruction.operandAt(0);
+ const Register *Destination = Definition == nullptr ? nullptr : Definition->getIf<Register>();
+ const Register *Source = Captured == nullptr ? nullptr : Captured->Operand.getIf<Register>();
+ if (Destination == nullptr || Source == nullptr || !Definition->isDef() || Definition->isUse() ||
+ (!Source->isVirtual() && !Source->isPhysical()) || Destination->isNoRegister() ||
+ Source->isNoRegister() || !Destination->isVirtual() ||
+ Function.registerInfo().getUniqueVRegDef(*Destination) != Definition ||
+ !compatibleReplacement(*Destination, *Source, Function, Target)) {
+ return false;
+ }
+ if (Instruction.parent() == nullptr)
+ return makeUnexpected(ErrorCode::InternalError, "generated combiner root is detached");
+ std::vector<MachineOperand *> Uses;
+ for (MachineOperand &Use : Function.registerInfo().useOperands(*Destination, true))
+ Uses.push_back(&Use);
+ for (MachineOperand *Use : Uses) {
+ auto Replaced = Use->setRegister(*Source);
+ if (!Replaced)
+ return std::unexpected(Replaced.error());
+ }
+ auto Erased = eraseInstr(Instruction, Function.registerInfo(), Target);
+ if (!Erased)
+ return std::unexpected(Erased.error());
+ return true;
+}
+
template <typename Finalizer, typename ComplexRenderer>
[[nodiscard]] Expected<void> applyRule(const MatchedRule &Rule, MachineInstr &Instruction,
MachineFunction &Function, const TargetDescription &Target,
@@ -967,6 +1108,32 @@ template <typename Finalizer, typename ComplexRenderer>
return makeUnexpected(ErrorCode::VerificationError,
"generated match table input has no instruction descriptor");
}
+ if (Rule.ReplaceRootCapture) {
+ auto Replaced = replaceRootWithCapturedOperand(Rule, Instruction, Function, Target);
+ if (!Replaced)
+ return std::unexpected(Replaced.error());
+ if (!*Replaced)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated combiner root replacement is incompatible");
+ for (const Register Reg : Rule.EraseOperandDefinitions) {
+ MachineInstr *Definition = Function.registerInfo().getVRegDef(Reg);
+ if (Definition == nullptr || !isTriviallyDead(*Definition, Function.registerInfo(), Target))
+ continue;
+ auto Erased = eraseInstr(*Definition, Function.registerInfo(), Target);
+ if (!Erased)
+ return std::unexpected(Erased.error());
+ }
+ if (Rule.ClearInstructionFlags != 0) {
+ MachineInstrFlags Flags = Instruction.flags();
+ for (std::uint32_t Index = 0; Index < static_cast<std::uint32_t>(MachineInstrFlag::Count);
+ ++Index) {
+ if ((Rule.ClearInstructionFlags & (std::uint32_t{1} << Index)) != 0)
+ Flags.clear(static_cast<MachineInstrFlag>(Index));
+ }
+ Instruction.setFlags(Flags);
+ }
+ return {};
+ }
const MachineInstrFlags InputFlags = Instruction.flags();
const bool InputMayRaiseFPException =
InputDescriptor->Flags.has(InstructionFlag::MayRaiseFPException);
@@ -1262,6 +1429,15 @@ template <typename Finalizer, typename ComplexRenderer>
if (!Erased)
return Rollback(Erased.error());
}
+ if (Rule.ClearInstructionFlags != 0) {
+ MachineInstrFlags Flags = Instruction.flags();
+ for (std::uint32_t Index = 0; Index < static_cast<std::uint32_t>(MachineInstrFlag::Count);
+ ++Index) {
+ if ((Rule.ClearInstructionFlags & (std::uint32_t{1} << Index)) != 0)
+ Flags.clear(static_cast<MachineInstrFlag>(Index));
+ }
+ Instruction.setFlags(Flags);
+ }
return {};
}
@@ -1370,4 +1546,47 @@ Expected<bool> GIMatchTableExecutor::select(const GIMatchTable &Table, MachineIn
return false;
}
+Expected<bool> GIMatchTableExecutor::combine(const GIMatchTable &Table, MachineInstr &Instruction,
+ MachineFunction &Function,
+ const TargetDescription &Target) const {
+ if (Table.Kind != GIMatchTableKind::Combiner)
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "GlobalISel combiner received a selection match table");
+ for (const GIMatchTableRule &Rule : Table.Rules) {
+ 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)
+ continue;
+ if (!(*Match)->ReplaceRootCapture) {
+ for (const MatchedRule::Instruction &Action : (*Match)->Instructions) {
+ if (Target.instructionDescriptor(Action.ResultOpcode) == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "generated combiner selects an unknown instruction opcode");
+ }
+ }
+ auto Applied = applyRule(
+ **Match, Instruction, Function, Target,
+ [this, &Function, &Target](MachineInstr &Output, MachineInstrFlags InputFlags,
+ bool InputMayRaiseFPException) {
+ return finalizeGeneratedInstruction(Output, Function, Target, InputFlags,
+ InputMayRaiseFPException);
+ },
+ [this](std::string_view Name, const MachineInstr &Input,
+ const MachineFunction &InputFunction, const TargetDescription &InputTarget,
+ std::uint32_t OperandIndex) {
+ return renderComplexOperand(Name, Input, InputFunction, InputTarget, OperandIndex);
+ });
+ if (!Applied)
+ return std::unexpected(Applied.error());
+ return true;
+ }
+ return false;
+}
+
} // namespace rcc
diff --git a/backend/lib/TableGen/Parser.cpp b/backend/lib/TableGen/Parser.cpp
index 50588fb..6c3b866 100644
--- a/backend/lib/TableGen/Parser.cpp
+++ b/backend/lib/TableGen/Parser.cpp
@@ -40,7 +40,8 @@ public:
{"schema", "target", "register_units", "registers", "register_banks",
"register_classes", "register_masks", "mir_operand_flags", "named_operands",
"immediate_predicates", "scheduling_classes", "encoding_categories",
- "assembly_formats", "calling_conventions", "instructions", "selection_rules"},
+ "assembly_formats", "calling_conventions", "instructions", "selection_rules",
+ "combiner_rules"},
"target description root")) {
return std::nullopt;
}
@@ -81,6 +82,7 @@ public:
const yaml::Node *InstructionsNode =
requiredNode(*Root, "instructions", "target description root");
const yaml::Node *SelectionRulesNode = optionalNode(*Root, "selection_rules");
+ const yaml::Node *CombinerRulesNode = optionalNode(*Root, "combiner_rules");
if (UnitsNode == nullptr || RegistersNode == nullptr || BanksNode == nullptr ||
ClassesNode == nullptr || MasksNode == nullptr || NamedOperandsNode == nullptr ||
ImmediatePredicatesNode == nullptr || SchedulingClassesNode == nullptr ||
@@ -101,7 +103,9 @@ public:
!parseCallingConventions(*CallingConventionsNode, Result.CallingConventions) ||
!parseInstructions(*InstructionsNode, Result.Instructions) ||
(SelectionRulesNode != nullptr &&
- !parseSelectionRules(*SelectionRulesNode, Result.SelectionRules))) {
+ !parseSelectionRules(*SelectionRulesNode, Result.SelectionRules)) ||
+ (CombinerRulesNode != nullptr &&
+ !parseCombinerRules(*CombinerRulesNode, Result.CombinerRules))) {
return std::nullopt;
}
return Result;
@@ -1712,6 +1716,181 @@ private:
return true;
}
+ [[nodiscard]] bool
+ parseCombinerOperandRenderers(const yaml::Node &Node,
+ std::vector<SourceCombinerOperandRenderer> &Result) {
+ if (!requireSequence(&Node, "combiner operand renderers"))
+ return false;
+ for (const yaml::NodeID ElementID : Node.sequence()) {
+ const yaml::Node *Element = Input.node(ElementID);
+ if (!requireMapping(Element, "combiner operand renderer") ||
+ !checkKeys(*Element, {"operand", "captured_operand", "captured_type_bits", "immediate"},
+ "combiner operand renderer")) {
+ return false;
+ }
+ const yaml::Node *Operand = optionalNode(*Element, "operand");
+ const yaml::Node *CapturedOperand = optionalNode(*Element, "captured_operand");
+ const yaml::Node *CapturedTypeBits = optionalNode(*Element, "captured_type_bits");
+ const yaml::Node *Immediate = optionalNode(*Element, "immediate");
+ const std::uint32_t SourceCount = static_cast<std::uint32_t>(Operand != nullptr) +
+ static_cast<std::uint32_t>(CapturedOperand != nullptr) +
+ static_cast<std::uint32_t>(CapturedTypeBits != nullptr) +
+ static_cast<std::uint32_t>(Immediate != nullptr);
+ if (SourceCount != 1) {
+ fail(Element->range(), "combiner operand renderer requires exactly one source");
+ return false;
+ }
+ SourceCombinerOperandRenderer Renderer{.SourceKind =
+ SourceCombinerOperandRenderer::Kind::RootOperand,
+ .OperandIndex = 0,
+ .CaptureSymbol = {},
+ .Immediate = 0,
+ .Range = Element->range()};
+ if (Operand != nullptr) {
+ const auto Index = unsignedInteger32(*Operand, "combiner operand renderer operand");
+ if (!Index)
+ return false;
+ Renderer.OperandIndex = *Index;
+ } else if (CapturedOperand != nullptr) {
+ const auto Symbol = scalar(*CapturedOperand, "combiner operand renderer captured operand");
+ if (!Symbol)
+ return false;
+ Renderer.SourceKind = SourceCombinerOperandRenderer::Kind::CapturedOperand;
+ Renderer.CaptureSymbol = *Symbol;
+ } else if (CapturedTypeBits != nullptr) {
+ const auto Symbol =
+ scalar(*CapturedTypeBits, "combiner operand renderer captured type bits");
+ if (!Symbol)
+ return false;
+ Renderer.SourceKind = SourceCombinerOperandRenderer::Kind::CapturedTypeBits;
+ Renderer.CaptureSymbol = *Symbol;
+ } else {
+ const auto Value = signedInteger(*Immediate, "combiner operand renderer immediate");
+ if (!Value)
+ return false;
+ Renderer.SourceKind = SourceCombinerOperandRenderer::Kind::Immediate;
+ Renderer.Immediate = *Value;
+ }
+ Result.push_back(std::move(Renderer));
+ }
+ return true;
+ }
+
+ [[nodiscard]] bool parseCombinerRuleMatch(const yaml::Node &Node, SourceCombinerRule &Result) {
+ if (!requireMapping(&Node, "combiner rule match") ||
+ !checkKeys(
+ Node,
+ {"opcode", "result_type", "operand_types", "target_predicates", "flags", "def_use"},
+ "combiner rule match")) {
+ return false;
+ }
+ const auto Opcode = requiredScalar(Node, "opcode", "combiner rule match");
+ if (!Opcode)
+ return false;
+ Result.MatchOpcodeSymbol = *Opcode;
+ if (const yaml::Node *Type = optionalNode(Node, "result_type")) {
+ auto Parsed = parseSelectionTypePredicate(*Type, "combiner result type predicate");
+ if (!Parsed)
+ return false;
+ Result.ResultType = std::move(*Parsed);
+ }
+ if (const yaml::Node *Types = optionalNode(Node, "operand_types")) {
+ if (!parseSelectionOperandTypes(*Types, Result.OperandTypes))
+ return false;
+ }
+ if (const yaml::Node *Predicates = optionalNode(Node, "target_predicates")) {
+ if (!parseSelectionTargetPredicates(*Predicates, Result.TargetPredicates))
+ return false;
+ }
+ if (const yaml::Node *Flags = optionalNode(Node, "flags")) {
+ const auto Parsed = scalarSequence(*Flags, "combiner instruction flags");
+ if (!Parsed)
+ return false;
+ Result.InstructionFlags = *Parsed;
+ }
+ if (const yaml::Node *DefUse = optionalNode(Node, "def_use")) {
+ if (!parseSelectionDefUsePredicates(*DefUse, Result.DefUsePredicates))
+ return false;
+ }
+ return true;
+ }
+
+ [[nodiscard]] bool parseCombinerRuleApply(const yaml::Node &Node, SourceCombinerRule &Result) {
+ if (!requireMapping(&Node, "combiner rule apply") ||
+ !checkKeys(
+ Node,
+ {"action", "capture", "opcode", "operands", "clear_flags", "erase_operand_definitions"},
+ "combiner rule apply")) {
+ return false;
+ }
+ const auto Action = requiredScalar(Node, "action", "combiner rule apply");
+ if (!Action)
+ return false;
+ if (*Action == "replace_root_with_capture") {
+ const auto Capture = requiredScalar(Node, "capture", "combiner rule apply");
+ if (!Capture)
+ return false;
+ Result.Action.Kind = SourceCombinerActionKind::ReplaceRootWithCapturedOperand;
+ Result.Action.CapturedOperandSymbol = *Capture;
+ } else if (*Action == "mutate_root") {
+ const auto Opcode = requiredScalar(Node, "opcode", "combiner rule apply");
+ const yaml::Node *Operands = requiredNode(Node, "operands", "combiner rule apply");
+ if (!Opcode || Operands == nullptr)
+ return false;
+ Result.Action.Kind = SourceCombinerActionKind::MutateRoot;
+ Result.Action.ResultOpcodeSymbol = *Opcode;
+ if (!parseCombinerOperandRenderers(*Operands, Result.Action.OperandRenderers))
+ return false;
+ } else {
+ fail(Node.range(),
+ "combiner rule apply action must be replace_root_with_capture or mutate_root");
+ return false;
+ }
+ if (const yaml::Node *ClearFlags = optionalNode(Node, "clear_flags")) {
+ const auto Parsed = scalarSequence(*ClearFlags, "combiner action clear flags");
+ if (!Parsed)
+ return false;
+ Result.Action.ClearInstructionFlags = *Parsed;
+ }
+ if (const yaml::Node *Erase = optionalNode(Node, "erase_operand_definitions")) {
+ auto Indices = unsignedInteger32Sequence(*Erase, "combiner operand definitions");
+ if (!Indices)
+ return false;
+ Result.EraseOperandDefinitions = std::move(*Indices);
+ }
+ return true;
+ }
+
+ [[nodiscard]] bool parseCombinerRules(const yaml::Node &Node,
+ std::vector<SourceCombinerRule> &Result) {
+ if (!requireSequence(&Node, "combiner_rules"))
+ return false;
+ for (const yaml::NodeID ElementID : Node.sequence()) {
+ const yaml::Node *Element = Input.node(ElementID);
+ if (!requireMapping(Element, "combiner rule") ||
+ !checkKeys(*Element, {"id", "priority", "match", "apply"}, "combiner rule")) {
+ return false;
+ }
+ const auto Symbol = requiredScalar(*Element, "id", "combiner rule");
+ const yaml::Node *PriorityNode = requiredNode(*Element, "priority", "combiner rule");
+ const yaml::Node *MatchNode = requiredNode(*Element, "match", "combiner rule");
+ const yaml::Node *ApplyNode = requiredNode(*Element, "apply", "combiner rule");
+ if (!Symbol || PriorityNode == nullptr || MatchNode == nullptr || ApplyNode == nullptr)
+ return false;
+ const auto Priority = unsignedInteger32(*PriorityNode, "combiner rule priority");
+ if (!Priority)
+ return false;
+ SourceCombinerRule Rule;
+ Rule.Symbol = *Symbol;
+ Rule.Priority = *Priority;
+ Rule.Range = Element->range();
+ if (!parseCombinerRuleMatch(*MatchNode, Rule) || !parseCombinerRuleApply(*ApplyNode, Rule))
+ return false;
+ Result.push_back(std::move(Rule));
+ }
+ return true;
+ }
+
[[nodiscard]] bool parseInstructions(const yaml::Node &Node,
std::vector<SourceInstruction> &Result) {
if (!requireSequence(&Node, "instructions"))
diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt
index 3972a92..2e1e224 100644
--- a/backend/lib/Target/RISCV/CMakeLists.txt
+++ b/backend/lib/Target/RISCV/CMakeLists.txt
@@ -19,6 +19,7 @@ set(
"${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelControlFlow.rccdesc"
"${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelShift.rccdesc"
"${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelFloating.rccdesc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelCombiner.rccdesc"
)
set(RCCBackendRISCVTableGenArguments)
foreach(RCCBackendRISCVDescriptionSource IN LISTS RCCBackendRISCVDescriptionSources)
@@ -40,6 +41,10 @@ set(
RCCBackendRISCVGeneratedGlobalISel
"${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV/RISCVGenGlobalISel.inc"
)
+set(
+ RCCBackendRISCVGeneratedGlobalISelCombiner
+ "${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV/RISCVGenGlobalISelCombiner.inc"
+)
add_custom_command(
OUTPUT
@@ -47,6 +52,7 @@ add_custom_command(
"${RCCBackendRISCVGeneratedInstructionHeader}"
"${RCCBackendRISCVGeneratedTables}"
"${RCCBackendRISCVGeneratedGlobalISel}"
+ "${RCCBackendRISCVGeneratedGlobalISelCombiner}"
COMMAND
"$<TARGET_FILE:RCCBackendTableGenTool>"
${RCCBackendRISCVTableGenArguments}
@@ -54,6 +60,7 @@ add_custom_command(
--instruction-header "${RCCBackendRISCVGeneratedInstructionHeader}"
--tables "${RCCBackendRISCVGeneratedTables}"
--global-isel "${RCCBackendRISCVGeneratedGlobalISel}"
+ --global-isel-combiner "${RCCBackendRISCVGeneratedGlobalISelCombiner}"
DEPENDS RCCBackendTableGenTool ${RCCBackendRISCVDescriptionSources}
COMMENT "Generating RCC RV64GC target tables"
VERBATIM
@@ -66,6 +73,7 @@ add_custom_target(
"${RCCBackendRISCVGeneratedInstructionHeader}"
"${RCCBackendRISCVGeneratedTables}"
"${RCCBackendRISCVGeneratedGlobalISel}"
+ "${RCCBackendRISCVGeneratedGlobalISelCombiner}"
)
set_source_files_properties(
@@ -73,6 +81,7 @@ set_source_files_properties(
"${RCCBackendRISCVGeneratedInstructionHeader}"
"${RCCBackendRISCVGeneratedTables}"
"${RCCBackendRISCVGeneratedGlobalISel}"
+ "${RCCBackendRISCVGeneratedGlobalISelCombiner}"
PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE
)
@@ -80,6 +89,7 @@ add_library(
RCCBackendRISCV
GISel/RISCVCallLowering.cpp
GISel/RISCVInstructionSelector.cpp
+ GISel/RISCVGISelCombiner.cpp
GISel/RISCVLegalizerInfo.cpp
GISel/RISCVRegisterBankInfo.cpp
RISCVInstrInfo.cpp
@@ -106,6 +116,7 @@ add_library(
"${RCCBackendRISCVGeneratedInstructionHeader}"
"${RCCBackendRISCVGeneratedTables}"
"${RCCBackendRISCVGeneratedGlobalISel}"
+ "${RCCBackendRISCVGeneratedGlobalISelCombiner}"
)
add_library(RCCBackend::RISCV ALIAS RCCBackendRISCV)
add_dependencies(RCCBackendRISCV RCCBackendRISCVGeneratedTablesTarget)
@@ -155,6 +166,7 @@ rcc_backend_register_format_files(
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVCallLowering.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVCallLowering.h"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVInstructionSelector.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVGISelCombiner.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVLegalizerInfo.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVLegalizerInfo.h"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVRegisterBankInfo.cpp"
@@ -199,6 +211,7 @@ rcc_backend_register_format_files(
rcc_backend_register_tidy_files(
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVCallLowering.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVInstructionSelector.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVGISelCombiner.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVLegalizerInfo.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GISel/RISCVRegisterBankInfo.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/RISCVInstrInfo.cpp"
diff --git a/backend/lib/Target/RISCV/GISel/RISCVGISelCombiner.cpp b/backend/lib/Target/RISCV/GISel/RISCVGISelCombiner.cpp
new file mode 100644
index 0000000..bf67c0a
--- /dev/null
+++ b/backend/lib/Target/RISCV/GISel/RISCVGISelCombiner.cpp
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "RISCV.h"
+#include "rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h"
+#include "rcc/CodeGen/MachineFunction.h"
+#include "rcc/CodeGen/MachineInstr.h"
+#include "rcc/CodeGen/MachineRegisterInfo.h"
+#include "rcc/CodeGen/TargetDescription.h"
+
+#include <string>
+
+namespace rcc::riscv {
+namespace {
+
+#define GET_GLOBALISEL_COMBINER_TABLE
+#include "RISCVGenGlobalISelCombiner.inc"
+#undef GET_GLOBALISEL_COMBINER_TABLE
+
+class RISCVGISelCombinerExecutor final : public GIMatchTableExecutor {
+protected:
+ [[nodiscard]] Expected<bool>
+ matchesTargetPredicate(std::string_view Name, const MachineInstr &Instruction,
+ const MachineFunction &Function,
+ const TargetDescription &Target) const override {
+ if (Name != "sext_cheaper_than_zext")
+ return GIMatchTableExecutor::matchesTargetPredicate(Name, Instruction, Function, Target);
+ const MachineOperand *Destination = Instruction.operandAt(0);
+ const MachineOperand *Source = Instruction.operandAt(1);
+ const Register *DestinationReg =
+ Destination == nullptr ? nullptr : Destination->getIf<Register>();
+ const Register *SourceReg = Source == nullptr ? nullptr : Source->getIf<Register>();
+ if (DestinationReg == nullptr || SourceReg == nullptr || !DestinationReg->isVirtual() ||
+ !SourceReg->isVirtual())
+ return false;
+ auto DestinationType = Function.registerInfo().getType(*DestinationReg);
+ auto SourceType = Function.registerInfo().getType(*SourceReg);
+ if (!DestinationType || !SourceType)
+ return false;
+ return DestinationType->isCategoryNeutralScalar() && SourceType->isCategoryNeutralScalar() &&
+ DestinationType->scalarBitWidth() == 64 && SourceType->scalarBitWidth() == 32;
+ }
+};
+
+} // namespace
+
+const GIMatchTable &giselCombinerTable() noexcept {
+ static constexpr GIMatchTable Table = generatedGlobalISelCombinerMatchTable();
+ return Table;
+}
+
+const GIMatchTableExecutor &giselCombinerExecutor() noexcept {
+ static const RISCVGISelCombinerExecutor Executor;
+ return Executor;
+}
+
+} // namespace rcc::riscv
diff --git a/backend/lib/Target/RISCV/RISCV.h b/backend/lib/Target/RISCV/RISCV.h
index 1a81f59..4699091 100644
--- a/backend/lib/Target/RISCV/RISCV.h
+++ b/backend/lib/Target/RISCV/RISCV.h
@@ -3,6 +3,7 @@
#ifndef RCC_LIB_TARGET_RISCV_RISCV_H
#define RCC_LIB_TARGET_RISCV_RISCV_H
+#include "rcc/CodeGen/GlobalISel/GIMatchTableExecutor.h"
#include "rcc/CodeGen/MachineCombinerPattern.h"
#include "rcc/CodeGen/MachineOptimizationPipeline.h"
#include "rcc/CodeGen/TargetFrameLowering.h"
@@ -28,6 +29,8 @@ createRISCVInstructionSelector(const RISCVSubtarget &Subtarget,
[[nodiscard]] const TargetFrameLowering &frameLowering() noexcept;
[[nodiscard]] const TargetSchedulingModel &schedulingModel() noexcept;
[[nodiscard]] const TargetMachineCombinerInfo &machineCombinerInfo() noexcept;
+[[nodiscard]] const GIMatchTable &giselCombinerTable() noexcept;
+[[nodiscard]] const GIMatchTableExecutor &giselCombinerExecutor() noexcept;
[[nodiscard]] const TargetMemoryFoldingInfo &memoryFoldingInfo() noexcept;
[[nodiscard]] const TargetPseudoExpansionInfo &pseudoExpansionInfo() noexcept;
[[nodiscard]] MachineOptimizationPipelineTargetInfo optimizationPipelineInfo() noexcept;
diff --git a/backend/lib/Target/RISCV/RISCVGISelCombiner.rccdesc b/backend/lib/Target/RISCV/RISCVGISelCombiner.rccdesc
new file mode 100644
index 0000000..5f8585b
--- /dev/null
+++ b/backend/lib/Target/RISCV/RISCVGISelCombiner.rccdesc
@@ -0,0 +1,173 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+combiner_rules:
+ -
+ id: combine_nneg_zext
+ priority: 500
+ match:
+ opcode: G_ZEXT
+ result_type: { kind: scalar, bits: 64 }
+ operand_types:
+ - { index: 1, kind: scalar, bits: 32 }
+ target_predicates: [sext_cheaper_than_zext]
+ flags: [nneg]
+ def_use:
+ -
+ operand: 1
+ opcode: G_TRUNC
+ captures:
+ - { id: source, operand: 1 }
+ - { id: trunc_result, operand: 0 }
+ apply:
+ action: mutate_root
+ opcode: G_SEXT_INREG
+ operands:
+ - { operand: 0 }
+ - { captured_operand: source }
+ - { captured_type_bits: trunc_result }
+ clear_flags: [nneg]
+ erase_operand_definitions: [1]
+ -
+ id: combine_shl_zero
+ priority: 100
+ match:
+ opcode: G_SHL
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
+ -
+ id: combine_lshr_zero
+ priority: 100
+ match:
+ opcode: G_LSHR
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
+ -
+ id: combine_ashr_zero
+ priority: 100
+ match:
+ opcode: G_ASHR
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
+ -
+ id: combine_sdiv_zero
+ priority: 100
+ match:
+ opcode: G_SDIV
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
+ -
+ id: combine_udiv_zero
+ priority: 100
+ match:
+ opcode: G_UDIV
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
+ -
+ id: combine_srem_zero
+ priority: 100
+ match:
+ opcode: G_SREM
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
+ -
+ id: combine_urem_zero
+ priority: 100
+ match:
+ opcode: G_UREM
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
+ -
+ id: combine_mul_zero
+ priority: 100
+ match:
+ opcode: G_MUL
+ def_use:
+ -
+ operand: 1
+ opcode: G_CONSTANT
+ captures:
+ - { id: zero, operand: 0 }
+ operand_def_constants:
+ - index: 1
+ ranges: [{ min: 0, max: 0 }]
+ apply:
+ action: replace_root_with_capture
+ capture: zero
+ erase_operand_definitions: [1]
diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp
index 00a4398..c24c57f 100644
--- a/backend/lib/Target/RISCV/RISCVPipeline.cpp
+++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp
@@ -6,10 +6,10 @@
#include "GISel/RISCVRegisterBankInfo.h"
#include "RISCV.h"
#include "RISCVInstrInfo.h"
+#include "rcc/CodeGen/GlobalISel/Combiner.h"
#include "rcc/CodeGen/GlobalISel/InstructionSelect.h"
#include "rcc/CodeGen/GlobalISel/Legalizer.h"
#include "rcc/CodeGen/GlobalISel/RegBankSelect.h"
-#include "rcc/CodeGen/MachineCombiner.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineOptimizationPipeline.h"
#include "rcc/CodeGen/MachinePseudoExpansion.h"
@@ -41,8 +41,8 @@ template <typename PassT, typename... ArgumentT>
[[nodiscard]] Expected<void> addInitialPipeline(MachineFunctionPassManager &Pipeline,
const RISCVSubtarget &Subtarget,
RISCVPipelineOptions Options) {
- auto Added = addPass<MachineCombinerPass>(Pipeline, machineCombinerInfo(),
- MachineCombinerStage::PreLegalizer);
+ auto Added = addPass<GlobalISelCombinerPass>(
+ Pipeline, giselCombinerTable(), giselCombinerExecutor(), "riscv-prelegalizer-combiner");
if (!Added)
return std::unexpected(Added.error());
Added = addPass<Legalizer>(Pipeline, Subtarget.getLegalizerInfo(), Options.Optimization,
@@ -99,8 +99,8 @@ Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline,
const MachineFunction &Function,
const RISCVSubtarget &Subtarget, RISCVPipelineOptions Options) {
if (!Function.properties().has(MachineFunctionProperty::Legalized)) {
- auto Added = addPass<MachineCombinerPass>(Pipeline, machineCombinerInfo(),
- MachineCombinerStage::PreLegalizer);
+ auto Added = addPass<GlobalISelCombinerPass>(
+ Pipeline, giselCombinerTable(), giselCombinerExecutor(), "riscv-prelegalizer-combiner");
if (!Added)
return std::unexpected(Added.error());
Added = addPass<Legalizer>(Pipeline, Subtarget.getLegalizerInfo(), Options.Optimization,