aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests/Target
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 21:35:21 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 21:35:21 +0800
commitf8daf08aba1f09c3024a70d3426891112d1662a2 (patch)
treedaf3a5e309e41c3bef92efdb496806061d2a2c02 /backend/unittests/Target
parent8721893d3ba605f5374d9c0c7987af6110355638 (diff)
downloadrcc-project-f8daf08aba1f09c3024a70d3426891112d1662a2.tar.gz
rcc-project-f8daf08aba1f09c3024a70d3426891112d1662a2.tar.xz
[RISCV] Consolidate instruction behavior in RISCVInstrInfo
Diffstat (limited to 'backend/unittests/Target')
-rw-r--r--backend/unittests/Target/CMakeLists.txt8
-rw-r--r--backend/unittests/Target/RISCVLateCodeGenTest.cpp55
-rw-r--r--backend/unittests/Target/RISCVSSAExitTest.cpp85
3 files changed, 113 insertions, 35 deletions
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();
}