Skip to content

Commit f63adf3

Browse files
[SPIR-V] Introduce support of llvm.ptr.annotation to SPIR-V Backend and implement extensions which make use of spirv.Decorations (#93561)
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
1 parent 7fa45af commit f63adf3

File tree

11 files changed

+379
-0
lines changed

11 files changed

+379
-0
lines changed

llvm/docs/SPIRVUsage.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,16 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
141141
- Allows generating arbitrary width integer types.
142142
* - ``SPV_INTEL_bfloat16_conversion``
143143
- Adds instructions to convert between single-precision 32-bit floating-point values and 16-bit bfloat16 values.
144+
* - ``SPV_INTEL_cache_controls``
145+
- Allows cache control information to be applied to memory access instructions.
144146
* - ``SPV_INTEL_function_pointers``
145147
- Allows translation of function pointers.
146148
* - ``SPV_INTEL_inline_assembly``
147149
- Allows to use inline assembly.
150+
* - ``SPV_INTEL_global_variable_host_access``
151+
- Adds decorations that can be applied to global (module scope) variables.
152+
* - ``SPV_INTEL_global_variable_fpga_decorations``
153+
- Adds decorations that can be applied to global (module scope) variables to help code generation for FPGA devices.
148154
* - ``SPV_INTEL_optnone``
149155
- Adds OptNoneINTEL value for Function Control mask that indicates a request to not optimize the function.
150156
* - ``SPV_INTEL_subgroups``

llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,13 @@ void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) {
272272
case Decoration::UserSemantic:
273273
printStringImm(MI, NumFixedOps, O);
274274
break;
275+
case Decoration::HostAccessINTEL:
276+
printOperand(MI, NumFixedOps, O);
277+
if (NumFixedOps + 1 < MI->getNumOperands()) {
278+
O << ' ';
279+
printStringImm(MI, NumFixedOps + 1, O);
280+
}
281+
break;
275282
default:
276283
printRemainingVariableOps(MI, NumFixedOps, O, true);
277284
break;

llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ static const std::map<std::string, SPIRV::Extension::Extension>
3030
SPIRV::Extension::Extension::SPV_EXT_shader_atomic_float_min_max},
3131
{"SPV_INTEL_arbitrary_precision_integers",
3232
SPIRV::Extension::Extension::SPV_INTEL_arbitrary_precision_integers},
33+
{"SPV_INTEL_cache_controls",
34+
SPIRV::Extension::Extension::SPV_INTEL_cache_controls},
35+
{"SPV_INTEL_global_variable_fpga_decorations",
36+
SPIRV::Extension::Extension::
37+
SPV_INTEL_global_variable_fpga_decorations},
38+
{"SPV_INTEL_global_variable_host_access",
39+
SPIRV::Extension::Extension::SPV_INTEL_global_variable_host_access},
3340
{"SPV_INTEL_optnone", SPIRV::Extension::Extension::SPV_INTEL_optnone},
3441
{"SPV_INTEL_usm_storage_classes",
3542
SPIRV::Extension::Extension::SPV_INTEL_usm_storage_classes},

llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,15 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
703703
static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
704704
if (LnkType == SPIRV::LinkageType::LinkOnceODR)
705705
Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
706+
} else if (Dec == SPIRV::Decoration::CacheControlLoadINTEL ||
707+
Dec == SPIRV::Decoration::CacheControlStoreINTEL) {
708+
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_cache_controls);
709+
} else if (Dec == SPIRV::Decoration::HostAccessINTEL) {
710+
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_global_variable_host_access);
711+
} else if (Dec == SPIRV::Decoration::InitModeINTEL ||
712+
Dec == SPIRV::Decoration::ImplementInRegisterMapINTEL) {
713+
Reqs.addExtension(
714+
SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations);
706715
}
707716
}
708717

llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@
2222
#include "SPIRVSubtarget.h"
2323
#include "SPIRVTargetMachine.h"
2424
#include "SPIRVUtils.h"
25+
#include "llvm/Analysis/ValueTracking.h"
2526
#include "llvm/CodeGen/IntrinsicLowering.h"
2627
#include "llvm/IR/IRBuilder.h"
2728
#include "llvm/IR/IntrinsicInst.h"
2829
#include "llvm/IR/Intrinsics.h"
2930
#include "llvm/IR/IntrinsicsSPIRV.h"
3031
#include "llvm/Transforms/Utils/Cloning.h"
3132
#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
33+
#include <charconv>
34+
#include <regex>
3235

3336
using namespace llvm;
3437

@@ -152,6 +155,132 @@ static bool lowerIntrinsicToFunction(IntrinsicInst *Intrinsic) {
152155
return true;
153156
}
154157

158+
static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal) {
159+
if (auto *Ref = dyn_cast_or_null<GetElementPtrInst>(AnnoVal))
160+
AnnoVal = Ref->getOperand(0);
161+
if (auto *Ref = dyn_cast_or_null<BitCastInst>(OptAnnoVal))
162+
OptAnnoVal = Ref->getOperand(0);
163+
164+
std::string Anno;
165+
if (auto *C = dyn_cast_or_null<Constant>(AnnoVal)) {
166+
StringRef Str;
167+
if (getConstantStringInfo(C, Str))
168+
Anno = Str;
169+
}
170+
// handle optional annotation parameter in a way that Khronos Translator do
171+
// (collect integers wrapped in a struct)
172+
if (auto *C = dyn_cast_or_null<Constant>(OptAnnoVal);
173+
C && C->getNumOperands()) {
174+
Value *MaybeStruct = C->getOperand(0);
175+
if (auto *Struct = dyn_cast<ConstantStruct>(MaybeStruct)) {
176+
for (unsigned I = 0, E = Struct->getNumOperands(); I != E; ++I) {
177+
if (auto *CInt = dyn_cast<ConstantInt>(Struct->getOperand(I)))
178+
Anno += (I == 0 ? ": " : ", ") +
179+
std::to_string(CInt->getType()->getIntegerBitWidth() == 1
180+
? CInt->getZExtValue()
181+
: CInt->getSExtValue());
182+
}
183+
} else if (auto *Struct = dyn_cast<ConstantAggregateZero>(MaybeStruct)) {
184+
// { i32 i32 ... } zeroinitializer
185+
for (unsigned I = 0, E = Struct->getType()->getStructNumElements();
186+
I != E; ++I)
187+
Anno += I == 0 ? ": 0" : ", 0";
188+
}
189+
}
190+
return Anno;
191+
}
192+
193+
static SmallVector<Metadata *> parseAnnotation(Value *I,
194+
const std::string &Anno,
195+
LLVMContext &Ctx,
196+
Type *Int32Ty) {
197+
// Try to parse the annotation string according to the following rules:
198+
// annotation := ({kind} | {kind:value,value,...})+
199+
// kind := number
200+
// value := number | string
201+
static const std::regex R(
202+
"\\{(\\d+)(?:[:,](\\d+|\"[^\"]*\")(?:,(\\d+|\"[^\"]*\"))*)?\\}");
203+
SmallVector<Metadata *> MDs;
204+
int Pos = 0;
205+
for (std::sregex_iterator
206+
It = std::sregex_iterator(Anno.begin(), Anno.end(), R),
207+
ItEnd = std::sregex_iterator();
208+
It != ItEnd; ++It) {
209+
if (It->position() != Pos)
210+
return SmallVector<Metadata *>{};
211+
Pos = It->position() + It->length();
212+
std::smatch Match = *It;
213+
SmallVector<Metadata *> MDsItem;
214+
for (std::size_t i = 1; i < Match.size(); ++i) {
215+
std::ssub_match SMatch = Match[i];
216+
std::string Item = SMatch.str();
217+
if (Item.length() == 0)
218+
break;
219+
if (Item[0] == '"') {
220+
Item = Item.substr(1, Item.length() - 2);
221+
// Acceptable format of the string snippet is:
222+
static const std::regex RStr("^(\\d+)(?:,(\\d+))*$");
223+
if (std::smatch MatchStr; std::regex_match(Item, MatchStr, RStr)) {
224+
for (std::size_t SubIdx = 1; SubIdx < MatchStr.size(); ++SubIdx)
225+
if (std::string SubStr = MatchStr[SubIdx].str(); SubStr.length())
226+
MDsItem.push_back(ConstantAsMetadata::get(
227+
ConstantInt::get(Int32Ty, std::stoi(SubStr))));
228+
} else {
229+
MDsItem.push_back(MDString::get(Ctx, Item));
230+
}
231+
} else if (int32_t Num;
232+
std::from_chars(Item.data(), Item.data() + Item.size(), Num)
233+
.ec == std::errc{}) {
234+
MDsItem.push_back(
235+
ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Num)));
236+
} else {
237+
MDsItem.push_back(MDString::get(Ctx, Item));
238+
}
239+
}
240+
if (MDsItem.size() == 0)
241+
return SmallVector<Metadata *>{};
242+
MDs.push_back(MDNode::get(Ctx, MDsItem));
243+
}
244+
return Pos == static_cast<int>(Anno.length()) ? MDs
245+
: SmallVector<Metadata *>{};
246+
}
247+
248+
static void lowerPtrAnnotation(IntrinsicInst *II) {
249+
LLVMContext &Ctx = II->getContext();
250+
Type *Int32Ty = Type::getInt32Ty(Ctx);
251+
252+
// Retrieve an annotation string from arguments.
253+
Value *PtrArg = nullptr;
254+
if (auto *BI = dyn_cast<BitCastInst>(II->getArgOperand(0)))
255+
PtrArg = BI->getOperand(0);
256+
else
257+
PtrArg = II->getOperand(0);
258+
std::string Anno =
259+
getAnnotation(II->getArgOperand(1),
260+
4 < II->arg_size() ? II->getArgOperand(4) : nullptr);
261+
262+
// Parse the annotation.
263+
SmallVector<Metadata *> MDs = parseAnnotation(II, Anno, Ctx, Int32Ty);
264+
265+
// If the annotation string is not parsed successfully we don't know the
266+
// format used and output it as a general UserSemantic decoration.
267+
// Otherwise MDs is a Metadata tuple (a decoration list) in the format
268+
// expected by `spirv.Decorations`.
269+
if (MDs.size() == 0) {
270+
auto UserSemantic = ConstantAsMetadata::get(ConstantInt::get(
271+
Int32Ty, static_cast<uint32_t>(SPIRV::Decoration::UserSemantic)));
272+
MDs.push_back(MDNode::get(Ctx, {UserSemantic, MDString::get(Ctx, Anno)}));
273+
}
274+
275+
// Build the internal intrinsic function.
276+
IRBuilder<> IRB(II->getParent());
277+
IRB.SetInsertPoint(II);
278+
IRB.CreateIntrinsic(
279+
Intrinsic::spv_assign_decoration, {PtrArg->getType()},
280+
{PtrArg, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
281+
II->replaceAllUsesWith(II->getOperand(0));
282+
}
283+
155284
static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic) {
156285
// Get a separate function - otherwise, we'd have to rework the CFG of the
157286
// current one. Then simply replace the intrinsic uses with a call to the new
@@ -334,6 +463,10 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
334463
Changed |= toSpvOverloadedIntrinsic(
335464
II, Intrinsic::SPVIntrinsics::spv_lifetime_end, {1});
336465
break;
466+
case Intrinsic::ptr_annotation:
467+
lowerPtrAnnotation(II);
468+
Changed = true;
469+
break;
337470
}
338471
}
339472
}

llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ defm SPV_INTEL_function_pointers : ExtensionOperand<104>;
299299
defm SPV_INTEL_variable_length_array : ExtensionOperand<105>;
300300
defm SPV_INTEL_bfloat16_conversion : ExtensionOperand<106>;
301301
defm SPV_INTEL_inline_assembly : ExtensionOperand<107>;
302+
defm SPV_INTEL_cache_controls : ExtensionOperand<108>;
303+
defm SPV_INTEL_global_variable_host_access : ExtensionOperand<109>;
304+
defm SPV_INTEL_global_variable_fpga_decorations : ExtensionOperand<110>;
302305

303306
//===----------------------------------------------------------------------===//
304307
// Multiclass used to define Capabilities enum values and at the same time
@@ -471,6 +474,10 @@ defm VariableLengthArrayINTEL : CapabilityOperand<5817, 0, 0, [SPV_INTEL_variabl
471474
defm GroupUniformArithmeticKHR : CapabilityOperand<6400, 0, 0, [SPV_KHR_uniform_group_instructions], []>;
472475
defm USMStorageClassesINTEL : CapabilityOperand<5935, 0, 0, [SPV_INTEL_usm_storage_classes], [Kernel]>;
473476
defm BFloat16ConversionINTEL : CapabilityOperand<6115, 0, 0, [SPV_INTEL_bfloat16_conversion], []>;
477+
defm GlobalVariableHostAccessINTEL : CapabilityOperand<6187, 0, 0, [SPV_INTEL_global_variable_host_access], []>;
478+
defm HostAccessINTEL : CapabilityOperand<6188, 0, 0, [SPV_INTEL_global_variable_host_access], []>;
479+
defm GlobalVariableFPGADecorationsINTEL : CapabilityOperand<6189, 0, 0, [SPV_INTEL_global_variable_fpga_decorations], []>;
480+
defm CacheControlsINTEL : CapabilityOperand<6441, 0, 0, [SPV_INTEL_cache_controls], []>;
474481

475482
//===----------------------------------------------------------------------===//
476483
// Multiclass used to define SourceLanguage enum values and at the same time
@@ -1206,6 +1213,11 @@ defm ReferencedIndirectlyINTEL : DecorationOperand<5602, 0, 0, [], [IndirectRefe
12061213
defm ClobberINTEL : DecorationOperand<5607, 0, 0, [SPV_INTEL_inline_assembly], [AsmINTEL]>;
12071214
defm SideEffectsINTEL : DecorationOperand<5608, 0, 0, [SPV_INTEL_inline_assembly], [AsmINTEL]>;
12081215
defm ArgumentAttributeINTEL : DecorationOperand<6409, 0, 0, [], [FunctionPointersINTEL]>;
1216+
defm CacheControlLoadINTEL : DecorationOperand<6442, 0, 0, [], [CacheControlsINTEL]>;
1217+
defm CacheControlStoreINTEL : DecorationOperand<6443, 0, 0, [], [CacheControlsINTEL]>;
1218+
defm HostAccessINTEL : DecorationOperand<6188, 0, 0, [], [GlobalVariableHostAccessINTEL]>;
1219+
defm InitModeINTEL : DecorationOperand<6190, 0, 0, [], [GlobalVariableFPGADecorationsINTEL]>;
1220+
defm ImplementInRegisterMapINTEL : DecorationOperand<6191, 0, 0, [], [GlobalVariableFPGADecorationsINTEL]>;
12091221

12101222
//===----------------------------------------------------------------------===//
12111223
// Multiclass used to define BuiltIn enum values and at the same time
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_cache_controls
2+
3+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV
4+
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - -filetype=obj | spirv-val %}
5+
6+
; CHECK-SPIRV: Capability CacheControlsINTEL
7+
; CHECK-SPIRV: Extension "SPV_INTEL_cache_controls"
8+
; CHECK-SPIRV-DAG: OpName %[[#GVar:]] "G"
9+
; CHECK-SPIRV-DAG: OpName %[[#Arg:]] "buffer"
10+
; CHECK-SPIRV-DAG: OpDecorate %[[#GVar]] CacheControlStoreINTEL 0 1
11+
; CHECK-SPIRV-DAG: OpDecorate %[[#GVar]] CacheControlStoreINTEL 1 3
12+
; CHECK-SPIRV-DAG: OpDecorate %[[#Arg]] CacheControlLoadINTEL 0 0
13+
; CHECK-SPIRV-DAG: OpDecorate %[[#Arg]] CacheControlStoreINTEL 0 1
14+
; CHECK-SPIRV-DAG: OpDecorate %[[#LoadPtr:]] CacheControlLoadINTEL 0 1
15+
; CHECK-SPIRV-DAG: OpDecorate %[[#LoadPtr]] CacheControlLoadINTEL 1 1
16+
; CHECK-SPIRV-DAG: OpDecorate %[[#StorePtr:]] CacheControlStoreINTEL 0 1
17+
; CHECK-SPIRV-DAG: OpDecorate %[[#StorePtr]] CacheControlStoreINTEL 1 2
18+
; CHECK-SPIRV: OpLoad %[[#]] %[[#LoadPtr]]
19+
; CHECK-SPIRV: OpStore %[[#StorePtr]] %[[#]]
20+
21+
@G = common addrspace(1) global i32 0, align 4, !spirv.Decorations !9
22+
23+
define spir_kernel void @test(ptr addrspace(1) %dummy, ptr addrspace(1) %buffer) !spirv.ParameterDecorations !12 {
24+
entry:
25+
%arrayidx = getelementptr inbounds i32, ptr addrspace(1) %buffer, i64 1, !spirv.Decorations !3
26+
%0 = load i32, ptr addrspace(1) %arrayidx, align 4
27+
%arrayidx1 = getelementptr inbounds i32, ptr addrspace(1) %buffer, i64 0, !spirv.Decorations !6
28+
store i32 %0, ptr addrspace(1) %arrayidx1, align 4
29+
ret void
30+
}
31+
32+
!spirv.MemoryModel = !{!0}
33+
!spirv.Source = !{!1}
34+
!opencl.spir.version = !{!2}
35+
!opencl.ocl.version = !{!2}
36+
37+
!0 = !{i32 2, i32 2}
38+
!1 = !{i32 3, i32 102000}
39+
!2 = !{i32 1, i32 2}
40+
!3 = !{!4, !5}
41+
!4 = !{i32 6442, i32 0, i32 1} ; {CacheControlLoadINTEL, CacheLevel=0, Cached}
42+
!5 = !{i32 6442, i32 1, i32 1} ; {CacheControlLoadINTEL, CacheLevel=1, Cached}
43+
!6 = !{!7, !8}
44+
!7 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
45+
!8 = !{i32 6443, i32 1, i32 2} ; {CacheControlStoreINTEL, CacheLevel=1, WriteBack}
46+
!9 = !{!10, !11}
47+
!10 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
48+
!11 = !{i32 6443, i32 1, i32 3} ; {CacheControlStoreINTEL, CacheLevel=1, Streaming}
49+
!12 = !{!13, !14}
50+
!13 = !{}
51+
!14 = !{!15, !16}
52+
!15 = !{i32 6442, i32 0, i32 0} ; {CacheControlLoadINTEL, CacheLevel=0, Uncached}
53+
!16 = !{i32 6443, i32 0, i32 1} ; {CacheControlStoreINTEL, CacheLevel=0, WriteThrough}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_cache_controls
2+
3+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV
4+
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_cache_controls %s -o - -filetype=obj | spirv-val %}
5+
6+
; CHECK-SPIRV: Capability CacheControlsINTEL
7+
; CHECK-SPIRV: Extension "SPV_INTEL_cache_controls"
8+
9+
; CHECK-SPIRV-DAG: OpName %[[#Ptr1:]] "ptr1"
10+
; CHECK-SPIRV-DAG: OpName %[[#Ptr2:]] "ptr2"
11+
; CHECK-SPIRV-DAG: OpName %[[#Ptr3:]] "ptr3"
12+
; CHECK-SPIRV-DAG: OpDecorate %[[#Ptr1]] CacheControlLoadINTEL 0 1
13+
; CHECK-SPIRV-DAG: OpDecorate %[[#Ptr2]] CacheControlLoadINTEL 1 1
14+
; CHECK-SPIRV-DAG: OpDecorate %[[#Ptr3]] CacheControlStoreINTEL 2 3
15+
; CHECK-SPIRV: OpExtInst %[[#]] %[[#]] prefetch %[[#Ptr1]] %[[#]]
16+
; CHECK-SPIRV: OpExtInst %[[#]] %[[#]] prefetch %[[#Ptr2]] %[[#]]
17+
; CHECK-SPIRV: OpExtInst %[[#]] %[[#]] prefetch %[[#Ptr3]] %[[#]]
18+
19+
; 6442 stands for CacheControlLoadINTEL token
20+
@.str.1 = private unnamed_addr addrspace(1) constant [16 x i8] c"../prefetch.hpp\00", section "llvm.metadata"
21+
@.str.9 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6442:\220,1\22}\00", section "llvm.metadata"
22+
@.str.10 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6442:\221,1\22}\00", section "llvm.metadata"
23+
@.str.11 = private unnamed_addr addrspace(1) constant [13 x i8] c"{6443:\222,3\22}\00", section "llvm.metadata"
24+
25+
define weak_odr dso_local spir_kernel void @foo(ptr addrspace(1) noundef align 1 %_arg_dataPtr) {
26+
entry:
27+
%r0 = addrspacecast ptr addrspace(1) %_arg_dataPtr to ptr addrspace(4)
28+
%ptr1 = tail call spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef %r0, i32 noundef 5)
29+
%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)
30+
tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef %r1, i64 noundef 1)
31+
%arrayidx3.i = getelementptr inbounds i8, ptr addrspace(4) %r0, i64 1
32+
%ptr2 = tail call spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef %arrayidx3.i, i32 noundef 5)
33+
%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)
34+
tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef %r2, i64 noundef 1)
35+
%arrayidx7.i = getelementptr inbounds i8, ptr addrspace(4) %r0, i64 2
36+
%ptr3 = tail call spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef %arrayidx7.i, i32 noundef 5)
37+
%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)
38+
tail call spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef %r3, i64 noundef 2)
39+
ret void
40+
}
41+
42+
declare ptr addrspace(1) @llvm.ptr.annotation.p1.p1(ptr addrspace(1), ptr addrspace(1), ptr addrspace(1), i32, ptr addrspace(1))
43+
declare dso_local spir_func void @_Z20__spirv_ocl_prefetchPU3AS1Kcm(ptr addrspace(1) noundef, i64 noundef)
44+
declare dso_local spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef, i32 noundef)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
; Adapted from https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/main/test/extensions/INTEL/SPV_INTEL_global_variable_fpga_decorations
2+
3+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_global_variable_fpga_decorations %s -o - | FileCheck %s --check-prefixes=CHECK-SPIRV
4+
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_global_variable_fpga_decorations %s -o - -filetype=obj | spirv-val %}
5+
6+
; CHECK-SPIRV: Capability GlobalVariableFPGADecorationsINTEL
7+
; CHECK-SPIRV: Extension "SPV_INTEL_global_variable_fpga_decorations"
8+
; CHECK-SPIRV-DAG: OpName %[[#G1:]] "int_var"
9+
; CHECK-SPIRV-DAG: OpName %[[#G2:]] "float_var"
10+
; CHECK-SPIRV-DAG: OpName %[[#G3:]] "bool_var"
11+
; CHECK-SPIRV-DAG: OpDecorate %[[#G1]] ImplementInRegisterMapINTEL 1
12+
; CHECK-SPIRV-DAG: OpDecorate %[[#G1]] InitModeINTEL 0
13+
; CHECK-SPIRV-DAG: OpDecorate %[[#G2]] ImplementInRegisterMapINTEL 1
14+
; CHECK-SPIRV-DAG: OpDecorate %[[#G2]] InitModeINTEL 1
15+
; CHECK-SPIRV-DAG: OpDecorate %[[#G3]] ImplementInRegisterMapINTEL 0
16+
; CHECK-SPIRV-DAG: OpDecorate %[[#G3]] InitModeINTEL 0
17+
18+
@int_var = addrspace(1) global i32 42, !spirv.Decorations !1
19+
@float_var = addrspace(1) global float 1.0, !spirv.Decorations !5
20+
@bool_var = addrspace(1) global i1 0, !spirv.Decorations !7
21+
22+
define spir_kernel void @test() {
23+
entry:
24+
ret void
25+
}
26+
27+
!1 = !{!2, !3}
28+
!2 = !{i32 6191, i1 true} ; ImplementInRegisterMapINTEL = true
29+
!3 = !{i32 6190, i32 0} ; InitModeINTEL = 0
30+
!4 = !{i32 6190, i32 1} ; InitModeINTEL = 1
31+
!5 = !{!2, !4}
32+
!6 = !{i32 6191, i1 false} ; ImplementInRegisterMapINTEL = false
33+
!7 = !{!6, !3}

0 commit comments

Comments
 (0)