From f6fdfb8d484b4e52cdb24a94a31b0f00d41a5eb7 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sat, 15 Aug 2026 00:38:20 +0800 Subject: [GlobalISel] Match LLVM CSE builder result semantics --- .../CodeGen/GlobalISel/InstructionSelectTest.cpp | 11 +- .../unittests/CodeGen/GlobalISel/LegalizerTest.cpp | 116 ++++++++------------- 2 files changed, 48 insertions(+), 79 deletions(-) (limited to 'backend/unittests') diff --git a/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp b/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp index 6d9fa3c..9f3f0b5 100644 --- a/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp +++ b/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp @@ -121,9 +121,11 @@ void testPipeline(TestContext &Context) { rcc::MachineFunctionProperty::TracksLiveness}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); rcc::MachineFunctionPassManager Pipeline; - Context.expect( - Pipeline.addPass(std::make_unique(Subtarget.getLegalizerInfo())).has_value(), - "legalizer must be accepted by the pass manager"); + Context.expect(Pipeline + .addPass(std::make_unique(Subtarget.getLegalizerInfo(), + rcc::OptimizationLevel::O2)) + .has_value(), + "legalizer must be accepted by the pass manager"); Context.expect(Pipeline.addPass(std::make_unique(Subtarget.getRegBankInfo())) .has_value(), "register-bank selector must be accepted by the pass manager"); @@ -327,7 +329,8 @@ void testExtendedRV64GCPipeline(TestContext &Context) { rcc::MachineFunctionProperty::TracksLiveness}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); rcc::MachineFunctionPassManager Pipeline; - if (!Pipeline.addPass(std::make_unique(Subtarget.getLegalizerInfo())) || + if (!Pipeline.addPass(std::make_unique(Subtarget.getLegalizerInfo(), + rcc::OptimizationLevel::O2)) || !Pipeline.addPass(std::make_unique(Subtarget.getRegBankInfo())) || !Pipeline.addPass( std::make_unique(Subtarget.getInstructionSelector()))) { diff --git a/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp b/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp index b191a3f..eaf3741 100644 --- a/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp +++ b/backend/unittests/CodeGen/GlobalISel/LegalizerTest.cpp @@ -3,6 +3,9 @@ #include "rcc/CodeGen/GlobalISel/Legalizer.h" #include "GISelMITest.h" +#include "rcc/CodeGen/GlobalISel/GISelChangeObserver.h" +#include "rcc/CodeGen/GlobalISel/LegalizerHelper.h" +#include "rcc/Target/RISCV/RISCVRegisters.h" #include "rcc/Target/RISCV/RISCVSubtarget.h" #include "rcc/Target/RISCV/RISCVTarget.h" @@ -14,53 +17,38 @@ namespace { using rcc::test::buildAdd; using rcc::test::createFixture; -using rcc::test::createFloatRegister; using rcc::test::createRegister; using rcc::test::TestContext; -class TogglingLegalizer final : public rcc::LegalizerInfo { -public: - [[nodiscard]] rcc::Expected - classify(const rcc::MachineInstr &, const rcc::MachineFunction &, - const rcc::TargetDescription &) const override { - return rcc::LegalizationAction::Lower; - } - - [[nodiscard]] rcc::Expected lower(rcc::MachineInstr &Instruction, rcc::MachineFunction &, - const rcc::TargetDescription &, - rcc::LegalizationAction) const override { - const auto Generic = static_cast(Instruction.opcode().value()); - return Instruction.setOpcode(rcc::opcode(Generic == rcc::GenericOpcode::G_ADD - ? rcc::GenericOpcode::G_SUB - : rcc::GenericOpcode::G_ADD)); - } -}; - class BackwardInvalidatingLegalizer final : public rcc::LegalizerInfo { public: - [[nodiscard]] rcc::Expected - classify(const rcc::MachineInstr &Instruction, const rcc::MachineFunction &, - const rcc::TargetDescription &) const override { - return Instruction.opcode() == rcc::opcode(rcc::GenericOpcode::G_SUB) - ? rcc::LegalizationAction::Custom - : rcc::LegalizationAction::Legal; + BackwardInvalidatingLegalizer() { + getActionDefinitionsBuilder(rcc::opcode(rcc::GenericOpcode::G_ADD)).alwaysLegal(); + getActionDefinitionsBuilder(rcc::opcode(rcc::GenericOpcode::G_SUB)).custom(); } - [[nodiscard]] rcc::Expected lower(rcc::MachineInstr &Instruction, - rcc::MachineFunction &Function, - const rcc::TargetDescription &, - rcc::LegalizationAction) const override { + [[nodiscard]] rcc::Expected + legalizeCustom(rcc::LegalizerHelper &Helper, rcc::MachineInstr &Instruction, + const rcc::LegalizationDecision &) const override { + rcc::MachineFunction &Function = Helper.MIRBuilder.function(); for (rcc::MachineInstr *Candidate : Function.allInstructions()) { if (Candidate != &Instruction && Candidate->opcode() == rcc::opcode(rcc::GenericOpcode::G_ADD)) { + Helper.Observer.changingInstr(*Candidate); auto Invalidated = Candidate->setOpcode(rcc::opcode(rcc::GenericOpcode::G_SUB)); if (!Invalidated) return std::unexpected(Invalidated.error()); + Helper.Observer.changedInstr(*Candidate); break; } } - return Instruction.setOpcode( + Helper.Observer.changingInstr(Instruction); + auto Changed = Instruction.setOpcode( rcc::Opcode::fromValue(static_cast(rcc::riscv::InstructionOpcode::ADD))); + if (!Changed) + return std::unexpected(Changed.error()); + Helper.Observer.changedInstr(Instruction); + return {}; } }; @@ -72,7 +60,7 @@ void testNullAndMissingContracts(TestContext &Context) { if (!Target || !Fixture.Function) return; - rcc::Legalizer NullPass(nullptr); + rcc::Legalizer NullPass(nullptr, rcc::OptimizationLevel::O2); rcc::MachineFunctionAnalysisManager Analyses; auto NullResult = NullPass.run(*Fixture.Function, *Target, Analyses); Context.expect(!NullResult && NullResult.error().code() == rcc::ErrorCode::InvalidArgument, @@ -81,7 +69,7 @@ void testNullAndMissingContracts(TestContext &Context) { "a rejected pass must not publish function properties"); const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); - rcc::Legalizer ValidPass(Subtarget.getLegalizerInfo()); + rcc::Legalizer ValidPass(Subtarget.getLegalizerInfo(), rcc::OptimizationLevel::O2); auto MissingResult = ValidPass.run(*Fixture.Function, *Target, Analyses); Context.expect(!MissingResult && MissingResult.error().code() == rcc::ErrorCode::VerificationError, @@ -97,14 +85,13 @@ void testUnsupportedRollback(TestContext &Context) { "unsupported pipeline fixture must be complete"); if (!Unsupported.Function || Unsupported.Entry == nullptr) return; - const rcc::Register UnsupportedReg = createFloatRegister(Context, *Unsupported.Function); - const rcc::Register UnsupportedSource = createFloatRegister(Context, *Unsupported.Function); + const rcc::Register UnsupportedReg = createRegister(Context, *Unsupported.Function, 64); rcc::MachineIRBuilder UnsupportedBuilder(*Unsupported.Function, *Target); Context.expect(UnsupportedBuilder.setInsertPoint(*Unsupported.Entry).has_value(), "unsupported pipeline insertion point must be valid"); - if (UnsupportedReg.isNoRegister() || UnsupportedSource.isNoRegister()) + if (UnsupportedReg.isNoRegister()) return; - auto Pending = UnsupportedBuilder.buildInstr(rcc::opcode(rcc::GenericOpcode::G_FEXP)); + auto Pending = UnsupportedBuilder.buildInstr(rcc::opcode(rcc::GenericOpcode::G_GET_FPENV)); Context.expect(Pending.has_value(), "unsupported generic instruction must be constructible"); if (!Pending) return; @@ -112,21 +99,22 @@ void testUnsupportedRollback(TestContext &Context) { Context.expect(Built.has_value(), "unsupported generic definition must be accepted"); if (!Built) return; - Context.expect(Pending->addUse(UnsupportedSource).has_value() && Pending->build().has_value(), - "unsupported floating operation must be constructible"); + Context.expect(Pending->build().has_value(), + "unsupported floating-point environment operation must be constructible"); Unsupported.Function->properties() = {rcc::MachineFunctionProperty::IsSSA, rcc::MachineFunctionProperty::TracksLiveness}; const rcc::riscv::RISCVSubtarget Subtarget(rcc::riscv::RISCVSubtargetFeatures::rv64gc()); rcc::MachineFunctionPassManager OnlyLegalizer; - Context.expect( - OnlyLegalizer.addPass(std::make_unique(Subtarget.getLegalizerInfo())) - .has_value(), - "standalone legalizer must be accepted"); + Context.expect(OnlyLegalizer + .addPass(std::make_unique(Subtarget.getLegalizerInfo(), + rcc::OptimizationLevel::O2)) + .has_value(), + "standalone legalizer must be accepted"); rcc::MachineFunctionAnalysisManager UnsupportedAnalyses; auto Failure = OnlyLegalizer.run(*Unsupported.Function, *Target, UnsupportedAnalyses); Context.expect(!Failure && Failure.error().code() == rcc::ErrorCode::Unsupported, "unsupported generic instructions must produce a target diagnostic"); - Context.expect(!Failure && Failure.error().message().find("G_FEXP") != std::string::npos, + Context.expect(!Failure && Failure.error().message().find("G_GET_FPENV") != std::string::npos, "unsupported legalization diagnostics must name the rejected opcode"); Context.expect( Unsupported.Function->properties().has(rcc::MachineFunctionProperty::IsSSA) && @@ -134,36 +122,6 @@ void testUnsupportedRollback(TestContext &Context) { "failed legalizer execution must not publish Legalized"); } -void testLegalizerCycleDiagnostic(TestContext &Context) { - auto Target = rcc::riscv::createTargetDescription(); - auto Fixture = createFixture(Context, "pipeline_legalizer_cycle", 6); - Context.expect(Target.has_value() && Fixture.Function != nullptr && Fixture.Entry != nullptr, - "legalizer cycle fixture must be complete"); - if (!Target || !Fixture.Function || Fixture.Entry == nullptr) - return; - const rcc::Register Left = createRegister(Context, *Fixture.Function, 64); - const rcc::Register Right = createRegister(Context, *Fixture.Function, 64); - const rcc::Register Result = createRegister(Context, *Fixture.Function, 64); - rcc::MachineIRBuilder Builder(*Fixture.Function, *Target); - if (Left.isNoRegister() || Right.isNoRegister() || Result.isNoRegister() || - !Builder.setInsertPoint(*Fixture.Entry) || !buildAdd(Context, Builder, Result, Left, Right)) - return; - Fixture.Function->properties() = {rcc::MachineFunctionProperty::IsSSA, - rcc::MachineFunctionProperty::TracksLiveness}; - TogglingLegalizer Legalizer; - rcc::Legalizer StablePass(Legalizer); - rcc::MachineFunctionAnalysisManager Analyses; - auto ResultRun = StablePass.run(*Fixture.Function, *Target, Analyses); - Context.expect(!ResultRun && ResultRun.error().code() == rcc::ErrorCode::InternalError, - "repeated legalization states must report InternalError"); - Context.expect(Fixture.Entry->firstInstruction() != nullptr && - Fixture.Entry->firstInstruction()->opcode() == - rcc::opcode(rcc::GenericOpcode::G_ADD), - "failed legalization preflight must preserve the original instruction"); - Context.expect(!Fixture.Function->properties().has(rcc::MachineFunctionProperty::Legalized), - "a failed legalization cycle must not publish Legalized"); -} - void testLegalizerRevisitsInvalidatedInstructions(TestContext &Context) { auto Target = rcc::riscv::createTargetDescription(); auto Fixture = createFixture(Context, "pipeline_legalizer_revisit", 7); @@ -183,11 +141,20 @@ void testLegalizerRevisitsInvalidatedInstructions(TestContext &Context) { rcc::MachineInstr *Second = First == nullptr ? nullptr : First->next(); if (Second == nullptr || !Second->setOpcode(rcc::opcode(rcc::GenericOpcode::G_SUB))) return; + auto X10 = rcc::riscv::physicalRegister(rcc::riscv::PhysicalRegisterID::X10); + auto X11 = rcc::riscv::physicalRegister(rcc::riscv::PhysicalRegisterID::X11); + auto FirstCopy = Builder.buildInstr(rcc::opcode(rcc::GenericOpcode::COPY)); + auto SecondCopy = Builder.buildInstr(rcc::opcode(rcc::GenericOpcode::COPY)); + if (!X10 || !X11 || !FirstCopy || !FirstCopy->addDef(rcc::Register::fromPhysical(*X10)) || + !FirstCopy->addUse(FirstResult) || !FirstCopy->build() || !SecondCopy || + !SecondCopy->addDef(rcc::Register::fromPhysical(*X11)) || !SecondCopy->addUse(SecondResult) || + !SecondCopy->build()) + return; Fixture.Function->properties() = {rcc::MachineFunctionProperty::IsSSA, rcc::MachineFunctionProperty::TracksLiveness}; BackwardInvalidatingLegalizer Legalizer; - rcc::Legalizer Pass(Legalizer); + rcc::Legalizer Pass(Legalizer, rcc::OptimizationLevel::O2); rcc::MachineFunctionAnalysisManager Analyses; auto Run = Pass.run(*Fixture.Function, *Target, Analyses); const rcc::Opcode LegalOpcode = @@ -202,7 +169,6 @@ int main() { TestContext Context; testNullAndMissingContracts(Context); testUnsupportedRollback(Context); - testLegalizerCycleDiagnostic(Context); testLegalizerRevisitsInvalidatedInstructions(Context); return Context.result(); } -- cgit v1.2.3