diff options
Diffstat (limited to 'backend')
23 files changed, 366 insertions, 347 deletions
diff --git a/backend/include/rcc/CodeGen/MachineCopyPropagation.h b/backend/include/rcc/CodeGen/MachineCopyPropagation.h index e8ee788..43baa7e 100644 --- a/backend/include/rcc/CodeGen/MachineCopyPropagation.h +++ b/backend/include/rcc/CodeGen/MachineCopyPropagation.h @@ -10,7 +10,7 @@ namespace rcc { -class TargetSSAInfo; +class TargetInstrInfo; enum class MachineCopyPropagationStage : std::uint8_t { PreRegisterAllocation, @@ -23,7 +23,7 @@ struct MachineCopyPropagationOptions final { class MachineCopyPropagationPass final : public MachineFunctionPass { public: - MachineCopyPropagationPass(const TargetSSAInfo &Info, MachineCopyPropagationStage Stage, + MachineCopyPropagationPass(const TargetInstrInfo &Info, MachineCopyPropagationStage Stage, MachineCopyPropagationOptions Options = {}) noexcept : Info(&Info), Stage(Stage), Options(Options) {} @@ -37,7 +37,7 @@ private: const TargetDescription &Target, MachineActionReplay &Actions) const; - const TargetSSAInfo *Info; + const TargetInstrInfo *Info; MachineCopyPropagationStage Stage; MachineCopyPropagationOptions Options; }; diff --git a/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h b/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h index 2cf1bcd..10bcbc6 100644 --- a/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h +++ b/backend/include/rcc/CodeGen/MachineOptimizationPipeline.h @@ -13,16 +13,14 @@ class TargetMachineCombinerInfo; class TargetMemoryFoldingInfo; class TargetPseudoExpansionInfo; class TargetSchedulingModel; -class TargetSSAInfo; struct MachineOptimizationPipelineTargetInfo final { - const TargetSSAInfo &SSA; + const TargetInstrInfo &InstrInfo; const TargetMachineCombinerInfo &Combiner; const TargetMemoryFoldingInfo &MemoryFolding; const TargetFrameLowering &FrameLowering; const TargetPseudoExpansionInfo &PseudoExpansion; const TargetSchedulingModel &SchedulingModel; - const TargetInstrInfo &BranchInfo; }; [[nodiscard]] Expected<void> registerMachineOptimizationAnalyses(MachineAnalysisManager &Analyses); diff --git a/backend/include/rcc/CodeGen/MachineSSAExit.h b/backend/include/rcc/CodeGen/MachineSSAExit.h index fdf74f0..4b6966d 100644 --- a/backend/include/rcc/CodeGen/MachineSSAExit.h +++ b/backend/include/rcc/CodeGen/MachineSSAExit.h @@ -4,14 +4,14 @@ #define RCC_CODEGEN_MACHINESSAEXIT_H #include "rcc/CodeGen/MachinePass.h" -#include "rcc/CodeGen/TargetCodeGen.h" +#include "rcc/CodeGen/TargetInstrInfo.h" namespace rcc { class PHIEliminationPass final : public MachineFunctionPass { public: PHIEliminationPass() noexcept = default; - explicit PHIEliminationPass(const TargetSSAInfo &Info) noexcept : Info(&Info) {} + explicit PHIEliminationPass(const TargetInstrInfo &Info) noexcept : Info(&Info) {} [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, @@ -23,13 +23,13 @@ private: const TargetDescription &Target, MachineActionReplay &Actions); - const TargetSSAInfo *Info = nullptr; + const TargetInstrInfo *Info = nullptr; }; class TwoAddressRewritePass final : public MachineFunctionPass { public: TwoAddressRewritePass() noexcept = default; - explicit TwoAddressRewritePass(const TargetSSAInfo &Info) noexcept : Info(&Info) {} + explicit TwoAddressRewritePass(const TargetInstrInfo &Info) noexcept : Info(&Info) {} [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, @@ -41,7 +41,7 @@ private: const TargetDescription &Target, MachineActionReplay &Actions); - const TargetSSAInfo *Info = nullptr; + const TargetInstrInfo *Info = nullptr; }; } // namespace rcc diff --git a/backend/include/rcc/CodeGen/TargetCodeGen.h b/backend/include/rcc/CodeGen/TargetCodeGen.h index 34a6de4..65f65a4 100644 --- a/backend/include/rcc/CodeGen/TargetCodeGen.h +++ b/backend/include/rcc/CodeGen/TargetCodeGen.h @@ -3,20 +3,14 @@ #ifndef RCC_CODEGEN_TARGETCODEGEN_H #define RCC_CODEGEN_TARGETCODEGEN_H -#include "rcc/CodeGen/MachineIRTypes.h" -#include "rcc/CodeGen/Register.h" #include "rcc/Support/Error.h" -#include <cstddef> #include <cstdint> -#include <optional> namespace rcc { class MachineFunction; -class MachineBasicBlock; class MachineInstr; -class MachineRegisterInfo; class TargetDescription; struct VirtualRegisterInfo; @@ -96,38 +90,6 @@ public: } }; -class TargetSSAInfo { -public: - virtual ~TargetSSAInfo() = default; - - [[nodiscard]] virtual Expected<bool> isFallthroughEdge(const MachineBasicBlock &From, - const MachineBasicBlock &To, - const MachineFunction &Function, - const TargetDescription &Target) const = 0; - - [[nodiscard]] virtual Expected<bool> - rewriteBranchTarget(MachineBasicBlock &Block, MachineBasicBlock &OldTarget, - MachineBasicBlock &NewTarget, MachineFunction &Function, - const TargetDescription &Target) const = 0; - - [[nodiscard]] virtual Expected<void> - insertUnconditionalBranch(MachineBasicBlock &Block, MachineBasicBlock &Target, - MachineFunction &Function, - const TargetDescription &TargetDescription) const = 0; - - [[nodiscard]] virtual Expected<void> validateCopy(Register Destination, - SubRegIndex DestinationSubReg, Register Source, - SubRegIndex SourceSubReg, - const MachineFunction &Function, - const TargetDescription &Target) const = 0; - - [[nodiscard]] virtual Expected<bool> tryConvertToThreeAddress(MachineInstr &, std::size_t, - std::size_t, MachineFunction &, - const TargetDescription &) const { - return false; - } -}; - } // namespace rcc #endif // RCC_CODEGEN_TARGETCODEGEN_H diff --git a/backend/include/rcc/CodeGen/TargetInstrInfo.h b/backend/include/rcc/CodeGen/TargetInstrInfo.h index d9f0906..34752c5 100644 --- a/backend/include/rcc/CodeGen/TargetInstrInfo.h +++ b/backend/include/rcc/CodeGen/TargetInstrInfo.h @@ -3,8 +3,11 @@ #ifndef RCC_CODEGEN_TARGETINSTRINFO_H #define RCC_CODEGEN_TARGETINSTRINFO_H +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/CodeGen/Register.h" #include "rcc/Support/Error.h" +#include <cstddef> #include <cstdint> #include <optional> @@ -40,8 +43,25 @@ public: MachineBasicBlock &NewTarget, MachineFunction &Function, const TargetDescription &Target) const = 0; [[nodiscard]] virtual Expected<MachineInstr *> - insertUnconditionalBranch(MachineBasicBlock &Block, MachineBasicBlock &TargetBlock, - MachineFunction &Function, const TargetDescription &Target) const = 0; + insertBranch(MachineBasicBlock &Block, MachineBasicBlock &TargetBlock, MachineFunction &Function, + const TargetDescription &Target) const = 0; + + [[nodiscard]] virtual Expected<bool> isFallthroughEdge(const MachineBasicBlock &From, + const MachineBasicBlock &To, + const MachineFunction &Function, + const TargetDescription &Target) const = 0; + + [[nodiscard]] virtual Expected<void> validateCopy(Register Destination, + SubRegIndex DestinationSubReg, Register Source, + SubRegIndex SourceSubReg, + const MachineFunction &Function, + const TargetDescription &Target) const = 0; + + [[nodiscard]] virtual Expected<bool> tryConvertToThreeAddress(MachineInstr &, std::size_t, + std::size_t, MachineFunction &, + const TargetDescription &) const { + return false; + } [[nodiscard]] virtual Expected<std::uint32_t> instructionSize(const MachineInstr &Instruction, const MachineFunction &Function, diff --git a/backend/include/rcc/Target/RISCV/RISCVCodeGen.h b/backend/include/rcc/Target/RISCV/RISCVCodeGen.h index d68157a..6cda815 100644 --- a/backend/include/rcc/Target/RISCV/RISCVCodeGen.h +++ b/backend/include/rcc/Target/RISCV/RISCVCodeGen.h @@ -7,7 +7,6 @@ #include "rcc/CodeGen/MachineOptimizationPipeline.h" #include "rcc/CodeGen/TargetCodeGen.h" #include "rcc/CodeGen/TargetFrameLowering.h" -#include "rcc/CodeGen/TargetInstrInfo.h" #include "rcc/CodeGen/TargetMemoryFolding.h" #include "rcc/CodeGen/TargetPseudoExpansion.h" #include "rcc/CodeGen/TargetRegisterAllocationInfo.h" @@ -23,13 +22,11 @@ namespace rcc::riscv { createLegalizerInfo(RISCVSubtargetFeatures Features); [[nodiscard]] const TargetRegisterBankInfo ®isterBankInfo() noexcept; [[nodiscard]] const TargetInstructionSelector &instructionSelector() noexcept; -[[nodiscard]] const TargetSSAInfo &ssaInfo() noexcept; [[nodiscard]] const TargetRegisterAllocationInfo ®isterAllocationInfo() noexcept; [[nodiscard]] const TargetFrameLowering &frameLowering() noexcept; [[nodiscard]] const TargetSchedulingModel &schedulingModel() noexcept; [[nodiscard]] const TargetMachineCombinerInfo &machineCombinerInfo() noexcept; [[nodiscard]] const TargetMemoryFoldingInfo &memoryFoldingInfo() noexcept; -[[nodiscard]] const TargetInstrInfo &branchInfo() noexcept; [[nodiscard]] const TargetPseudoExpansionInfo &pseudoExpansionInfo() noexcept; [[nodiscard]] MachineOptimizationPipelineTargetInfo optimizationPipelineInfo() noexcept; diff --git a/backend/lib/CodeGen/MachineBranchOptimization.cpp b/backend/lib/CodeGen/MachineBranchOptimization.cpp index 19127ea..df25a4a 100644 --- a/backend/lib/CodeGen/MachineBranchOptimization.cpp +++ b/backend/lib/CodeGen/MachineBranchOptimization.cpp @@ -142,7 +142,7 @@ namespace { if (!RemovedUnconditional) return std::unexpected(RemovedUnconditional.error()); } - auto Inserted = Info.insertUnconditionalBranch(*Block, *Selected, Function, Target); + auto Inserted = Info.insertBranch(*Block, *Selected, Function, Target); if (!Inserted) return std::unexpected(Inserted.error()); @@ -269,8 +269,7 @@ namespace { } else { if (Predecessor->next() != Block) continue; - auto Inserted = - Info.insertUnconditionalBranch(*Predecessor, *Successor, Function, Target); + auto Inserted = Info.insertBranch(*Predecessor, *Successor, Function, Target); if (!Inserted) return std::unexpected(Inserted.error()); } diff --git a/backend/lib/CodeGen/MachineCopyPropagation.cpp b/backend/lib/CodeGen/MachineCopyPropagation.cpp index f9211f9..60992a5 100644 --- a/backend/lib/CodeGen/MachineCopyPropagation.cpp +++ b/backend/lib/CodeGen/MachineCopyPropagation.cpp @@ -12,8 +12,8 @@ #include "rcc/CodeGen/MachineOperand.h" #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/RegisterMask.h" -#include "rcc/CodeGen/TargetCodeGen.h" #include "rcc/CodeGen/TargetDescription.h" +#include "rcc/CodeGen/TargetInstrInfo.h" #include "rcc/CodeGen/TargetRegisterInfo.h" #include <algorithm> @@ -127,7 +127,7 @@ struct CopyOperands final { [[nodiscard]] Expected<bool> propagateVirtualCopy(MachineInstr &Copy, const CopyOperands &Operands, MachineFunction &Function, const TargetDescription &Target, - const TargetSSAInfo &Info) { + const TargetInstrInfo &Info) { if (!Operands.Destination.isVirtual() || !Operands.Source.isVirtual()) return false; if (Function.registerInfo().getUniqueVRegDef(Operands.Destination) != @@ -231,7 +231,7 @@ struct CopyOperands final { [[nodiscard]] Expected<bool> propagatePhysicalCopy(MachineInstr &Copy, const CopyOperands &Operands, MachineFunction &Function, const TargetDescription &Target, - const TargetSSAInfo &Info) { + const TargetInstrInfo &Info) { const std::optional<PhysicalRegister> Destination = Operands.Destination.physicalRegister(); const std::optional<PhysicalRegister> Source = Operands.Source.physicalRegister(); if (!Destination || !Source || Operands.DestinationOperand->subReg().value() != 0 || diff --git a/backend/lib/CodeGen/MachineFallthrough.cpp b/backend/lib/CodeGen/MachineFallthrough.cpp index a853f96..e912f0b 100644 --- a/backend/lib/CodeGen/MachineFallthrough.cpp +++ b/backend/lib/CodeGen/MachineFallthrough.cpp @@ -83,8 +83,7 @@ normalizeFallthroughs(MachineFunction &Function, const TargetDescription &Target Changed = true; } else if (Analysis->Conditional != nullptr && Analysis->Unconditional == nullptr && Analysis->FalseTarget != nullptr) { - auto Inserted = - Info.insertUnconditionalBranch(*Block, *Analysis->FalseTarget, Function, Target); + auto Inserted = Info.insertBranch(*Block, *Analysis->FalseTarget, Function, Target); if (!Inserted) return std::unexpected(Inserted.error()); Changed = true; @@ -102,7 +101,7 @@ normalizeFallthroughs(MachineFunction &Function, const TargetDescription &Target return makeUnexpected(ErrorCode::VerificationError, "fallthrough normalization encountered a null successor"); } - auto Inserted = Info.insertUnconditionalBranch(*Block, *Successor, Function, Target); + auto Inserted = Info.insertBranch(*Block, *Successor, Function, Target); if (!Inserted) return std::unexpected(Inserted.error()); Changed = true; diff --git a/backend/lib/CodeGen/MachineOptimizationPipeline.cpp b/backend/lib/CodeGen/MachineOptimizationPipeline.cpp index 76dbd44..6d24034 100644 --- a/backend/lib/CodeGen/MachineOptimizationPipeline.cpp +++ b/backend/lib/CodeGen/MachineOptimizationPipeline.cpp @@ -69,10 +69,10 @@ addSelectedSSAOptimizationPipeline(MachinePassManager &Pipeline, Expected<void> addPreRegisterAllocationOptimizationPipeline( MachinePassManager &Pipeline, const MachineOptimizationPipelineTargetInfo &TargetInfo) { - auto Added = addPass<MachineBranchOptimizationPass>(Pipeline, TargetInfo.BranchInfo); + auto Added = addPass<MachineBranchOptimizationPass>(Pipeline, TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); - Added = addPass<MachineCopyPropagationPass>(Pipeline, TargetInfo.SSA, + Added = addPass<MachineCopyPropagationPass>(Pipeline, TargetInfo.InstrInfo, MachineCopyPropagationStage::PreRegisterAllocation); if (!Added) return std::unexpected(Added.error()); @@ -92,7 +92,7 @@ addPostRegisterAllocationPipeline(MachinePassManager &Pipeline, auto Added = addPass<MachineStackSlotColoringPass>(Pipeline); if (!Added) return std::unexpected(Added.error()); - Added = addPass<MachineCopyPropagationPass>(Pipeline, TargetInfo.SSA, + Added = addPass<MachineCopyPropagationPass>(Pipeline, TargetInfo.InstrInfo, MachineCopyPropagationStage::PostRegisterAllocation); if (!Added) return std::unexpected(Added.error()); @@ -128,29 +128,29 @@ addPostRegisterAllocationPipeline(MachinePassManager &Pipeline, Added = addPass<PostRASchedulerPass>(Pipeline, TargetInfo.SchedulingModel); if (!Added) return std::unexpected(Added.error()); - Added = addPass<MachineTailDuplicationPass>(Pipeline, TargetInfo.BranchInfo); + Added = addPass<MachineTailDuplicationPass>(Pipeline, TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); - Added = addPass<MachineTailMergePass>(Pipeline, TargetInfo.BranchInfo); + Added = addPass<MachineTailMergePass>(Pipeline, TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); Added = addPass<MachineBlockPlacementPass>(Pipeline); if (!Added) return std::unexpected(Added.error()); - Added = addPass<MachineFallthroughPass>(Pipeline, TargetInfo.BranchInfo); + Added = addPass<MachineFallthroughPass>(Pipeline, TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); - Added = addPass<MachineBranchRelaxationPass>(Pipeline, TargetInfo.BranchInfo); + Added = addPass<MachineBranchRelaxationPass>(Pipeline, TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); Added = addPass<TargetLatePseudoExpansionPass>(Pipeline, TargetInfo.PseudoExpansion, - TargetInfo.BranchInfo); + TargetInfo.InstrInfo); if (!Added) return std::unexpected(Added.error()); Added = addPass<FinalizeEmissionPseudosPass>(Pipeline); if (!Added) return std::unexpected(Added.error()); - return addPass<FinalEncodabilityVerifierPass>(Pipeline, TargetInfo.BranchInfo); + return addPass<FinalEncodabilityVerifierPass>(Pipeline, TargetInfo.InstrInfo); } } // namespace rcc diff --git a/backend/lib/CodeGen/MachineSSAExit.cpp b/backend/lib/CodeGen/MachineSSAExit.cpp index 76963ea..ec10b3b 100644 --- a/backend/lib/CodeGen/MachineSSAExit.cpp +++ b/backend/lib/CodeGen/MachineSSAExit.cpp @@ -167,7 +167,7 @@ struct PhiPlan final { [[nodiscard]] Expected<MachineInstr *> buildCopy(MachineFunction &Function, const TargetDescription &Target, - const TargetSSAInfo &TargetInfo, MachineBasicBlock &Block, MachineInstr *Before, + const TargetInstrInfo &TargetInfo, MachineBasicBlock &Block, MachineInstr *Before, RegisterValue Destination, RegisterValue Source, const MachineInstr *DebugSource) { auto Legality = TargetInfo.validateCopy(Destination.Reg, Destination.SubReg, Source.Reg, Source.SubReg, Function, Target); @@ -388,7 +388,7 @@ buildImplicitDef(MachineFunction &Function, const TargetDescription &Target, [[nodiscard]] Expected<MachineBasicBlock *> placePhiCopiesOnEdge(MachineFunction &Function, const TargetDescription &Target, - const TargetSSAInfo &TargetInfo, MachineBasicBlock &From, + const TargetInstrInfo &TargetInfo, MachineBasicBlock &From, MachineBasicBlock &To, std::unordered_map<EdgeKey, MachineBasicBlock *, EdgeKeyHash> &Cache, MachinePassResult &PassResult) { @@ -415,7 +415,7 @@ placePhiCopiesOnEdge(MachineFunction &Function, const TargetDescription &Target, if (!OtherFallthrough) return std::unexpected(OtherFallthrough.error()); if (*OtherFallthrough) { - auto Branch = TargetInfo.insertUnconditionalBranch(*LayoutPredecessor, To, Function, Target); + auto Branch = TargetInfo.insertBranch(*LayoutPredecessor, To, Function, Target); if (!Branch) return std::unexpected(Branch.error()); PassResult.Changed = true; @@ -445,7 +445,7 @@ placePhiCopiesOnEdge(MachineFunction &Function, const TargetDescription &Target, auto LiveIns = copyLiveIns(To, *EdgeBlock); if (!LiveIns) return std::unexpected(LiveIns.error()); - auto Branch = TargetInfo.insertUnconditionalBranch(*EdgeBlock, To, Function, Target); + auto Branch = TargetInfo.insertBranch(*EdgeBlock, To, Function, Target); if (!Branch) return std::unexpected(Branch.error()); @@ -526,7 +526,7 @@ placePhiCopiesOnEdge(MachineFunction &Function, const TargetDescription &Target, [[nodiscard]] Expected<void> expandRegSequence(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - const TargetSSAInfo &TargetInfo) { + const TargetInstrInfo &TargetInfo) { if (Instruction.operandCount() < 3 || (Instruction.operandCount() - 1U) % 2U != 0) { return makeUnexpected(ErrorCode::VerificationError, "REG_SEQUENCE requires a destination and source/subregister pairs"); @@ -588,7 +588,7 @@ placePhiCopiesOnEdge(MachineFunction &Function, const TargetDescription &Target, [[nodiscard]] Expected<void> expandInsertSubreg(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - const TargetSSAInfo &TargetInfo) { + const TargetInstrInfo &TargetInfo) { if (Instruction.operandCount() != 4) { return makeUnexpected(ErrorCode::VerificationError, "INSERT_SUBREG requires destination, base, inserted value, and index"); @@ -792,7 +792,7 @@ Expected<MachinePassResult> PHIEliminationPass::run(MachineFunction &Function, MachineAnalysisManager &Analyses) { if (Info == nullptr) { return makeUnexpected(ErrorCode::InvalidArgument, - "PHI elimination has no target SSA behavior interface"); + "PHI elimination has no target instruction information"); } auto Required = requireProperties(Function, contract()); if (!Required) @@ -927,7 +927,7 @@ Expected<MachinePassResult> TwoAddressRewritePass::run(MachineFunction &Function MachineAnalysisManager &Analyses) { if (Info == nullptr) { return makeUnexpected(ErrorCode::InvalidArgument, - "two-address rewrite has no target SSA behavior interface"); + "two-address rewrite has no target instruction information"); } auto Required = requireProperties(Function, contract()); if (!Required) diff --git a/backend/lib/CodeGen/MachineTailDuplication.cpp b/backend/lib/CodeGen/MachineTailDuplication.cpp index a4b31b2..80c58c9 100644 --- a/backend/lib/CodeGen/MachineTailDuplication.cpp +++ b/backend/lib/CodeGen/MachineTailDuplication.cpp @@ -230,8 +230,7 @@ duplicateTailIntoPredecessor(const TailCandidate &Candidate, MachineBasicBlock & if (!Removed) return std::unexpected(Removed.error()); } - auto NewBranch = - Info.insertUnconditionalBranch(Predecessor, *Candidate.Successor, Function, Target); + auto NewBranch = Info.insertBranch(Predecessor, *Candidate.Successor, Function, Target); if (!NewBranch) return std::unexpected(NewBranch.error()); MachineCFGUpdater CFG = Function.cfgUpdater(); diff --git a/backend/lib/CodeGen/MachineTailMerge.cpp b/backend/lib/CodeGen/MachineTailMerge.cpp index c8aad80..07608cc 100644 --- a/backend/lib/CodeGen/MachineTailMerge.cpp +++ b/backend/lib/CodeGen/MachineTailMerge.cpp @@ -279,7 +279,7 @@ redirectPredecessor(MachineBasicBlock &Predecessor, MachineBasicBlock &Duplicate Analysis->FalseTarget == &Duplicate); if (!IsImplicitEdge) return false; - auto Inserted = Info.insertUnconditionalBranch(Predecessor, Canonical, Function, Target); + auto Inserted = Info.insertBranch(Predecessor, Canonical, Function, Target); if (!Inserted) return std::unexpected(Inserted.error()); } diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt index 68bd444..d28cdf3 100644 --- a/backend/lib/Target/RISCV/CMakeLists.txt +++ b/backend/lib/Target/RISCV/CMakeLists.txt @@ -47,7 +47,7 @@ set_source_files_properties( add_library( RCCBackendRISCV - RISCVBranchInfo.cpp + RISCVInstrInfo.cpp RISCVCodeGen.cpp RISCVCallLowering.cpp RISCVAssemblyPrinter.cpp @@ -84,7 +84,9 @@ target_include_directories( "$<BUILD_INTERFACE:${RCC_BACKEND_SOURCE_DIR}/include>" "$<BUILD_INTERFACE:${RCC_BACKEND_BINARY_DIR}/generated/include>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" - PRIVATE "${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV" + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}" + "${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV" ) target_link_libraries( RCCBackendRISCV @@ -116,7 +118,7 @@ install( ) rcc_backend_register_format_files( - "${CMAKE_CURRENT_SOURCE_DIR}/RISCVBranchInfo.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVInstrInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVAssemblyPrinter.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVCodeGen.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVCallLowering.cpp" @@ -140,6 +142,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetConstant.cpp" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVCodeGen.h" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVInstrInfo.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVAssemblyPrinter.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVCallLowering.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVInstPrinter.h" @@ -156,7 +159,7 @@ rcc_backend_register_format_files( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVTargetRelocationKinds.h" ) rcc_backend_register_tidy_files( - "${CMAKE_CURRENT_SOURCE_DIR}/RISCVBranchInfo.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVInstrInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVAssemblyPrinter.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVCodeGen.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVCallLowering.cpp" diff --git a/backend/lib/Target/RISCV/RISCVCodeGen.cpp b/backend/lib/Target/RISCV/RISCVCodeGen.cpp index d03653f..00dba94 100644 --- a/backend/lib/Target/RISCV/RISCVCodeGen.cpp +++ b/backend/lib/Target/RISCV/RISCVCodeGen.cpp @@ -6512,198 +6512,6 @@ private: } }; -class RISCVSSAInfo final : public TargetSSAInfo { -public: - [[nodiscard]] Expected<bool> isFallthroughEdge(const MachineBasicBlock &From, - const MachineBasicBlock &To, - const MachineFunction &, - const TargetDescription &Target) const override { - if (From.next() != &To || - std::ranges::none_of(From.successors(), [&To](const MachineSuccessor &Successor) { - return Successor.Block == &To; - })) { - return false; - } - - bool CanFallThrough = true; - for (const MachineInstr *Instruction = From.firstInstruction(); Instruction != nullptr; - Instruction = Instruction->next()) { - const InstructionDescriptor *Descriptor = Target.instructionDescriptor(Instruction->opcode()); - if (Descriptor == nullptr) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V fallthrough analysis encountered an unknown opcode"); - } - if (!Descriptor->Flags.has(InstructionFlag::Terminator)) - continue; - CanFallThrough = isConditionalBranch(Instruction->opcode()); - } - return CanFallThrough; - } - - [[nodiscard]] Expected<bool> rewriteBranchTarget(MachineBasicBlock &Block, - MachineBasicBlock &OldTarget, - MachineBasicBlock &NewTarget, - MachineFunction &Function, - const TargetDescription &Target) const override { - if (&Block.function() != &Function || &OldTarget.function() != &Function || - &NewTarget.function() != &Function) { - return makeUnexpected(ErrorCode::InvalidArgument, - "RISC-V branch rewrite references another machine function"); - } - - bool Changed = false; - for (MachineInstr *Instruction = Block.firstInstruction(); Instruction != nullptr; - Instruction = Instruction->next()) { - const InstructionDescriptor *Descriptor = Target.instructionDescriptor(Instruction->opcode()); - if (Descriptor == nullptr) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V branch rewrite encountered an unknown opcode"); - } - if (!Descriptor->Flags.has(InstructionFlag::Branch) || - Descriptor->Flags.has(InstructionFlag::IndirectBranch)) { - continue; - } - for (std::size_t Index = 0; Index < Instruction->operandCount(); ++Index) { - MachineOperand *Operand = Instruction->operandAt(Index); - const BasicBlockOperand *TargetOperand = - Operand == nullptr ? nullptr : Operand->getIf<BasicBlockOperand>(); - if (TargetOperand == nullptr || TargetOperand->Block != &OldTarget) - continue; - auto Rewritten = Operand->setBasicBlock(NewTarget); - if (!Rewritten) - return std::unexpected(Rewritten.error()); - Changed = true; - } - } - return Changed; - } - - [[nodiscard]] Expected<void> - insertUnconditionalBranch(MachineBasicBlock &Block, MachineBasicBlock &TargetBlock, - MachineFunction &Function, - const TargetDescription &Target) const override { - if (&Block.function() != &Function || &TargetBlock.function() != &Function) { - return makeUnexpected(ErrorCode::InvalidArgument, - "RISC-V branch insertion references another machine function"); - } - auto Zero = physicalRegister(PhysicalRegisterID::X0); - if (!Zero) - return std::unexpected(Zero.error()); - MachineIRBuilder Builder(Function, Target); - auto Point = Builder.setInsertPoint(Block); - if (!Point) - return std::unexpected(Point.error()); - auto Branch = Builder.buildInstr(targetOpcode(InstructionOpcode::JAL)); - if (!Branch) - return std::unexpected(Branch.error()); - auto Link = Branch->addDef(Register::fromPhysical(*Zero)); - if (!Link) - return std::unexpected(Link.error()); - auto Destination = Branch->addBasicBlock(TargetBlock); - if (!Destination) - return std::unexpected(Destination.error()); - auto Built = Branch->build(); - if (!Built) - return std::unexpected(Built.error()); - return {}; - } - - [[nodiscard]] Expected<void> validateCopy(Register Destination, SubRegIndex DestinationSubReg, - Register Source, SubRegIndex SourceSubReg, - const MachineFunction &Function, - const TargetDescription &Target) const override { - if (Destination.isNoRegister() || Source.isNoRegister()) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V COPY requires two nonzero registers"); - } - if (DestinationSubReg.value() != 0 || SourceSubReg.value() != 0) { - return makeUnexpected(ErrorCode::Unsupported, "RV64GC does not model register subindices"); - } - - auto DestinationShape = copyShape(Destination, Function, Target); - if (!DestinationShape) - return std::unexpected(DestinationShape.error()); - auto SourceShape = copyShape(Source, Function, Target); - if (!SourceShape) - return std::unexpected(SourceShape.error()); - if (DestinationShape->Bank == SourceShape->Bank) { - if (DestinationShape->Width && SourceShape->Width && - DestinationShape->Width != SourceShape->Width) { - return makeUnexpected(ErrorCode::Unsupported, - "RISC-V same-bank COPY has incompatible register widths"); - } - return {}; - } - - const RegisterBankID GPR = - RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::GPR)); - const RegisterBankID FPR = - RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::FPR)); - const bool IsCrossBankMove = (DestinationShape->Bank == GPR && SourceShape->Bank == FPR) || - (DestinationShape->Bank == FPR && SourceShape->Bank == GPR); - if (!IsCrossBankMove) { - return makeUnexpected(ErrorCode::Unsupported, - "RISC-V COPY crosses unsupported register banks"); - } - auto SupportedWidth = [](std::optional<std::uint32_t> Width) { - return !Width || *Width == 32 || *Width == 64; - }; - if (!SupportedWidth(DestinationShape->Width) || !SupportedWidth(SourceShape->Width)) { - return makeUnexpected(ErrorCode::Unsupported, - "RISC-V GPR/FPR COPY requires 32-bit or 64-bit values"); - } - return {}; - } - -private: - struct CopyShape final { - RegisterBankID Bank; - std::optional<std::uint32_t> Width; - }; - - [[nodiscard]] static bool isConditionalBranch(Opcode Value) noexcept { - return Value == targetOpcode(InstructionOpcode::BEQ) || - Value == targetOpcode(InstructionOpcode::BNE) || - Value == targetOpcode(InstructionOpcode::BLT) || - Value == targetOpcode(InstructionOpcode::BGE) || - Value == targetOpcode(InstructionOpcode::BLTU) || - Value == targetOpcode(InstructionOpcode::BGEU); - } - - [[nodiscard]] static Expected<CopyShape> copyShape(Register Reg, const MachineFunction &Function, - const TargetDescription &Target) { - if (Reg.isVirtual()) { - auto Info = Function.registerInfo().virtualRegisterInfo(Reg); - if (!Info) - return std::unexpected(Info.error()); - const std::optional<RegisterBankID> &Bank = Info->get().Bank; - const std::optional<RegisterClassID> &RegClass = Info->get().RegClass; - if (!Bank || !RegClass) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V COPY virtual register is not fully constrained"); - } - const RegisterClassDesc *Class = Target.registers().registerClass(RegClass.value()); - if (Class == nullptr) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V COPY references an unknown register class"); - } - return CopyShape{Bank.value(), Class->SizeInBits}; - } - - const std::optional<PhysicalRegister> Physical = Reg.physicalRegister(); - if (!Physical || !Target.registers().isKnownPhysicalRegister(*Physical)) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V COPY references an unknown physical register"); - } - for (const RegisterBankDesc &Bank : Target.registers().registerBanks()) { - if (Target.registers().bankContainsRegister(Bank.ID, *Physical)) - return CopyShape{Bank.ID, std::nullopt}; - } - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V physical register is not assigned to a register bank"); - } -}; - } // namespace const TargetLegalizerInfo &legalizerInfo() noexcept { @@ -6725,9 +6533,4 @@ const TargetInstructionSelector &instructionSelector() noexcept { return Value; } -const TargetSSAInfo &ssaInfo() noexcept { - static const RISCVSSAInfo Value; - return Value; -} - } // namespace rcc::riscv diff --git a/backend/lib/Target/RISCV/RISCVBranchInfo.cpp b/backend/lib/Target/RISCV/RISCVInstrInfo.cpp index 059bbef..6e26e2c 100644 --- a/backend/lib/Target/RISCV/RISCVBranchInfo.cpp +++ b/backend/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later +#include "RISCVInstrInfo.h" + #include "rcc/CodeGen/InstructionDescriptor.h" #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineFunction.h" @@ -8,7 +10,6 @@ #include "rcc/CodeGen/MachineOperand.h" #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/TargetDescription.h" -#include "rcc/Target/RISCV/RISCVCodeGen.h" #include "rcc/Target/RISCV/RISCVInstructions.h" #include "rcc/Target/RISCV/RISCVRegisters.h" #include "rcc/Target/RISCV/RISCVTarget.h" @@ -497,7 +498,7 @@ selectLongBranchScratch(const MachineInstr &Instruction, const MachineBasicBlock return true; } -class RISCVBranchInfo final : public TargetInstrInfo { +class RISCVInstrInfo final : public TargetInstrInfo { public: [[nodiscard]] Expected<MachineBranchAnalysis> analyzeBranch(MachineBasicBlock &Block, MachineFunction &Function, @@ -623,9 +624,8 @@ public: } [[nodiscard]] Expected<MachineInstr *> - insertUnconditionalBranch(MachineBasicBlock &Block, MachineBasicBlock &TargetBlock, - MachineFunction &Function, - const TargetDescription &Target) const override { + insertBranch(MachineBasicBlock &Block, MachineBasicBlock &TargetBlock, MachineFunction &Function, + const TargetDescription &Target) const override { if (&Block.function() != &Function || &TargetBlock.function() != &Function) return makeUnexpected(ErrorCode::InvalidArgument, "RISC-V branch insertion references another function"); @@ -635,6 +635,75 @@ public: return buildJAL(Function, Target, Block, nullptr, *Zero, TargetBlock); } + [[nodiscard]] Expected<bool> isFallthroughEdge(const MachineBasicBlock &From, + const MachineBasicBlock &To, + const MachineFunction &Function, + const TargetDescription &Target) const override { + if (&From.function() != &Function || &To.function() != &Function) + return makeUnexpected(ErrorCode::InvalidArgument, + "RISC-V fallthrough query references another machine function"); + if (From.next() != &To || + std::ranges::none_of(From.successors(), [&To](const MachineSuccessor &Successor) { + return Successor.Block == &To; + })) { + return false; + } + + bool CanFallThrough = true; + for (const MachineInstr *Instruction = From.firstInstruction(); Instruction != nullptr; + Instruction = Instruction->next()) { + const InstructionDescriptor *Descriptor = Target.instructionDescriptor(Instruction->opcode()); + if (Descriptor == nullptr) + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V fallthrough analysis encountered an unknown opcode"); + if (Descriptor->Flags.has(InstructionFlag::Terminator)) + CanFallThrough = isConditionalBranch(Instruction->opcode()); + } + return CanFallThrough; + } + + [[nodiscard]] Expected<void> validateCopy(Register Destination, SubRegIndex DestinationSubReg, + Register Source, SubRegIndex SourceSubReg, + const MachineFunction &Function, + const TargetDescription &Target) const override { + if (Destination.isNoRegister() || Source.isNoRegister()) + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V COPY requires two nonzero registers"); + if (DestinationSubReg.value() != 0 || SourceSubReg.value() != 0) + return makeUnexpected(ErrorCode::Unsupported, "RV64GC does not model register subindices"); + + auto DestinationShape = copyShape(Destination, Function, Target); + if (!DestinationShape) + return std::unexpected(DestinationShape.error()); + auto SourceShape = copyShape(Source, Function, Target); + if (!SourceShape) + return std::unexpected(SourceShape.error()); + if (DestinationShape->Bank == SourceShape->Bank) { + if (DestinationShape->Width && SourceShape->Width && + DestinationShape->Width != SourceShape->Width) + return makeUnexpected(ErrorCode::Unsupported, + "RISC-V same-bank COPY has incompatible register widths"); + return {}; + } + + const RegisterBankID GPR = + RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::GPR)); + const RegisterBankID FPR = + RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::FPR)); + const bool IsCrossBankMove = (DestinationShape->Bank == GPR && SourceShape->Bank == FPR) || + (DestinationShape->Bank == FPR && SourceShape->Bank == GPR); + if (!IsCrossBankMove) + return makeUnexpected(ErrorCode::Unsupported, + "RISC-V COPY crosses unsupported register banks"); + const auto SupportedWidth = [](std::optional<std::uint32_t> Width) { + return !Width || *Width == 32 || *Width == 64; + }; + if (!SupportedWidth(DestinationShape->Width) || !SupportedWidth(SourceShape->Width)) + return makeUnexpected(ErrorCode::Unsupported, + "RISC-V GPR/FPR COPY requires 32-bit or 64-bit values"); + return {}; + } + [[nodiscard]] Expected<std::uint32_t> instructionSize(const MachineInstr &Instruction, const MachineFunction &, const TargetDescription &Target) const override { @@ -726,12 +795,48 @@ public: return relaxJAL(Instruction, Offset, Function, Target); return false; } + +private: + struct CopyShape final { + RegisterBankID Bank; + std::optional<std::uint32_t> Width; + }; + + [[nodiscard]] static Expected<CopyShape> copyShape(Register Reg, const MachineFunction &Function, + const TargetDescription &Target) { + if (Reg.isVirtual()) { + auto Info = Function.registerInfo().virtualRegisterInfo(Reg); + if (!Info) + return std::unexpected(Info.error()); + const std::optional<RegisterBankID> &Bank = Info->get().Bank; + const std::optional<RegisterClassID> &RegClass = Info->get().RegClass; + if (!Bank || !RegClass) + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V COPY virtual register is not fully constrained"); + const RegisterClassDesc *Class = Target.registers().registerClass(*RegClass); + if (Class == nullptr) + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V COPY references an unknown register class"); + return CopyShape{*Bank, Class->SizeInBits}; + } + + const std::optional<PhysicalRegister> Physical = Reg.physicalRegister(); + if (!Physical || !Target.registers().isKnownPhysicalRegister(*Physical)) + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V COPY references an unknown physical register"); + for (const RegisterBankDesc &Bank : Target.registers().registerBanks()) { + if (Target.registers().bankContainsRegister(Bank.ID, *Physical)) + return CopyShape{Bank.ID, std::nullopt}; + } + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V physical register is not assigned to a register bank"); + } }; } // namespace -const TargetInstrInfo &branchInfo() noexcept { - static const RISCVBranchInfo Value; +const TargetInstrInfo &instrInfo() noexcept { + static const RISCVInstrInfo Value; return Value; } diff --git a/backend/lib/Target/RISCV/RISCVInstrInfo.h b/backend/lib/Target/RISCV/RISCVInstrInfo.h new file mode 100644 index 0000000..62c7723 --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVInstrInfo.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_LIB_TARGET_RISCV_RISCVINSTRINFO_H +#define RCC_LIB_TARGET_RISCV_RISCVINSTRINFO_H + +#include "rcc/CodeGen/TargetInstrInfo.h" + +namespace rcc::riscv { + +[[nodiscard]] const TargetInstrInfo &instrInfo() noexcept; + +} // namespace rcc::riscv + +#endif // RCC_LIB_TARGET_RISCV_RISCVINSTRINFO_H diff --git a/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp b/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp index 2f8c5d1..9301757 100644 --- a/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp +++ b/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp @@ -1,18 +1,18 @@ // SPDX-License-Identifier: GPL-3.0-or-later +#include "RISCVInstrInfo.h" #include "rcc/Target/RISCV/RISCVCodeGen.h" namespace rcc::riscv { MachineOptimizationPipelineTargetInfo optimizationPipelineInfo() noexcept { return { - .SSA = ssaInfo(), + .InstrInfo = instrInfo(), .Combiner = machineCombinerInfo(), .MemoryFolding = memoryFoldingInfo(), .FrameLowering = frameLowering(), .PseudoExpansion = pseudoExpansionInfo(), .SchedulingModel = schedulingModel(), - .BranchInfo = branchInfo(), }; } diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp index 3665db5..08a4653 100644 --- a/backend/lib/Target/RISCV/RISCVPipeline.cpp +++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp @@ -2,6 +2,7 @@ #include "rcc/Target/RISCV/RISCVPipeline.h" +#include "RISCVInstrInfo.h" #include "rcc/CodeGen/MachineCombiner.h" #include "rcc/CodeGen/MachineFunction.h" #include "rcc/CodeGen/MachineOptimizationPipeline.h" @@ -45,10 +46,10 @@ template <typename PassT, typename... ArgumentT> auto Added = addSelectedSSAOptimizationPipeline(Pipeline, optimizationPipelineInfo()); if (!Added) return std::unexpected(Added.error()); - Added = addPass<PHIEliminationPass>(Pipeline, ssaInfo()); + Added = addPass<PHIEliminationPass>(Pipeline, instrInfo()); if (!Added) return std::unexpected(Added.error()); - return addPass<TwoAddressRewritePass>(Pipeline, ssaInfo()); + return addPass<TwoAddressRewritePass>(Pipeline, instrInfo()); } [[nodiscard]] Expected<void> addRegisterAllocationPipeline(MachinePassManager &Pipeline) { @@ -104,13 +105,13 @@ Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineF if (!Added) return std::unexpected(Added.error()); if (!Function.properties().has(MachineFunctionProperty::NoPHIs)) { - Added = addPass<PHIEliminationPass>(Pipeline, ssaInfo()); + Added = addPass<PHIEliminationPass>(Pipeline, instrInfo()); if (!Added) return std::unexpected(Added.error()); } } if (!Function.properties().has(MachineFunctionProperty::TiedOpsRewritten)) { - auto Added = addPass<TwoAddressRewritePass>(Pipeline, ssaInfo()); + auto Added = addPass<TwoAddressRewritePass>(Pipeline, instrInfo()); if (!Added) return std::unexpected(Added.error()); } diff --git a/backend/unittests/CodeGen/MachineSSAExitTest.cpp b/backend/unittests/CodeGen/MachineSSAExitTest.cpp index a3940c2..a5cc1c7 100644 --- a/backend/unittests/CodeGen/MachineSSAExitTest.cpp +++ b/backend/unittests/CodeGen/MachineSSAExitTest.cpp @@ -15,6 +15,7 @@ #include "rcc/CodeGen/MachineRegisterInfo.h" #include "rcc/CodeGen/MachineVerifier.h" #include "rcc/CodeGen/TargetDescription.h" +#include "rcc/CodeGen/TargetInstrInfo.h" #include <algorithm> #include <array> @@ -158,9 +159,26 @@ private: return rcc::test::createTestTargetDescription(std::move(*Instructions)); } -class TestSSAInfo final : public rcc::TargetSSAInfo { +class TestInstrInfo final : public rcc::TargetInstrInfo { public: - explicit TestSSAInfo(bool RejectCopies = false) : RejectCopies(RejectCopies) {} + explicit TestInstrInfo(bool RejectCopies = false) : RejectCopies(RejectCopies) {} + + [[nodiscard]] rcc::Expected<rcc::MachineBranchAnalysis> + analyzeBranch(rcc::MachineBasicBlock &, rcc::MachineFunction &, + const rcc::TargetDescription &) const override { + return rcc::MachineBranchAnalysis{}; + } + + [[nodiscard]] rcc::Expected<void> + reverseBranchCondition(rcc::MachineInstr &, rcc::MachineBasicBlock &, rcc::MachineFunction &, + const rcc::TargetDescription &) const override { + return rcc::makeUnexpected(rcc::ErrorCode::Unsupported, "test target has no branch reversal"); + } + + [[nodiscard]] rcc::Expected<void> removeBranch(rcc::MachineInstr &, rcc::MachineFunction &, + const rcc::TargetDescription &) const override { + return rcc::makeUnexpected(rcc::ErrorCode::Unsupported, "test target has no branch removal"); + } [[nodiscard]] rcc::Expected<bool> isFallthroughEdge(const rcc::MachineBasicBlock &From, const rcc::MachineBasicBlock &To, @@ -225,10 +243,10 @@ public: return Changed; } - [[nodiscard]] rcc::Expected<void> - insertUnconditionalBranch(rcc::MachineBasicBlock &Block, rcc::MachineBasicBlock &TargetBlock, - rcc::MachineFunction &Function, - const rcc::TargetDescription &Target) const override { + [[nodiscard]] rcc::Expected<rcc::MachineInstr *> + insertBranch(rcc::MachineBasicBlock &Block, rcc::MachineBasicBlock &TargetBlock, + rcc::MachineFunction &Function, + const rcc::TargetDescription &Target) const override { rcc::MachineIRBuilder Builder(Function, Target); auto Point = Builder.setInsertPoint(Block); if (!Point) @@ -242,7 +260,7 @@ public: auto Built = Pending->build(); if (!Built) return std::unexpected(Built.error()); - return {}; + return *Built; } [[nodiscard]] rcc::Expected<void> @@ -289,6 +307,29 @@ public: return true; } + [[nodiscard]] rcc::Expected<std::uint32_t> + instructionSize(const rcc::MachineInstr &, const rcc::MachineFunction &, + const rcc::TargetDescription &) const override { + return 4; + } + + [[nodiscard]] rcc::Expected<rcc::MachineBasicBlock *> + branchTarget(rcc::MachineInstr &, rcc::MachineFunction &, + const rcc::TargetDescription &) const override { + return static_cast<rcc::MachineBasicBlock *>(nullptr); + } + + [[nodiscard]] bool isBranchOffsetInRange(const rcc::MachineInstr &, + std::int64_t) const noexcept override { + return true; + } + + [[nodiscard]] rcc::Expected<bool> relaxBranch(rcc::MachineInstr &, std::int64_t, + rcc::MachineFunction &, + const rcc::TargetDescription &) const override { + return false; + } + private: bool RejectCopies = false; }; @@ -430,7 +471,7 @@ buildPhi(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, [[nodiscard]] rcc::Expected<void> runPHIElimination(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, - const rcc::TargetSSAInfo &Info) { + const rcc::TargetInstrInfo &Info) { rcc::MachinePassManager Pipeline; auto Added = Pipeline.addPass(std::make_unique<rcc::PHIEliminationPass>(Info)); if (!Added) @@ -469,7 +510,7 @@ instructionsWithOpcode(rcc::MachineFunction &Function, rcc::Opcode Opcode) { } void testParallelPHIsAndPlacement(TestContext &Context, const rcc::TargetDescription &Target, - const TestSSAInfo &Info) { + const TestInstrInfo &Info) { auto Fixture = createFunction(Context, "parallel_phis", 1, 3); if (!Fixture.Function || Fixture.Blocks.size() != 3) return; @@ -620,7 +661,7 @@ void testParallelPHIsAndPlacement(TestContext &Context, const rcc::TargetDescrip } void testCriticalEdgeAndPhysicalLiveIn(TestContext &Context, const rcc::TargetDescription &Target, - const TestSSAInfo &Info) { + const TestInstrInfo &Info) { auto Fixture = createFunction(Context, "critical_edge", 2, 4); if (!Fixture.Function || Fixture.Blocks.size() != 4) return; @@ -721,7 +762,7 @@ void testCriticalEdgeAndPhysicalLiveIn(TestContext &Context, const rcc::TargetDe } void testUndefAndFailureAtomicity(TestContext &Context, const rcc::TargetDescription &Target, - const TestSSAInfo &Info) { + const TestInstrInfo &Info) { auto BuildFixture = [&](std::uint64_t ID) { auto Fixture = createFunction(Context, "undef_phi", ID, 2); if (!Fixture.Function || Fixture.Blocks.size() != 2) @@ -773,7 +814,7 @@ void testUndefAndFailureAtomicity(TestContext &Context, const rcc::TargetDescrip instructionsWithOpcode(*Atomic.Function, rcc::opcode(rcc::GenericOpcode::PHI)).size(); const std::size_t RegistersBefore = Atomic.Function->registerInfo().virtualRegisters().size(); const std::uint64_t PropertiesBefore = Atomic.Function->properties().rawValue(); - TestSSAInfo RejectingInfo(true); + TestInstrInfo RejectingInfo(true); rcc::MachineAnalysisManager Analyses; rcc::PHIEliminationPass FailingPass(RejectingInfo); auto Failed = FailingPass.run(*Atomic.Function, Target, Analyses); @@ -794,7 +835,7 @@ void testUndefAndFailureAtomicity(TestContext &Context, const rcc::TargetDescrip } void testTwoAddressAndSubregisterPseudos(TestContext &Context, const rcc::TargetDescription &Target, - const TestSSAInfo &Info) { + const TestInstrInfo &Info) { auto Fixture = createFunction(Context, "two_address", 5, 1); if (!Fixture.Function || Fixture.Blocks.empty()) return; @@ -1015,7 +1056,7 @@ void testTwoAddressAndSubregisterPseudos(TestContext &Context, const rcc::Target AtomicFixture.Function->registerInfo().virtualRegisters().size(); const std::uint64_t AtomicPropertiesBefore = AtomicFixture.Function->properties().rawValue(); - TestSSAInfo RejectingInfo(true); + TestInstrInfo RejectingInfo(true); rcc::MachineAnalysisManager AtomicAnalyses; rcc::TwoAddressRewritePass FailingPass(RejectingInfo); auto Failed = FailingPass.run(*AtomicFixture.Function, Target, AtomicAnalyses); @@ -1128,7 +1169,7 @@ int main() { Context.expect(Target.has_value(), "SSA-exit TestTarget must be created"); if (!Target) return Context.result(); - TestSSAInfo Info; + TestInstrInfo Info; testParallelPHIsAndPlacement(Context, *Target, Info); testCriticalEdgeAndPhysicalLiveIn(Context, *Target, Info); testUndefAndFailureAtomicity(Context, *Target, Info); diff --git a/backend/unittests/Target/CMakeLists.txt b/backend/unittests/Target/CMakeLists.txt index e68c525..0b4ed74 100644 --- a/backend/unittests/Target/CMakeLists.txt +++ b/backend/unittests/Target/CMakeLists.txt @@ -34,6 +34,10 @@ target_link_libraries(RCCBackendRISCVCodeGenTests PRIVATE RCCBackend::RISCV RCCB add_test(NAME RCCBackendRISCVCodeGenTests COMMAND RCCBackendRISCVCodeGenTests) add_executable(RCCBackendRISCVSSAExitTests RISCVSSAExitTest.cpp) +target_include_directories( + RCCBackendRISCVSSAExitTests + PRIVATE "${RCC_BACKEND_SOURCE_DIR}/lib/Target/RISCV" +) rcc_backend_configure_target(RCCBackendRISCVSSAExitTests) target_link_libraries(RCCBackendRISCVSSAExitTests PRIVATE RCCBackend::RISCV RCCBackend::CodeGen) add_test(NAME RCCBackendRISCVSSAExitTests COMMAND RCCBackendRISCVSSAExitTests) @@ -61,6 +65,10 @@ add_test( ) add_executable(RCCBackendRISCVLateCodeGenTests RISCVLateCodeGenTest.cpp) +target_include_directories( + RCCBackendRISCVLateCodeGenTests + PRIVATE "${RCC_BACKEND_SOURCE_DIR}/lib/Target/RISCV" +) rcc_backend_configure_target(RCCBackendRISCVLateCodeGenTests) target_link_libraries( RCCBackendRISCVLateCodeGenTests diff --git a/backend/unittests/Target/RISCVLateCodeGenTest.cpp b/backend/unittests/Target/RISCVLateCodeGenTest.cpp index 97590cd..d0bd952 100644 --- a/backend/unittests/Target/RISCVLateCodeGenTest.cpp +++ b/backend/unittests/Target/RISCVLateCodeGenTest.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later +#include "RISCVInstrInfo.h" #include "rcc/CodeGen/GenericOpcodes.h" #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineBlockPlacement.h" @@ -102,7 +103,7 @@ public: } }; -class FixedSizeBranchInfo final : public rcc::TargetInstrInfo { +class FixedSizeInstrInfo final : public rcc::TargetInstrInfo { public: [[nodiscard]] rcc::Expected<rcc::MachineBranchAnalysis> analyzeBranch(rcc::MachineBasicBlock &, rcc::MachineFunction &, @@ -128,11 +129,23 @@ public: } [[nodiscard]] rcc::Expected<rcc::MachineInstr *> - insertUnconditionalBranch(rcc::MachineBasicBlock &, rcc::MachineBasicBlock &, - rcc::MachineFunction &, const rcc::TargetDescription &) const override { + insertBranch(rcc::MachineBasicBlock &, rcc::MachineBasicBlock &, rcc::MachineFunction &, + const rcc::TargetDescription &) const override { return rcc::makeUnexpected(rcc::ErrorCode::Unsupported, "test target has no branches"); } + [[nodiscard]] rcc::Expected<bool> + isFallthroughEdge(const rcc::MachineBasicBlock &, const rcc::MachineBasicBlock &, + const rcc::MachineFunction &, const rcc::TargetDescription &) const override { + return false; + } + + [[nodiscard]] rcc::Expected<void> validateCopy(rcc::Register, rcc::SubRegIndex, rcc::Register, + rcc::SubRegIndex, const rcc::MachineFunction &, + const rcc::TargetDescription &) const override { + return rcc::makeUnexpected(rcc::ErrorCode::Unsupported, "test target has no COPY support"); + } + [[nodiscard]] rcc::Expected<std::uint32_t> instructionSize(const rcc::MachineInstr &, const rcc::MachineFunction &, const rcc::TargetDescription &) const override { @@ -398,7 +411,7 @@ void testFallthroughNormalization(TestContext &Context, const rcc::TargetDescrip auto Liveness = rcc::rebuildMachineLiveness(*Function, Target); Context.expect(Liveness.has_value(), "fallthrough fixture liveness must be rebuilt"); rcc::MachineAnalysisManager Analyses; - rcc::MachineFallthroughPass Pass(rcc::riscv::branchInfo()); + rcc::MachineFallthroughPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) std::cerr << "fallthrough normalization failure: " << Result.error().message() << '\n'; @@ -433,7 +446,7 @@ void testFallthroughMaterialization(TestContext &Context, const rcc::TargetDescr Context.expect(rcc::rebuildMachineLiveness(*Function, Target).has_value(), "materialized fallthrough liveness must be rebuilt"); rcc::MachineAnalysisManager Analyses; - rcc::MachineFallthroughPass Pass(rcc::riscv::branchInfo()); + rcc::MachineFallthroughPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) std::cerr << "fallthrough materialization failure: " << Result.error().message() << '\n'; @@ -474,7 +487,7 @@ void testBranchOptimization(TestContext &Context, const rcc::TargetDescription & } setSelectedProperties(*Function); rcc::MachineAnalysisManager Analyses; - rcc::MachineBranchOptimizationPass Pass(rcc::riscv::branchInfo()); + rcc::MachineBranchOptimizationPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) std::cerr << "branch optimization failure: " << Result.error().message() << '\n'; @@ -554,7 +567,7 @@ void testTailDuplication(TestContext &Context, const rcc::TargetDescription &Tar } setRelaxationProperties(Context, *Function, Target); rcc::MachineAnalysisManager Analyses; - rcc::MachineTailDuplicationPass Pass(rcc::riscv::branchInfo()); + rcc::MachineTailDuplicationPass Pass(rcc::riscv::instrInfo()); Tail->attributes().set(rcc::MachineBasicBlockAttribute::MachineBlockAddressTaken); auto Protected = Pass.run(*Function, Target, Analyses); Context.expect(Protected && !Protected->Changed && Tail->isLinked(), @@ -605,7 +618,7 @@ void testTailMerge(TestContext &Context, const rcc::TargetDescription &Target) { } setRelaxationProperties(Context, *Function, Target); rcc::MachineAnalysisManager Analyses; - rcc::MachineTailMergePass Pass(rcc::riscv::branchInfo()); + rcc::MachineTailMergePass Pass(rcc::riscv::instrInfo()); Second->attributes().set(rcc::MachineBasicBlockAttribute::MachineBlockAddressTaken); auto Protected = Pass.run(*Function, Target, Analyses); Context.expect(Protected && !Protected->Changed && Second->isLinked(), @@ -650,7 +663,7 @@ void testCopyPropagation(TestContext &Context, const rcc::TargetDescription &Tar return; setSelectedProperties(*Function); rcc::MachineAnalysisManager Analyses; - rcc::MachineCopyPropagationPass PreRA(rcc::riscv::ssaInfo(), + rcc::MachineCopyPropagationPass PreRA(rcc::riscv::instrInfo(), rcc::MachineCopyPropagationStage::PreRegisterAllocation); auto PreResult = PreRA.run(*Function, Target, Analyses); if (!PreResult) @@ -690,7 +703,7 @@ void testCopyPropagation(TestContext &Context, const rcc::TargetDescription &Tar Context.expect(rcc::rebuildMachineLiveness(*PostFunction, Target).has_value(), "post-RA COPY propagation liveness must be rebuilt"); rcc::MachineAnalysisManager PostAnalyses; - rcc::MachineCopyPropagationPass PostRA(rcc::riscv::ssaInfo(), + rcc::MachineCopyPropagationPass PostRA(rcc::riscv::instrInfo(), rcc::MachineCopyPropagationStage::PostRegisterAllocation); auto PostResult = PostRA.run(*PostFunction, Target, PostAnalyses); if (!PostResult) @@ -963,7 +976,7 @@ void testCompressedAndConditionalRelaxation(TestContext &Context, return; setRelaxationProperties(Context, *Function, Target); rcc::MachineAnalysisManager Analyses; - rcc::MachineBranchRelaxationPass Pass(rcc::riscv::branchInfo()); + rcc::MachineBranchRelaxationPass Pass(rcc::riscv::instrInfo()); auto Result = Pass.run(*Function, Target, Analyses); if (!Result) std::cerr << "conditional relaxation failure: " << Result.error().message() << '\n'; @@ -998,7 +1011,7 @@ void testCompressedAndConditionalRelaxation(TestContext &Context, if (!Compressed) return; auto Expanded = - rcc::riscv::branchInfo().relaxBranch(**Compressed, 4096, *CompressedFunction, Target); + rcc::riscv::instrInfo().relaxBranch(**Compressed, 4096, *CompressedFunction, Target); Context.expect(Expanded && *Expanded && CompressedEntry->firstInstruction() != nullptr && CompressedEntry->firstInstruction()->opcode() == opcode(rcc::riscv::InstructionOpcode::JAL) && @@ -1029,13 +1042,13 @@ void testLongJALRelaxation(TestContext &Context, const rcc::TargetDescription &T "long JAL live-in and annotation fixture must be valid"); if (!X5 || !X6) return; - auto TooFar = rcc::riscv::branchInfo().relaxBranch(*JAL, std::numeric_limits<std::int64_t>::max(), - *Function, Target); + auto TooFar = rcc::riscv::instrInfo().relaxBranch(*JAL, std::numeric_limits<std::int64_t>::max(), + *Function, Target); Context.expect(!TooFar && TooFar.error().code() == rcc::ErrorCode::BranchRelaxationFailed && JAL->parent() == Entry, "long JAL relaxation must reject an unencodable PC-relative distance atomically"); auto Relaxed = - rcc::riscv::branchInfo().relaxBranch(*JAL, std::int64_t{2} * 1024 * 1024, *Function, Target); + rcc::riscv::instrInfo().relaxBranch(*JAL, std::int64_t{2} * 1024 * 1024, *Function, Target); if (!Relaxed) std::cerr << "long JAL relaxation failure: " << Relaxed.error().message() << '\n'; rcc::MachineInstr *High = Entry->firstInstruction(); @@ -1186,7 +1199,7 @@ void testPostRAPseudoExpansionAndFinalization(TestContext &Context, rcc::MachinePassManager Pipeline; Context.expect(Pipeline.addPass(std::make_unique<rcc::FinalizeEmissionPseudosPass>()) && Pipeline.addPass(std::make_unique<rcc::FinalEncodabilityVerifierPass>( - rcc::riscv::branchInfo())), + rcc::riscv::instrInfo())), "finalization passes must register"); auto Finalized = Pipeline.run(*Function, Target, Analyses); if (!Finalized) @@ -1310,8 +1323,8 @@ void testTargetLateExpansionRejectsSizeGrowth(TestContext &Context) { return; GrowingLatePseudoInfo ExpansionInfo; - FixedSizeBranchInfo BranchInfo; - rcc::TargetLatePseudoExpansionPass Pass(ExpansionInfo, BranchInfo); + FixedSizeInstrInfo InstrInfo; + rcc::TargetLatePseudoExpansionPass Pass(ExpansionInfo, InstrInfo); rcc::MachineAnalysisManager Analyses; auto Result = Pass.run(*Function, *Target, Analyses); Context.expect(!Result && Result.error().code() == rcc::ErrorCode::PseudoExpansionFailed && @@ -1358,8 +1371,8 @@ void testTargetLateExpansionRejectsCompensatedGrowth(TestContext &Context) { return; GrowingLatePseudoInfo ExpansionInfo; - FixedSizeBranchInfo BranchInfo; - rcc::TargetLatePseudoExpansionPass Pass(ExpansionInfo, BranchInfo); + FixedSizeInstrInfo InstrInfo; + rcc::TargetLatePseudoExpansionPass Pass(ExpansionInfo, InstrInfo); rcc::MachineAnalysisManager Analyses; auto Result = Pass.run(*Function, *Target, Analyses); Context.expect( @@ -1391,7 +1404,7 @@ void testFinalEncodabilityRejectsInvalidInstruction(TestContext &Context, } setRelaxationProperties(Context, *ImmediateFunction, Target); rcc::MachineAnalysisManager Analyses; - rcc::FinalEncodabilityVerifierPass Verifier(rcc::riscv::branchInfo()); + rcc::FinalEncodabilityVerifierPass Verifier(rcc::riscv::instrInfo()); auto ImmediateResult = Verifier.run(*ImmediateFunction, Target, Analyses); Context.expect(!ImmediateResult && ImmediateResult.error().code() == rcc::ErrorCode::FinalEncodabilityFailed, diff --git a/backend/unittests/Target/RISCVSSAExitTest.cpp b/backend/unittests/Target/RISCVSSAExitTest.cpp index 8e1f5a2..18cbea9 100644 --- a/backend/unittests/Target/RISCVSSAExitTest.cpp +++ b/backend/unittests/Target/RISCVSSAExitTest.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later +#include "RISCVInstrInfo.h" #include "rcc/CodeGen/GenericOpcodes.h" #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineCFGUpdater.h" @@ -196,11 +197,11 @@ void testBehaviorAndCopyLegality(TestContext &Context, const rcc::TargetDescript if (!CFG.addSuccessor(**First, **Second, rcc::BranchProbability::one())) return; - auto Fallthrough = rcc::riscv::ssaInfo().isFallthroughEdge(**First, **Second, **Function, Target); + auto Fallthrough = + rcc::riscv::instrInfo().isFallthroughEdge(**First, **Second, **Function, Target); Context.expect(Fallthrough && *Fallthrough, "RV64GC SSA behavior must recognize an empty layout fallthrough edge"); - auto Inserted = - rcc::riscv::ssaInfo().insertUnconditionalBranch(**First, **Second, **Function, Target); + auto Inserted = rcc::riscv::instrInfo().insertBranch(**First, **Second, **Function, Target); Context.expect(Inserted.has_value(), "RV64GC SSA behavior must insert an unconditional branch"); if (!Inserted) return; @@ -212,10 +213,10 @@ void testBehaviorAndCopyLegality(TestContext &Context, const rcc::TargetDescript blockOperand(*Jump, 1) != nullptr && blockOperand(*Jump, 1)->Block == *Second, "RV64GC unconditional branches must use JAL with x0 as the link destination"); auto NoFallthrough = - rcc::riscv::ssaInfo().isFallthroughEdge(**First, **Second, **Function, Target); + rcc::riscv::instrInfo().isFallthroughEdge(**First, **Second, **Function, Target); Context.expect(NoFallthrough && !*NoFallthrough, "JAL must terminate RV64GC layout fallthrough"); auto Rewritten = - rcc::riscv::ssaInfo().rewriteBranchTarget(**First, **Second, **Third, **Function, Target); + rcc::riscv::instrInfo().rewriteBranchTarget(**First, **Second, **Third, **Function, Target); Context.expect(Rewritten && *Rewritten && blockOperand(*Jump, 1)->Block == *Third, "RV64GC branch target rewriting must update direct JAL operands"); @@ -237,21 +238,75 @@ void testBehaviorAndCopyLegality(TestContext &Context, const rcc::TargetDescript return; Context.expect( - rcc::riscv::ssaInfo().validateCopy(*GPR, {}, *OtherGPR, {}, **Function, Target).has_value(), + rcc::riscv::instrInfo().validateCopy(*GPR, {}, *OtherGPR, {}, **Function, Target).has_value(), "RV64GC must allow a compatible GPR COPY"); Context.expect( - rcc::riscv::ssaInfo().validateCopy(*GPR, {}, *FPR64, {}, **Function, Target).has_value(), + rcc::riscv::instrInfo().validateCopy(*GPR, {}, *FPR64, {}, **Function, Target).has_value(), "RV64GC must allow supported 64-bit GPR/FPR bit moves"); - Context.expect(!rcc::riscv::ssaInfo().validateCopy(*FPR64, {}, *FPR32, {}, **Function, Target), + Context.expect(!rcc::riscv::instrInfo().validateCopy(*FPR64, {}, *FPR32, {}, **Function, Target), "RV64GC must reject incompatible same-bank COPY widths"); - Context.expect(!rcc::riscv::ssaInfo().validateCopy(*GPR, rcc::SubRegIndex::fromValue(1), - *OtherGPR, {}, **Function, Target), + Context.expect(!rcc::riscv::instrInfo().validateCopy(*GPR, rcc::SubRegIndex::fromValue(1), + *OtherGPR, {}, **Function, Target), "RV64GC must reject unmodeled subregister COPYs"); Context.expect( - !rcc::riscv::ssaInfo().validateCopy(*GPR, {}, *Unclassified, {}, **Function, Target), + !rcc::riscv::instrInfo().validateCopy(*GPR, {}, *Unclassified, {}, **Function, Target), "RV64GC must reject COPYs involving an unconstrained virtual register"); } +void testCompressedConditionalBranchBehavior(TestContext &Context, + const rcc::TargetDescription &Target) { + auto Function = rcc::MachineFunction::create("riscv_compressed_branch", + rcc::MachineFunctionStableID::fromValue(3)); + if (!Function) + return; + auto Source = appendBlock(**Function); + auto LayoutSuccessor = appendBlock(**Function); + auto BranchTarget = appendBlock(**Function); + auto ReplacementTarget = appendBlock(**Function); + if (!Source || !LayoutSuccessor || !BranchTarget || !ReplacementTarget) + return; + auto Half = rcc::BranchProbability::fromFraction(1, 2); + auto CFG = (*Function)->cfgUpdater(); + if (!Half || !CFG.addSuccessor(**Source, **BranchTarget, *Half) || + !CFG.addSuccessor(**Source, **LayoutSuccessor, *Half)) { + Context.expect(false, "compressed-branch CFG construction must succeed"); + return; + } + + auto X8 = rcc::riscv::physicalRegister(rcc::riscv::PhysicalRegisterID::X8); + rcc::MachineIRBuilder Builder(**Function, Target); + auto Point = Builder.setInsertPoint(**Source); + if (!Point) { + Context.expect(false, "compressed conditional branch insertion point must be established"); + return; + } + auto Pending = Builder.buildInstr(targetOpcode(rcc::riscv::InstructionOpcode::C_BEQZ)); + if (!X8 || !Pending || !Pending->addUse(rcc::Register::fromPhysical(*X8)) || + !Pending->addBasicBlock(**BranchTarget)) { + Context.expect(false, "compressed conditional branch construction must succeed"); + return; + } + auto Branch = Pending->build(); + if (!Branch) { + Context.expect(false, "compressed conditional branch insertion must succeed"); + return; + } + + auto Fallthrough = + rcc::riscv::instrInfo().isFallthroughEdge(**Source, **LayoutSuccessor, **Function, Target); + auto Analysis = rcc::riscv::instrInfo().analyzeBranch(**Source, **Function, Target); + Context.expect(Fallthrough && *Fallthrough && Analysis && Analysis->Conditional == *Branch && + Analysis->TrueTarget == *BranchTarget && + Analysis->FalseTarget == *LayoutSuccessor, + "RV64GC instruction information must recognize compressed conditional branches"); + + auto Rewritten = rcc::riscv::instrInfo().rewriteBranchTarget( + **Source, **BranchTarget, **ReplacementTarget, **Function, Target); + Context.expect(Rewritten && *Rewritten && blockOperand(**Branch, 1) != nullptr && + blockOperand(**Branch, 1)->Block == *ReplacementTarget, + "RV64GC instruction information must rewrite compressed branch targets"); +} + void testRV64GCCriticalEdge(TestContext &Context, const rcc::TargetDescription &Target) { auto Function = rcc::MachineFunction::create("riscv_ssa_critical_edge", rcc::MachineFunctionStableID::fromValue(2)); @@ -298,9 +353,10 @@ void testRV64GCCriticalEdge(TestContext &Context, const rcc::TargetDescription & return; rcc::MachinePassManager Pipeline; - Context.expect(Pipeline.addPass(std::make_unique<rcc::PHIEliminationPass>(rcc::riscv::ssaInfo())) - .has_value(), - "RV64GC PHI-elimination pass must be registered"); + Context.expect( + Pipeline.addPass(std::make_unique<rcc::PHIEliminationPass>(rcc::riscv::instrInfo())) + .has_value(), + "RV64GC PHI-elimination pass must be registered"); rcc::MachineAnalysisManager Analyses; auto Run = Pipeline.run(**Function, Target, Analyses); Context.expect(Run.has_value(), "RV64GC critical-edge PHI elimination must succeed"); @@ -350,6 +406,7 @@ int main() { if (!Target) return Context.result(); testBehaviorAndCopyLegality(Context, *Target); + testCompressedConditionalBranchBehavior(Context, *Target); testRV64GCCriticalEdge(Context, *Target); return Context.result(); } |
