[clang] c52a343 - [AsmPrinter] add optimisation remark for target-features (#222074)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 10 03:53:56 PDT 2026
Author: Tomas Matheson
Date: 2026-09-10T11:53:49+01:00
New Revision: c52a3432d6a8187dd0f22ad1f8fde6774167dc89
URL: https://github.com/llvm/llvm-project/commit/c52a3432d6a8187dd0f22ad1f8fde6774167dc89
DIFF: https://github.com/llvm/llvm-project/commit/c52a3432d6a8187dd0f22ad1f8fde6774167dc89.diff
LOG: [AsmPrinter] add optimisation remark for target-features (#222074)
In clang we have `--print-enabled-extensions` which will print the
AArch64 extensions enabled for a given TU. However, sometimes it is
useful to be able to print out the actual subtarget features for each
function, for debugging/testing purposes. Add an optimisation remark for
that.
Added:
clang/test/Frontend/optimization-remark-target-features-aarch64.c
clang/test/Frontend/optimization-remark-target-features-arm.c
llvm/test/CodeGen/AArch64/optimization-remark-target-features.ll
llvm/test/CodeGen/ARM/optimization-remark-target-features.ll
Modified:
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Removed:
################################################################################
diff --git a/clang/test/Frontend/optimization-remark-target-features-aarch64.c b/clang/test/Frontend/optimization-remark-target-features-aarch64.c
new file mode 100644
index 0000000000000..f73c69ec7daa7
--- /dev/null
+++ b/clang/test/Frontend/optimization-remark-target-features-aarch64.c
@@ -0,0 +1,30 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang --target=aarch64-unknown-linux-gnu --rtlib=compiler-rt \
+// RUN: -S -O0 -Rpass-analysis=target-features -fno-caret-diagnostics %s -o /dev/null 2>&1 | FileCheck %s
+
+int baseline(void) { return 0; }
+__attribute__((target("sve2"))) int targeted(void) { return 1; }
+__attribute__((target_clones("sve2", "default"))) int clones(void) { return 2; }
+__attribute__((target_version("sve2"))) int versioned(void) { return 3; }
+__attribute__((target_version("default"))) int versioned(void) { return 4; }
+int caller(void) { return clones() + versioned(); }
+
+// Inspect the subtarget used for each emitted function, including FMV variants
+// and their resolvers. Default functions must not inherit variant features.
+// CHECK-NOT: Enabled features
+// CHECK: {{.*}}remark: Enabled features for @baseline:
+// CHECK-NOT: {{(^|[ ,])(sve|sve2)(,| |$)}}
+// CHECK-NEXT: {{.*}}remark: Enabled features for @targeted: {{([^,]+,)*}}fp-armv8,fullfp16,{{([^,]+,)*}}sve,sve2{{(,.*)?}} [-Rpass-analysis=target-features]
+// CHECK-NEXT: {{.*}}remark: Enabled features for @clones._Msve2: {{([^,]+,)*}}fp-armv8,fullfp16,{{([^,]+,)*}}sve,sve2{{(,.*)?}} [-Rpass-analysis=target-features]
+// CHECK-NEXT: {{.*}}remark: Enabled features for @clones.default:
+// CHECK-NOT: {{(^|[ ,])(sve|sve2)(,| |$)}}
+// CHECK-NEXT: {{.*}}remark: Enabled features for @versioned._Msve2: {{([^,]+,)*}}fp-armv8,fullfp16,{{([^,]+,)*}}sve,sve2{{(,.*)?}} [-Rpass-analysis=target-features]
+// CHECK-NEXT: {{.*}}remark: Enabled features for @versioned.default:
+// CHECK-NOT: {{(^|[ ,])(sve|sve2)(,| |$)}}
+// CHECK-NEXT: {{.*}}remark: Enabled features for @caller:
+// CHECK-NOT: {{(^|[ ,])(sve|sve2)(,| |$)}}
+// CHECK-NEXT: {{.*}}remark: Enabled features for @clones.resolver:
+// CHECK-NOT: {{(^|[ ,])(sve|sve2)(,| |$)}}
+// CHECK-NEXT: {{.*}}remark: Enabled features for @versioned.resolver:
+// CHECK-NOT: {{(^|[ ,])(sve|sve2)(,| |$)}}
+// CHECK-NOT: Enabled features
diff --git a/clang/test/Frontend/optimization-remark-target-features-arm.c b/clang/test/Frontend/optimization-remark-target-features-arm.c
new file mode 100644
index 0000000000000..e27de210236f4
--- /dev/null
+++ b/clang/test/Frontend/optimization-remark-target-features-arm.c
@@ -0,0 +1,19 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang --target=armv7-unknown-linux-gnueabi \
+// RUN: -S -O0 -Rpass-analysis=target-features -fno-caret-diagnostics %s -o /dev/null 2>&1 | FileCheck %s
+
+int baseline(void) { return 0; }
+__attribute__((target("thumb"))) int thumb_function(void) { return 1; }
+__attribute__((target("arm"))) int arm_function(void) { return 2; }
+int baseline_again(void) { return 3; }
+
+// ARM and Thumb functions in the same translation unit use distinct subtargets.
+// CHECK-NOT: Enabled features
+// CHECK: {{.*}}remark: Enabled features for @baseline:
+// CHECK-NOT: {{(^|[ ,])thumb-mode(,| |$)}}
+// CHECK-NEXT: {{.*}}remark: Enabled features for @thumb_function: {{([^,]+,)*}}thumb-mode{{(,.*)?}} [-Rpass-analysis=target-features]
+// CHECK-NEXT: {{.*}}remark: Enabled features for @arm_function:
+// CHECK-NOT: {{(^|[ ,])thumb-mode(,| |$)}}
+// CHECK-NEXT: {{.*}}remark: Enabled features for @baseline_again:
+// CHECK-NOT: {{(^|[ ,])thumb-mode(,| |$)}}
+// CHECK-NOT: Enabled features
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 3d06677d1706b..5440e1a3cdbae 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2425,6 +2425,23 @@ void AsmPrinter::emitFunctionBody() {
<< " instructions in function";
ORE->emit(R);
+ if (ORE->allowExtraAnalysis("target-features")) {
+ const Function &F = MF->getFunction();
+ std::string FunctionName;
+ raw_string_ostream OS(FunctionName);
+ F.printAsOperand(OS, /*PrintType=*/false);
+
+ MachineOptimizationRemarkAnalysis Remark(
+ "target-features", "EnabledFeatures", F.getSubprogram(), &MF->front());
+ Remark << "Enabled features for " << ore::NV("Function", FunctionName)
+ << ": ";
+ // The processor feature table is sorted by feature name.
+ ListSeparator LS(",");
+ for (const auto *Feature : MF->getSubtarget().getEnabledProcessorFeatures())
+ Remark << LS << ore::NV("Feature", Feature->key());
+ ORE->emit(Remark);
+ }
+
// If the function is empty and the object file uses .subsections_via_symbols,
// then we need to emit *something* to the function body to prevent the
// labels from collapsing together. Just emit a noop.
diff --git a/llvm/test/CodeGen/AArch64/optimization-remark-target-features.ll b/llvm/test/CodeGen/AArch64/optimization-remark-target-features.ll
new file mode 100644
index 0000000000000..ebf1ce000789c
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/optimization-remark-target-features.ll
@@ -0,0 +1,45 @@
+; RUN: llc -mtriple=aarch64-linux-gnu -mcpu=generic -pass-remarks-analysis=target-features %s -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc -mtriple=aarch64-linux-gnu -mcpu=generic -mattr=+sve2 -pass-remarks-analysis=target-features %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=COMMAND
+; RUN: llc -mtriple=aarch64-linux-gnu -mcpu=generic -pass-remarks-output=- -pass-remarks-filter=target-features %s -o /dev/null | FileCheck %s --check-prefix=YAML
+
+; CPU defaults, implications and explicit disabling are resolved per function.
+define void @baseline() { ret void }
+define void @enabled() "target-features"="+sve2" { ret void }
+define void @disabled() "target-features"="+sve2,-sve" { ret void }
+define void @cpu() "target-cpu"="neoverse-v1" { ret void }
+define void @baseline_again() { ret void }
+define void @"escaped\0Aname"() { ret void }
+
+; Declarations and aliases do not create machine functions.
+declare void @declaration()
+ at alias = alias void (), ptr @baseline
+
+; The baseline is unchanged after functions with custom attributes.
+; CHECK-NOT: Enabled features
+; CHECK: remark: <unknown>:0:0: Enabled features for @baseline: [[BASELINE:enable-select-opt,ete,fixed-load-latency-4,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler]]{{$}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @enabled: {{([^,]+,)*}}fp-armv8,fullfp16,{{([^,]+,)*}}sve,sve2{{(,.*)?$}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @disabled:
+; CHECK-NOT: {{(^|[ ,])(sve|sve2)(,|$)}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @cpu: {{([^,]+,)*}}bf16,{{([^,]+,)*}}sve{{(,.*)?$}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @baseline_again: [[BASELINE]]{{$}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @"escaped\0Aname": [[BASELINE]]{{$}}
+; CHECK-NOT: Enabled features
+
+; llc appends -mattr to existing function attributes, so the command line
+; re-enables features explicitly disabled by the IR.
+; COMMAND: remark: <unknown>:0:0: Enabled features for @baseline: {{([^,]+,)*}}sve,sve2{{(,.*)?$}}
+; COMMAND: remark: <unknown>:0:0: Enabled features for @disabled: {{([^,]+,)*}}sve,sve2{{(,.*)?$}}
+
+; Saved analysis remarks expose individual features as structured arguments.
+; YAML: --- !Analysis
+; YAML-NEXT: Pass: target-features
+; YAML-NEXT: Name: EnabledFeatures
+; YAML-NEXT: Function: baseline
+; YAML: - Feature: fp-armv8
+; YAML: Function: enabled
+; YAML: - Feature: fullfp16
+; YAML: - Feature: sve{{$}}
+; YAML: - Feature: sve2{{$}}
+; YAML: Function: disabled
+; YAML-NOT: - Feature: {{sve2?$}}
+; YAML: ...
diff --git a/llvm/test/CodeGen/ARM/optimization-remark-target-features.ll b/llvm/test/CodeGen/ARM/optimization-remark-target-features.ll
new file mode 100644
index 0000000000000..6182fb5e70e44
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/optimization-remark-target-features.ll
@@ -0,0 +1,30 @@
+; RUN: llc -mtriple=armv7-linux-gnueabi -mcpu=generic -pass-remarks-analysis=target-features %s -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc -mtriple=armv7-linux-gnueabi -mcpu=generic -mattr=+neon -pass-remarks-analysis=target-features %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=COMMAND
+
+; CPU defaults, implications and explicit disabling are resolved per function.
+define void @baseline() { ret void }
+define void @enabled() "target-features"="+neon" { ret void }
+define void @disabled() "target-features"="+neon,-vfp3" { ret void }
+define void @cpu() "target-cpu"="cortex-a8" { ret void }
+define void @baseline_again() { ret void }
+define void @"escaped\0Aname"() { ret void }
+
+; Declarations and aliases do not create machine functions.
+declare void @declaration()
+ at alias = alias void (), ptr @baseline
+
+; The baseline is unchanged after functions with custom attributes.
+; CHECK-NOT: Enabled features
+; CHECK: remark: <unknown>:0:0: Enabled features for @baseline: [[BASELINE:.*]]
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @enabled: {{([^,]+,)*}}neon,{{([^,]+,)*}}vfp2,{{([^,]+,)*}}vfp3{{(,.*)?$}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @disabled:
+; CHECK-NOT: {{(^|[ ,])(neon|vfp3)(,|$)}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @cpu: {{([^,]+,)*}}neon,{{([^,]+,)*}}vfp3{{(,.*)?$}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @baseline_again: [[BASELINE]]{{$}}
+; CHECK-NEXT: remark: <unknown>:0:0: Enabled features for @"escaped\0Aname": [[BASELINE]]{{$}}
+; CHECK-NOT: Enabled features
+
+; llc appends -mattr to existing function attributes, so the command line
+; re-enables features explicitly disabled by the IR.
+; COMMAND: remark: <unknown>:0:0: Enabled features for @baseline: {{([^,]+,)*}}neon{{(,.*)?$}}
+; COMMAND: remark: <unknown>:0:0: Enabled features for @disabled: {{([^,]+,)*}}neon{{(,.*)?$}}
More information about the cfe-commits
mailing list