Skip to content

Commit f6625d4

Browse files
haonanya1stanleygambarin
authored andcommitted
[Backport to 8] Add support for split barriers extension SPV_INTEL_split_barrier
This backports KhronosGroup#1424 This PR adds support for split barriers and the SPV_INTEL_split_barrier extension. The related SPIR-V extension spec can be found here: * KhronosGroup/SPIRV-Registry#136 The related OpenCL C extension spec can be found here: * KhronosGroup/OpenCL-Docs#765
1 parent f5bc1ff commit f6625d4

19 files changed

+582
-4
lines changed

include/LLVMSPIRVExtensions.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ EXT(SPV_INTEL_bfloat16_conversion)
1818
EXT(SPV_INTEL_tensor_float32_conversion)
1919
EXT(SPV_INTEL_hw_thread_queries)
2020
EXT(SPV_EXT_relaxed_printf_string_address_space)
21+
EXT(SPV_INTEL_split_barrier)

lib/SPIRV/OCL20ToSPIRV.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ class OCL20ToSPIRV : public ModulePass, public InstVisitor<OCL20ToSPIRV> {
279279
StringRef MangledName,
280280
const std::string &DemangledName);
281281

282+
/// For cl_intel_split_work_group_barrier built-ins:
283+
void visitCallSplitBarrierINTEL(CallInst *CI, StringRef DemangledName);
284+
282285
static char ID;
283286

284287
private:
@@ -544,6 +547,10 @@ void OCL20ToSPIRV::visitCallInst(CallInst &CI) {
544547
visitSubgroupImageMediaBlockINTEL(&CI, DemangledName);
545548
return;
546549
}
550+
if (DemangledName.find(kOCLBuiltinName::SplitBarrierINTELPrefix) == 0) {
551+
visitCallSplitBarrierINTEL(&CI, DemangledName);
552+
return;
553+
}
547554
// Handle 'cl_intel_device_side_avc_motion_estimation' extension built-ins
548555
if (DemangledName.find(kOCLSubgroupsAVCIntel::Prefix) == 0 ||
549556
// Workaround for a bug in the extension specification
@@ -1846,6 +1853,37 @@ void OCL20ToSPIRV::visitSubgroupAVCBuiltinCallWithSampler(
18461853
&Attrs);
18471854
}
18481855

1856+
void OCL20ToSPIRV::visitCallSplitBarrierINTEL(CallInst *CI,
1857+
StringRef DemangledName) {
1858+
auto Lit = getBarrierLiterals(CI);
1859+
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
1860+
Op OpCode =
1861+
StringSwitch<Op>(DemangledName)
1862+
.Case("intel_work_group_barrier_arrive", OpControlBarrierArriveINTEL)
1863+
.Case("intel_work_group_barrier_wait", OpControlBarrierWaitINTEL)
1864+
.Default(OpNop);
1865+
1866+
mutateCallInstSPIRV(
1867+
M, CI,
1868+
[=](CallInst *, std::vector<Value *> &Args) {
1869+
Args.resize(3);
1870+
// Execution scope
1871+
Args[0] = addInt32(map<Scope>(std::get<2>(Lit)));
1872+
// Memory scope
1873+
Args[1] = addInt32(map<Scope>(std::get<1>(Lit)));
1874+
// Memory semantics
1875+
// OpControlBarrierArriveINTEL -> Release,
1876+
// OpControlBarrierWaitINTEL -> Acquire
1877+
unsigned MemFenceFlag = std::get<0>(Lit);
1878+
OCLMemOrderKind MemOrder = OpCode == OpControlBarrierArriveINTEL
1879+
? OCLMO_release
1880+
: OCLMO_acquire;
1881+
Args[2] = addInt32(mapOCLMemSemanticToSPIRV(MemFenceFlag, MemOrder));
1882+
return getSPIRVFuncName(OpCode);
1883+
},
1884+
&Attrs);
1885+
}
1886+
18491887
} // namespace SPIRV
18501888

18511889
INITIALIZE_PASS_BEGIN(OCL20ToSPIRV, "cl20tospv", "Transform OCL 2.0 to SPIR-V",

lib/SPIRV/OCLUtil.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,9 @@ class OCLBuiltinFuncMangleInfo : public SPIRV::BuiltinFuncMangleInfo {
479479
} else if (UnmangledName.find("barrier") != std::string::npos) {
480480
addUnsignedArg(0);
481481
if (UnmangledName == "work_group_barrier" ||
482-
UnmangledName == "sub_group_barrier")
482+
UnmangledName == "sub_group_barrier" ||
483+
UnmangledName == "intel_work_group_barrier_arrive" ||
484+
UnmangledName == "intel_work_group_barrier_wait")
483485
setEnumArg(1, SPIR::PRIMITIVE_MEMORY_SCOPE);
484486
} else if (UnmangledName.find("atomic_work_item_fence") == 0) {
485487
addUnsignedArg(0);

lib/SPIRV/OCLUtil.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ const static char SubgroupBlockWriteINTELPrefix[] =
235235
"intel_sub_group_block_write";
236236
const static char SubgroupImageMediaBlockINTELPrefix[] =
237237
"intel_sub_group_media_block";
238+
const static char SplitBarrierINTELPrefix[] = "intel_work_group_barrier_";
238239
} // namespace kOCLBuiltinName
239240

240241
/// Offset for OpenCL image channel order enumeration values.
@@ -886,6 +887,9 @@ template <> inline void SPIRVMap<std::string, Op, SPIRVInstruction>::init() {
886887
// cl_khr_subgroup_shuffle_relative
887888
_SPIRV_OP(group_shuffle_up, GroupNonUniformShuffleUp)
888889
_SPIRV_OP(group_shuffle_down, GroupNonUniformShuffleDown)
890+
// cl_khr_split_work_group_barrier
891+
_SPIRV_OP(intel_work_group_barrier_arrive, ControlBarrierArriveINTEL)
892+
_SPIRV_OP(intel_work_group_barrier_wait, ControlBarrierWaitINTEL)
889893
#undef _SPIRV_OP
890894
}
891895

lib/SPIRV/SPIRVReader.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,6 +2261,10 @@ Instruction *SPIRVToLLVM::transBuiltinFromInst(const std::string &FuncName,
22612261
Func->setCallingConv(CallingConv::SPIR_FUNC);
22622262
if (isFuncNoUnwind())
22632263
Func->addFnAttr(Attribute::NoUnwind);
2264+
auto OC = BI->getOpCode();
2265+
if (isGroupOpCode(OC) || isIntelSubgroupOpCode(OC) ||
2266+
isSplitBarrierINTELOpCode(OC) || OC == OpControlBarrier)
2267+
Func->addFnAttr(Attribute::Convergent);
22642268
}
22652269
auto Call =
22662270
CallInst::Create(Func, transValue(Ops, BB->getParent(), BB), "", BB);

lib/SPIRV/SPIRVToOCL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ void SPIRVToOCL::visitCallInst(CallInst &CI) {
123123
if (OC == OpControlBarrier) {
124124
visitCallSPIRVControlBarrier(&CI);
125125
}
126+
if (isSplitBarrierINTELOpCode(OC)) {
127+
visitCallSPIRVSplitBarrierINTEL(&CI, OC);
128+
return;
129+
}
126130
if (isAtomicOpCode(OC)) {
127131
visitCallSPIRVAtomicBuiltin(&CI, OC);
128132
return;

lib/SPIRV/SPIRVToOCL.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ class SPIRVToOCL : public ModulePass, public InstVisitor<SPIRVToOCL> {
152152
/// - OCL1.2: barrier
153153
virtual void visitCallSPIRVControlBarrier(CallInst *CI) = 0;
154154

155+
/// Transform split __spirv_ControlBarrier barrier to:
156+
/// - OCL2.0: overload with a memory_scope argument
157+
/// - OCL1.2: overload with no memory_scope argument
158+
virtual void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) = 0;
159+
155160
/// Conduct generic mutations for all atomic builtins
156161
virtual CallInst *mutateCommonAtomicArguments(CallInst *CI, Op OC) = 0;
157162

lib/SPIRV/SPIRVToOCL12.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ class SPIRVToOCL12 : public SPIRVToOCL {
6060
/// barrier(flag(sema))
6161
void visitCallSPIRVControlBarrier(CallInst *CI) override;
6262

63+
/// Transform split __spirv_ControlBarrier barrier to overloads without a
64+
/// memory_scope argument.
65+
void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) override;
66+
6367
/// Transform __spirv_OpAtomic functions. It firstly conduct generic
6468
/// mutations for all builtins and then mutate some of them seperately
6569
Instruction *visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) override;
@@ -154,6 +158,19 @@ void SPIRVToOCL12::visitCallSPIRVControlBarrier(CallInst *CI) {
154158
&Attrs);
155159
}
156160

161+
void SPIRVToOCL12::visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) {
162+
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
163+
mutateCallInstOCL(
164+
M, CI,
165+
[=](CallInst *, std::vector<Value *> &Args) {
166+
Value *MemFenceFlags =
167+
SPIRV::transSPIRVMemorySemanticsIntoOCLMemFenceFlags(Args[2], CI);
168+
Args.assign(1, MemFenceFlags);
169+
return OCLSPIRVBuiltinMap::rmap(OC);
170+
},
171+
&Attrs);
172+
}
173+
157174
Instruction *SPIRVToOCL12::visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) {
158175
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
159176
return mutateCallInstOCL(

lib/SPIRV/SPIRVToOCL20.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ class SPIRVToOCL20 : public SPIRVToOCL {
6464
/// sub_group_barrier(flag(sema), map(memScope))
6565
void visitCallSPIRVControlBarrier(CallInst *CI) override;
6666

67+
/// Transform split __spirv_ControlBarrier barrier to overloads without a
68+
/// memory_scope argument.
69+
void visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) override;
70+
6771
/// Transform __spirv_Atomic* to atomic_*.
6872
/// __spirv_Atomic*(atomic_op, scope, sema, ops, ...) =>
6973
/// atomic_*(generic atomic_op, ops, ..., order(sema), map(scope))
@@ -152,6 +156,28 @@ void SPIRVToOCL20::visitCallSPIRVControlBarrier(CallInst *CI) {
152156
&Attrs);
153157
}
154158

159+
void SPIRVToOCL20::visitCallSPIRVSplitBarrierINTEL(CallInst *CI, Op OC) {
160+
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
161+
mutateCallInstOCL(
162+
M, CI,
163+
[=](CallInst *, std::vector<Value *> &Args) {
164+
auto GetArg = [=](unsigned I) {
165+
return cast<ConstantInt>(Args[I])->getZExtValue();
166+
};
167+
Value *MemScope =
168+
getInt32(M, rmap<OCLScopeKind>(static_cast<Scope>(GetArg(1))));
169+
Value *MemFenceFlags =
170+
SPIRV::transSPIRVMemorySemanticsIntoOCLMemFenceFlags(Args[2], CI);
171+
172+
Args.resize(2);
173+
Args[0] = MemFenceFlags;
174+
Args[1] = MemScope;
175+
176+
return OCLSPIRVBuiltinMap::rmap(OC);
177+
},
178+
&Attrs);
179+
}
180+
155181
Instruction *SPIRVToOCL20::mutateAtomicName(CallInst *CI, Op OC) {
156182
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
157183
return mutateCallInstOCL(

lib/SPIRV/libSPIRV/SPIRVInstruction.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2819,6 +2819,23 @@ class SPIRVTensorFloat32ConversionINTELInstBase : public SPIRVUnaryInst<OC> {
28192819
typedef SPIRVTensorFloat32ConversionINTELInstBase<Op##x> SPIRV##x;
28202820
_SPIRV_OP(ConvertFToTF32INTEL)
28212821
#undef _SPIRV_OP
2822-
} // namespace SPIRV
28232822

2823+
class SPIRVSplitBarrierINTELBase : public SPIRVInstTemplateBase {
2824+
protected:
2825+
SPIRVCapVec getRequiredCapability() const override {
2826+
return getVec(CapabilitySplitBarrierINTEL);
2827+
}
2828+
2829+
SPIRVExtSet getRequiredExtensions() const override {
2830+
return getSet(ExtensionID::SPV_INTEL_split_barrier);
2831+
}
2832+
};
2833+
2834+
#define _SPIRV_OP(x, ...) \
2835+
typedef SPIRVInstTemplate<SPIRVSplitBarrierINTELBase, Op##x, __VA_ARGS__> \
2836+
SPIRV##x;
2837+
_SPIRV_OP(ControlBarrierArriveINTEL, false, 4)
2838+
_SPIRV_OP(ControlBarrierWaitINTEL, false, 4)
2839+
#undef _SPIRV_OP
2840+
} // namespace SPIRV
28242841
#endif // SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H

0 commit comments

Comments
 (0)