From 3ff79b508202b47fb3cc6fa51197e0b9348deeeb Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Tue, 4 Nov 2025 02:01:10 +0000 Subject: [PATCH 1/5] Add support for handling unknown intrinsics. --- .../Target/SPIRV/SPIRVPrepareFunctions.cpp | 21 ++++++++++ .../CodeGen/SPIRV/allow_unknown_intrinsics.ll | 38 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp index 4e4e6fb4ab791..3334bb18deab9 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp @@ -56,6 +56,13 @@ class SPIRVPrepareFunctions : public ModulePass { } }; +static cl::list SPVAllowUnknownIntrinsics( + "spv-allow-unknown-intrinsics", cl::CommaSeparated, + cl::desc("Emit unknown intrinsics as calls to external functions. If a " + "comma-separated input list of intrinsic prefixes is provided, " + "only intrinsics carrying a listed prefix get emitted. Otherwise, " + "all unknown intrinsics are emitted"), + cl::value_desc("intrinsic_prefix_0,intrinsic_prefix_1"), cl::ValueOptional); } // namespace char SPIRVPrepareFunctions::ID = 0; @@ -445,6 +452,20 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { EraseFromParent); Changed = true; break; + default: + if (TM.getTargetTriple().getVendor() == Triple::AMD || + any_of(SPVAllowUnknownIntrinsics, [II](auto &&Prefix) { + return II->getCalledFunction()->getName().starts_with(Prefix); + })) + Changed |= lowerIntrinsicToFunction(II); + else + report_fatal_error( + "Encountered unknown intrinsic: " + + II->getCalledFunction()->getName() + + ", which requires the --spv-allow-unknown-intrinsics option, " + "in function: " + II->getParent()->getParent()->getName(), + false); + break; } } } diff --git a/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll new file mode 100644 index 0000000000000..872c4a68a8160 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll @@ -0,0 +1,38 @@ +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=notllvm %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.some.custom %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.readcyclecounter %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR1 %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm. %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.,random.prefix %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %} + +; The test checks command-line option which allows to represent unknown +; intrinsics as external function calls in SPIR-V. + +; CHECK-ERROR: LLVM ERROR: Encountered unknown intrinsic: llvm.readcyclecounter, which requires the --spv-allow-unknown-intrinsics option, in function: foo +; CHECK-ERROR1: LLVM ERROR: Encountered unknown intrinsic: llvm.some.custom.intrinsic, which requires the --spv-allow-unknown-intrinsics option, in function: foo + +; CHECK: Name %[[READCYCLECOUNTER:[0-9]+]] "spirv.llvm_readcyclecounter" +; CHECK: Name %[[SOME_CUSTOM_INTRINSIC:[0-9]+]] "spirv.llvm_some_custom_intrinsic" +; CHECK-DAG: Decorate %[[READCYCLECOUNTER]] LinkageAttributes {{.*}} Import +; CHECK: Decorate %[[SOME_CUSTOM_INTRINSIC]] LinkageAttributes {{.*}} Import +; CHECK-DAG: %[[I64:[0-9]+]] = OpTypeInt 64 +; CHECK: %[[FnTy:[0-9]+]] = OpTypeFunction %[[I64]] +; CHECK: %[[READCYCLECOUNTER]] = OpFunction %[[I64]] {{.*}} %[[FnTy]] +; CHECK-DAG: %[[SOME_CUSTOM_INTRINSIC]] = OpFunction %[[I64]] {{.*}} %[[FnTy]] +; CHECK-DAG: OpFunctionCall %[[I64]] %[[READCYCLECOUNTER]] +; CHECK: OpFunctionCall %[[I64]] %[[SOME_CUSTOM_INTRINSIC]] + +define spir_func void @foo() { +entry: + %0 = call i64 @llvm.readcyclecounter() + %1 = call i64 @llvm.some.custom.intrinsic() + ret void +} + +declare i64 @llvm.readcyclecounter() +declare i64 @llvm.some.custom.intrinsic() From a06986e8b2a352a589f24f2a21a62eff2d9e17c7 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Tue, 4 Nov 2025 02:56:02 +0000 Subject: [PATCH 2/5] Fix formatting. --- llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp index 3334bb18deab9..1e16b82396ba2 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp @@ -461,9 +461,10 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { else report_fatal_error( "Encountered unknown intrinsic: " + - II->getCalledFunction()->getName() + - ", which requires the --spv-allow-unknown-intrinsics option, " - "in function: " + II->getParent()->getParent()->getName(), + II->getCalledFunction()->getName() + + ", which requires the --spv-allow-unknown-intrinsics option, " + "in function: " + + II->getParent()->getParent()->getName(), false); break; } From 893974678bbc67ceb481db79dba377983f1aa763 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Tue, 4 Nov 2025 03:17:42 +0000 Subject: [PATCH 3/5] Fix breakage, we cannot error out so aggressively. --- llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp | 8 -------- llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll | 4 +--- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp index 1e16b82396ba2..804cfb6b17490 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp @@ -458,14 +458,6 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { return II->getCalledFunction()->getName().starts_with(Prefix); })) Changed |= lowerIntrinsicToFunction(II); - else - report_fatal_error( - "Encountered unknown intrinsic: " + - II->getCalledFunction()->getName() + - ", which requires the --spv-allow-unknown-intrinsics option, " - "in function: " + - II->getParent()->getParent()->getName(), - false); break; } } diff --git a/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll index 872c4a68a8160..c7af93e8fd0fd 100644 --- a/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll +++ b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll @@ -1,7 +1,6 @@ ; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s ; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=notllvm %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s ; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.some.custom %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s -; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.readcyclecounter %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR1 %s ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics %s -o - | FileCheck %s ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm. %s -o - | FileCheck %s ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.,random.prefix %s -o - | FileCheck %s @@ -13,8 +12,7 @@ ; The test checks command-line option which allows to represent unknown ; intrinsics as external function calls in SPIR-V. -; CHECK-ERROR: LLVM ERROR: Encountered unknown intrinsic: llvm.readcyclecounter, which requires the --spv-allow-unknown-intrinsics option, in function: foo -; CHECK-ERROR1: LLVM ERROR: Encountered unknown intrinsic: llvm.some.custom.intrinsic, which requires the --spv-allow-unknown-intrinsics option, in function: foo +; CHECK-ERROR: LLVM ERROR: unable to legalize instruction: %3:iid(s64) = G_READCYCLECOUNTER (in function: foo) ; CHECK: Name %[[READCYCLECOUNTER:[0-9]+]] "spirv.llvm_readcyclecounter" ; CHECK: Name %[[SOME_CUSTOM_INTRINSIC:[0-9]+]] "spirv.llvm_some_custom_intrinsic" From a71afc4f1102ac163340f31492d47dc710e13657 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Tue, 4 Nov 2025 14:52:30 +0000 Subject: [PATCH 4/5] Implement review suggestion. --- llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp | 10 ++++++---- llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll | 5 ++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp index 804cfb6b17490..be88f334d2171 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp @@ -58,10 +58,10 @@ class SPIRVPrepareFunctions : public ModulePass { static cl::list SPVAllowUnknownIntrinsics( "spv-allow-unknown-intrinsics", cl::CommaSeparated, - cl::desc("Emit unknown intrinsics as calls to external functions. If a " - "comma-separated input list of intrinsic prefixes is provided, " - "only intrinsics carrying a listed prefix get emitted. Otherwise, " - "all unknown intrinsics are emitted"), + cl::desc("Emit unknown intrinsics as calls to external functions. A " + "comma-separated input list of intrinsic prefixes must be " + "provided, and only intrinsics carrying a listed prefix get " + "emitted as described."), cl::value_desc("intrinsic_prefix_0,intrinsic_prefix_1"), cl::ValueOptional); } // namespace @@ -455,6 +455,8 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { default: if (TM.getTargetTriple().getVendor() == Triple::AMD || any_of(SPVAllowUnknownIntrinsics, [II](auto &&Prefix) { + if (Prefix.empty()) + return false; return II->getCalledFunction()->getName().starts_with(Prefix); })) Changed |= lowerIntrinsicToFunction(II); diff --git a/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll index c7af93e8fd0fd..843fd4ae469f8 100644 --- a/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll +++ b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll @@ -1,12 +1,11 @@ ; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics %s -o %t.spvt 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s ; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=notllvm %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s ; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.some.custom %s -o %t.spvt 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s -; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics %s -o - | FileCheck %s ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm. %s -o - | FileCheck %s ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm.,random.prefix %s -o - | FileCheck %s -; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm %s -o - | FileCheck %s ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-amd-amdhsa %s -o - | FileCheck %s -; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spv-allow-unknown-intrinsics=llvm. %s -o - -filetype=obj | spirv-val %} ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-amd-amdhsa %s -o - -filetype=obj | spirv-val %} ; The test checks command-line option which allows to represent unknown From af079fd822e1d792b684656e4c4e5541f9b4fc2c Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Wed, 5 Nov 2025 19:33:13 +0000 Subject: [PATCH 5/5] Add comment about having needing an unsupported intrinsic in the test. --- llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll index 843fd4ae469f8..677291a322900 100644 --- a/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll +++ b/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll @@ -26,6 +26,7 @@ define spir_func void @foo() { entry: +; TODO: if and when the SPIR-V learns how to lower readcyclecounter, we will have to pick another unhandled intrinsic %0 = call i64 @llvm.readcyclecounter() %1 = call i64 @llvm.some.custom.intrinsic() ret void