diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-13 21:11:10 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-13 21:11:10 +0800 |
| commit | cd30fb546e389d1fb78ce8e579b3dba3a8fdb52a (patch) | |
| tree | 891d7065c52e56d3f559b146f3a07055105d9d4e /backend | |
| parent | 98cae0e8835a1eb8fcb0e43870c04ed934cc51ac (diff) | |
| download | rcc-project-cd30fb546e389d1fb78ce8e579b3dba3a8fdb52a.tar.gz rcc-project-cd30fb546e389d1fb78ce8e579b3dba3a8fdb52a.tar.xz | |
[CodeGen] Match LLVM machine copy propagation
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineCopyPropagation.h | 14 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineOperand.h | 2 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineOptimizationPipeline.h | 7 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/TargetInstrInfo.h | 16 | ||||
| -rw-r--r-- | backend/include/rcc/Target/RISCV/RISCVPipeline.h | 10 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineCopyPropagation.cpp | 240 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineOperand.cpp | 20 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineOptimizationPipeline.cpp | 17 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVInstrInfo.cpp | 328 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPipeline.cpp | 20 | ||||
| -rw-r--r-- | backend/lib/Tooling/PipelineDriver.cpp | 12 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVLateCodeGenTest.cpp | 84 |
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 ©PropagationContract() { + 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); |
