aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 21:11:10 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 21:11:10 +0800
commitcd30fb546e389d1fb78ce8e579b3dba3a8fdb52a (patch)
tree891d7065c52e56d3f559b146f3a07055105d9d4e
parent98cae0e8835a1eb8fcb0e43870c04ed934cc51ac (diff)
downloadrcc-project-cd30fb546e389d1fb78ce8e579b3dba3a8fdb52a.tar.gz
rcc-project-cd30fb546e389d1fb78ce8e579b3dba3a8fdb52a.tar.xz
[CodeGen] Match LLVM machine copy propagation
-rw-r--r--backend/include/rcc/CodeGen/MachineCopyPropagation.h14
-rw-r--r--backend/include/rcc/CodeGen/MachineOperand.h2
-rw-r--r--backend/include/rcc/CodeGen/MachineOptimizationPipeline.h7
-rw-r--r--backend/include/rcc/CodeGen/TargetInstrInfo.h16
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVPipeline.h10
-rw-r--r--backend/lib/CodeGen/MachineCopyPropagation.cpp240
-rw-r--r--backend/lib/CodeGen/MachineOperand.cpp20
-rw-r--r--backend/lib/CodeGen/MachineOptimizationPipeline.cpp17
-rw-r--r--backend/lib/Target/RISCV/RISCVInstrInfo.cpp328
-rw-r--r--backend/lib/Target/RISCV/RISCVPipeline.cpp20
-rw-r--r--backend/lib/Tooling/PipelineDriver.cpp12
-rw-r--r--backend/unittests/Target/RISCVLateCodeGenTest.cpp84
12 files changed, 524 insertions, 246 deletions
diff --git a/backend/include/rcc/CodeGen/MachineCopyPropagation.h b/backend/include/rcc/CodeGen/MachineCopyPropagation.h
index ab8b23f..59a3a77 100644
--- a/backend/include/rcc/CodeGen/MachineCopyPropagation.h
+++ b/backend/include/rcc/CodeGen/MachineCopyPropagation.h
@@ -6,26 +6,21 @@
#include "rcc/CodeGen/MachinePassManager.h"
#include <cstddef>
-#include <cstdint>
namespace rcc {
class TargetInstrInfo;
-enum class MachineCopyPropagationStage : std::uint8_t {
- PreRegisterAllocation,
- PostRegisterAllocation,
-};
-
struct MachineCopyPropagationOptions final {
std::size_t MaximumPropagatedCopies = 10'000;
+ bool UseTargetCopyInstructions = false;
};
class MachineCopyPropagationPass final : public MachineFunctionPass {
public:
- MachineCopyPropagationPass(const TargetInstrInfo &Info, MachineCopyPropagationStage Stage,
- MachineCopyPropagationOptions Options = {}) noexcept
- : Info(&Info), Stage(Stage), Options(Options) {}
+ explicit MachineCopyPropagationPass(const TargetInstrInfo &Info,
+ MachineCopyPropagationOptions Options = {}) noexcept
+ : Info(&Info), Options(Options) {}
[[nodiscard]] const MachinePassContract &contract() const noexcept override;
[[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function,
@@ -38,7 +33,6 @@ private:
MachineActionReplay &Actions) const;
const TargetInstrInfo *Info;
- MachineCopyPropagationStage Stage;
MachineCopyPropagationOptions Options;
};
diff --git a/backend/include/rcc/CodeGen/MachineOperand.h b/backend/include/rcc/CodeGen/MachineOperand.h
index ef14638..db04795 100644
--- a/backend/include/rcc/CodeGen/MachineOperand.h
+++ b/backend/include/rcc/CodeGen/MachineOperand.h
@@ -382,6 +382,8 @@ public:
[[nodiscard]] bool isImplicit() const noexcept;
[[nodiscard]] Expected<void> setRegister(Register Reg);
+ [[nodiscard]] Expected<void> changeToImmediate(std::int64_t Value);
+ [[nodiscard]] Expected<void> setImmediate(std::int64_t Value);
[[nodiscard]] Expected<void> setRegisterFlags(RegisterOperandFlags Flags);
[[nodiscard]] Expected<void> setSubReg(SubRegIndex SubReg);
[[nodiscard]] Expected<void> setBasicBlock(MachineBasicBlock &Block);
diff --git a/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h b/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h
index 51b4ed2..911cb86 100644
--- a/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h
+++ b/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h
@@ -23,6 +23,10 @@ struct MachineOptimizationPipelineTargetInfo final {
const TargetSchedulingModel &SchedulingModel;
};
+struct MachineOptimizationPipelineOptions final {
+ bool UseTargetCopyInstructions = false;
+};
+
[[nodiscard]] Expected<void>
registerMachineOptimizationAnalyses(MachineFunctionAnalysisManager &Analyses);
@@ -35,7 +39,8 @@ addSelectedSSAOptimizationPipeline(MachineFunctionPassManager &Pipeline,
[[nodiscard]] Expected<void>
addPostRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline,
- const MachineOptimizationPipelineTargetInfo &TargetInfo);
+ const MachineOptimizationPipelineTargetInfo &TargetInfo,
+ MachineOptimizationPipelineOptions Options = {});
} // namespace rcc
diff --git a/backend/include/rcc/CodeGen/TargetInstrInfo.h b/backend/include/rcc/CodeGen/TargetInstrInfo.h
index 34752c5..8457ede 100644
--- a/backend/include/rcc/CodeGen/TargetInstrInfo.h
+++ b/backend/include/rcc/CodeGen/TargetInstrInfo.h
@@ -16,8 +16,14 @@ namespace rcc {
class MachineBasicBlock;
class MachineFunction;
class MachineInstr;
+class MachineOperand;
class TargetDescription;
+struct MachineCopyOperands final {
+ MachineOperand *Destination = nullptr;
+ MachineOperand *Source = nullptr;
+};
+
struct MachineBranchAnalysis final {
MachineInstr *Conditional = nullptr;
MachineInstr *Unconditional = nullptr;
@@ -57,6 +63,16 @@ public:
const MachineFunction &Function,
const TargetDescription &Target) const = 0;
+ [[nodiscard]] virtual std::optional<MachineCopyOperands>
+ getCopyOperands(MachineInstr &) const noexcept {
+ return std::nullopt;
+ }
+
+ [[nodiscard]] virtual Expected<bool> simplifyInstruction(MachineInstr &, MachineFunction &,
+ const TargetDescription &) const {
+ return false;
+ }
+
[[nodiscard]] virtual Expected<bool> tryConvertToThreeAddress(MachineInstr &, std::size_t,
std::size_t, MachineFunction &,
const TargetDescription &) const {
diff --git a/backend/include/rcc/Target/RISCV/RISCVPipeline.h b/backend/include/rcc/Target/RISCV/RISCVPipeline.h
index 8b27032..267c497 100644
--- a/backend/include/rcc/Target/RISCV/RISCVPipeline.h
+++ b/backend/include/rcc/Target/RISCV/RISCVPipeline.h
@@ -19,11 +19,17 @@ class TargetDescription;
namespace riscv {
+struct RISCVPipelineOptions final {
+ bool UseTargetCopyInstructions = false;
+};
+
[[nodiscard]] Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline,
const MachineFunction &Function,
- const RISCVSubtarget &Subtarget);
+ const RISCVSubtarget &Subtarget,
+ RISCVPipelineOptions Options = {});
[[nodiscard]] Expected<std::unique_ptr<MachineFunctionPass>>
-createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget);
+createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget,
+ RISCVPipelineOptions Options = {});
[[nodiscard]] Expected<std::vector<std::string>>
canonicalPipelinePassNames(const MachineFunction &Function, const RISCVSubtarget &Subtarget);
} // namespace riscv
diff --git a/backend/lib/CodeGen/MachineCopyPropagation.cpp b/backend/lib/CodeGen/MachineCopyPropagation.cpp
index 2c4cc44..aafed4b 100644
--- a/backend/lib/CodeGen/MachineCopyPropagation.cpp
+++ b/backend/lib/CodeGen/MachineCopyPropagation.cpp
@@ -4,13 +4,11 @@
#include "rcc/CodeGen/GenericOpcodes.h"
#include "rcc/CodeGen/InstructionDescriptor.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 "rcc/CodeGen/MachineOperand.h"
-#include "rcc/CodeGen/MachineRegisterInfo.h"
#include "rcc/CodeGen/RegisterMask.h"
#include "rcc/CodeGen/TargetDescription.h"
#include "rcc/CodeGen/TargetInstrInfo.h"
@@ -20,46 +18,26 @@
#include <cstddef>
#include <optional>
#include <ranges>
-#include <string>
#include <utility>
-#include <vector>
namespace rcc {
namespace {
-[[nodiscard]] const MachinePassContract &
-copyPropagationContract(MachineCopyPropagationStage Stage) {
- static const MachinePassContract PreRA = [] {
+[[nodiscard]] const MachinePassContract &copyPropagationContract() {
+ static const MachinePassContract Contract = [] {
MachinePassContract Value{
- .Name = "pre-ra-machine-copy-propagation",
- .Requires = {MachineFunctionProperty::Selected, MachineFunctionProperty::NoPHIs,
- MachineFunctionProperty::TiedOpsRewritten},
+ .Name = "machine-cp",
+ .Requires = {MachineFunctionProperty::NoVRegs},
.Sets = {},
.Clears = {},
.RequiredAnalyses = {},
- .VerificationStage = PipelineStage::TiedOpsRewritten,
- };
- Value.ThreadSafety = PassThreadSafety::ThreadSafe;
- Value.DeclaredChanges = {MachinePassChange::Instructions, MachinePassChange::Operands,
- MachinePassChange::Registers};
- return Value;
- }();
- static const MachinePassContract PostRA = [] {
- MachinePassContract Value{
- .Name = "post-ra-machine-copy-propagation",
- .Requires = {MachineFunctionProperty::Selected, MachineFunctionProperty::NoPHIs,
- MachineFunctionProperty::TiedOpsRewritten, MachineFunctionProperty::NoVRegs,
- MachineFunctionProperty::TracksLiveness},
- .Sets = {},
- .Clears = {},
- .RequiredAnalyses = {},
- .VerificationStage = PipelineStage::RegisterAllocated,
+ .VerificationStage = std::nullopt,
};
Value.ThreadSafety = PassThreadSafety::ThreadSafe;
Value.DeclaredChanges = {MachinePassChange::Instructions, MachinePassChange::Operands};
return Value;
}();
- return Stage == MachineCopyPropagationStage::PreRegisterAllocation ? PreRA : PostRA;
+ return Contract;
}
[[nodiscard]] bool hasProtectedAttachment(const MachineInstr &Instruction) noexcept {
@@ -78,13 +56,25 @@ struct CopyOperands final {
Register Source;
};
-[[nodiscard]] std::optional<CopyOperands> copyOperands(MachineInstr &Instruction) {
- if (Instruction.opcode() != opcode(GenericOpcode::COPY) || Instruction.operandCount() != 2 ||
- hasProtectedAttachment(Instruction)) {
+[[nodiscard]] std::optional<CopyOperands> copyOperands(MachineInstr &Instruction,
+ const TargetInstrInfo &Info,
+ bool UseTargetCopyInstructions) {
+ if (hasProtectedAttachment(Instruction))
return std::nullopt;
+ MachineOperand *DestinationOperand = nullptr;
+ MachineOperand *SourceOperand = nullptr;
+ if (UseTargetCopyInstructions) {
+ const std::optional<MachineCopyOperands> TargetCopy = Info.getCopyOperands(Instruction);
+ if (!TargetCopy)
+ return std::nullopt;
+ DestinationOperand = TargetCopy->Destination;
+ SourceOperand = TargetCopy->Source;
+ } else {
+ if (Instruction.opcode() != opcode(GenericOpcode::COPY) || Instruction.operandCount() < 2)
+ return std::nullopt;
+ DestinationOperand = Instruction.operandAt(0);
+ SourceOperand = Instruction.operandAt(1);
}
- MachineOperand *DestinationOperand = Instruction.operandAt(0);
- MachineOperand *SourceOperand = Instruction.operandAt(1);
const Register *Destination =
DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>();
@@ -95,88 +85,6 @@ struct CopyOperands final {
return CopyOperands{DestinationOperand, SourceOperand, *Destination, *Source};
}
-[[nodiscard]] Expected<bool> compatibleVirtualRegisters(Register Destination, Register Source,
- const MachineFunction &Function,
- const TargetDescription &Target) {
- if (!Destination.isVirtual() || !Source.isVirtual())
- return false;
- auto DestinationInfo = Function.registerInfo().virtualRegisterInfo(Destination);
- auto SourceInfo = Function.registerInfo().virtualRegisterInfo(Source);
- if (!DestinationInfo || !SourceInfo)
- return std::unexpected(!DestinationInfo ? DestinationInfo.error() : SourceInfo.error());
- const VirtualRegisterInfo &DestinationValue = DestinationInfo->get();
- 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().isSubclass(*SourceValue.RegClass, *DestinationValue.RegClass)) {
- return false;
- }
- return true;
-}
-
-[[nodiscard]] Expected<bool> propagateVirtualCopy(MachineInstr &Copy, const CopyOperands &Operands,
- MachineFunction &Function,
- const TargetDescription &Target,
- const TargetInstrInfo &Info) {
- if (!Operands.Destination.isVirtual() || !Operands.Source.isVirtual())
- return false;
- if (Function.registerInfo().getUniqueVRegDef(Operands.Destination) !=
- Operands.DestinationOperand) {
- return false;
- }
- auto Compatible =
- compatibleVirtualRegisters(Operands.Destination, Operands.Source, Function, Target);
- if (!Compatible)
- return std::unexpected(Compatible.error());
- if (!*Compatible)
- return false;
- auto ValidCopy =
- Info.validateCopy(Operands.Destination, Operands.DestinationOperand->subReg(),
- Operands.Source, Operands.SourceOperand->subReg(), Function, Target);
- if (!ValidCopy) {
- if (ValidCopy.error().code() == ErrorCode::Unsupported)
- return false;
- return std::unexpected(ValidCopy.error());
- }
-
- std::vector<MachineOperand *> Uses;
- for (MachineOperand &Use : Function.registerInfo().useOperands(Operands.Destination, true)) {
- if (&Use == Operands.SourceOperand)
- continue;
- if (Use.tiedOperandIndex() || Use.isImplicit() ||
- Use.subReg() != Operands.DestinationOperand->subReg()) {
- return false;
- }
- Uses.push_back(&Use);
- }
- for (MachineOperand *Use : Uses) {
- auto Replaced = Use->setRegister(Operands.Source);
- if (!Replaced)
- return std::unexpected(Replaced.error());
- }
- MachineBasicBlock *Block = Copy.parent();
- if (Block == nullptr)
- return makeUnexpected(ErrorCode::InternalError,
- "virtual COPY propagation candidate is detached");
- auto Removed = Block->removeInstruction(Copy);
- if (!Removed)
- return std::unexpected(Removed.error());
- if (!Function.registerInfo().useEmpty(Operands.Destination, true) ||
- Function.registerInfo().getUniqueVRegDef(Operands.Destination) != nullptr) {
- return makeUnexpected(ErrorCode::InternalError,
- "virtual COPY propagation left destination references");
- }
- auto Erased = Function.registerInfo().eraseVirtualRegister(Operands.Destination);
- if (!Erased)
- return std::unexpected(Erased.error());
- return true;
-}
-
[[nodiscard]] bool shareRegisterClass(PhysicalRegister Left, PhysicalRegister Right,
const TargetRegisterInfo &Registers) noexcept {
return std::ranges::any_of(Registers.registerClasses(), [&](const RegisterClassDesc &Class) {
@@ -203,8 +111,9 @@ struct CopyOperands final {
}
[[nodiscard]] bool canReplacePhysicalUse(const MachineInstr &Instruction, std::size_t OperandIndex,
- PhysicalRegister Source,
- const TargetDescription &Target) noexcept {
+ PhysicalRegister Source, const MachineFunction &Function,
+ const TargetDescription &Target,
+ const TargetInstrInfo &Info) noexcept {
const MachineOperand *Operand = Instruction.operandAt(OperandIndex);
const InstructionDescriptor *Descriptor = Target.instructionDescriptor(Instruction.opcode());
if (Operand == nullptr || Descriptor == nullptr || Operand->isImplicit() ||
@@ -220,9 +129,57 @@ struct CopyOperands final {
if (Constraint.RegBank && !Target.registers().bankContainsRegister(*Constraint.RegBank, Source)) {
return false;
}
+ if (Instruction.opcode() == opcode(GenericOpcode::COPY)) {
+ const MachineOperand *DestinationOperand = Instruction.operandAt(0);
+ const Register *Destination =
+ DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
+ if (Destination == nullptr)
+ return false;
+ auto Valid =
+ Info.validateCopy(*Destination, DestinationOperand->subReg(),
+ Register::fromPhysical(Source), Operand->subReg(), Function, Target);
+ if (!Valid)
+ return false;
+ }
return true;
}
+[[nodiscard]] bool valueUsedAfter(const MachineInstr &Copy, PhysicalRegister Destination,
+ const TargetDescription &Target) noexcept {
+ for (const MachineInstr *Instruction = Copy.next(); Instruction != nullptr;
+ Instruction = Instruction->next()) {
+ for (const MachineOperand &Operand : Instruction->operands()) {
+ if (const auto *Mask = Operand.getIf<RegisterMaskOperand>()) {
+ if (Mask->Mask && Mask->Mask->clobbers(Destination))
+ return false;
+ continue;
+ }
+ const Register *Reg = Operand.getIf<Register>();
+ const std::optional<PhysicalRegister> Physical =
+ Reg == nullptr ? std::nullopt : Reg->physicalRegister();
+ if (!Physical || !Target.registers().regsOverlap(*Physical, Destination))
+ continue;
+ if (Operand.isUse())
+ return true;
+ if (Operand.isDef())
+ return false;
+ }
+ }
+ const MachineBasicBlock *Block = Copy.parent();
+ if (Block == nullptr)
+ return true;
+ if (!Block->successors().empty() &&
+ !Copy.function().properties().has(MachineFunctionProperty::TracksLiveness)) {
+ return true;
+ }
+ return std::ranges::any_of(Block->successors(), [&](const MachineSuccessor &Successor) {
+ return Successor.Block != nullptr &&
+ std::ranges::any_of(Successor.Block->liveIns(), [&](const MachineBasicBlockLiveIn &In) {
+ return Target.registers().regsOverlap(In.PhysReg, Destination);
+ });
+ });
+}
+
[[nodiscard]] Expected<bool> propagatePhysicalCopy(MachineInstr &Copy, const CopyOperands &Operands,
MachineFunction &Function,
const TargetDescription &Target,
@@ -244,7 +201,8 @@ struct CopyOperands final {
if (Block == nullptr)
return makeUnexpected(ErrorCode::InternalError,
"physical COPY propagation candidate is detached");
- if (*Destination == *Source) {
+ const bool IsGenericCopy = Copy.opcode() == opcode(GenericOpcode::COPY);
+ if (*Destination == *Source && IsGenericCopy) {
auto Removed = Block->removeInstruction(Copy);
if (!Removed)
return std::unexpected(Removed.error());
@@ -265,24 +223,43 @@ struct CopyOperands final {
const Register *Reg = Operand == nullptr ? nullptr : Operand->getIf<Register>();
const std::optional<PhysicalRegister> Physical =
Reg == nullptr ? std::nullopt : Reg->physicalRegister();
- if (!Physical || !Operand->isUse() || Operand->isDebugUse() ||
- !Target.registers().regsOverlap(*Physical, *Destination) ||
- !canReplacePhysicalUse(*Instruction, Index, *Source, Target)) {
+ if (!Physical || *Physical != *Destination || !Operand->isUse() || Operand->isDebugUse() ||
+ !Operand->registerFlags().has(RegisterOperandFlag::Renamable) ||
+ !canReplacePhysicalUse(*Instruction, Index, *Source, Function, Target, Info)) {
continue;
}
auto Replaced = Operand->setRegister(Operands.Source);
if (!Replaced)
return std::unexpected(Replaced.error());
+ RegisterOperandFlags Flags = Operand->registerFlags();
+ Flags.clear(RegisterOperandFlag::Kill);
+ if (!Operands.SourceOperand->registerFlags().has(RegisterOperandFlag::Renamable))
+ Flags.clear(RegisterOperandFlag::Renamable);
+ if (Operands.SourceOperand->registerFlags().has(RegisterOperandFlag::Undef))
+ Flags.set(RegisterOperandFlag::Undef);
+ else
+ Flags.clear(RegisterOperandFlag::Undef);
+ auto SetFlags = Operand->setRegisterFlags(Flags);
+ if (!SetFlags)
+ return std::unexpected(SetFlags.error());
Changed = true;
}
}
+ if (IsGenericCopy &&
+ Operands.DestinationOperand->registerFlags().has(RegisterOperandFlag::Renamable) &&
+ !valueUsedAfter(Copy, *Destination, Target)) {
+ auto Removed = Block->removeInstruction(Copy);
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ Changed = true;
+ }
return Changed;
}
} // namespace
const MachinePassContract &MachineCopyPropagationPass::contract() const noexcept {
- return copyPropagationContract(Stage);
+ return copyPropagationContract();
}
Expected<MachinePassResult>
@@ -325,7 +302,13 @@ MachineCopyPropagationPass::runImplementation(MachineFunction &Function,
for (MachineInstr *Instruction = Block->firstInstruction();
Instruction != nullptr && PropagatedCopies < Options.MaximumPropagatedCopies;) {
MachineInstr *Next = Instruction->next();
- const std::optional<CopyOperands> Operands = copyOperands(*Instruction);
+ auto Simplified = Info->simplifyInstruction(*Instruction, Function, Target);
+ if (!Simplified)
+ return std::unexpected(Simplified.error());
+ if (*Simplified)
+ Result.Changed = true;
+ const std::optional<CopyOperands> Operands =
+ copyOperands(*Instruction, *Info, Options.UseTargetCopyInstructions);
if (!Operands) {
Instruction = Next;
continue;
@@ -338,9 +321,7 @@ MachineCopyPropagationPass::runImplementation(MachineFunction &Function,
continue;
}
Expected<bool> Changed =
- Stage == MachineCopyPropagationStage::PreRegisterAllocation
- ? propagateVirtualCopy(*Instruction, *Operands, Function, Target, *Info)
- : propagatePhysicalCopy(*Instruction, *Operands, Function, Target, *Info);
+ propagatePhysicalCopy(*Instruction, *Operands, Function, Target, *Info);
if (!Changed)
return std::unexpected(Changed.error());
if (*Changed) {
@@ -355,14 +336,7 @@ MachineCopyPropagationPass::runImplementation(MachineFunction &Function,
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};
- if (Stage == MachineCopyPropagationStage::PreRegisterAllocation)
- Result.Changes.add(MachinePassChange::Registers);
Result.Preserved = PreservedAnalyses::none();
return Result;
}
diff --git a/backend/lib/CodeGen/MachineOperand.cpp b/backend/lib/CodeGen/MachineOperand.cpp
index 44ad8b6..9b54bb9 100644
--- a/backend/lib/CodeGen/MachineOperand.cpp
+++ b/backend/lib/CodeGen/MachineOperand.cpp
@@ -315,6 +315,26 @@ Expected<void> MachineOperand::setRegister(Register Reg) {
return {};
}
+Expected<void> MachineOperand::changeToImmediate(std::int64_t Value) {
+ if (!isRegister() || isImplicit() || isDef() || tiedOperandIndex()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "only an untied explicit register use can become an immediate");
+ }
+ unlinkFromRegInfo();
+ OperandKind = Kind::Immediate;
+ Storage = Value;
+ RegFlags = {};
+ RegSubReg = {};
+ return {};
+}
+
+Expected<void> MachineOperand::setImmediate(std::int64_t Value) {
+ if (OperandKind != Kind::Immediate)
+ return makeUnexpected(ErrorCode::InvalidArgument, "setImmediate requires an immediate operand");
+ Storage = Value;
+ return {};
+}
+
Expected<void> MachineOperand::setRegisterFlags(RegisterOperandFlags Flags) {
if (!isRegister()) {
return makeUnexpected(ErrorCode::InvalidArgument, "register flags require a register operand");
diff --git a/backend/lib/CodeGen/MachineOptimizationPipeline.cpp b/backend/lib/CodeGen/MachineOptimizationPipeline.cpp
index 4a9d7f5..dc64b8f 100644
--- a/backend/lib/CodeGen/MachineOptimizationPipeline.cpp
+++ b/backend/lib/CodeGen/MachineOptimizationPipeline.cpp
@@ -72,10 +72,6 @@ Expected<void> addPreRegisterAllocationOptimizationPipeline(
auto Added = addPass<MachineBranchOptimizationPass>(Pipeline, TargetInfo.InstrInfo);
if (!Added)
return std::unexpected(Added.error());
- Added = addPass<MachineCopyPropagationPass>(Pipeline, TargetInfo.InstrInfo,
- MachineCopyPropagationStage::PreRegisterAllocation);
- if (!Added)
- return std::unexpected(Added.error());
Added = addPass<MachineCombinerPass>(Pipeline, TargetInfo.Combiner,
MachineCombinerStage::PreRegisterAllocation);
if (!Added)
@@ -88,14 +84,11 @@ Expected<void> addPreRegisterAllocationOptimizationPipeline(
Expected<void>
addPostRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline,
- const MachineOptimizationPipelineTargetInfo &TargetInfo) {
+ const MachineOptimizationPipelineTargetInfo &TargetInfo,
+ MachineOptimizationPipelineOptions Options) {
auto Added = addPass<MachineStackSlotColoringPass>(Pipeline);
if (!Added)
return std::unexpected(Added.error());
- Added = addPass<MachineCopyPropagationPass>(Pipeline, TargetInfo.InstrInfo,
- MachineCopyPropagationStage::PostRegisterAllocation);
- if (!Added)
- return std::unexpected(Added.error());
Added = addPass<MachineCombinerPass>(Pipeline, TargetInfo.Combiner,
MachineCombinerStage::PostRegisterAllocation);
if (!Added)
@@ -140,6 +133,12 @@ addPostRegisterAllocationPipeline(MachineFunctionPassManager &Pipeline,
Added = addPass<MachineFallthroughPass>(Pipeline, TargetInfo.InstrInfo);
if (!Added)
return std::unexpected(Added.error());
+ Added = addPass<MachineCopyPropagationPass>(
+ Pipeline, TargetInfo.InstrInfo,
+ MachineCopyPropagationOptions{.UseTargetCopyInstructions =
+ Options.UseTargetCopyInstructions});
+ if (!Added)
+ return std::unexpected(Added.error());
Added = addPass<MachineBranchRelaxationPass>(Pipeline, TargetInfo.InstrInfo);
if (!Added)
return std::unexpected(Added.error());
diff --git a/backend/lib/Target/RISCV/RISCVInstrInfo.cpp b/backend/lib/Target/RISCV/RISCVInstrInfo.cpp
index 886bf2b..c5cdd44 100644
--- a/backend/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/backend/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -124,6 +124,50 @@ constexpr std::uint32_t PCRelativeLowFlag = 4;
Left->subReg() == Right->subReg();
}
+[[nodiscard]] bool isPhysicalRegister(const MachineOperand *Operand,
+ PhysicalRegisterID Expected) noexcept {
+ const Register *Reg = Operand == nullptr ? nullptr : Operand->getIf<Register>();
+ const std::optional<PhysicalRegister> Physical =
+ Reg == nullptr ? std::nullopt : Reg->physicalRegister();
+ return Physical && Physical->number() == static_cast<std::uint32_t>(Expected);
+}
+
+[[nodiscard]] Expected<void> swapRegisters(MachineOperand &Left, MachineOperand &Right) {
+ const Register *LeftReg = Left.getIf<Register>();
+ const Register *RightReg = Right.getIf<Register>();
+ if (LeftReg == nullptr || RightReg == nullptr)
+ return makeUnexpected(ErrorCode::InvalidArgument, "register swap requires two registers");
+ const Register LeftValue = *LeftReg;
+ const Register RightValue = *RightReg;
+ const RegisterOperandFlags LeftFlags = Left.registerFlags();
+ const RegisterOperandFlags RightFlags = Right.registerFlags();
+ const SubRegIndex LeftSubReg = Left.subReg();
+ const SubRegIndex RightSubReg = Right.subReg();
+ const std::uint32_t LeftTargetFlags = Left.targetFlags();
+ const std::uint32_t RightTargetFlags = Right.targetFlags();
+ auto SetLeft = Left.setRegister(RightValue);
+ if (!SetLeft)
+ return std::unexpected(SetLeft.error());
+ auto SetRight = Right.setRegister(LeftValue);
+ if (!SetRight)
+ return std::unexpected(SetRight.error());
+ SetLeft = Left.setRegisterFlags(RightFlags);
+ if (!SetLeft)
+ return std::unexpected(SetLeft.error());
+ SetRight = Right.setRegisterFlags(LeftFlags);
+ if (!SetRight)
+ return std::unexpected(SetRight.error());
+ SetLeft = Left.setSubReg(RightSubReg);
+ if (!SetLeft)
+ return std::unexpected(SetLeft.error());
+ SetRight = Right.setSubReg(LeftSubReg);
+ if (!SetRight)
+ return std::unexpected(SetRight.error());
+ Left.setTargetFlags(RightTargetFlags);
+ Right.setTargetFlags(LeftTargetFlags);
+ return {};
+}
+
[[nodiscard]] bool isUnconditionalBranch(const MachineInstr &Instruction) noexcept {
if (Instruction.opcode() == instructionOpcode(InstructionOpcode::C_J) ||
Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoBR)) {
@@ -757,6 +801,290 @@ public:
return {};
}
+ [[nodiscard]] std::optional<MachineCopyOperands>
+ getCopyOperands(MachineInstr &Instruction) const noexcept override {
+ auto Pair = [&Instruction](std::size_t Destination,
+ std::size_t Source) -> std::optional<MachineCopyOperands> {
+ MachineOperand *DestinationOperand = Instruction.operandAt(Destination);
+ MachineOperand *SourceOperand = Instruction.operandAt(Source);
+ return DestinationOperand != nullptr && SourceOperand != nullptr
+ ? std::optional<MachineCopyOperands>{MachineCopyOperands{DestinationOperand,
+ SourceOperand}}
+ : std::nullopt;
+ };
+ if (Instruction.opcode() == opcode(GenericOpcode::COPY))
+ return Pair(0, 1);
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::ADD) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::OR) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::XOR)) {
+ if (isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0))
+ return Pair(0, 2);
+ if (isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0))
+ return Pair(0, 1);
+ }
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::ADDI)) {
+ const auto *Immediate = Instruction.operandAt(2) == nullptr
+ ? nullptr
+ : Instruction.operandAt(2)->getIf<std::int64_t>();
+ if (Immediate != nullptr && *Immediate == 0)
+ return Pair(0, 1);
+ }
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::SUB) &&
+ isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0)) {
+ return Pair(0, 1);
+ }
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::SH1ADD) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::SH1ADD_UW) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::SH2ADD) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::SH2ADD_UW) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::SH3ADD) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::SH3ADD_UW)) {
+ if (isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0))
+ return Pair(0, 2);
+ }
+ if (Instruction.opcode() == instructionOpcode(InstructionOpcode::FSGNJ_D) ||
+ Instruction.opcode() == instructionOpcode(InstructionOpcode::FSGNJ_S)) {
+ if (sameRegister(Instruction.operandAt(1), Instruction.operandAt(2)))
+ return Pair(0, 1);
+ }
+ return std::nullopt;
+ }
+
+ [[nodiscard]] Expected<bool> simplifyInstruction(MachineInstr &Instruction,
+ MachineFunction &Function,
+ const TargetDescription &) const override {
+ if (&Instruction.function() != &Function)
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "RISC-V instruction simplification references another function");
+ auto SetOpcode = [&Instruction](InstructionOpcode NewOpcode) -> Expected<bool> {
+ auto Result = Instruction.setOpcode(instructionOpcode(NewOpcode));
+ if (!Result)
+ return std::unexpected(Result.error());
+ return true;
+ };
+ auto SetZeroImmediate = [&Instruction, &SetOpcode](
+ std::size_t Index, InstructionOpcode NewOpcode) -> Expected<bool> {
+ MachineOperand *Operand = Instruction.operandAt(Index);
+ if (Operand == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V simplification has no source operand");
+ auto Changed = Operand->changeToImmediate(0);
+ if (!Changed)
+ return std::unexpected(Changed.error());
+ return SetOpcode(NewOpcode);
+ };
+ const Opcode Value = Instruction.opcode();
+ if (Value == instructionOpcode(InstructionOpcode::ADD) ||
+ Value == instructionOpcode(InstructionOpcode::OR) ||
+ Value == instructionOpcode(InstructionOpcode::XOR)) {
+ if (isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ auto Swapped = swapRegisters(*Instruction.operandAt(1), *Instruction.operandAt(2));
+ if (!Swapped)
+ return std::unexpected(Swapped.error());
+ }
+ if (isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0))
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ if (Value == instructionOpcode(InstructionOpcode::XOR) &&
+ sameRegister(Instruction.operandAt(1), Instruction.operandAt(2))) {
+ auto Zero = physicalRegister(PhysicalRegisterID::X0);
+ if (!Zero)
+ return std::unexpected(Zero.error());
+ auto SetSource = Instruction.operandAt(1)->setRegister(Register::fromPhysical(*Zero));
+ if (!SetSource)
+ return std::unexpected(SetSource.error());
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ }
+ return false;
+ }
+ if ((Value == instructionOpcode(InstructionOpcode::ORI) ||
+ Value == instructionOpcode(InstructionOpcode::XORI)) &&
+ isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ return SetOpcode(InstructionOpcode::ADDI);
+ }
+ if (Value == instructionOpcode(InstructionOpcode::SUB) &&
+ isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0)) {
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ }
+ if (Value == instructionOpcode(InstructionOpcode::SUBW) &&
+ isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0)) {
+ return SetZeroImmediate(2, InstructionOpcode::ADDIW);
+ }
+ if (Value == instructionOpcode(InstructionOpcode::ADDW)) {
+ if (isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ auto Swapped = swapRegisters(*Instruction.operandAt(1), *Instruction.operandAt(2));
+ if (!Swapped)
+ return std::unexpected(Swapped.error());
+ }
+ if (isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0))
+ return SetZeroImmediate(2, InstructionOpcode::ADDIW);
+ return false;
+ }
+ if (Value == instructionOpcode(InstructionOpcode::SH1ADD) ||
+ Value == instructionOpcode(InstructionOpcode::SH1ADD_UW) ||
+ Value == instructionOpcode(InstructionOpcode::SH2ADD) ||
+ Value == instructionOpcode(InstructionOpcode::SH2ADD_UW) ||
+ Value == instructionOpcode(InstructionOpcode::SH3ADD) ||
+ Value == instructionOpcode(InstructionOpcode::SH3ADD_UW)) {
+ if (isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ auto Removed = Instruction.eraseOperand(1);
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ Removed = Instruction.addOperand(MachineOperand::immediate(0));
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ return SetOpcode(InstructionOpcode::ADDI);
+ }
+ if (isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0)) {
+ const bool IsUnsignedWord = Value == instructionOpcode(InstructionOpcode::SH1ADD_UW) ||
+ Value == instructionOpcode(InstructionOpcode::SH2ADD_UW) ||
+ Value == instructionOpcode(InstructionOpcode::SH3ADD_UW);
+ const std::int64_t Shift = Value == instructionOpcode(InstructionOpcode::SH1ADD) ||
+ Value == instructionOpcode(InstructionOpcode::SH1ADD_UW)
+ ? 1
+ : Value == instructionOpcode(InstructionOpcode::SH2ADD) ||
+ Value == instructionOpcode(InstructionOpcode::SH2ADD_UW)
+ ? 2
+ : 3;
+ auto Removed = Instruction.eraseOperand(2);
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ Removed = Instruction.addOperand(MachineOperand::immediate(Shift));
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ return SetOpcode(IsUnsignedWord ? InstructionOpcode::SLLI_UW : InstructionOpcode::SLLI);
+ }
+ return false;
+ }
+ if (Value == instructionOpcode(InstructionOpcode::AND) ||
+ Value == instructionOpcode(InstructionOpcode::MUL) ||
+ Value == instructionOpcode(InstructionOpcode::MULH) ||
+ Value == instructionOpcode(InstructionOpcode::MULHSU) ||
+ Value == instructionOpcode(InstructionOpcode::MULHU) ||
+ Value == instructionOpcode(InstructionOpcode::MULW)) {
+ if (!isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0) &&
+ !isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0)) {
+ return false;
+ }
+ auto Zero = physicalRegister(PhysicalRegisterID::X0);
+ if (!Zero)
+ return std::unexpected(Zero.error());
+ auto SetSource = Instruction.operandAt(1)->setRegister(Register::fromPhysical(*Zero));
+ if (!SetSource)
+ return std::unexpected(SetSource.error());
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ }
+ if (Value == instructionOpcode(InstructionOpcode::ANDI) &&
+ isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ MachineOperand *Immediate = Instruction.operandAt(2);
+ if (Immediate == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V ANDI simplification has no immediate operand");
+ auto SetImmediate = Immediate->setImmediate(0);
+ if (!SetImmediate)
+ return std::unexpected(SetImmediate.error());
+ return SetOpcode(InstructionOpcode::ADDI);
+ }
+ if (Value == instructionOpcode(InstructionOpcode::SLL) ||
+ Value == instructionOpcode(InstructionOpcode::SRL) ||
+ Value == instructionOpcode(InstructionOpcode::SRA)) {
+ if (isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0) ||
+ isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0)) {
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ }
+ return false;
+ }
+ if ((Value == instructionOpcode(InstructionOpcode::SLLW) ||
+ Value == instructionOpcode(InstructionOpcode::SRLW) ||
+ Value == instructionOpcode(InstructionOpcode::SRAW)) &&
+ isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ }
+ if ((Value == instructionOpcode(InstructionOpcode::SLLI) ||
+ Value == instructionOpcode(InstructionOpcode::SRLI) ||
+ Value == instructionOpcode(InstructionOpcode::SRAI) ||
+ Value == instructionOpcode(InstructionOpcode::SLLIW) ||
+ Value == instructionOpcode(InstructionOpcode::SRLIW) ||
+ Value == instructionOpcode(InstructionOpcode::SRAIW) ||
+ Value == instructionOpcode(InstructionOpcode::SLLI_UW)) &&
+ isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ MachineOperand *Immediate = Instruction.operandAt(2);
+ if (Immediate == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V shift simplification has no immediate operand");
+ auto SetImmediate = Immediate->setImmediate(0);
+ if (!SetImmediate)
+ return std::unexpected(SetImmediate.error());
+ return SetOpcode(InstructionOpcode::ADDI);
+ }
+ if (Value == instructionOpcode(InstructionOpcode::SLTU) ||
+ Value == instructionOpcode(InstructionOpcode::ADD_UW)) {
+ const bool LeftZero = isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0);
+ const bool RightZero = isPhysicalRegister(Instruction.operandAt(2), PhysicalRegisterID::X0);
+ if (LeftZero && RightZero)
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ if (Value == instructionOpcode(InstructionOpcode::ADD_UW) && LeftZero) {
+ auto Removed = Instruction.eraseOperand(1);
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ Removed = Instruction.addOperand(MachineOperand::immediate(0));
+ if (!Removed)
+ return std::unexpected(Removed.error());
+ return SetOpcode(InstructionOpcode::ADDI);
+ }
+ return false;
+ }
+ if (Value == instructionOpcode(InstructionOpcode::SLTIU) &&
+ isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ MachineOperand *Immediate = Instruction.operandAt(2);
+ const auto *ImmediateValue =
+ Immediate == nullptr ? nullptr : Immediate->getIf<std::int64_t>();
+ if (ImmediateValue == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V SLTIU simplification has no immediate operand");
+ const std::int64_t Result = *ImmediateValue != 0 ? 1 : 0;
+ auto SetImmediate = Immediate->setImmediate(Result);
+ if (!SetImmediate)
+ return std::unexpected(SetImmediate.error());
+ return SetOpcode(InstructionOpcode::ADDI);
+ }
+ if ((Value == instructionOpcode(InstructionOpcode::SEXT_H) ||
+ Value == instructionOpcode(InstructionOpcode::SEXT_B) ||
+ Value == instructionOpcode(InstructionOpcode::ZEXT_H_RV32) ||
+ Value == instructionOpcode(InstructionOpcode::ZEXT_H_RV64)) &&
+ isPhysicalRegister(Instruction.operandAt(1), PhysicalRegisterID::X0)) {
+ auto Added = Instruction.addOperand(MachineOperand::immediate(0));
+ if (!Added)
+ return std::unexpected(Added.error());
+ return SetOpcode(InstructionOpcode::ADDI);
+ }
+ if ((Value == instructionOpcode(InstructionOpcode::MIN) ||
+ Value == instructionOpcode(InstructionOpcode::MINU) ||
+ Value == instructionOpcode(InstructionOpcode::MAX) ||
+ Value == instructionOpcode(InstructionOpcode::MAXU)) &&
+ sameRegister(Instruction.operandAt(1), Instruction.operandAt(2))) {
+ return SetZeroImmediate(2, InstructionOpcode::ADDI);
+ }
+ if ((Value == instructionOpcode(InstructionOpcode::BEQ) ||
+ Value == instructionOpcode(InstructionOpcode::BNE)) &&
+ isPhysicalRegister(Instruction.operandAt(0), PhysicalRegisterID::X0)) {
+ auto Swapped = swapRegisters(*Instruction.operandAt(0), *Instruction.operandAt(1));
+ if (!Swapped)
+ return std::unexpected(Swapped.error());
+ return true;
+ }
+ if ((Value == instructionOpcode(InstructionOpcode::BLTU) ||
+ Value == instructionOpcode(InstructionOpcode::BGEU)) &&
+ isPhysicalRegister(Instruction.operandAt(0), PhysicalRegisterID::X0)) {
+ auto Swapped = swapRegisters(*Instruction.operandAt(0), *Instruction.operandAt(1));
+ if (!Swapped)
+ return std::unexpected(Swapped.error());
+ return SetOpcode(Value == instructionOpcode(InstructionOpcode::BLTU)
+ ? InstructionOpcode::BNE
+ : InstructionOpcode::BEQ);
+ }
+ return false;
+ }
+
[[nodiscard]] Expected<std::uint32_t>
instructionSize(const MachineInstr &Instruction, const MachineFunction &,
const TargetDescription &Target) const override {
diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp
index 60f798c..9ce9f92 100644
--- a/backend/lib/Target/RISCV/RISCVPipeline.cpp
+++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp
@@ -65,7 +65,8 @@ template <typename PassT, typename... ArgumentT>
}
[[nodiscard]] Expected<void> addCompleteRegistry(MachineFunctionPassManager &Pipeline,
- const RISCVSubtarget &Subtarget) {
+ const RISCVSubtarget &Subtarget,
+ RISCVPipelineOptions Options) {
auto Added = addInitialPipeline(Pipeline, Subtarget);
if (!Added)
return std::unexpected(Added.error());
@@ -75,14 +76,17 @@ template <typename PassT, typename... ArgumentT>
Added = addRegisterAllocationPipeline(Pipeline);
if (!Added)
return std::unexpected(Added.error());
- return addPostRegisterAllocationPipeline(Pipeline, optimizationPipelineInfo());
+ return addPostRegisterAllocationPipeline(
+ Pipeline, optimizationPipelineInfo(),
+ MachineOptimizationPipelineOptions{.UseTargetCopyInstructions =
+ Options.UseTargetCopyInstructions});
}
} // namespace
Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline,
const MachineFunction &Function,
- const RISCVSubtarget &Subtarget) {
+ const RISCVSubtarget &Subtarget, RISCVPipelineOptions Options) {
if (!Function.properties().has(MachineFunctionProperty::Legalized)) {
auto Added = addPass<MachineCombinerPass>(Pipeline, machineCombinerInfo(),
MachineCombinerStage::PreLegalizer);
@@ -123,7 +127,10 @@ Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline,
return std::unexpected(Added.error());
}
if (!Function.properties().has(MachineFunctionProperty::NoExecutablePseudos)) {
- auto Added = addPostRegisterAllocationPipeline(Pipeline, optimizationPipelineInfo());
+ auto Added = addPostRegisterAllocationPipeline(
+ Pipeline, optimizationPipelineInfo(),
+ MachineOptimizationPipelineOptions{.UseTargetCopyInstructions =
+ Options.UseTargetCopyInstructions});
if (!Added)
return std::unexpected(Added.error());
}
@@ -131,11 +138,12 @@ Expected<void> addCanonicalPipeline(MachineFunctionPassManager &Pipeline,
}
Expected<std::unique_ptr<MachineFunctionPass>>
-createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget) {
+createCanonicalPipelinePass(std::string_view Name, const RISCVSubtarget &Subtarget,
+ RISCVPipelineOptions Options) {
if (Name.empty())
return makeUnexpected(ErrorCode::InvalidArgument, "pipeline pass name cannot be empty");
MachineFunctionPassManager Registry;
- auto Added = addCompleteRegistry(Registry, Subtarget);
+ auto Added = addCompleteRegistry(Registry, Subtarget, Options);
if (!Added)
return std::unexpected(Added.error());
MachineFunctionPassManager::PassList Passes = std::move(Registry).takePasses();
diff --git a/backend/lib/Tooling/PipelineDriver.cpp b/backend/lib/Tooling/PipelineDriver.cpp
index 9e2ba46..542e2b5 100644
--- a/backend/lib/Tooling/PipelineDriver.cpp
+++ b/backend/lib/Tooling/PipelineDriver.cpp
@@ -100,7 +100,9 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio
const riscv::RISCVSubtarget &Subtarget, MachinePassManagerOptions Options) {
MachineFunctionPassManager Pipeline(Options);
if (Invocation.PassPipeline.size() == 1 && Invocation.PassPipeline.front() == "default") {
- auto Added = riscv::addCanonicalPipeline(Pipeline, Function, Subtarget);
+ auto Added =
+ riscv::addCanonicalPipeline(Pipeline, Function, Subtarget,
+ riscv::RISCVPipelineOptions{.UseTargetCopyInstructions = true});
if (!Added)
return std::unexpected(Added.error());
} else {
@@ -108,8 +110,14 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio
return makeUnexpected(ErrorCode::InvalidInvocation,
"the default pipeline marker cannot be mixed with named passes");
}
+ const auto TargetCopyOption = std::ranges::find(
+ Invocation.TargetOptions, std::string_view{"mcp-use-is-copy-instr"}, &BackendOption::Name);
+ const bool UseTargetCopyInstructions =
+ TargetCopyOption != Invocation.TargetOptions.end() && TargetCopyOption->Value == "true";
for (const std::string &Name : Invocation.PassPipeline) {
- auto Pass = riscv::createCanonicalPipelinePass(Name, Subtarget);
+ auto Pass = riscv::createCanonicalPipelinePass(
+ Name, Subtarget,
+ riscv::RISCVPipelineOptions{.UseTargetCopyInstructions = UseTargetCopyInstructions});
if (!Pass)
return std::unexpected(Pass.error());
auto Added = Pipeline.addPass(std::move(*Pass));
diff --git a/backend/unittests/Target/RISCVLateCodeGenTest.cpp b/backend/unittests/Target/RISCVLateCodeGenTest.cpp
index 868d18f..89da994 100644
--- a/backend/unittests/Target/RISCVLateCodeGenTest.cpp
+++ b/backend/unittests/Target/RISCVLateCodeGenTest.cpp
@@ -636,87 +636,6 @@ void testTailMerge(TestContext &Context, const rcc::TargetDescription &Target) {
"tail merge must redirect identical tails and repair liveness");
}
-void testCopyPropagation(TestContext &Context, const rcc::TargetDescription &Target) {
- auto Function = makeFunction(Context, "pre_ra_copy_propagation", 13);
- if (!Function)
- return;
- rcc::MachineBasicBlock *Block = appendBlock(Context, *Function);
- auto I64 = rcc::LLT::makeInteger(64);
- if (Block == nullptr || !I64)
- return;
- auto Source = Function->registerInfo().createVirtualRegister(*I64);
- auto CopyResult = Function->registerInfo().createVirtualRegister(*I64);
- auto ResultReg = Function->registerInfo().createVirtualRegister(*I64);
- if (!Source || !CopyResult || !ResultReg || !constrainGPR64(Context, *Function, *Source) ||
- !constrainGPR64(Context, *Function, *CopyResult) ||
- !constrainGPR64(Context, *Function, *ResultReg)) {
- return;
- }
- rcc::MachineIRBuilder Builder(*Function, Target);
- if (!Builder.setInsertPoint(*Block))
- return;
- auto Copy = Builder.buildInstr(rcc::opcode(rcc::GenericOpcode::COPY));
- if (!Copy || !Copy->addDef(*CopyResult) || !Copy->addUse(*Source) || !Copy->build())
- return;
- rcc::MachineInstr *Add = buildADDI(Context, Builder, *ResultReg, *CopyResult, 3);
- if (Add == nullptr)
- return;
- setSelectedProperties(*Function);
- rcc::MachineFunctionAnalysisManager Analyses;
- rcc::MachineCopyPropagationPass PreRA(rcc::riscv::instrInfo(),
- rcc::MachineCopyPropagationStage::PreRegisterAllocation);
- auto PreResult = PreRA.run(*Function, Target, Analyses);
- if (!PreResult)
- std::cerr << "pre-RA COPY propagation failure: " << PreResult.error().message() << '\n';
- Context.expect(PreResult && PreResult->Changed && Block->instructionCount() == 1 &&
- Add->operandAt(1)->registerValue() == *Source &&
- !Function->registerInfo().isKnownVirtualRegister(*CopyResult),
- "pre-RA COPY propagation must replace uses and retire the COPY result");
-
- auto PostFunction = makeFunction(Context, "post_ra_copy_propagation", 14);
- if (!PostFunction)
- return;
- rcc::MachineBasicBlock *PostBlock = appendBlock(Context, *PostFunction);
- if (PostBlock == nullptr)
- return;
- rcc::MachineIRBuilder PostBuilder(*PostFunction, Target);
- if (!PostBuilder.setInsertPoint(*PostBlock))
- return;
- auto PhysicalCopy = PostBuilder.buildInstr(rcc::opcode(rcc::GenericOpcode::COPY));
- if (!PhysicalCopy || !PhysicalCopy->addDef(physical(rcc::riscv::PhysicalRegisterID::X11)) ||
- !PhysicalCopy->addUse(physical(rcc::riscv::PhysicalRegisterID::X10)) ||
- !PhysicalCopy->build()) {
- return;
- }
- rcc::MachineInstr *PhysicalAdd =
- buildADDI(Context, PostBuilder, physical(rcc::riscv::PhysicalRegisterID::X12),
- physical(rcc::riscv::PhysicalRegisterID::X11), 5);
- rcc::MachineInstr *SourceClobber =
- buildADDI(Context, PostBuilder, physical(rcc::riscv::PhysicalRegisterID::X10),
- physical(rcc::riscv::PhysicalRegisterID::X0), 9);
- rcc::MachineInstr *AfterClobber =
- buildADDI(Context, PostBuilder, physical(rcc::riscv::PhysicalRegisterID::X13),
- physical(rcc::riscv::PhysicalRegisterID::X11), 6);
- if (PhysicalAdd == nullptr || SourceClobber == nullptr || AfterClobber == nullptr)
- return;
- setPostRAProperties(*PostFunction);
- Context.expect(rcc::rebuildMachineLiveness(*PostFunction, Target).has_value(),
- "post-RA COPY propagation liveness must be rebuilt");
- rcc::MachineFunctionAnalysisManager PostAnalyses;
- rcc::MachineCopyPropagationPass PostRA(rcc::riscv::instrInfo(),
- rcc::MachineCopyPropagationStage::PostRegisterAllocation);
- auto PostResult = PostRA.run(*PostFunction, Target, PostAnalyses);
- if (!PostResult)
- std::cerr << "post-RA COPY propagation failure: " << PostResult.error().message() << '\n';
- Context.expect(PostResult && PostResult->Changed &&
- PhysicalAdd->operandAt(1)->registerValue() ==
- physical(rcc::riscv::PhysicalRegisterID::X10) &&
- AfterClobber->operandAt(1)->registerValue() ==
- physical(rcc::riscv::PhysicalRegisterID::X11) &&
- rcc::verifyTrackedMachineLiveness(*PostFunction, Target).has_value(),
- "post-RA COPY propagation must stop at clobbers and repair liveness");
-}
-
void testStackSlotColoring(TestContext &Context, const rcc::TargetDescription &Target) {
auto Function = makeFunction(Context, "stack_slot_coloring", 15);
if (!Function)
@@ -1219,7 +1138,7 @@ void testCanonicalOptimizationPipelines(TestContext &Context,
SelectedPipeline.size() == 6,
"canonical selected-SSA optimization pipeline must register completely");
Context.expect(rcc::addPreRegisterAllocationOptimizationPipeline(PreRAPipeline, TargetInfo) &&
- PreRAPipeline.size() == 5,
+ PreRAPipeline.size() == 4,
"canonical pre-RA optimization pipeline must register completely");
auto Function = makeFunction(Context, "canonical_post_ra_pipeline", 21);
@@ -1446,7 +1365,6 @@ int main() {
testBranchOptimization(Context, *Target);
testTailDuplication(Context, *Target);
testTailMerge(Context, *Target);
- testCopyPropagation(Context, *Target);
testStackSlotColoring(Context, *Target);
testRISCVMemoryFoldingBoundary(Context, *Target);
testShrinkWrappedFrameRegion(Context, *Target);