[llvm] [SPIR-V] Introduce support of llvm.ptr.annotation to SPIR-V Backend and implement extensions which make use of spirv.Decorations (PR #93479)
Vyacheslav Levytskyy via llvm-commits
llvm-commits at lists.llvm.org
Mon May 27 07:07:20 PDT 2024
https://github.com/VyacheslavLevytskyy created https://github.com/llvm/llvm-project/pull/93479
This PR introduces support of llvm.ptr.annotation to SPIR-V Backend, and implement several extensions which make use of spirv.Decorations and llvm.ptr.annotation to annotate global variables and pointers:
* SPV_INTEL_cache_controls
* SPV_INTEL_global_variable_host_access
* SPV_INTEL_global_variable_fpga_decorations
>From 98b6ef15b4ab122f5febbbee4ea475e4180d2471 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Thu, 23 May 2024 03:58:39 -0700
Subject: [PATCH 1/2] Update docs to describe support of SPV_KHR_shader_clock
---
llvm/docs/SPIRVUsage.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index d27177a4541a4..a0b3b3805044f 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -161,6 +161,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
- Allows to use the LinkOnceODR linkage type that lets a function or global variable to be merged with other functions or global variables of the same name when linkage occurs.
* - ``SPV_KHR_no_integer_wrap_decoration``
- Adds decorations to indicate that a given instruction does not cause integer wrapping.
+ * - ``SPV_KHR_shader_clock``
+ - Adds the extension cl_khr_kernel_clock that adds the ability for a kernel to sample the value from clocks provided by compute units.
* - ``SPV_KHR_subgroup_rotate``
- Adds a new instruction that enables rotating values across invocations within a subgroup.
* - ``SPV_KHR_uniform_group_instructions``
>From 301bd46b6656f27eb3742f61ecf16860a6e843c0 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Mon, 27 May 2024 07:02:28 -0700
Subject: [PATCH 2/2] Introduce support of llvm.ptr.annotation
---
llvm/docs/SPIRVUsage.rst | 6 +
llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp | 2 +
llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 6 +
.../Target/SPIRV/SPIRVPrepareFunctions.cpp | 133 ++++++++++++++++++
.../lib/Target/SPIRV/SPIRVSymbolicOperands.td | 12 ++
.../basic_load_store.ll | 53 +++++++
.../decorate-prefetch-w-cache-controls.ll | 44 ++++++
.../SPIRV/llvm-intrinsics/ptr-annotation.ll | 41 ++++++
8 files changed, 297 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/basic_load_store.ll
create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/decorate-prefetch-w-cache-controls.ll
create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/ptr-annotation.ll
diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index a0b3b3805044f..dfda184087c6f 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -141,8 +141,14 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
- Allows generating arbitrary width integer types.
* - ``SPV_INTEL_bfloat16_conversion``
- Adds instructions to convert between single-precision 32-bit floating-point values and 16-bit bfloat16 values.
+ * - ``SPV_INTEL_cache_controls``
+ - Allows cache control information to be applied to memory access instructions.
* - ``SPV_INTEL_function_pointers``
- Allows translation of function pointers.
+ * - ``SPV_INTEL_global_variable_host_access``
+ - Adds decorations that can be applied to global (module scope) variables.
+ * - ``SPV_INTEL_global_variable_fpga_decorations``
+ - Adds decorations that can be applied to global (module scope) variables to help code generation for FPGA devices.
* - ``SPV_INTEL_optnone``
- Adds OptNoneINTEL value for Function Control mask that indicates a request to not optimize the function.
* - ``SPV_INTEL_subgroups``
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index 691e6ee0e5829..65bb870ef0fdb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -30,6 +30,8 @@ static const std::map<std::string, SPIRV::Extension::Extension>
SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float_min_max},
{"SPV_INTEL_arbitrary_precision_integers",
SPIRV::Extension::Extension::SPV_INTEL_arbitrary_precision_integers},
+ {"SPV_INTEL_cache_controls",
+ SPIRV::Extension::Extension::SPV_INTEL_cache_controls},
{"SPV_INTEL_optnone", SPIRV::Extension::Extension::SPV_INTEL_optnone},
{"SPV_INTEL_usm_storage_classes",
SPIRV::Extension::Extension::SPV_INTEL_usm_storage_classes},
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 235f947901d83..2bf8bc4f41105 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -703,6 +703,12 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
if (LnkType == SPIRV::LinkageType::LinkOnceODR)
Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
+ } else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL || Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
+ Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
+ } else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
+ Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
+ } else if (Dec == SPIRV::Decoration::InitModeINTEL || Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
+ Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
}
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
index a8a0577f60564..7bee87d7204ed 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
@@ -22,6 +22,7 @@
#include "SPIRVSubtarget.h"
#include "SPIRVTargetMachine.h"
#include "SPIRVUtils.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -29,6 +30,8 @@
#include "llvm/IR/IntrinsicsSPIRV.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
+#include <charconv>
+#include <regex>
using namespace llvm;
@@ -152,6 +155,132 @@ static bool lowerIntrinsicToFunction(IntrinsicInst *Intrinsic) {
return true;
}
+static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal) {
+ if (auto *Ref = dyn_cast_or_null<GetElementPtrInst>(AnnoVal))
+ AnnoVal = Ref->getOperand(0);
+ if (auto *Ref = dyn_cast_or_null<BitCastInst>(OptAnnoVal))
+ OptAnnoVal = Ref->getOperand(0);
+
+ std::string Anno;
+ if (auto *C = dyn_cast_or_null<Constant>(AnnoVal)) {
+ StringRef Str;
+ if (getConstantStringInfo(C, Str))
+ Anno = Str;
+ }
+ // handle optional annotation parameter in a way that Khronos Translator do
+ // (collect integers wrapped in a struct)
+ if (auto *C = dyn_cast_or_null<Constant>(OptAnnoVal);
+ C && C->getNumOperands()) {
+ Value *MaybeStruct = C->getOperand(0);
+ if (auto *Struct = dyn_cast<ConstantStruct>(MaybeStruct)) {
+ for (unsigned I = 0, E = Struct->getNumOperands(); I != E; ++I) {
+ if (auto *CInt = dyn_cast<ConstantInt>(Struct->getOperand(I)))
+ Anno += (I == 0 ? ": " : ", ") +
+ std::to_string(CInt->getType()->getIntegerBitWidth() == 1
+ ? CInt->getZExtValue()
+ : CInt->getSExtValue());
+ }
+ } else if (auto *Struct = dyn_cast<ConstantAggregateZero>(MaybeStruct)) {
+ // { i32 i32 ... } zeroinitializer
+ for (unsigned I = 0, E = Struct->getType()->getStructNumElements();
+ I != E; ++I)
+ Anno += I == 0 ? ": 0" : ", 0";
+ }
+ }
+ return Anno;
+}
+
+static SmallVector<Metadata *> parseAnnotation(Value *I,
+ const std::string &Anno,
+ LLVMContext &Ctx,
+ Type *Int32Ty) {
+ // Try to parse the annotation string according to the following rules:
+ // annotation := ({kind} | {kind:value,value,...})+
+ // kind := number
+ // value := number | string
+ static const std::regex R(
+ "\\{(\\d+)(?:[:,](\\d+|\"[^\"]*\")(?:,(\\d+|\"[^\"]*\"))*)?\\}");
+ SmallVector<Metadata *> MDs;
+ int Pos = 0;
+ for (std::sregex_iterator
+ It = std::sregex_iterator(Anno.begin(), Anno.end(), R),
+ ItEnd = std::sregex_iterator();
+ It != ItEnd; ++It) {
+ if (It->position() != Pos)
+ return SmallVector<Metadata *>{};
+ Pos = It->position() + It->length();
+ std::smatch Match = *It;
+ SmallVector<Metadata *> MDsItem;
+ for (std::size_t i = 1; i < Match.size(); ++i) {
+ std::ssub_match SMatch = Match[i];
+ std::string Item = SMatch.str();
+ if (Item.length() == 0)
+ break;
+ if (Item[0] == '"') {
+ Item = Item.substr(1, Item.length() - 2);
+ // Acceptable format of the string snippet is:
+ static const std::regex RStr("^(\\d+)(?:,(\\d+))*$");
+ if (std::smatch MatchStr; std::regex_match(Item, MatchStr, RStr)) {
+ for (std::size_t SubIdx = 1; SubIdx < MatchStr.size(); ++SubIdx)
+ if (std::string SubStr = MatchStr[SubIdx].str(); SubStr.length())
+ MDsItem.push_back(ConstantAsMetadata::get(
+ ConstantInt::get(Int32Ty, std::stoi(SubStr))));
+ } else {
+ MDsItem.push_back(MDString::get(Ctx, Item));
+ }
+ } else if (int32_t Num;
+ std::from_chars(Item.data(), Item.data() + Item.size(), Num)
+ .ec == std::errc{}) {
+ MDsItem.push_back(
+ ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Num)));
+ } else {
+ MDsItem.push_back(MDString::get(Ctx, Item));
+ }
+ }
+ if (MDsItem.size() == 0)
+ return SmallVector<Metadata *>{};
+ MDs.push_back(MDNode::get(Ctx, MDsItem));
+ }
+ return Pos == static_cast<int>(Anno.length()) ? MDs
+ : SmallVector<Metadata *>{};
+}
+
+static void lowerPtrAnnotation(IntrinsicInst *II) {
+ LLVMContext &Ctx = II->getContext();
+ Type *Int32Ty = Type::getInt32Ty(Ctx);
+
+ // Retrieve an annotation string from arguments.
+ Value *PtrArg = nullptr;
+ if (auto *BI = dyn_cast<BitCastInst>(II->getArgOperand(0)))
+ PtrArg = BI->getOperand(0);
+ else
+ PtrArg = II->getOperand(0);
+ std::string Anno =
+ getAnnotation(II->getArgOperand(1),
+ 4 < II->arg_size() ? II->getArgOperand(4) : nullptr);
+
+ // Parse the annotation.
+ SmallVector<Metadata *> MDs = parseAnnotation(II, Anno, Ctx, Int32Ty);
+
+ // If the annotation string is not parsed successfully we don't know the
+ // format used and output it as a general UserSemantic decoration.
+ // Otherwise MDs is a Metadata tuple (a decoration list) in the format
+ // expected by `spirv.Decorations`.
+ if (MDs.size() == 0) {
+ auto UserSemantic = ConstantAsMetadata::get(ConstantInt::get(
+ Int32Ty, static_cast<uint32_t>(SPIRV::Decoration::UserSemantic)));
+ MDs.push_back(MDNode::get(Ctx, {UserSemantic, MDString::get(Ctx, Anno)}));
+ }
+
+ // Build the internal intrinsic function.
+ IRBuilder<> IRB(II->getParent());
+ IRB.SetInsertPoint(II);
+ IRB.CreateIntrinsic(
+ Intrinsic::spv_assign_decoration, {PtrArg->getType()},
+ {PtrArg, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
+ II->replaceAllUsesWith(II->getOperand(0));
+}
+
static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic) {
// Get a separate function - otherwise, we'd have to rework the CFG of the
// current one. Then simply replace the intrinsic uses with a call to the new
@@ -334,6 +463,10 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
Changed |= toSpvOverloadedIntrinsic(
II, Intrinsic::SPVIntrinsics::spv_lifetime_end, {1});
break;
+ case Intrinsic::ptr_annotation:
+ lowerPtrAnnotation(II);
+ Changed = true;
+ break;
}
}
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index 31e19ad8630cd..b60ea9f36be89 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -298,6 +298,9 @@ defm SPV_INTEL_optnone : ExtensionOperand<103>;
defm SPV_INTEL_function_pointers : ExtensionOperand<104>;
defm SPV_INTEL_variable_length_array : ExtensionOperand<105>;
defm SPV_INTEL_bfloat16_conversion : ExtensionOperand<106>;
+defm SPV_INTEL_cache_controls : ExtensionOperand<107>;
+defm SPV_INTEL_global_variable_host_access : ExtensionOperand<108>;
+defm SPV_INTEL_global_variable_fpga_decorations : ExtensionOperand<109>;
//===----------------------------------------------------------------------===//
// Multiclass used to define Capabilities enum values and at the same time
@@ -468,6 +471,10 @@ defm VariableLengthArrayINTEL : CapabilityOperand<5817, 0, 0, [SPV_INTEL_variabl
defm GroupUniformArithmeticKHR : CapabilityOperand<6400, 0, 0, [SPV_KHR_uniform_group_instructions], []>;
defm USMStorageClassesINTEL : CapabilityOperand<5935, 0, 0, [SPV_INTEL_usm_storage_classes], [Kernel]>;
defm BFloat16ConversionINTEL : CapabilityOperand<6115, 0, 0, [SPV_INTEL_bfloat16_conversion], []>;
+defm GlobalVariableHostAccessINTEL : CapabilityOperand<6187, 0, 0, [SPV_INTEL_global_variable_host_access], []>;
+defm HostAccessINTEL : CapabilityOperand<6188, 0, 0, [SPV_INTEL_global_variable_host_access], []>;
+defm GlobalVariableFPGADecorationsINTEL : CapabilityOperand<6189, 0, 0, [SPV_INTEL_global_variable_fpga_decorations], []>;
+defm CacheControlsINTEL : CapabilityOperand<6441, 0, 0, [SPV_INTEL_cache_controls], []>;
//===----------------------------------------------------------------------===//
// Multiclass used to define SourceLanguage enum values and at the same time
@@ -1201,6 +1208,11 @@ defm RestrictPointerEXT : DecorationOperand<5355, 0, 0, [], [PhysicalStorageBuff
defm AliasedPointerEXT : DecorationOperand<5356, 0, 0, [], [PhysicalStorageBufferAddressesEXT]>;
defm ReferencedIndirectlyINTEL : DecorationOperand<5602, 0, 0, [], [IndirectReferencesINTEL]>;
defm ArgumentAttributeINTEL : DecorationOperand<6409, 0, 0, [], [FunctionPointersINTEL]>;
+defm CacheControlLoadINTEL : DecorationOperand<6442, 0, 0, [], [CacheControlsINTEL]>;
+defm CacheControlStoreINTEL : DecorationOperand<6443, 0, 0, [], [CacheControlsINTEL]>;
+defm HostAccessINTEL : DecorationOperand<6188, 0, 0, [], [GlobalVariableHostAccessINTEL]>;
+defm InitModeINTEL : DecorationOperand<6190, 0, 0, [], [GlobalVariableFPGADecorationsINTEL]>;
+defm ImplementInRegisterMapINTEL : DecorationOperand<6191, 0, 0, [], [GlobalVariableFPGADecorationsINTEL]>;
//===----------------------------------------------------------------------===//
// Multiclass used to define BuiltIn enum values and at the same time
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/basic_load_store.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/basic_load_store.ll
new file mode 100644
index 0000000000000..359f6d1c0f8e5
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/basic_load_store.ll
@@ -0,0 +1,53 @@
+; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_cache_controls
+
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-SPIRV: Capability CacheControlsINTEL
+; CHECK-SPIRV: Extension "SPV_INTEL_cache_controls"
+; CHECK-SPIRV-DAG: OpName %[[#GVar:]] "G"
+; CHECK-SPIRV-DAG: OpName %[[#Arg:]] "buffer"
+; CHECK-SPIRV-DAG: OpDecorate %[[#GVar]] CacheControlStoreINTEL 0 1
+; CHECK-SPIRV-DAG: OpDecorate %[[#GVar]] CacheControlStoreINTEL 1 3
+; CHECK-SPIRV-DAG: OpDecorate %[[#Arg]] CacheControlLoadINTEL 0 0
+; CHECK-SPIRV-DAG: OpDecorate %[[#Arg]] CacheControlStoreINTEL 0 1
+; CHECK-SPIRV-DAG: OpDecorate %[[#LoadPtr:]] CacheControlLoadINTEL 0 1
+; CHECK-SPIRV-DAG: OpDecorate %[[#LoadPtr]] CacheControlLoadINTEL 1 1
+; CHECK-SPIRV-DAG: OpDecorate %[[#StorePtr:]] CacheControlStoreINTEL 0 1
+; CHECK-SPIRV-DAG: OpDecorate %[[#StorePtr]] CacheControlStoreINTEL 1 2
+; CHECK-SPIRV: OpLoad %[[#]] %[[#LoadPtr]]
+; CHECK-SPIRV: OpStore %[[#StorePtr]] %[[#]]
+
+ at G = common addrspace(1) global i32 0, align 4, !spirv.Decorations !9
+
+define spir_kernel void @test(ptr addrspace(1) %dummy, ptr addrspace(1) %buffer) !spirv.ParameterDecorations !12 {
+entry:
+ %arrayidx = getelementptr inbounds i32, ptr addrspace(1) %buffer, i64 1, !spirv.Decorations !3
+ %0 = load i32, ptr addrspace(1) %arrayidx, align 4
+ %arrayidx1 = getelementptr inbounds i32, ptr addrspace(1) %buffer, i64 0, !spirv.Decorations !6
+ store i32 %0, ptr addrspace(1) %arrayidx1, align 4
+ ret void
+}
+
+!spirv.MemoryModel = !{!0}
+!spirv.Source = !{!1}
+!opencl.spir.version = !{!2}
+!opencl.ocl.version = !{!2}
+
+!0 = !{i32 2, i32 2}
+!1 = !{i32 3, i32 102000}
+!2 = !{i32 1, i32 2}
+!3 = !{!4, !5}
+!4 = !{i32 6442, i32 0, i32 1} ; {CacheControlLoadINTEL, CacheLevel=0, Cached}
+!5 = !{i32 6442, i32 1, i32 1} ; {CacheControlLoadINTEL, CacheLevel=1, Cached}
+!6 = !{!7, !8}
+!7 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
+!8 = !{i32 6443, i32 1, i32 2} ; {CacheControlStoreINTEL, CacheLevel=1, WriteBack}
+!9 = !{!10, !11}
+!10 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
+!11 = !{i32 6443, i32 1, i32 3} ; {CacheControlStoreINTEL, CacheLevel=1, Streaming}
+!12 = !{!13, !14}
+!13 = !{}
+!14 = !{!15, !16}
+!15 = !{i32 6442, i32 0, i32 0} ; {CacheControlLoadINTEL, CacheLevel=0, Uncached}
+!16 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/decorate-prefetch-w-cache-controls.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/decorate-prefetch-w-cache-controls.ll
new file mode 100644
index 0000000000000..9a13b720f61f7
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_cache_controls/decorate-prefetch-w-cache-controls.ll
@@ -0,0 +1,44 @@
+; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_cache_controls
+
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-SPIRV: Capability CacheControlsINTEL
+; CHECK-SPIRV: Extension "SPV_INTEL_cache_controls"
+
+; CHECK-SPIRV-DAG: OpName %[[#Ptr1:]] "ptr1"
+; CHECK-SPIRV-DAG: OpName %[[#Ptr2:]] "ptr2"
+; CHECK-SPIRV-DAG: OpName %[[#Ptr3:]] "ptr3"
+; CHECK-SPIRV-DAG: OpDecorate %[[#Ptr1]] CacheControlLoadINTEL 0 1
+; CHECK-SPIRV-DAG: OpDecorate %[[#Ptr2]] CacheControlLoadINTEL 1 1
+; CHECK-SPIRV-DAG: OpDecorate %[[#Ptr3]] CacheControlStoreINTEL 2 3
+; CHECK-SPIRV: OpExtInst %[[#]] %[[#]] prefetch %[[#Ptr1]] %[[#]]
+; CHECK-SPIRV: OpExtInst %[[#]] %[[#]] prefetch %[[#Ptr2]] %[[#]]
+; CHECK-SPIRV: OpExtInst %[[#]] %[[#]] prefetch %[[#Ptr3]] %[[#]]
+
+; 6442 stands for CacheControlLoadINTEL token
+ at .str.1 = private unnamed_addr addrspace(1) constant [16 x i8] c"../prefetch.hpp\00", section "llvm.metadata"
+ at .str.9 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6442:\220,1\22}\00", section "llvm.metadata"
+ at .str.10 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6442:\221,1\22}\00", section "llvm.metadata"
+ at .str.11 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6443:\222,3\22}\00", section "llvm.metadata"
+
+define weak_odr dso_local spir_kernel void @foo(ptr addrspace(1) noundef align 1 %_arg_dataPtr) {
+entry:
+ %r0 = addrspacecast ptr addrspace(1) %_arg_dataPtr to ptr addrspace(4)
+ %ptr1 = tail call spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef %r0, i32 noundef 5)
+ %r1 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %ptr1, ptr addrspace(1) @.str.9, ptr addrspace(1) @.str.1, i32 76, ptr addrspace(1) null)
+ tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef %r1, i64 noundef 1)
+ %arrayidx3.i = getelementptr inbounds i8, ptr addrspace(4) %r0, i64 1
+ %ptr2 = tail call spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef %arrayidx3.i, i32 noundef 5)
+ %r2 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %ptr2, ptr addrspace(1) @.str.10, ptr addrspace(1) @.str.1, i32 80, ptr addrspace(1) null)
+ tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef %r2, i64 noundef 1)
+ %arrayidx7.i = getelementptr inbounds i8, ptr addrspace(4) %r0, i64 2
+ %ptr3 = tail call spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef %arrayidx7.i, i32 noundef 5)
+ %r3 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %ptr3, ptr addrspace(1) @.str.11, ptr addrspace(1) @.str.1, i32 80, ptr addrspace(1) null)
+ tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef %r3, i64 noundef 2)
+ ret void
+}
+
+declare ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1), ptr addrspace(1), ptr addrspace(1), i32, ptr addrspace(1))
+declare dso_local spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef, i64 noundef)
+declare dso_local spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef, i32 noundef)
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/ptr-annotation.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/ptr-annotation.ll
new file mode 100644
index 0000000000000..06f1d0bf7fd37
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/ptr-annotation.ll
@@ -0,0 +1,41 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: OpName %[[#Foo:]] "foo"
+; CHECK-DAG: OpName %[[#Ptr1:]] "_arg1"
+; CHECK-DAG: OpName %[[#Ptr2:]] "_arg2"
+; CHECK-DAG: OpName %[[#Ptr3:]] "_arg3"
+; CHECK-DAG: OpName %[[#Ptr4:]] "_arg4"
+; CHECK-DAG: OpName %[[#Ptr5:]] "_arg5"
+; CHECK-DAG: OpDecorate %[[#Ptr1]] NonReadable
+; CHECK-DAG: OpDecorate %[[#Ptr2]] Alignment 128
+; CHECK-DAG: OpDecorate %[[#Ptr2]] NonReadable
+; CHECK-DAG: OpDecorate %[[#Ptr3]] Alignment 128
+; CHECK-DAG: OpDecorate %[[#Ptr3]] NonReadable
+; CHECK-DAG: OpDecorate %[[#Ptr4]] Alignment 128
+; CHECK-DAG: OpDecorate %[[#Ptr4]] NonReadable
+; CHECK-DAG: OpDecorate %[[#Ptr5]] UserSemantic "Unknown format"
+; CHECK: %[[#Foo]] = OpFunction
+; CHECK-NEXT: %[[#Ptr1]] = OpFunctionParameter
+; CHECK-NEXT: %[[#Ptr2]] = OpFunctionParameter
+; CHECK-NEXT: %[[#Ptr3]] = OpFunctionParameter
+; CHECK-NEXT: %[[#Ptr4]] = OpFunctionParameter
+; CHECK-NEXT: %[[#Ptr5]] = OpFunctionParameter
+; CHECK: OpFunctionEnd
+
+ at .str.0 = private unnamed_addr addrspace(1) constant [16 x i8] c"../prefetch.hpp\00", section "llvm.metadata"
+ at .str.1 = private unnamed_addr addrspace(1) constant [5 x i8] c"{25}\00", section "llvm.metadata"
+ at .str.2 = private unnamed_addr addrspace(1) constant [13 x i8] c"{44:128}{25}\00", section "llvm.metadata"
+ at .str.3 = private unnamed_addr addrspace(1) constant [15 x i8] c"{44:\22128\22}{25}\00", section "llvm.metadata"
+ at .str.4 = private unnamed_addr addrspace(1) constant [13 x i8] c"{44,128}{25}\00", section "llvm.metadata"
+ at .str.5 = private unnamed_addr addrspace(1) constant [15 x i8] c"Unknown format\00", section "llvm.metadata"
+
+define spir_kernel void @foo(ptr addrspace(1) %_arg1, ptr addrspace(1) %_arg2, ptr addrspace(1) %_arg3, ptr addrspace(1) %_arg4, ptr addrspace(1) %_arg5) {
+entry:
+ %r1 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %_arg1, ptr addrspace(1) @.str.1, ptr addrspace(1) @.str.0, i32 80, ptr addrspace(1) null)
+ %r2 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %_arg2, ptr addrspace(1) @.str.2, ptr addrspace(1) @.str.0, i32 80, ptr addrspace(1) null)
+ %r3 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %_arg3, ptr addrspace(1) @.str.3, ptr addrspace(1) @.str.0, i32 80, ptr addrspace(1) null)
+ %r4 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %_arg4, ptr addrspace(1) @.str.4, ptr addrspace(1) @.str.0, i32 80, ptr addrspace(1) null)
+ %r5 = tail call ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1) %_arg5, ptr addrspace(1) @.str.5, ptr addrspace(1) @.str.0, i32 80, ptr addrspace(1) null)
+ ret void
+}
More information about the llvm-commits
mailing list