[llvm] da8497e - [IR][Verifier] Verification for `target-features` attribute (#173119)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 22 02:14:00 PST 2025
Author: Stefan Weigl-Bosker
Date: 2025-12-22T11:13:56+01:00
New Revision: da8497ed08f5b5f0f938b488d8540333133d685b
URL: https://github.com/llvm/llvm-project/commit/da8497ed08f5b5f0f938b488d8540333133d685b
DIFF: https://github.com/llvm/llvm-project/commit/da8497ed08f5b5f0f938b488d8540333133d685b.diff
LOG: [IR][Verifier] Verification for `target-features` attribute (#173119)
Fixes https://github.com/llvm/llvm-project/issues/172647
Currently, MC assumes that all `target-feature` flag attributes are well
formed and will crash otherwise. This change handles those cases more
gracefully.
Added:
llvm/test/Verifier/invalid-target-feature.ll
Modified:
llvm/lib/IR/Verifier.cpp
llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
llvm/test/CodeGen/AMDGPU/bug-deadlanes.ll
llvm/test/CodeGen/AMDGPU/mixed-wave32-wave64.ll
llvm/test/CodeGen/AMDGPU/pal-metadata-3.0-dvgpr.ll
llvm/test/CodeGen/AMDGPU/pal-metadata-3.0.ll
llvm/test/CodeGen/AMDGPU/pal-metadata-3.6-dvgpr.ll
llvm/test/CodeGen/AMDGPU/pal-metadata-3.6.ll
llvm/test/CodeGen/AMDGPU/ps-shader-arg-count.ll
llvm/test/CodeGen/AMDGPU/sgpr-spill-overlap-wwm-reserve.mir
llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-bug-deadlanes.mir
llvm/test/CodeGen/Hexagon/bit-rie.ll
llvm/test/CodeGen/Hexagon/hasfp-crash2.ll
llvm/test/CodeGen/WebAssembly/multivalue-dont-move-def-past-use.mir
llvm/test/tools/llvm-reduce/reduce-target-features-attr.ll
Removed:
################################################################################
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index dd42623a1de75..78e96e51eabcb 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2613,6 +2613,22 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
Check(FirstArgIdx > 0 && FirstArgIdx <= UpperBound,
"modular-format attribute first arg index is out of bounds", V);
}
+
+ if (auto A = Attrs.getFnAttr("target-features"); A.isValid()) {
+ StringRef S = A.getValueAsString();
+ if (!S.empty()) {
+ for (auto FeatureFlag : split(S, ',')) {
+ if (FeatureFlag.empty())
+ CheckFailed(
+ "target-features attribute should not contain an empty string");
+ else
+ Check(FeatureFlag[0] == '+' || FeatureFlag[0] == '-',
+ "target feature '" + FeatureFlag +
+ "' must start with a '+' or '-'",
+ V);
+ }
+ }
+ }
}
void Verifier::verifyUnknownProfileMetadata(MDNode *MD) {
Check(MD->getNumOperands() == 2,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 621640c12f695..402929caa760c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -334,6 +334,8 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass {
else
Ret += (StringRef("-") + KV.Key + ",").str();
}
+ // remove trailing ','
+ Ret.pop_back();
return Ret;
}
diff --git a/llvm/test/CodeGen/AMDGPU/bug-deadlanes.ll b/llvm/test/CodeGen/AMDGPU/bug-deadlanes.ll
index 8d9c1b69592dc..10ed7bd870491 100644
--- a/llvm/test/CodeGen/AMDGPU/bug-deadlanes.ll
+++ b/llvm/test/CodeGen/AMDGPU/bug-deadlanes.ll
@@ -87,4 +87,4 @@ declare float @llvm.amdgcn.struct.buffer.load.format.f32(<4 x i32>, i32, i32, i3
declare i32 @llvm.amdgcn.s.buffer.load.i32(<4 x i32>, i32, i32 immarg)
declare <3 x i32> @llvm.amdgcn.s.buffer.load.v3i32(<4 x i32>, i32, i32 immarg)
-attributes #0 = { "target-features"=",+wavefrontsize64,+cumode" }
+attributes #0 = { "target-features"="+wavefrontsize64,+cumode" }
diff --git a/llvm/test/CodeGen/AMDGPU/mixed-wave32-wave64.ll b/llvm/test/CodeGen/AMDGPU/mixed-wave32-wave64.ll
index aba14c3b97509..e82c03c21b6ee 100644
--- a/llvm/test/CodeGen/AMDGPU/mixed-wave32-wave64.ll
+++ b/llvm/test/CodeGen/AMDGPU/mixed-wave32-wave64.ll
@@ -34,8 +34,8 @@ define amdgpu_gs void @_amdgpu_gs_main() #4 {
declare float @llvm.amdgcn.interp.p2(float, float, i32, i32, i32) #2
declare float @llvm.amdgcn.image.sample.2d.f32.f32(i32, float, float, <8 x i32>, <4 x i32>, i1, i32, i32) #3
-attributes #0 = { "amdgpu-max-work-group-size"="128" "target-features"=",+wavefrontsize32" }
-attributes #1 = { "target-features"=",+wavefrontsize64" }
+attributes #0 = { "amdgpu-max-work-group-size"="128" "target-features"="+wavefrontsize32" }
+attributes #1 = { "target-features"="+wavefrontsize64" }
attributes #2 = { nounwind readnone speculatable }
attributes #3 = { nounwind readonly }
-attributes #4 = { "target-features"=",+wavefrontsize32" }
+attributes #4 = { "target-features"="+wavefrontsize32" }
diff --git a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0-dvgpr.ll b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0-dvgpr.ll
index c1846c0f2c23b..cb2c8ddbaa6f2 100644
--- a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0-dvgpr.ll
+++ b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0-dvgpr.ll
@@ -201,7 +201,7 @@ declare i64 @llvm.amdgcn.s.getpc() #2
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(write)
declare void @llvm.amdgcn.raw.buffer.store.i32(i32, <4 x i32>, i32, i32, i32 immarg) #3
-attributes #0 = { nounwind memory(readwrite) "amdgpu-flat-work-group-size"="1024,1024" "amdgpu-memory-bound"="false" "amdgpu-unroll-threshold"="700" "amdgpu-wave-limiter"="false" "amdgpu-work-group-info-arg-no"="4" "denormal-fp-math-f32"="preserve-sign" "target-features"=",+wavefrontsize64,+cumode" "amdgpu-dynamic-vgpr-block-size"="16" }
+attributes #0 = { nounwind memory(readwrite) "amdgpu-flat-work-group-size"="1024,1024" "amdgpu-memory-bound"="false" "amdgpu-unroll-threshold"="700" "amdgpu-wave-limiter"="false" "amdgpu-work-group-info-arg-no"="4" "denormal-fp-math-f32"="preserve-sign" "target-features"="+wavefrontsize64,+cumode" "amdgpu-dynamic-vgpr-block-size"="16" }
attributes #1 = { nounwind memory(readwrite) "InitialPSInputAddr"="36983" }
diff --git a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0.ll b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0.ll
index 53254992c1122..05f3e9e14c77a 100644
--- a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0.ll
+++ b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.0.ll
@@ -199,7 +199,7 @@ declare ptr addrspace(7) @lgc.buffer.desc.to.ptr(<4 x i32>) #1
declare i64 @llvm.amdgcn.s.getpc()
declare void @llvm.amdgcn.raw.buffer.store.i32(i32, <4 x i32>, i32, i32, i32 immarg) #3
-attributes #0 = { nounwind memory(readwrite) "target-features"=",+wavefrontsize64,+cumode" }
+attributes #0 = { nounwind memory(readwrite) "target-features"="+wavefrontsize64,+cumode" }
attributes #1 = { nounwind memory(readwrite) "InitialPSInputAddr"="36983" }
diff --git a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6-dvgpr.ll b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6-dvgpr.ll
index e598b0c5bef4d..9006aaa84cb1f 100644
--- a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6-dvgpr.ll
+++ b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6-dvgpr.ll
@@ -196,7 +196,7 @@ define dllexport amdgpu_hs void @hs_shader() {
!amdgpu.pal.metadata.msgpack = !{!0}
-attributes #0 = { nounwind memory(readwrite) "target-features"=",+wavefrontsize64,+cumode" "amdgpu-dynamic-vgpr-block-size"="16" }
+attributes #0 = { nounwind memory(readwrite) "target-features"="+wavefrontsize64,+cumode" "amdgpu-dynamic-vgpr-block-size"="16" }
attributes #1 = { nounwind memory(readwrite) "InitialPSInputAddr"="36983" "amdgpu-dynamic-vgpr-block-size"="16" }
diff --git a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6.ll b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6.ll
index d2f26e87243d2..8fc533028357d 100644
--- a/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6.ll
+++ b/llvm/test/CodeGen/AMDGPU/pal-metadata-3.6.ll
@@ -195,7 +195,7 @@ define dllexport amdgpu_hs void @hs_shader() {
!amdgpu.pal.metadata.msgpack = !{!0}
-attributes #0 = { nounwind memory(readwrite) "target-features"=",+wavefrontsize64,+cumode" }
+attributes #0 = { nounwind memory(readwrite) "target-features"="+wavefrontsize64,+cumode" }
attributes #1 = { nounwind memory(readwrite) "InitialPSInputAddr"="36983" }
diff --git a/llvm/test/CodeGen/AMDGPU/ps-shader-arg-count.ll b/llvm/test/CodeGen/AMDGPU/ps-shader-arg-count.ll
index 99e5d0017f30b..a466df21a5e71 100644
--- a/llvm/test/CodeGen/AMDGPU/ps-shader-arg-count.ll
+++ b/llvm/test/CodeGen/AMDGPU/ps-shader-arg-count.ll
@@ -359,7 +359,7 @@ define dllexport amdgpu_ps { <4 x float>, <4 x float>, <4 x float>, <4 x float>
ret { < 4 x float>, <4 x float>, <4 x float>, <4 x float> } %ret.res
}
-attributes #0 = { nounwind "target-features"=",+wavefrontsize64,+cumode" }
-attributes #1 = { nounwind "InitialPSInputAddr"="2" "target-features"=",+wavefrontsize64,+cumode" }
-attributes #2 = { nounwind "InitialPSInputAddr"="0xffff" "target-features"=",+wavefrontsize64,+cumode" }
-attributes #3 = { nounwind "InitialPSInputAddr"="0" "target-features"=",+wavefrontsize64,+cumode" }
+attributes #0 = { nounwind "target-features"="+wavefrontsize64,+cumode" }
+attributes #1 = { nounwind "InitialPSInputAddr"="2" "target-features"="+wavefrontsize64,+cumode" }
+attributes #2 = { nounwind "InitialPSInputAddr"="0xffff" "target-features"="+wavefrontsize64,+cumode" }
+attributes #3 = { nounwind "InitialPSInputAddr"="0" "target-features"="+wavefrontsize64,+cumode" }
diff --git a/llvm/test/CodeGen/AMDGPU/sgpr-spill-overlap-wwm-reserve.mir b/llvm/test/CodeGen/AMDGPU/sgpr-spill-overlap-wwm-reserve.mir
index 925984b15367d..b4f23ec00b8e2 100644
--- a/llvm/test/CodeGen/AMDGPU/sgpr-spill-overlap-wwm-reserve.mir
+++ b/llvm/test/CodeGen/AMDGPU/sgpr-spill-overlap-wwm-reserve.mir
@@ -6,7 +6,7 @@
ret [13 x i32] poison
}
- attributes #0 = { alwaysinline nounwind memory(readwrite) "amdgpu-flat-work-group-size"="32,32" "amdgpu-memory-bound"="false" "amdgpu-unroll-threshold"="700" "amdgpu-wave-limiter"="false" "denormal-fp-math-f32"="preserve-sign" "target-cpu"="gfx1030" "target-features"=",+wavefrontsize32,+cumode,+enable-flat-scratch" "uniform-work-group-size"="false" }
+ attributes #0 = { alwaysinline nounwind memory(readwrite) "amdgpu-flat-work-group-size"="32,32" "amdgpu-memory-bound"="false" "amdgpu-unroll-threshold"="700" "amdgpu-wave-limiter"="false" "denormal-fp-math-f32"="preserve-sign" "target-cpu"="gfx1030" "target-features"="+wavefrontsize32,+cumode,+enable-flat-scratch" "uniform-work-group-size"="false" }
...
---
diff --git a/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-bug-deadlanes.mir b/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-bug-deadlanes.mir
index 93796b3049b5b..683a1c062ba65 100644
--- a/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-bug-deadlanes.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-opt-vgpr-liverange-bug-deadlanes.mir
@@ -11,7 +11,7 @@
unreachable
}
- attributes #0 = { "target-cpu"="gfx1100" "target-features"=",+wavefrontsize64,+cumode" "uniform-work-group-size"="false" }
+ attributes #0 = { "target-cpu"="gfx1100" "target-features"="+wavefrontsize64,+cumode" "uniform-work-group-size"="false" }
...
---
name: _amdgpu_ps_main
diff --git a/llvm/test/CodeGen/Hexagon/bit-rie.ll b/llvm/test/CodeGen/Hexagon/bit-rie.ll
index 6bb8e912d2043..3b470787772f8 100644
--- a/llvm/test/CodeGen/Hexagon/bit-rie.ll
+++ b/llvm/test/CodeGen/Hexagon/bit-rie.ll
@@ -190,7 +190,7 @@ declare i64 @llvm.hexagon.M2.mpyd.ll.s1(i32, i32) #2
declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1
declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1
-attributes #0 = { norecurse nounwind "target-cpu"="hexagonv60" "target-features"="+hvx,,+hvx-length64b" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #0 = { norecurse nounwind "target-cpu"="hexagonv60" "target-features"="+hvx,+hvx-length64b" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { argmemonly nounwind }
attributes #2 = { nounwind readnone }
diff --git a/llvm/test/CodeGen/Hexagon/hasfp-crash2.ll b/llvm/test/CodeGen/Hexagon/hasfp-crash2.ll
index e2c6efc159d93..309e8b8bf616b 100644
--- a/llvm/test/CodeGen/Hexagon/hasfp-crash2.ll
+++ b/llvm/test/CodeGen/Hexagon/hasfp-crash2.ll
@@ -19,7 +19,7 @@ entry:
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
-attributes #0 = { nounwind "disable-tail-calls"="true" "frame-pointer"="all" "stack-protector-buffer-size"="8" "target-cpu"="hexagonv5" "target-features"=",-hvx,-long-calls" }
+attributes #0 = { nounwind "disable-tail-calls"="true" "frame-pointer"="all" "stack-protector-buffer-size"="8" "target-cpu"="hexagonv5" "target-features"="-hvx,-long-calls" }
attributes #1 = { nounwind readnone speculatable }
!llvm.dbg.cu = !{!0}
diff --git a/llvm/test/CodeGen/WebAssembly/multivalue-dont-move-def-past-use.mir b/llvm/test/CodeGen/WebAssembly/multivalue-dont-move-def-past-use.mir
index 14a21a06c8fcd..7e928a559613b 100644
--- a/llvm/test/CodeGen/WebAssembly/multivalue-dont-move-def-past-use.mir
+++ b/llvm/test/CodeGen/WebAssembly/multivalue-dont-move-def-past-use.mir
@@ -19,7 +19,7 @@
ret i32 %b
}
- attributes #0 = { "target-features"="+multivalue,+mutable-globals,+sign-ext," }
+ attributes #0 = { "target-features"="+multivalue,+mutable-globals,+sign-ext" }
!llvm.module.flags = !{!0, !1, !2}
diff --git a/llvm/test/Verifier/invalid-target-feature.ll b/llvm/test/Verifier/invalid-target-feature.ll
new file mode 100644
index 0000000000000..60f5319c7e284
--- /dev/null
+++ b/llvm/test/Verifier/invalid-target-feature.ll
@@ -0,0 +1,13 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: target feature 'foobar' must start with a '+' or '-'
+define void @f1() "target-features"="foobar" {
+entry:
+ ret void
+}
+
+; CHECK: target-features attribute should not contain an empty string
+define void @f2() "target-features"="+a,-b,,+c" {
+entry:
+ ret void
+}
diff --git a/llvm/test/tools/llvm-reduce/reduce-target-features-attr.ll b/llvm/test/tools/llvm-reduce/reduce-target-features-attr.ll
index b497758437358..1e36de061466f 100644
--- a/llvm/test/tools/llvm-reduce/reduce-target-features-attr.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-target-features-attr.ll
@@ -26,11 +26,6 @@ define void @keep_all_of_two() #4 {
ret void
}
-; CHECK: @drop_empty_element() [[$DROP_EMPTY_ELEMENT:#[0-9]+]]
-define void @drop_empty_element() #5 {
- ret void
-}
-
; CHECK: @keep_second_from_three() [[$KEEP_SECOND_FROM_THREE:#[0-9]+]]
define void @keep_second_from_three() #6 {
ret void
@@ -52,7 +47,6 @@ attributes #1 = { "target-features"="+foo" "unique-attr-1" }
attributes #2 = { "target-features"="+first,+second" "unique-attr-2" }
attributes #3 = { "target-features"="+first,+second" "unique-attr-3" }
attributes #4 = { "target-features"="+first,+second" "unique-attr-4" }
-attributes #5 = { "target-features"="+dead,,+beef" "unique-attr-5" }
attributes #6 = { "target-features"="+a,+b,+c" "unique-attr-6" }
attributes #7 = { "target-features" }
@@ -60,7 +54,6 @@ attributes #7 = { "target-features" }
; INTERESTING-DAG: [[$KEEP_FIRST_FROM_TWO]] = { "target-features"="{{.*}}+first
; INTERESTING-DAG: [[$KEEP_SECOND_FROM_TWO]] = { "target-features"="{{.*}}+second
; INTERESTING-DAG: [[$KEEP_ALL_OF_TWO]] = { "target-features"="{{.*}}+first,+second
-; INTERESTING-DAG: [[$DROP_EMPTY_ELEMENT]] = { "target-features"="{{.*}}+dead{{.*}}+beef
; INTERESTING-DAG: [[$KEEP_SECOND_FROM_THREE]] = { "target-features"="{{.*}}+b
@@ -68,5 +61,4 @@ attributes #7 = { "target-features" }
; RESULT-DAG: [[$KEEP_FIRST_FROM_TWO]] = { "target-features"="+first" "unique-attr-2" }
; RESULT-DAG: [[$KEEP_SECOND_FROM_TWO]] = { "target-features"="+second" "unique-attr-3" }
; RESULT-DAG: [[$KEEP_ALL_OF_TWO]] = { "target-features"="+first,+second" "unique-attr-4" }
-; RESULT-DAG: [[$DROP_EMPTY_ELEMENT]] = { "target-features"="+dead,+beef" "unique-attr-5" }
; RESULT-DAG: [[$KEEP_SECOND_FROM_THREE]] = { "target-features"="+b" "unique-attr-6" }
More information about the llvm-commits
mailing list