diff options
Diffstat (limited to 'backend/unittests')
| -rw-r--r-- | backend/unittests/CodeGen/MachineSSAExitTest.cpp | 71 | ||||
| -rw-r--r-- | backend/unittests/Target/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVLateCodeGenTest.cpp | 55 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVSSAExitTest.cpp | 85 |
4 files changed, 169 insertions, 50 deletions
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(); } |
