[llvm] [opt] Enable -mcpu=help without an input file (PR #187876)
Tomer Shafir via llvm-commits
llvm-commits at lists.llvm.org
Sat Mar 21 11:03:36 PDT 2026
https://github.com/tomershafir updated https://github.com/llvm/llvm-project/pull/187876
>From 1b443e4420d4fb862f290650ea546e0e662e2fd1 Mon Sep 17 00:00:00 2001
From: tomershafir <tomer.shafir8 at gmail.com>
Date: Sat, 21 Mar 2026 19:45:43 +0200
Subject: [PATCH] [opt] Enable -mcpu=help without an input file
This patch enables `-mcpu=help` or `-mattr=help` invocation without an input file, like `llc`. For example, the following command `opt -mtriple=aarch64 -mattr=help` would previously hang but now it succeeds.
The implementation is similar to llc, creating a target machine for help printing side effects and existing early. Note: llc has a bug in the default triple handling that we already fix here upfront. Ill submit a separate fix for llc.
---
llvm/test/tools/opt/mattr-mcpu-help.ll | 34 ++++++++++++++++++++++++++
llvm/tools/opt/optdriver.cpp | 32 +++++++++++++++++++++---
2 files changed, 63 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/tools/opt/mattr-mcpu-help.ll
diff --git a/llvm/test/tools/opt/mattr-mcpu-help.ll b/llvm/test/tools/opt/mattr-mcpu-help.ll
new file mode 100644
index 0000000000000..c4de602d00540
--- /dev/null
+++ b/llvm/test/tools/opt/mattr-mcpu-help.ll
@@ -0,0 +1,34 @@
+; REQUIRES: aarch64-registered-target
+; REQUIRES: default_triple
+
+;; Test -mattr=help
+; RUN: opt -mtriple=aarch64 -mattr=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt -mtriple=aarch64 -mattr=help -o %t.s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt < %s -mtriple=aarch64 -mattr=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt < %s -mtriple=aarch64 -mattr=help -o %t.s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+
+;; -mattr=help doesn't have to be first
+; RUN: opt -mtriple=aarch64 -mattr=+zcm-fpr64 -mattr=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+
+;; Using default target triple for -mattr=help
+; RUN: opt -mattr=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt < %s -mattr=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+
+;; Test -mcpu=help
+; RUN: opt -mtriple=aarch64 -mcpu=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt -mtriple=aarch64 -mcpu=help -o %t.s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt < %s -mtriple=aarch64 -mcpu=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt < %s -mtriple=aarch64 -mcpu=help -o %t.s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+
+;; Using default target triple for -mcpu=help
+; RUN: opt -mcpu=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+; RUN: opt < %s -mcpu=help 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-NO-OPTIMIZE
+
+; CHECK: Available CPUs for this target:
+; CHECK: Available features for this target:
+
+;; To check we dont compile the file
+; CHECK-NO-OPTIMIZE-NOT: foo
+define i32 @foo() {
+ ret i32 0
+}
diff --git a/llvm/tools/opt/optdriver.cpp b/llvm/tools/opt/optdriver.cpp
index 2d1613edc2c83..7a64f28ed86b2 100644
--- a/llvm/tools/opt/optdriver.cpp
+++ b/llvm/tools/opt/optdriver.cpp
@@ -488,6 +488,33 @@ optMain(int argc, char **argv,
return 0;
}
+ // If user just wants to list available options, skip module loading.
+ std::string CPUStr = codegen::getCPUStr();
+ auto MAttrs = codegen::getMAttrs();
+ bool SkipModule = CPUStr == "help" || is_contained(MAttrs, "help");
+ if (SkipModule) {
+ Triple TheTriple;
+ if (!TargetTriple.empty())
+ TheTriple = Triple(Triple::normalize(TargetTriple));
+ else
+ TheTriple = Triple(sys::getDefaultTargetTriple());
+
+ // Create the target machine just to print the help info. Use unique_ptr
+ // to avoid a memory leak.
+ Expected<std::unique_ptr<TargetMachine>> ExpectedTM =
+ codegen::createTargetMachineForTriple(TheTriple.str(),
+ GetCodeGenOptLevel());
+ if (Error E = ExpectedTM.takeError()) {
+ errs() << argv[0] << ": " << toString(std::move(E)) << "\n";
+ return 1;
+ }
+
+ // If we don't have a module then just exit now. We do this down
+ // here since the CPU/Feature help is underneath the target machine
+ // creation.
+ return 0;
+ }
+
TimeTracerRAII TimeTracer(argv[0]);
SMDiagnostic Err;
@@ -627,11 +654,8 @@ optMain(int argc, char **argv,
}
Triple ModuleTriple(M->getTargetTriple());
- std::string CPUStr, FeaturesStr;
std::unique_ptr<TargetMachine> TM;
if (ModuleTriple.getArch()) {
- CPUStr = codegen::getCPUStr();
- FeaturesStr = codegen::getFeaturesStr();
Expected<std::unique_ptr<TargetMachine>> ExpectedTM =
codegen::createTargetMachineForTriple(ModuleTriple.str(),
GetCodeGenOptLevel());
@@ -655,6 +679,8 @@ optMain(int argc, char **argv,
codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple);
}
+ std::string FeaturesStr = codegen::getFeaturesStr();
+
// Override function attributes based on CPUStr, FeaturesStr, and command line
// flags.
codegen::setFunctionAttributes(*M, CPUStr, FeaturesStr);
More information about the llvm-commits
mailing list