Skip to content

Commit b0174ab

Browse files
committed
Add support for split barriers extension SPV_INTEL_split_barrier
This backports KhronosGroup/SPIRV-LLVM-Translator#1424 Signed-off-by: haonanya <[email protected]>
1 parent e4d885d commit b0174ab

File tree

1 file changed

+326
-0
lines changed

1 file changed

+326
-0
lines changed
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
From c1cefd2c2b233132904b8f31ae7ca68965ecc431 Mon Sep 17 00:00:00 2001
2+
From: haonanya <[email protected]>
3+
Date: Mon, 28 Feb 2022 22:27:54 +0800
4+
Subject: [PATCH] Add support for split barriers extension
5+
SPV_INTEL_split_barrier
6+
7+
Signed-off-by: haonanya <[email protected]>
8+
---
9+
include/LLVMSPIRVExtensions.inc | 1 +
10+
lib/SPIRV/OCLToSPIRV.cpp | 38 +++++++++++++++++++++++++++
11+
lib/SPIRV/OCLUtil.cpp | 7 ++++-
12+
lib/SPIRV/OCLUtil.h | 1 +
13+
lib/SPIRV/SPIRVReader.cpp | 3 ++-
14+
lib/SPIRV/SPIRVToOCL.cpp | 4 +++
15+
lib/SPIRV/SPIRVToOCL.h | 13 +++++++++
16+
lib/SPIRV/SPIRVToOCL12.cpp | 13 +++++++++
17+
lib/SPIRV/SPIRVToOCL20.cpp | 22 ++++++++++++++++
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, 126 insertions(+), 3 deletions(-)
23+
24+
diff --git a/include/LLVMSPIRVExtensions.inc b/include/LLVMSPIRVExtensions.inc
25+
index 3faf76e2..47b5c268 100644
26+
--- a/include/LLVMSPIRVExtensions.inc
27+
+++ b/include/LLVMSPIRVExtensions.inc
28+
@@ -36,3 +36,4 @@ EXT(SPV_INTEL_variable_length_array)
29+
EXT(SPV_INTEL_fp_fast_math_mode)
30+
EXT(SPV_INTEL_optnone)
31+
EXT(SPV_INTEL_memory_access_aliasing)
32+
+EXT(SPV_INTEL_split_barrier)
33+
diff --git a/lib/SPIRV/OCLToSPIRV.cpp b/lib/SPIRV/OCLToSPIRV.cpp
34+
index 1a476fbf..71484429 100644
35+
--- a/lib/SPIRV/OCLToSPIRV.cpp
36+
+++ b/lib/SPIRV/OCLToSPIRV.cpp
37+
@@ -260,6 +260,9 @@ public:
38+
void visitSubgroupAVCBuiltinCallWithSampler(CallInst *CI,
39+
StringRef DemangledName);
40+
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+
47+
@@ -560,6 +563,10 @@ void OCLToSPIRVBase::visitCallInst(CallInst &CI) {
48+
visitSubgroupImageMediaBlockINTEL(&CI, DemangledName);
49+
return;
50+
}
51+
+ if (DemangledName.find(kOCLBuiltinName::SplitBarrierINTELPrefix) == 0) {
52+
+ visitCallSplitBarrierINTEL(&CI, DemangledName);
53+
+ return;
54+
+ }
55+
// Handle 'cl_intel_device_side_avc_motion_estimation' extension built-ins
56+
if (DemangledName.find(kOCLSubgroupsAVCIntel::Prefix) == 0 ||
57+
// Workaround for a bug in the extension specification
58+
@@ -1890,6 +1897,37 @@ void OCLToSPIRVBase::visitSubgroupAVCBuiltinCallWithSampler(
59+
&Attrs);
60+
}
61+
62+
+void OCLToSPIRVBase::visitCallSplitBarrierINTEL(CallInst *CI,
63+
+ StringRef DemangledName) {
64+
+ auto Lit = getBarrierLiterals(CI);
65+
+ AttributeList Attrs = CI->getCalledFunction()->getAttributes();
66+
+ Op OpCode =
67+
+ StringSwitch<Op>(DemangledName)
68+
+ .Case("intel_work_group_barrier_arrive", OpControlBarrierArriveINTEL)
69+
+ .Case("intel_work_group_barrier_wait", OpControlBarrierWaitINTEL)
70+
+ .Default(OpNop);
71+
+
72+
+ mutateCallInstSPIRV(
73+
+ M, CI,
74+
+ [=](CallInst *, std::vector<Value *> &Args) {
75+
+ Args.resize(3);
76+
+ // Execution scope
77+
+ Args[0] = addInt32(map<Scope>(std::get<2>(Lit)));
78+
+ // Memory scope
79+
+ Args[1] = addInt32(map<Scope>(std::get<1>(Lit)));
80+
+ // Memory semantics
81+
+ // OpControlBarrierArriveINTEL -> Release,
82+
+ // OpControlBarrierWaitINTEL -> Acquire
83+
+ unsigned MemFenceFlag = std::get<0>(Lit);
84+
+ OCLMemOrderKind MemOrder = OpCode == OpControlBarrierArriveINTEL
85+
+ ? OCLMO_release
86+
+ : OCLMO_acquire;
87+
+ Args[2] = addInt32(mapOCLMemSemanticToSPIRV(MemFenceFlag, MemOrder));
88+
+ return getSPIRVFuncName(OpCode);
89+
+ },
90+
+ &Attrs);
91+
+}
92+
+
93+
void OCLToSPIRVBase::visitCallLdexp(CallInst *CI, StringRef MangledName,
94+
StringRef DemangledName) {
95+
auto Args = getArguments(CI);
96+
diff --git a/lib/SPIRV/OCLUtil.cpp b/lib/SPIRV/OCLUtil.cpp
97+
index 35277022..01083173 100644
98+
--- a/lib/SPIRV/OCLUtil.cpp
99+
+++ b/lib/SPIRV/OCLUtil.cpp
100+
@@ -421,6 +421,9 @@ template <> void SPIRVMap<std::string, Op, SPIRVInstruction>::init() {
101+
_SPIRV_OP(bitfield_extract_signed, BitFieldSExtract)
102+
_SPIRV_OP(bitfield_extract_unsigned, BitFieldUExtract)
103+
_SPIRV_OP(bit_reverse, BitReverse)
104+
+ // cl_khr_split_work_group_barrier
105+
+ _SPIRV_OP(intel_work_group_barrier_arrive, ControlBarrierArriveINTEL)
106+
+ _SPIRV_OP(intel_work_group_barrier_wait, ControlBarrierWaitINTEL)
107+
#undef _SPIRV_OP
108+
}
109+
110+
@@ -1026,7 +1029,9 @@ public:
111+
} else if (NameRef.contains("barrier")) {
112+
addUnsignedArg(0);
113+
if (NameRef.equals("work_group_barrier") ||
114+
- NameRef.equals("sub_group_barrier"))
115+
+ NameRef.equals("sub_group_barrier") ||
116+
+ NameRef.equals("intel_work_group_barrier_arrive") ||
117+
+ NameRef.equals("intel_work_group_barrier_wait"))
118+
setEnumArg(1, SPIR::PRIMITIVE_MEMORY_SCOPE);
119+
} else if (NameRef.startswith("atomic_work_item_fence")) {
120+
addUnsignedArg(0);
121+
diff --git a/lib/SPIRV/OCLUtil.h b/lib/SPIRV/OCLUtil.h
122+
index 1d9e4f93..0f5c53ef 100644
123+
--- a/lib/SPIRV/OCLUtil.h
124+
+++ b/lib/SPIRV/OCLUtil.h
125+
@@ -304,6 +304,7 @@ const static char SubgroupBlockWriteINTELPrefix[] =
126+
"intel_sub_group_block_write";
127+
const static char SubgroupImageMediaBlockINTELPrefix[] =
128+
"intel_sub_group_media_block";
129+
+const static char SplitBarrierINTELPrefix[] = "intel_work_group_barrier_";
130+
const static char LDEXP[] = "ldexp";
131+
} // namespace kOCLBuiltinName
132+
133+
diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp
134+
index 6ef88cb8..51a3e563 100644
135+
--- a/lib/SPIRV/SPIRVReader.cpp
136+
+++ b/lib/SPIRV/SPIRVReader.cpp
137+
@@ -2877,7 +2877,8 @@ Instruction *SPIRVToLLVM::transBuiltinFromInst(const std::string &FuncName,
138+
if (isFuncNoUnwind())
139+
Func->addFnAttr(Attribute::NoUnwind);
140+
auto OC = BI->getOpCode();
141+
- if (isGroupOpCode(OC) || isIntelSubgroupOpCode(OC))
142+
+ if (isGroupOpCode(OC) || isIntelSubgroupOpCode(OC) ||
143+
+ isSplitBarrierINTELOpCode(OC))
144+
Func->addFnAttr(Attribute::Convergent);
145+
}
146+
auto Call =
147+
diff --git a/lib/SPIRV/SPIRVToOCL.cpp b/lib/SPIRV/SPIRVToOCL.cpp
148+
index 2e6b73f5..dafbfe0b 100644
149+
--- a/lib/SPIRV/SPIRVToOCL.cpp
150+
+++ b/lib/SPIRV/SPIRVToOCL.cpp
151+
@@ -107,6 +107,10 @@ void SPIRVToOCLBase::visitCallInst(CallInst &CI) {
152+
if (OC == OpControlBarrier) {
153+
visitCallSPIRVControlBarrier(&CI);
154+
}
155+
+ if (isSplitBarrierINTELOpCode(OC)) {
156+
+ visitCallSPIRVSplitBarrierINTEL(&CI, OC);
157+
+ return;
158+
+ }
159+
if (isAtomicOpCode(OC)) {
160+
visitCallSPIRVAtomicBuiltin(&CI, OC);
161+
return;
162+
diff --git a/lib/SPIRV/SPIRVToOCL.h b/lib/SPIRV/SPIRVToOCL.h
163+
index 380459fa..af64f645 100644
164+
--- a/lib/SPIRV/SPIRVToOCL.h
165+
+++ b/lib/SPIRV/SPIRVToOCL.h
166+
@@ -215,6 +215,11 @@ public:
167+
/// - OCL1.2: barrier
168+
virtual void visitCallSPIRVControlBarrier(CallInst *CI) = 0;
169+
170+
+ /// Transform split __spirv_ControlBarrier barrier to:
171+
+ /// - OCL2.0: overload with a memory_scope argument
172+
+ /// - OCL1.2: overload with no memory_scope argument
173+
+ virtual void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) = 0;
174+
+
175+
/// Transform __spirv_EnqueueKernel to __enqueue_kernel
176+
virtual void visitCallSPIRVEnqueueKernel(CallInst *CI, Op OC) = 0;
177+
178+
@@ -283,6 +288,10 @@ public:
179+
/// barrier(flag(sema))
180+
void visitCallSPIRVControlBarrier(CallInst *CI) override;
181+
182+
+ /// Transform split __spirv_ControlBarrier barrier to overloads without a
183+
+ /// memory_scope argument.
184+
+ void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) override;
185+
+
186+
/// Transform __spirv_OpAtomic functions. It firstly conduct generic
187+
/// mutations for all builtins and then mutate some of them seperately
188+
Instruction *visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) override;
189+
@@ -372,6 +381,10 @@ public:
190+
/// sub_group_barrier(flag(sema), map(memScope))
191+
void visitCallSPIRVControlBarrier(CallInst *CI) override;
192+
193+
+ /// Transform split __spirv_ControlBarrier barrier to overloads with a
194+
+ /// memory_scope argument.
195+
+ void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) override;
196+
+
197+
/// Transform __spirv_Atomic* to atomic_*.
198+
/// __spirv_Atomic*(atomic_op, scope, sema, ops, ...) =>
199+
/// atomic_*(generic atomic_op, ops, ..., order(sema), map(scope))
200+
diff --git a/lib/SPIRV/SPIRVToOCL12.cpp b/lib/SPIRV/SPIRVToOCL12.cpp
201+
index f34564b0..8f510d56 100644
202+
--- a/lib/SPIRV/SPIRVToOCL12.cpp
203+
+++ b/lib/SPIRV/SPIRVToOCL12.cpp
204+
@@ -102,6 +102,19 @@ void SPIRVToOCL12Base::visitCallSPIRVControlBarrier(CallInst *CI) {
205+
&Attrs);
206+
}
207+
208+
+void SPIRVToOCL12Base::visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) {
209+
+ AttributeList Attrs = CI->getCalledFunction()->getAttributes();
210+
+ mutateCallInstOCL(
211+
+ M, CI,
212+
+ [=](CallInst *, std::vector<Value *> &Args) {
213+
+ Value *MemFenceFlags =
214+
+ SPIRV::transSPIRVMemorySemanticsIntoOCLMemFenceFlags(Args[2], CI);
215+
+ Args.assign(1, MemFenceFlags);
216+
+ return OCLSPIRVBuiltinMap::rmap(OC);
217+
+ },
218+
+ &Attrs);
219+
+}
220+
+
221+
Instruction *SPIRVToOCL12Base::visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) {
222+
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
223+
return mutateCallInstOCL(
224+
diff --git a/lib/SPIRV/SPIRVToOCL20.cpp b/lib/SPIRV/SPIRVToOCL20.cpp
225+
index c9bb2829..3186c0ea 100644
226+
--- a/lib/SPIRV/SPIRVToOCL20.cpp
227+
+++ b/lib/SPIRV/SPIRVToOCL20.cpp
228+
@@ -121,6 +121,28 @@ void SPIRVToOCL20Base::visitCallSPIRVControlBarrier(CallInst *CI) {
229+
&Attrs);
230+
}
231+
232+
+void SPIRVToOCL20Base::visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) {
233+
+ AttributeList Attrs = CI->getCalledFunction()->getAttributes();
234+
+ mutateCallInstOCL(
235+
+ M, CI,
236+
+ [=](CallInst *, std::vector<Value *> &Args) {
237+
+ auto GetArg = [=](unsigned I) {
238+
+ return cast<ConstantInt>(Args[I])->getZExtValue();
239+
+ };
240+
+ Value *MemScope =
241+
+ getInt32(M, rmap<OCLScopeKind>(static_cast<Scope>(GetArg(1))));
242+
+ Value *MemFenceFlags =
243+
+ SPIRV::transSPIRVMemorySemanticsIntoOCLMemFenceFlags(Args[2], CI);
244+
+
245+
+ Args.resize(2);
246+
+ Args[0] = MemFenceFlags;
247+
+ Args[1] = MemScope;
248+
+
249+
+ return OCLSPIRVBuiltinMap::rmap(OC);
250+
+ },
251+
+ &Attrs);
252+
+}
253+
+
254+
std::string SPIRVToOCL20Base::mapFPAtomicName(Op OC) {
255+
assert(isFPAtomicOpCode(OC) && "Not intended to handle other opcodes than "
256+
"AtomicF{Add/Min/Max}EXT!");
257+
diff --git a/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/lib/SPIRV/libSPIRV/SPIRVInstruction.h
258+
index 2b4830c4..2e9bb5f6 100644
259+
--- a/lib/SPIRV/libSPIRV/SPIRVInstruction.h
260+
+++ b/lib/SPIRV/libSPIRV/SPIRVInstruction.h
261+
@@ -3177,6 +3177,23 @@ _SPIRV_OP(VariableLengthArray, true, 4)
262+
_SPIRV_OP(SaveMemory, true, 3)
263+
_SPIRV_OP(RestoreMemory, false, 2)
264+
#undef _SPIRV_OP
265+
-} // namespace SPIRV
266+
267+
+class SPIRVSplitBarrierINTELBase : public SPIRVInstTemplateBase {
268+
+protected:
269+
+ SPIRVCapVec getRequiredCapability() const override {
270+
+ return getVec(CapabilitySplitBarrierINTEL);
271+
+ }
272+
+
273+
+ llvm::Optional<ExtensionID> getRequiredExtension() const override {
274+
+ return ExtensionID::SPV_INTEL_split_barrier;
275+
+ }
276+
+};
277+
+
278+
+#define _SPIRV_OP(x, ...) \
279+
+ typedef SPIRVInstTemplate<SPIRVSplitBarrierINTELBase, Op##x, __VA_ARGS__> \
280+
+ SPIRV##x;
281+
+_SPIRV_OP(ControlBarrierArriveINTEL, false, 4)
282+
+_SPIRV_OP(ControlBarrierWaitINTEL, false, 4)
283+
+#undef _SPIRV_OP
284+
+} // namespace SPIRV
285+
#endif // SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H
286+
diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
287+
index 9d6f4070..b7a5f8b7 100644
288+
--- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
289+
+++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
290+
@@ -565,6 +565,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
291+
add(internal::CapabilityOptNoneINTEL, "OptNoneINTEL");
292+
add(internal::CapabilityMemoryAccessAliasingINTEL,
293+
"MemoryAccessAliasingINTEL");
294+
+ add(CapabilitySplitBarrierINTEL, "SplitBarrierINTEL");
295+
296+
add(CapabilityMax, "Max");
297+
}
298+
diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCode.h b/lib/SPIRV/libSPIRV/SPIRVOpCode.h
299+
index f400f87e..18b446be 100644
300+
--- a/lib/SPIRV/libSPIRV/SPIRVOpCode.h
301+
+++ b/lib/SPIRV/libSPIRV/SPIRVOpCode.h
302+
@@ -243,6 +243,11 @@ inline bool isEventOpCode(Op OpCode) {
303+
return OpRetainEvent <= OpCode && OpCode <= OpCaptureEventProfilingInfo;
304+
}
305+
306+
+inline bool isSplitBarrierINTELOpCode(Op OpCode) {
307+
+ return OpCode == OpControlBarrierArriveINTEL ||
308+
+ OpCode == OpControlBarrierWaitINTEL;
309+
+}
310+
+
311+
} // namespace SPIRV
312+
313+
#endif // SPIRV_LIBSPIRV_SPIRVOPCODE_H
314+
diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h
315+
index 3e841009..aa282e3e 100644
316+
--- a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h
317+
+++ b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h
318+
@@ -540,3 +540,5 @@ _SPIRV_OP(WritePipeBlockingINTEL, 5947)
319+
_SPIRV_OP(FPGARegINTEL, 5949)
320+
_SPIRV_OP(AtomicFAddEXT, 6035)
321+
_SPIRV_OP(TypeBufferSurfaceINTEL, 6086)
322+
+_SPIRV_OP(ControlBarrierArriveINTEL, 6142)
323+
+_SPIRV_OP(ControlBarrierWaitINTEL, 6143)
324+
--
325+
2.17.1
326+

0 commit comments

Comments
 (0)