From cd30fb546e389d1fb78ce8e579b3dba3a8fdb52a Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Thu, 13 Aug 2026 21:11:10 +0800 Subject: [CodeGen] Match LLVM machine copy propagation --- backend/lib/Target/RISCV/RISCVInstrInfo.cpp | 328 ++++++++++++++++++++++++++++ backend/lib/Target/RISCV/RISCVPipeline.cpp | 20 +- 2 files changed, 342 insertions(+), 6 deletions(-) (limited to 'backend/lib/Target') 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(); + const std::optional Physical = + Reg == nullptr ? std::nullopt : Reg->physicalRegister(); + return Physical && Physical->number() == static_cast(Expected); +} + +[[nodiscard]] Expected swapRegisters(MachineOperand &Left, MachineOperand &Right) { + const Register *LeftReg = Left.getIf(); + const Register *RightReg = Right.getIf(); + 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 + getCopyOperands(MachineInstr &Instruction) const noexcept override { + auto Pair = [&Instruction](std::size_t Destination, + std::size_t Source) -> std::optional { + MachineOperand *DestinationOperand = Instruction.operandAt(Destination); + MachineOperand *SourceOperand = Instruction.operandAt(Source); + return DestinationOperand != nullptr && SourceOperand != nullptr + ? std::optional{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(); + 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 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 { + 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 { + 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(); + 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 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 } [[nodiscard]] Expected 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 Added = addRegisterAllocationPipeline(Pipeline); if (!Added) return std::unexpected(Added.error()); - return addPostRegisterAllocationPipeline(Pipeline, optimizationPipelineInfo()); + return addPostRegisterAllocationPipeline( + Pipeline, optimizationPipelineInfo(), + MachineOptimizationPipelineOptions{.UseTargetCopyInstructions = + Options.UseTargetCopyInstructions}); } } // namespace Expected addCanonicalPipeline(MachineFunctionPassManager &Pipeline, const MachineFunction &Function, - const RISCVSubtarget &Subtarget) { + const RISCVSubtarget &Subtarget, RISCVPipelineOptions Options) { if (!Function.properties().has(MachineFunctionProperty::Legalized)) { auto Added = addPass(Pipeline, machineCombinerInfo(), MachineCombinerStage::PreLegalizer); @@ -123,7 +127,10 @@ Expected 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 addCanonicalPipeline(MachineFunctionPassManager &Pipeline, } Expected> -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(); -- cgit v1.2.3