Skip to content

Commit d6102d5

Browse files
authored
Add support for split barriers extension SPV_INTEL_split_barrier (#333)
This backports KhronosGroup/SPIRV-LLVM-Translator#1424 Signed-off-by: Haonan Yang <[email protected]>
1 parent 4529a57 commit d6102d5

File tree

1 file changed

+374
-0
lines changed

1 file changed

+374
-0
lines changed
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
From 6c69a15cbdc37219cbb855652027536c9d1194c4 Mon Sep 17 00:00:00 2001
2+
From: Haonan Yang <[email protected]>
3+
Date: Mon, 28 Feb 2022 18:33:05 +0800
4+
Subject: [PATCH] Add support for split barriers extension
5+
SPV_INTEL_split_barrier
6+
7+
Signed-off-by: Haonan Yang <[email protected]>
8+
---
9+
include/LLVMSPIRVExtensions.inc | 1 +
10+
lib/SPIRV/OCL20ToSPIRV.cpp | 37 +++++++++++++++++++++++++++
11+
lib/SPIRV/OCLUtil.cpp | 23 ++++++++++++++++-
12+
lib/SPIRV/OCLUtil.h | 20 +++++++++++++++
13+
lib/SPIRV/SPIRVReader.cpp | 3 ++-
14+
lib/SPIRV/SPIRVToOCL.cpp | 4 +++
15+
lib/SPIRV/SPIRVToOCL.h | 5 ++++
16+
lib/SPIRV/SPIRVToOCL12.cpp | 17 ++++++++++++
17+
lib/SPIRV/SPIRVToOCL20.cpp | 26 +++++++++++++++++++
18+
lib/SPIRV/libSPIRV/SPIRVInstruction.h | 19 +++++++++++++-
19+
lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h | 1 +
20+
lib/SPIRV/libSPIRV/SPIRVOpCode.h | 5 ++++
21+
lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h | 2 ++
22+
13 files changed, 160 insertions(+), 3 deletions(-)
23+
24+
diff --git a/include/LLVMSPIRVExtensions.inc b/include/LLVMSPIRVExtensions.inc
25+
index a5acbffc..2f9866fe 100644
26+
--- a/include/LLVMSPIRVExtensions.inc
27+
+++ b/include/LLVMSPIRVExtensions.inc
28+
@@ -30,3 +30,4 @@ EXT(SPV_INTEL_optnone)
29+
EXT(SPV_INTEL_arbitrary_precision_integers)
30+
EXT(SPV_INTEL_variable_length_array)
31+
EXT(SPV_INTEL_memory_access_aliasing)
32+
+EXT(SPV_INTEL_split_barrier)
33+
diff --git a/lib/SPIRV/OCL20ToSPIRV.cpp b/lib/SPIRV/OCL20ToSPIRV.cpp
34+
index 4e7904a1..5755a152 100644
35+
--- a/lib/SPIRV/OCL20ToSPIRV.cpp
36+
+++ b/lib/SPIRV/OCL20ToSPIRV.cpp
37+
@@ -278,6 +278,8 @@ public:
38+
void visitSubgroupAVCBuiltinCallWithSampler(CallInst *CI,
39+
StringRef MangledName,
40+
const std::string &DemangledName);
41+
+ /// For cl_intel_split_work_group_barrier built-ins:
42+
+ void visitCallSplitBarrierINTEL(CallInst *CI, StringRef DemangledName);
43+
44+
void visitCallLdexp(CallInst *CI, StringRef MangledName,
45+
StringRef DemangledName);
46+
@@ -546,6 +548,10 @@ void OCL20ToSPIRV::visitCallInst(CallInst &CI) {
47+
visitSubgroupImageMediaBlockINTEL(&CI, DemangledName);
48+
return;
49+
}
50+
+ if (DemangledName.find(kOCLBuiltinName::SplitBarrierINTELPrefix) == 0) {
51+
+ visitCallSplitBarrierINTEL(&CI, DemangledName);
52+
+ return;
53+
+ }
54+
// Handle 'cl_intel_device_side_avc_motion_estimation' extension built-ins
55+
if (DemangledName.find(kOCLSubgroupsAVCIntel::Prefix) == 0 ||
56+
// Workaround for a bug in the extension specification
57+
@@ -1889,6 +1895,37 @@ void OCL20ToSPIRV::visitSubgroupAVCBuiltinCallWithSampler(
58+
&Attrs);
59+
}
60+
61+
+void OCL20ToSPIRV::visitCallSplitBarrierINTEL(CallInst *CI,
62+
+ StringRef DemangledName) {
63+
+ auto Lit = getBarrierLiterals(CI);
64+
+ AttributeList Attrs = CI->getCalledFunction()->getAttributes();
65+
+ Op OpCode =
66+
+ StringSwitch<Op>(DemangledName)
67+
+ .Case("intel_work_group_barrier_arrive", OpControlBarrierArriveINTEL)
68+
+ .Case("intel_work_group_barrier_wait", OpControlBarrierWaitINTEL)
69+
+ .Default(OpNop);
70+
+
71+
+ mutateCallInstSPIRV(
72+
+ M, CI,
73+
+ [=](CallInst *, std::vector<Value *> &Args) {
74+
+ Args.resize(3);
75+
+ // Execution scope
76+
+ Args[0] = addInt32(map<Scope>(std::get<2>(Lit)));
77+
+ // Memory scope
78+
+ Args[1] = addInt32(map<Scope>(std::get<1>(Lit)));
79+
+ // Memory semantics
80+
+ // OpControlBarrierArriveINTEL -> Release,
81+
+ // OpControlBarrierWaitINTEL -> Acquire
82+
+ unsigned MemFenceFlag = std::get<0>(Lit);
83+
+ OCLMemOrderKind MemOrder = OpCode == OpControlBarrierArriveINTEL
84+
+ ? OCLMO_release
85+
+ : OCLMO_acquire;
86+
+ Args[2] = addInt32(mapOCLMemSemanticToSPIRV(MemFenceFlag, MemOrder));
87+
+ return getSPIRVFuncName(OpCode);
88+
+ },
89+
+ &Attrs);
90+
+}
91+
+
92+
void OCL20ToSPIRV::visitCallLdexp(CallInst *CI, StringRef MangledName,
93+
StringRef DemangledName) {
94+
auto Args = getArguments(CI);
95+
diff --git a/lib/SPIRV/OCLUtil.cpp b/lib/SPIRV/OCLUtil.cpp
96+
index 5032925b..9da1d9cf 100644
97+
--- a/lib/SPIRV/OCLUtil.cpp
98+
+++ b/lib/SPIRV/OCLUtil.cpp
99+
@@ -472,7 +472,9 @@ public:
100+
} else if (UnmangledName.find("barrier") != std::string::npos) {
101+
addUnsignedArg(0);
102+
if (UnmangledName == "work_group_barrier" ||
103+
- UnmangledName == "sub_group_barrier")
104+
+ UnmangledName == "sub_group_barrier" ||
105+
+ UnmangledName == "intel_work_group_barrier_arrive" ||
106+
+ UnmangledName == "intel_work_group_barrier_wait")
107+
setEnumArg(1, SPIR::PRIMITIVE_MEMORY_SCOPE);
108+
} else if (UnmangledName.find("atomic_work_item_fence") == 0) {
109+
addUnsignedArg(0);
110+
@@ -986,6 +988,25 @@ void insertImageNameAccessQualifier(SPIRVAccessQualifierKind Acc,
111+
}
112+
} // namespace OCLUtil
113+
114+
+Value *SPIRV::transSPIRVMemorySemanticsIntoOCLMemFenceFlags(
115+
+ Value *MemorySemantics, Instruction *InsertBefore) {
116+
+ if (auto *C = dyn_cast<ConstantInt>(MemorySemantics)) {
117+
+ return ConstantInt::get(C->getType(),
118+
+ mapSPIRVMemSemanticToOCL(C->getZExtValue()).first);
119+
+ }
120+
+
121+
+ // TODO: any possible optimizations?
122+
+ // SPIR-V MemorySemantics contains both OCL mem_fence_flags and mem_order and
123+
+ // therefore, we need to apply mask
124+
+ int Mask = MemorySemanticsWorkgroupMemoryMask |
125+
+ MemorySemanticsCrossWorkgroupMemoryMask |
126+
+ MemorySemanticsImageMemoryMask;
127+
+ return getOrCreateSwitchFunc(kSPIRVName::TranslateSPIRVMemFence,
128+
+ MemorySemantics,
129+
+ OCLMemFenceExtendedMap::getRMap(),
130+
+ /* IsReverse */ true, None, InsertBefore, InsertBefore->getModule(), Mask);
131+
+}
132+
+
133+
void llvm::mangleOpenClBuiltin(const std::string &UniqName,
134+
ArrayRef<Type *> ArgTypes,
135+
std::string &MangledName) {
136+
diff --git a/lib/SPIRV/OCLUtil.h b/lib/SPIRV/OCLUtil.h
137+
index c8f20c4b..8f21a6f9 100644
138+
--- a/lib/SPIRV/OCLUtil.h
139+
+++ b/lib/SPIRV/OCLUtil.h
140+
@@ -238,6 +238,7 @@ const static char SubgroupBlockWriteINTELPrefix[] =
141+
"intel_sub_group_block_write";
142+
const static char SubgroupImageMediaBlockINTELPrefix[] =
143+
"intel_sub_group_media_block";
144+
+const static char SplitBarrierINTELPrefix[] = "intel_work_group_barrier_";
145+
const static char LDEXP[] = "ldexp";
146+
} // namespace kOCLBuiltinName
147+
148+
@@ -545,6 +546,22 @@ getOrCreateSwitchFunc(StringRef MapName, Value *V,
149+
return addCallInst(M, MapName, Ty, V, nullptr, InsertPoint);
150+
}
151+
152+
+/// Performs conversion from SPIR-V Memory Semantics into OpenCL
153+
+/// mem_fence_flags.
154+
+///
155+
+/// Supports both constant and non-constant values. To handle the latter case,
156+
+/// function with switch..case statement will be inserted into module which
157+
+/// \arg InsertBefore belongs to (in order to perform mapping at runtime)
158+
+///
159+
+/// \param [in] MemorySemantics Memory Semantics value which needs to be
160+
+/// translated
161+
+/// \param [in] InsertBefore insertion point for call into conversion function
162+
+/// which is generated if \arg MemorySemantics is not a constant
163+
+/// \returns \c Value corresponding to OpenCL mem_fence_flags equivalent to
164+
+/// SPIR-V Memory Semantics passed in \arg MemorySemantics
165+
+Value *transSPIRVMemorySemanticsIntoOCLMemFenceFlags(Value *MemorySemantics,
166+
+ Instruction *InsertBefore);
167+
+
168+
template <> inline void SPIRVMap<std::string, SPIRVGroupOperationKind>::init() {
169+
add("reduce", GroupOperationReduce);
170+
add("scan_inclusive", GroupOperationInclusiveScan);
171+
@@ -815,6 +832,9 @@ template <> inline void SPIRVMap<std::string, Op, SPIRVInstruction>::init() {
172+
// cl_khr_subgroup_shuffle_relative
173+
_SPIRV_OP(group_shuffle_up, GroupNonUniformShuffleUp)
174+
_SPIRV_OP(group_shuffle_down, GroupNonUniformShuffleDown)
175+
+ // cl_khr_split_work_group_barrier
176+
+ _SPIRV_OP(intel_work_group_barrier_arrive, ControlBarrierArriveINTEL)
177+
+ _SPIRV_OP(intel_work_group_barrier_wait, ControlBarrierWaitINTEL)
178+
#undef _SPIRV_OP
179+
}
180+
181+
diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp
182+
index 02f7e52d..8ed593f4 100644
183+
--- a/lib/SPIRV/SPIRVReader.cpp
184+
+++ b/lib/SPIRV/SPIRVReader.cpp
185+
@@ -2433,7 +2433,8 @@ Instruction *SPIRVToLLVM::transBuiltinFromInst(const std::string &FuncName,
186+
if (isFuncNoUnwind())
187+
Func->addFnAttr(Attribute::NoUnwind);
188+
auto OC = BI->getOpCode();
189+
- if (isGroupOpCode(OC) || isIntelSubgroupOpCode(OC))
190+
+ if (isGroupOpCode(OC) || isIntelSubgroupOpCode(OC) ||
191+
+ isSplitBarrierINTELOpCode(OC))
192+
Func->addFnAttr(Attribute::Convergent);
193+
}
194+
auto Call =
195+
diff --git a/lib/SPIRV/SPIRVToOCL.cpp b/lib/SPIRV/SPIRVToOCL.cpp
196+
index 3da14587..1edba730 100644
197+
--- a/lib/SPIRV/SPIRVToOCL.cpp
198+
+++ b/lib/SPIRV/SPIRVToOCL.cpp
199+
@@ -107,6 +107,10 @@ void SPIRVToOCL::visitCallInst(CallInst &CI) {
200+
if (OC == OpControlBarrier) {
201+
visitCallSPIRVControlBarrier(&CI);
202+
}
203+
+ if (isSplitBarrierINTELOpCode(OC)) {
204+
+ visitCallSPIRVSplitBarrierINTEL(&CI, OC);
205+
+ return;
206+
+ }
207+
if (isAtomicOpCode(OC)) {
208+
visitCallSPIRVAtomicBuiltin(&CI, OC);
209+
return;
210+
diff --git a/lib/SPIRV/SPIRVToOCL.h b/lib/SPIRV/SPIRVToOCL.h
211+
index 127e8dd8..3577496b 100644
212+
--- a/lib/SPIRV/SPIRVToOCL.h
213+
+++ b/lib/SPIRV/SPIRVToOCL.h
214+
@@ -211,6 +211,11 @@ public:
215+
/// - OCL1.2: barrier
216+
virtual void visitCallSPIRVControlBarrier(CallInst *CI) = 0;
217+
218+
+ /// Transform split __spirv_ControlBarrier barrier to:
219+
+ /// - OCL2.0: overload with a memory_scope argument
220+
+ /// - OCL1.2: overload with no memory_scope argument
221+
+ virtual void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) = 0;
222+
+
223+
/// Transform __spirv_EnqueueKernel to __enqueue_kernel
224+
virtual void visitCallSPIRVEnqueueKernel(CallInst *CI, Op OC) = 0;
225+
226+
diff --git a/lib/SPIRV/SPIRVToOCL12.cpp b/lib/SPIRV/SPIRVToOCL12.cpp
227+
index 2b8b2967..f8084901 100644
228+
--- a/lib/SPIRV/SPIRVToOCL12.cpp
229+
+++ b/lib/SPIRV/SPIRVToOCL12.cpp
230+
@@ -60,6 +60,10 @@ public:
231+
/// barrier(flag(sema))
232+
void visitCallSPIRVControlBarrier(CallInst *CI) override;
233+
234+
+ /// Transform split __spirv_ControlBarrier barrier to overloads without a
235+
+ /// memory_scope argument.
236+
+ void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) override;
237+
+
238+
/// Transform __spirv_OpAtomic functions. It firstly conduct generic
239+
/// mutations for all builtins and then mutate some of them seperately
240+
Instruction *visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) override;
241+
@@ -202,6 +206,19 @@ void SPIRVToOCL12::visitCallSPIRVControlBarrier(CallInst *CI) {
242+
&Attrs);
243+
}
244+
245+
+void SPIRVToOCL12::visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) {
246+
+ AttributeList Attrs = CI->getCalledFunction()->getAttributes();
247+
+ mutateCallInstOCL(
248+
+ M, CI,
249+
+ [=](CallInst *, std::vector<Value *> &Args) {
250+
+ Value *MemFenceFlags =
251+
+ SPIRV::transSPIRVMemorySemanticsIntoOCLMemFenceFlags(Args[2], CI);
252+
+ Args.assign(1, MemFenceFlags);
253+
+ return OCLSPIRVBuiltinMap::rmap(OC);
254+
+ },
255+
+ &Attrs);
256+
+}
257+
+
258+
Instruction *SPIRVToOCL12::visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) {
259+
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
260+
return mutateCallInstOCL(
261+
diff --git a/lib/SPIRV/SPIRVToOCL20.cpp b/lib/SPIRV/SPIRVToOCL20.cpp
262+
index 8f639488..6f0dae46 100644
263+
--- a/lib/SPIRV/SPIRVToOCL20.cpp
264+
+++ b/lib/SPIRV/SPIRVToOCL20.cpp
265+
@@ -63,6 +63,10 @@ public:
266+
/// sub_group_barrier(flag(sema), map(memScope))
267+
void visitCallSPIRVControlBarrier(CallInst *CI) override;
268+
269+
+ /// Transform split __spirv_ControlBarrier barrier to overloads with a
270+
+ /// memory_scope argument.
271+
+ void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) override;
272+
+
273+
/// Transform __spirv_Atomic* to atomic_*.
274+
/// __spirv_Atomic*(atomic_op, scope, sema, ops, ...) =>
275+
/// atomic_*(generic atomic_op, ops, ..., order(sema), map(scope))
276+
@@ -206,6 +210,28 @@ Instruction *SPIRVToOCL20::visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) {
277+
return NewCI;
278+
}
279+
280+
+void SPIRVToOCL20::visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) {
281+
+ AttributeList Attrs = CI->getCalledFunction()->getAttributes();
282+
+ mutateCallInstOCL(
283+
+ M, CI,
284+
+ [=](CallInst *, std::vector<Value *> &Args) {
285+
+ auto GetArg = [=](unsigned I) {
286+
+ return cast<ConstantInt>(Args[I])->getZExtValue();
287+
+ };
288+
+ Value *MemScope =
289+
+ getInt32(M, rmap<OCLScopeKind>(static_cast<Scope>(GetArg(1))));
290+
+ Value *MemFenceFlags =
291+
+ SPIRV::transSPIRVMemorySemanticsIntoOCLMemFenceFlags(Args[2], CI);
292+
+
293+
+ Args.resize(2);
294+
+ Args[0] = MemFenceFlags;
295+
+ Args[1] = MemScope;
296+
+
297+
+ return OCLSPIRVBuiltinMap::rmap(OC);
298+
+ },
299+
+ &Attrs);
300+
+}
301+
+
302+
Instruction *SPIRVToOCL20::visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) {
303+
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
304+
return mutateCallInstOCL(
305+
diff --git a/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/lib/SPIRV/libSPIRV/SPIRVInstruction.h
306+
index 85ac0120..9d1dbf6c 100644
307+
--- a/lib/SPIRV/libSPIRV/SPIRVInstruction.h
308+
+++ b/lib/SPIRV/libSPIRV/SPIRVInstruction.h
309+
@@ -3183,6 +3183,23 @@ _SPIRV_OP(VariableLengthArray, true, 4)
310+
_SPIRV_OP(SaveMemory, true, 3)
311+
_SPIRV_OP(RestoreMemory, false, 2)
312+
#undef _SPIRV_OP
313+
-} // namespace SPIRV
314+
315+
+class SPIRVSplitBarrierINTELBase : public SPIRVInstTemplateBase {
316+
+protected:
317+
+ SPIRVCapVec getRequiredCapability() const override {
318+
+ return getVec(CapabilitySplitBarrierINTEL);
319+
+ }
320+
+
321+
+ SPIRVExtSet getRequiredExtensions() const override {
322+
+ return getSet(ExtensionID::SPV_INTEL_split_barrier);
323+
+ }
324+
+};
325+
+
326+
+#define _SPIRV_OP(x, ...) \
327+
+ typedef SPIRVInstTemplate<SPIRVSplitBarrierINTELBase, Op##x, __VA_ARGS__> \
328+
+ SPIRV##x;
329+
+_SPIRV_OP(ControlBarrierArriveINTEL, false, 4)
330+
+_SPIRV_OP(ControlBarrierWaitINTEL, false, 4)
331+
+#undef _SPIRV_OP
332+
+} // namespace SPIRV
333+
#endif // SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H
334+
diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
335+
index ed9d944f..1cde296a 100644
336+
--- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
337+
+++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
338+
@@ -576,6 +576,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
339+
"ArbitraryPrecisionIntegersINTEL");
340+
add(internal::CapabilityMemoryAccessAliasingINTEL,
341+
"MemoryAccessAliasingINTEL");
342+
+ add(CapabilitySplitBarrierINTEL, "SplitBarrierINTEL");
343+
344+
}
345+
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)
346+
diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCode.h b/lib/SPIRV/libSPIRV/SPIRVOpCode.h
347+
index c0f2b650..2a4012db 100644
348+
--- a/lib/SPIRV/libSPIRV/SPIRVOpCode.h
349+
+++ b/lib/SPIRV/libSPIRV/SPIRVOpCode.h
350+
@@ -242,6 +242,11 @@ inline bool isEventOpCode(Op OpCode) {
351+
return OpRetainEvent <= OpCode && OpCode <= OpCaptureEventProfilingInfo;
352+
}
353+
354+
+inline bool isSplitBarrierINTELOpCode(Op OpCode) {
355+
+ return OpCode == OpControlBarrierArriveINTEL ||
356+
+ OpCode == OpControlBarrierWaitINTEL;
357+
+}
358+
+
359+
} // namespace SPIRV
360+
361+
#endif // SPIRV_LIBSPIRV_SPIRVOPCODE_H
362+
diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h
363+
index e568bee5..3c9fbb5f 100644
364+
--- a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h
365+
+++ b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h
366+
@@ -489,3 +489,5 @@ _SPIRV_OP(TypeBufferSurfaceINTEL, 6086)
367+
_SPIRV_OP(TypeStructContinuedINTEL, 6090)
368+
_SPIRV_OP(ConstantCompositeContinuedINTEL, 6091)
369+
_SPIRV_OP(SpecConstantCompositeContinuedINTEL, 6092)
370+
+_SPIRV_OP(ControlBarrierArriveINTEL, 6142)
371+
+_SPIRV_OP(ControlBarrierWaitINTEL, 6143)
372+
--
373+
2.18.1
374+

0 commit comments

Comments
 (0)