diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index e6d8aed6aefc8..5840368d68766 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5260,7 +5260,7 @@ def print_supported_cpus : Flag<["-", "--"], "print-supported-cpus">, MarshallingInfoFlag>; def print_supported_extensions : Flag<["-", "--"], "print-supported-extensions">, Visibility<[ClangOption, CC1Option, CLOption]>, - HelpText<"Print supported extensions for RISC-V">, + HelpText<"Print supported -march extensions (RISC-V and AArch64 only)">, MarshallingInfoFlag>; def : Flag<["-"], "mcpu=help">, Alias; def : Flag<["-"], "mtune=help">, Alias; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 9d05549f671e2..ba723eac2a7ee 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -4284,7 +4284,8 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // and quits. if (Arg *A = Args.getLastArg(Opt)) { if (Opt == options::OPT_print_supported_extensions && - !C.getDefaultToolChain().getTriple().isRISCV()) { + !C.getDefaultToolChain().getTriple().isRISCV() && + !C.getDefaultToolChain().getTriple().isAArch64()) { C.getDriver().Diag(diag::err_opt_not_valid_on_target) << "--print-supported-extensions"; return; diff --git a/clang/test/Driver/print-supported-extensions.c b/clang/test/Driver/print-supported-extensions.c new file mode 100644 index 0000000000000..2cbd2d95816c2 --- /dev/null +++ b/clang/test/Driver/print-supported-extensions.c @@ -0,0 +1,14 @@ +// Test that --print-supported-extensions lists supported -march extensions +// on supported architectures, and errors on unsupported architectures. + +// RUN: %if aarch64-registered-target %{ %clang --target=aarch64-linux-gnu \ +// RUN: --print-supported-extensions 2>&1 | FileCheck %s --check-prefix AARCH64 %} +// AARCH64: All available -march extensions for AArch64 + +// RUN: %if aarch64-registered-target %{ %clang --target=riscv64-linux-gnu \ +// RUN: --print-supported-extensions 2>&1 | FileCheck %s --check-prefix RISCV %} +// RISCV: All available -march extensions for RISC-V + +// RUN: %if x86-registered-target %{ not %clang --target=x86_64-linux-gnu \ +// RUN: --print-supported-extensions 2>&1 | FileCheck %s --check-prefix X86 %} +// X86: error: option '--print-supported-extensions' cannot be specified on this target \ No newline at end of file diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index ab886d0adc7e5..ed68a11d0191f 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -45,6 +45,7 @@ #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/TargetParser/AArch64TargetParser.h" #include #ifdef CLANG_HAVE_RLIMITS @@ -183,6 +184,34 @@ static int PrintSupportedCPUs(std::string TargetStr) { return 0; } +static int PrintSupportedExtensions(std::string TargetStr) { + std::string Error; + const llvm::Target *TheTarget = + llvm::TargetRegistry::lookupTarget(TargetStr, Error); + if (!TheTarget) { + llvm::errs() << Error; + return 1; + } + + llvm::TargetOptions Options; + std::unique_ptr TheTargetMachine( + TheTarget->createTargetMachine(TargetStr, "", "", Options, std::nullopt)); + const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple(); + + if (MachineTriple.isRISCV()) + llvm::riscvExtensionsHelp(); + else if (MachineTriple.isAArch64()) + llvm::AArch64::PrintSupportedExtensions(); + else { + // The option was already checked in Driver::HandleImmediateArgs, + // so we do not expect to get here if we are not a supported architecture. + assert(0 && "Unhandled triple for --print-supported-extensions option."); + return 1; + } + + return 0; +} + int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { ensureSufficientStack(); @@ -224,7 +253,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { // --print-supported-extensions takes priority over the actual compilation. if (Clang->getFrontendOpts().PrintSupportedExtensions) - return llvm::riscvExtensionsHelp(), 0; + return PrintSupportedExtensions(Clang->getTargetOpts().Triple); // Infer the builtin include path if unspecified. if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h index dc4cdfa8e90ac..ba5c5fffd5f25 100644 --- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h +++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h @@ -576,6 +576,8 @@ bool isX18ReservedByDefault(const Triple &TT); // themselves, they are sequential (0, 1, 2, 3, ...). uint64_t getCpuSupportsMask(ArrayRef FeatureStrs); +void PrintSupportedExtensions(); + } // namespace AArch64 } // namespace llvm diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp index 3a1f549b28034..c4f689c5b497b 100644 --- a/llvm/lib/TargetParser/AArch64TargetParser.cpp +++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/TargetParser/AArch64TargetParser.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/ARMTargetParserCommon.h" #include "llvm/TargetParser/Triple.h" #include @@ -132,3 +133,12 @@ std::optional AArch64::parseCpu(StringRef Name) { return {}; } + +void AArch64::PrintSupportedExtensions() { + outs() << "All available -march extensions for AArch64\n\n"; + for (const auto &Ext : Extensions) { + // Extensions without a feature cannot be used with -march. + if (!Ext.Feature.empty()) + outs() << '\t' << Ext.Name << "\n"; + } +} diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp index 741d5a2d4b480..60b235d8d2d69 100644 --- a/llvm/unittests/TargetParser/TargetParserTest.cpp +++ b/llvm/unittests/TargetParser/TargetParserTest.cpp @@ -1805,4 +1805,26 @@ TEST(TargetParserTest, AArch64ArchExtFeature) { } } +TEST(TargetParserTest, AArch64PrintSupportedExtensions) { + std::string expected = "All available -march extensions for AArch64\n\n" + "\taes\n\tb16b16\n\tbf16"; + + outs().flush(); + testing::internal::CaptureStdout(); + AArch64::PrintSupportedExtensions(); + outs().flush(); + std::string captured = testing::internal::GetCapturedStdout(); + + // Check that the start of the output is as expected. + EXPECT_EQ(0ULL, captured.find(expected)); + + // Should not include "none". + EXPECT_EQ(std::string::npos, captured.find("none")); + // Should not include anything that lacks a feature name. Checking a few here + // but not all as if one is hidden correctly the rest should be. + EXPECT_EQ(std::string::npos, captured.find("memtag3")); + EXPECT_EQ(std::string::npos, captured.find("sha1")); + EXPECT_EQ(std::string::npos, captured.find("ssbs2")); +} + } // namespace