diff options
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/include/rcc/CodeGen/MachinePipelinePasses.h | 7 | ||||
| -rw-r--r-- | backend/include/rcc/Target/RISCV/RISCVCodeGen.h | 5 | ||||
| -rw-r--r-- | backend/include/rcc/Target/RISCV/RISCVPipeline.h | 6 | ||||
| -rw-r--r-- | backend/include/rcc/Target/RISCV/RISCVSubtarget.h | 47 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVCodeGen.cpp | 15 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPipeline.cpp | 24 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVSubtarget.cpp | 94 | ||||
| -rw-r--r-- | backend/lib/Tooling/PipelineDriver.cpp | 27 | ||||
| -rw-r--r-- | backend/unittests/Tooling/PipelineDriverTest.cpp | 19 |
10 files changed, 230 insertions, 18 deletions
diff --git a/backend/include/rcc/CodeGen/MachinePipelinePasses.h b/backend/include/rcc/CodeGen/MachinePipelinePasses.h index 08f0dac..1187e4a 100644 --- a/backend/include/rcc/CodeGen/MachinePipelinePasses.h +++ b/backend/include/rcc/CodeGen/MachinePipelinePasses.h @@ -6,12 +6,16 @@ #include "rcc/CodeGen/MachinePass.h" #include "rcc/CodeGen/TargetCodeGen.h" +#include <memory> + namespace rcc { class LegalizerPass final : public MachineFunctionPass { public: explicit LegalizerPass(const TargetLegalizerInfo *Info) : Info(Info) {} explicit LegalizerPass(const TargetLegalizerInfo &Info) : Info(&Info) {} + explicit LegalizerPass(std::unique_ptr<TargetLegalizerInfo> Info) + : OwnedInfo(std::move(Info)), Info(OwnedInfo.get()) {} [[nodiscard]] const MachinePassContract &contract() const noexcept override; [[nodiscard]] Expected<MachinePassResult> run(MachineFunction &Function, @@ -23,7 +27,8 @@ private: const TargetDescription &Target, MachineActionReplay &Actions); - const TargetLegalizerInfo *Info; + std::unique_ptr<TargetLegalizerInfo> OwnedInfo; + const TargetLegalizerInfo *Info = nullptr; }; class RegisterBankSelectPass final : public MachineFunctionPass { diff --git a/backend/include/rcc/Target/RISCV/RISCVCodeGen.h b/backend/include/rcc/Target/RISCV/RISCVCodeGen.h index b6b207c..a39a3fa 100644 --- a/backend/include/rcc/Target/RISCV/RISCVCodeGen.h +++ b/backend/include/rcc/Target/RISCV/RISCVCodeGen.h @@ -12,10 +12,15 @@ #include "rcc/CodeGen/TargetPseudoExpansion.h" #include "rcc/CodeGen/TargetRegisterAllocationInfo.h" #include "rcc/CodeGen/TargetSchedulingModel.h" +#include "rcc/Target/RISCV/RISCVSubtarget.h" + +#include <memory> namespace rcc::riscv { [[nodiscard]] const TargetLegalizerInfo &legalizerInfo() noexcept; +[[nodiscard]] std::unique_ptr<TargetLegalizerInfo> +createLegalizerInfo(RISCVSubtargetFeatures Features); [[nodiscard]] const TargetRegisterBankInfo ®isterBankInfo() noexcept; [[nodiscard]] const TargetInstructionSelector &instructionSelector() noexcept; [[nodiscard]] const TargetSSAInfo &ssaInfo() noexcept; diff --git a/backend/include/rcc/Target/RISCV/RISCVPipeline.h b/backend/include/rcc/Target/RISCV/RISCVPipeline.h index 8bd79e9..fa2cb45 100644 --- a/backend/include/rcc/Target/RISCV/RISCVPipeline.h +++ b/backend/include/rcc/Target/RISCV/RISCVPipeline.h @@ -5,6 +5,7 @@ #include "rcc/CodeGen/MachinePass.h" #include "rcc/Support/Error.h" +#include "rcc/Target/RISCV/RISCVSubtarget.h" #include <memory> #include <string> @@ -20,8 +21,13 @@ namespace riscv { [[nodiscard]] Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineFunction &Function); +[[nodiscard]] Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, + const MachineFunction &Function, + RISCVSubtargetFeatures Features); [[nodiscard]] Expected<std::unique_ptr<MachineFunctionPass>> createCanonicalPipelinePass(std::string_view Name); +[[nodiscard]] Expected<std::unique_ptr<MachineFunctionPass>> +createCanonicalPipelinePass(std::string_view Name, RISCVSubtargetFeatures Features); [[nodiscard]] Expected<std::vector<std::string>> canonicalPipelinePassNames(const MachineFunction &Function); [[nodiscard]] Expected<void> diff --git a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h new file mode 100644 index 0000000..d5f088f --- /dev/null +++ b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_TARGET_RISCV_RISCVSUBTARGET_H +#define RCC_TARGET_RISCV_RISCVSUBTARGET_H + +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <span> +#include <string> + +namespace rcc::riscv { + +enum class RISCVExtension : std::uint8_t { + I, + M, + A, + F, + D, + C, + Zicsr, + Zifencei, + Zacas, + Zabha, + Count, +}; + +class RISCVSubtargetFeatures final { +public: + [[nodiscard]] static Expected<RISCVSubtargetFeatures> + fromFeatureList(std::span<const std::string> Features); + [[nodiscard]] static RISCVSubtargetFeatures rv64gc() noexcept; + + [[nodiscard]] bool has(RISCVExtension Extension) const noexcept; + + friend bool operator==(const RISCVSubtargetFeatures &Left, + const RISCVSubtargetFeatures &Right) = default; + +private: + explicit constexpr RISCVSubtargetFeatures(std::uint16_t Enabled) noexcept : Enabled(Enabled) {} + + std::uint16_t Enabled = 0; +}; + +} // namespace rcc::riscv + +#endif // RCC_TARGET_RISCV_RISCVSUBTARGET_H diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt index eae426c..68bd444 100644 --- a/backend/lib/Target/RISCV/CMakeLists.txt +++ b/backend/lib/Target/RISCV/CMakeLists.txt @@ -66,6 +66,7 @@ add_library( RISCVPseudoExpansion.cpp RISCVRegisterAllocation.cpp RISCVScheduling.cpp + RISCVSubtarget.cpp RISCVTarget.cpp RISCVTargetConstant.cpp "${RCCBackendRISCVGeneratedRegisterHeader}" @@ -135,6 +136,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVPseudoExpansion.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVRegisterAllocation.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVScheduling.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVSubtarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetConstant.cpp" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVCodeGen.h" @@ -147,6 +149,7 @@ rcc_backend_register_format_files( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVMCCodeEmitter.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVObjectFile.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVPipeline.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVSubtarget.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVMCTargetLowering.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVTarget.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVTargetConstant.h" @@ -172,6 +175,7 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVPseudoExpansion.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVRegisterAllocation.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVScheduling.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVSubtarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTargetConstant.cpp" ) diff --git a/backend/lib/Target/RISCV/RISCVCodeGen.cpp b/backend/lib/Target/RISCV/RISCVCodeGen.cpp index 8676a2b..0bd3298 100644 --- a/backend/lib/Target/RISCV/RISCVCodeGen.cpp +++ b/backend/lib/Target/RISCV/RISCVCodeGen.cpp @@ -2879,9 +2879,15 @@ buildIncomingConversion(MachineFunction &Function, const TargetDescription &Targ class RISCVLegalizerInfo final : public TargetLegalizerInfo { public: + explicit RISCVLegalizerInfo(RISCVSubtargetFeatures Features) : Features(Features) {} + [[nodiscard]] Expected<LegalizationAction> classify(const MachineInstr &Instruction, const MachineFunction &Function, const TargetDescription &) const override { + if (!Features.has(RISCVExtension::I)) { + return makeUnexpected(ErrorCode::InternalError, + "RISC-V legalizer requires the base I extension"); + } if (!isGenericOpcode(Instruction.opcode())) return LegalizationAction::Legal; @@ -3560,6 +3566,9 @@ public: return makeUnexpected(ErrorCode::Unsupported, "RISC-V legalizer has no lowering rule for this instruction"); } + +private: + RISCVSubtargetFeatures Features; }; class RISCVRegisterBankInfo final : public TargetRegisterBankInfo { @@ -6284,10 +6293,14 @@ private: } // namespace const TargetLegalizerInfo &legalizerInfo() noexcept { - static const RISCVLegalizerInfo Value; + static const RISCVLegalizerInfo Value(RISCVSubtargetFeatures::rv64gc()); return Value; } +std::unique_ptr<TargetLegalizerInfo> createLegalizerInfo(RISCVSubtargetFeatures Features) { + return std::make_unique<RISCVLegalizerInfo>(Features); +} + const TargetRegisterBankInfo ®isterBankInfo() noexcept { static const RISCVRegisterBankInfo Value; return Value; diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp index 8d05bba..05d26b3 100644 --- a/backend/lib/Target/RISCV/RISCVPipeline.cpp +++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp @@ -25,8 +25,9 @@ template <typename PassT, typename... ArgumentT> return Pipeline.addPass(std::make_unique<PassT>(std::forward<ArgumentT>(Arguments)...)); } -[[nodiscard]] Expected<void> addInitialPipeline(MachinePassManager &Pipeline) { - auto Added = addPass<LegalizerPass>(Pipeline, legalizerInfo()); +[[nodiscard]] Expected<void> addInitialPipeline(MachinePassManager &Pipeline, + RISCVSubtargetFeatures Features) { + auto Added = addPass<LegalizerPass>(Pipeline, createLegalizerInfo(Features)); if (!Added) return std::unexpected(Added.error()); Added = addPass<RegisterBankSelectPass>(Pipeline, registerBankInfo()); @@ -52,8 +53,9 @@ template <typename PassT, typename... ArgumentT> return addPass<PBQPAllocatorPass>(Pipeline, registerAllocationInfo()); } -[[nodiscard]] Expected<void> addCompleteRegistry(MachinePassManager &Pipeline) { - auto Added = addInitialPipeline(Pipeline); +[[nodiscard]] Expected<void> addCompleteRegistry(MachinePassManager &Pipeline, + RISCVSubtargetFeatures Features) { + auto Added = addInitialPipeline(Pipeline, Features); if (!Added) return std::unexpected(Added.error()); Added = addSSAExitPipeline(Pipeline); @@ -68,8 +70,13 @@ template <typename PassT, typename... ArgumentT> } // namespace Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineFunction &Function) { + return addCanonicalPipeline(Pipeline, Function, RISCVSubtargetFeatures::rv64gc()); +} + +Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineFunction &Function, + RISCVSubtargetFeatures Features) { if (!Function.properties().has(MachineFunctionProperty::Legalized)) { - auto Added = addPass<LegalizerPass>(Pipeline, legalizerInfo()); + auto Added = addPass<LegalizerPass>(Pipeline, createLegalizerInfo(Features)); if (!Added) return std::unexpected(Added.error()); } @@ -112,10 +119,15 @@ Expected<void> addCanonicalPipeline(MachinePassManager &Pipeline, const MachineF } Expected<std::unique_ptr<MachineFunctionPass>> createCanonicalPipelinePass(std::string_view Name) { + return createCanonicalPipelinePass(Name, RISCVSubtargetFeatures::rv64gc()); +} + +Expected<std::unique_ptr<MachineFunctionPass>> +createCanonicalPipelinePass(std::string_view Name, RISCVSubtargetFeatures Features) { if (Name.empty()) return makeUnexpected(ErrorCode::InvalidArgument, "pipeline pass name cannot be empty"); MachinePassManager Registry; - auto Added = addCompleteRegistry(Registry); + auto Added = addCompleteRegistry(Registry, Features); if (!Added) return std::unexpected(Added.error()); MachinePassManager::PassList Passes = std::move(Registry).takePasses(); diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp new file mode 100644 index 0000000..3a3d9e2 --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/Target/RISCV/RISCVSubtarget.h" + +#include <array> +#include <cstddef> +#include <string_view> + +namespace rcc::riscv { +namespace { + +struct ExtensionName final { + std::string_view Name; + RISCVExtension Extension; +}; + +constexpr std::array ExtensionNames{ + ExtensionName{"i", RISCVExtension::I}, + ExtensionName{"m", RISCVExtension::M}, + ExtensionName{"a", RISCVExtension::A}, + ExtensionName{"f", RISCVExtension::F}, + ExtensionName{"d", RISCVExtension::D}, + ExtensionName{"c", RISCVExtension::C}, + ExtensionName{"zicsr", RISCVExtension::Zicsr}, + ExtensionName{"zifencei", RISCVExtension::Zifencei}, + ExtensionName{"zacas", RISCVExtension::Zacas}, + ExtensionName{"zabha", RISCVExtension::Zabha}, +}; + +[[nodiscard]] constexpr std::uint16_t extensionBit(RISCVExtension Extension) noexcept { + return static_cast<std::uint16_t>(std::uint16_t{1} << static_cast<std::uint8_t>(Extension)); +} + +[[nodiscard]] const ExtensionName *findExtension(std::string_view Name) noexcept { + for (const ExtensionName &Entry : ExtensionNames) { + if (Entry.Name == Name) + return &Entry; + } + return nullptr; +} + +} // namespace + +Expected<RISCVSubtargetFeatures> +RISCVSubtargetFeatures::fromFeatureList(std::span<const std::string> Features) { + std::uint16_t Enabled = extensionBit(RISCVExtension::I); + for (const std::string &Feature : Features) { + if (Feature.size() < 2 || (Feature.front() != '+' && Feature.front() != '-')) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V target feature must use canonical +/- spelling"); + } + const ExtensionName *Extension = findExtension(std::string_view(Feature).substr(1)); + if (Extension == nullptr) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V backend does not support target feature '" + Feature + "'"); + } + if (Feature.front() == '+') + Enabled |= extensionBit(Extension->Extension); + else + Enabled &= static_cast<std::uint16_t>(~extensionBit(Extension->Extension)); + } + + RISCVSubtargetFeatures Result(Enabled); + if (!Result.has(RISCVExtension::I)) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RV64 target feature configuration cannot disable the base I extension"); + } + if (Result.has(RISCVExtension::D) && !Result.has(RISCVExtension::F)) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V D extension requires the F extension"); + } + if ((Result.has(RISCVExtension::Zacas) || Result.has(RISCVExtension::Zabha)) && + !Result.has(RISCVExtension::A)) { + return makeUnexpected(ErrorCode::InvalidInvocation, + "RISC-V Zacas and Zabha extensions require the A extension"); + } + return Result; +} + +RISCVSubtargetFeatures RISCVSubtargetFeatures::rv64gc() noexcept { + return RISCVSubtargetFeatures(extensionBit(RISCVExtension::I) | extensionBit(RISCVExtension::M) | + extensionBit(RISCVExtension::A) | extensionBit(RISCVExtension::F) | + extensionBit(RISCVExtension::D) | extensionBit(RISCVExtension::C) | + extensionBit(RISCVExtension::Zicsr) | + extensionBit(RISCVExtension::Zifencei)); +} + +bool RISCVSubtargetFeatures::has(RISCVExtension Extension) const noexcept { + if (Extension >= RISCVExtension::Count) + return false; + return (Enabled & extensionBit(Extension)) != 0; +} + +} // namespace rcc::riscv diff --git a/backend/lib/Tooling/PipelineDriver.cpp b/backend/lib/Tooling/PipelineDriver.cpp index e9a3d9d..b7844cd 100644 --- a/backend/lib/Tooling/PipelineDriver.cpp +++ b/backend/lib/Tooling/PipelineDriver.cpp @@ -72,10 +72,10 @@ struct FunctionRunResult final { [[nodiscard]] Expected<MachinePassManager::PassList> createPasses(const MachineFunction &Function, const BackendInvocation &Invocation, - MachinePassManagerOptions Options) { + riscv::RISCVSubtargetFeatures Features, MachinePassManagerOptions Options) { MachinePassManager Pipeline(Options); if (Invocation.PassPipeline.size() == 1 && Invocation.PassPipeline.front() == "default") { - auto Added = riscv::addCanonicalPipeline(Pipeline, Function); + auto Added = riscv::addCanonicalPipeline(Pipeline, Function, Features); if (!Added) return std::unexpected(Added.error()); } else { @@ -86,7 +86,7 @@ createPasses(const MachineFunction &Function, const BackendInvocation &Invocatio for (const std::string &Name : Invocation.PassPipeline) { if (Name == "none") continue; - auto Pass = riscv::createCanonicalPipelinePass(Name); + auto Pass = riscv::createCanonicalPipelinePass(Name, Features); if (!Pass) return std::unexpected(Pass.error()); auto Added = Pipeline.addPass(std::move(*Pass)); @@ -171,14 +171,15 @@ captureSnapshot(FunctionRunResult &Result, const mir::MIRDocument &Document, [[nodiscard]] Expected<FunctionRunResult> runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetDescription &Target, const BackendInvocation &Invocation, const PipelineControls &Controls, - bool AllowSnapshots, MachinePassInstrumentation *Instrumentation) { + riscv::RISCVSubtargetFeatures Features, bool AllowSnapshots, + MachinePassInstrumentation *Instrumentation) { FunctionRunResult Result; MachinePassManagerOptions ManagerOptions{ .VerifyBefore = true, .VerifyEach = Controls.VerifyEach, .DetectUnreportedChanges = Controls.DetectUnreportedChanges, }; - auto Passes = createPasses(Function, Invocation, ManagerOptions); + auto Passes = createPasses(Function, Invocation, Features, ManagerOptions); if (!Passes) return std::unexpected(Passes.error()); MachineAnalysisManager Analyses; @@ -326,11 +327,14 @@ Expected<void> verifyRV64GCInvocation(const BackendInvocation &Invocation) { "RV64GC backend invocation must be canonicalized before execution"); } const BackendInvocation Expected = defaultRV64GCInvocation(); + auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features); + if (!Features) + return std::unexpected(Features.error()); if (Invocation.Triple != Expected.Triple || Invocation.CPU != Expected.CPU || - Invocation.TuneCPU != Expected.TuneCPU || Invocation.Features != Expected.Features || - Invocation.ABI != Expected.ABI || Invocation.DataLayout != Expected.DataLayout) { + Invocation.TuneCPU != Expected.TuneCPU || Invocation.ABI != Expected.ABI || + Invocation.DataLayout != Expected.DataLayout) { return makeUnexpected(ErrorCode::InvalidInvocation, - "backend invocation does not select the supported RV64GC LP64D target"); + "backend invocation does not select the supported RV64 LP64D target"); } if (Invocation.MIRReferenceRevision != LLVMReferenceRevision || Invocation.GenericOpcodeVersion != GenericOpcodeReferenceVersion || @@ -349,6 +353,9 @@ Expected<PipelineRunResult> runRV64GCPipeline(mir::MIRDocument &Document, auto InvocationVerification = verifyRV64GCInvocation(Invocation); if (!InvocationVerification) return std::unexpected(InvocationVerification.error()); + auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features); + if (!Features) + return std::unexpected(Features.error()); auto ControlVerification = validateControls(Controls); if (!ControlVerification) return std::unexpected(ControlVerification.error()); @@ -383,7 +390,7 @@ Expected<PipelineRunResult> runRV64GCPipeline(mir::MIRDocument &Document, if (Function == nullptr) return makeUnexpected(ErrorCode::InternalError, "compilation unit contains a null function"); - auto Run = runFunction(*Function, Document, Target, Invocation, Controls, true, + auto Run = runFunction(*Function, Document, Target, Invocation, Controls, *Features, true, ActiveInstrumentation); if (!Run) return std::unexpected(Run.error()); @@ -404,7 +411,7 @@ Expected<PipelineRunResult> runRV64GCPipeline(mir::MIRDocument &Document, Error(ErrorCode::InternalError, "compilation unit contains a null function"); continue; } - auto Run = runFunction(*Function, Document, Target, Invocation, Controls, false, + auto Run = runFunction(*Function, Document, Target, Invocation, Controls, *Features, false, ActiveInstrumentation); if (!Run) { FunctionResults[Index].Failure = Run.error(); diff --git a/backend/unittests/Tooling/PipelineDriverTest.cpp b/backend/unittests/Tooling/PipelineDriverTest.cpp index b9180ce..5815712 100644 --- a/backend/unittests/Tooling/PipelineDriverTest.cpp +++ b/backend/unittests/Tooling/PipelineDriverTest.cpp @@ -102,6 +102,25 @@ int main() { if (!Source) return tooling_test::fail(Source.error().message()); + rcc::tooling::BackendInvocation AtomicOnlyInvocation = Invocation; + AtomicOnlyInvocation.Features = {"+a", "+zacas", "+zabha"}; + AtomicOnlyInvocation.PassPipeline = {"Legalizer"}; + auto CanonicalAtomicOnly = AtomicOnlyInvocation.canonicalizeAndVerify(); + if (!CanonicalAtomicOnly) + return tooling_test::fail(CanonicalAtomicOnly.error().message()); + auto AtomicOnlyRun = runInput("atomic-only.mir", *Source, *Target, AtomicOnlyInvocation, + rcc::tooling::BackendOutputKind::LegalizedMIR); + if (!AtomicOnlyRun) + return tooling_test::fail(AtomicOnlyRun.error().message()); + + rcc::tooling::BackendInvocation UnsupportedFeatureInvocation = Invocation; + UnsupportedFeatureInvocation.Features = {"+v"}; + auto CanonicalUnsupported = UnsupportedFeatureInvocation.canonicalizeAndVerify(); + if (!CanonicalUnsupported) + return tooling_test::fail(CanonicalUnsupported.error().message()); + if (rcc::tooling::verifyRV64GCInvocation(UnsupportedFeatureInvocation)) + return tooling_test::fail("RV64 backend invocation must reject unsupported target features"); + constexpr std::array StageCases{ std::pair{rcc::tooling::BackendOutputKind::PreLegalizerMIR, rcc::tooling::BackendStage::PreLegalizerMIR}, |
