Skip to content

Commit b48690d

Browse files
MrSidimsbader
authored andcommitted
Sync with Khronos SPIR-V Translator 16a9caf09d
Signed-off-by: Dmitry Sidorov <[email protected]>
1 parent 2282e74 commit b48690d

38 files changed

+1254
-295
lines changed

llvm-spirv/lib/SPIRV/OCLUtil.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ size_t getAtomicBuiltinNumMemoryOrderArgs(StringRef Name) {
114114
return 1;
115115
}
116116

117+
size_t getSPIRVAtomicBuiltinNumMemoryOrderArgs(Op OC) {
118+
if (OC == OpAtomicCompareExchange || OC == OpAtomicCompareExchangeWeak)
119+
return 2;
120+
return 1;
121+
}
122+
117123
bool isComputeAtomicOCLBuiltin(StringRef DemangledName) {
118124
if (!DemangledName.startswith(kOCLBuiltinName::AtomicPrefix) &&
119125
!DemangledName.startswith(kOCLBuiltinName::AtomPrefix))
@@ -556,7 +562,6 @@ class OCLBuiltinFuncMangleInfo : public SPIRV::BuiltinFuncMangleInfo {
556562
addVoidPtrArg(1);
557563
addUnsignedArg(2);
558564
addUnsignedArg(3);
559-
560565
} else if (UnmangledName == "read_pipe_4" ||
561566
UnmangledName == "write_pipe_4") {
562567
// with 4 arguments (plus two i32 literals):

llvm-spirv/lib/SPIRV/OCLUtil.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@ enum OCLMemFenceKind {
6666
OCLMF_Image = 4,
6767
};
6868

69+
// This enum declares extra constants for OpenCL mem_fence flag. It includes
70+
// combinations of local/global/image flags.
71+
enum OCLMemFenceExtendedKind {
72+
OCLMFEx_Local = OCLMF_Local,
73+
OCLMFEx_Global = OCLMF_Global,
74+
OCLMFEx_Local_Global = OCLMF_Global | OCLMF_Local,
75+
OCLMFEx_Image = OCLMF_Image,
76+
OCLMFEx_Image_Local = OCLMF_Image | OCLMF_Local,
77+
OCLMFEx_Image_Global = OCLMF_Image | OCLMF_Global,
78+
OCLMFEx_Image_Local_Global = OCLMF_Image | OCLMF_Global | OCLMF_Local,
79+
};
80+
6981
enum OCLScopeKind {
7082
OCLMS_work_item,
7183
OCLMS_work_group,
@@ -95,6 +107,9 @@ enum OCLMemOrderKind {
95107

96108
typedef SPIRVMap<OCLMemFenceKind, MemorySemanticsMask> OCLMemFenceMap;
97109

110+
typedef SPIRVMap<OCLMemFenceExtendedKind, MemorySemanticsMask>
111+
OCLMemFenceExtendedMap;
112+
98113
typedef SPIRVMap<OCLMemOrderKind, unsigned, MemorySemanticsMask> OCLMemOrderMap;
99114

100115
typedef SPIRVMap<OCLScopeKind, Scope> OCLMemScopeMap;
@@ -107,6 +122,9 @@ typedef SPIRVMap<std::string, SPIRVFPRoundingModeKind>
107122

108123
typedef SPIRVMap<std::string, Op, SPIRVInstruction> OCLSPIRVBuiltinMap;
109124

125+
class OCL12Builtin;
126+
typedef SPIRVMap<std::string, Op, OCL12Builtin> OCL12SPIRVBuiltinMap;
127+
110128
typedef SPIRVMap<std::string, SPIRVBuiltinVariableKind>
111129
SPIRSPIRVBuiltinVariableMap;
112130

@@ -305,6 +323,9 @@ BarrierLiterals getBarrierLiterals(CallInst *CI);
305323
/// Get number of memory order arguments for atomic builtin function.
306324
size_t getAtomicBuiltinNumMemoryOrderArgs(StringRef Name);
307325

326+
/// Get number of memory order arguments for spirv atomic builtin function.
327+
size_t getSPIRVAtomicBuiltinNumMemoryOrderArgs(Op OC);
328+
308329
/// Return true for OpenCL builtins which do compute operations
309330
/// (like add, sub, min, max, inc, dec, ...) atomically
310331
bool isComputeAtomicOCLBuiltin(StringRef DemangledName);
@@ -422,6 +443,22 @@ template <> inline void SPIRVMap<OCLMemFenceKind, MemorySemanticsMask>::init() {
422443
add(OCLMF_Image, MemorySemanticsImageMemoryMask);
423444
}
424445

446+
template <>
447+
inline void SPIRVMap<OCLMemFenceExtendedKind, MemorySemanticsMask>::init() {
448+
add(OCLMFEx_Local, MemorySemanticsWorkgroupMemoryMask);
449+
add(OCLMFEx_Global, MemorySemanticsCrossWorkgroupMemoryMask);
450+
add(OCLMFEx_Local_Global, MemorySemanticsWorkgroupMemoryMask |
451+
MemorySemanticsCrossWorkgroupMemoryMask);
452+
add(OCLMFEx_Image, MemorySemanticsImageMemoryMask);
453+
add(OCLMFEx_Image_Local,
454+
MemorySemanticsWorkgroupMemoryMask | MemorySemanticsImageMemoryMask);
455+
add(OCLMFEx_Image_Global,
456+
MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsImageMemoryMask);
457+
add(OCLMFEx_Image_Local_Global, MemorySemanticsWorkgroupMemoryMask |
458+
MemorySemanticsCrossWorkgroupMemoryMask |
459+
MemorySemanticsImageMemoryMask);
460+
}
461+
425462
template <>
426463
inline void SPIRVMap<OCLMemOrderKind, unsigned, MemorySemanticsMask>::init() {
427464
add(OCLMO_relaxed, MemorySemanticsMaskNone);
@@ -622,6 +659,7 @@ template <> inline void SPIRVMap<std::string, Op, SPIRVInstruction>::init() {
622659
_SPIRV_OP(signbit, SignBitSet)
623660
_SPIRV_OP(any, Any)
624661
_SPIRV_OP(all, All)
662+
_SPIRV_OP(popcount, BitCount)
625663
_SPIRV_OP(get_fence, GenericPtrMemSemantics)
626664
// CL 2.0 kernel enqueue builtins
627665
_SPIRV_OP(enqueue_marker, EnqueueMarker)
@@ -696,6 +734,22 @@ template <> inline void SPIRVMap<std::string, Op, SPIRVInstruction>::init() {
696734
#undef _SPIRV_OP
697735
}
698736

737+
template <> inline void SPIRVMap<std::string, Op, OCL12Builtin>::init() {
738+
#define _SPIRV_OP(x, y) add("atomic_" #x, Op##y);
739+
_SPIRV_OP(add, AtomicIAdd)
740+
_SPIRV_OP(sub, AtomicISub)
741+
_SPIRV_OP(xchg, AtomicExchange)
742+
_SPIRV_OP(cmpxchg, AtomicCompareExchange)
743+
_SPIRV_OP(inc, AtomicIIncrement)
744+
_SPIRV_OP(dec, AtomicIDecrement)
745+
_SPIRV_OP(min, AtomicSMin)
746+
_SPIRV_OP(max, AtomicSMax)
747+
_SPIRV_OP(and, AtomicAnd)
748+
_SPIRV_OP(or, AtomicOr)
749+
_SPIRV_OP(xor, AtomicXor)
750+
#undef _SPIRV_OP
751+
}
752+
699753
// SPV_INTEL_device_side_avc_motion_estimation extension builtins
700754
class SPIRVSubgroupsAVCIntelInst;
701755
template <>

llvm-spirv/lib/SPIRV/SPIRVInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ const static char TranslateOCLMemOrder[] = "__translate_ocl_memory_order";
337337
const static char TranslateOCLMemScope[] = "__translate_ocl_memory_scope";
338338
const static char TranslateSPIRVMemOrder[] = "__translate_spirv_memory_order";
339339
const static char TranslateSPIRVMemScope[] = "__translate_spirv_memory_scope";
340+
const static char TranslateSPIRVMemFence[] = "__translate_spirv_memory_fence";
340341
} // namespace kSPIRVName
341342

342343
namespace kSPIRVPostfix {

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ SPIRVToLLVM::getMetadataFromNameAndParameter(std::string Name,
576576
ConstantInt::get(Type::getInt32Ty(*Context), Parameter))};
577577
}
578578

579-
void SPIRVToLLVM::setLLVMLoopMetadata(SPIRVLoopMerge *LM, BranchInst *BI) {
579+
template <typename LoopInstType>
580+
void SPIRVToLLVM::setLLVMLoopMetadata(LoopInstType *LM, BranchInst *BI) {
580581
if (!LM)
581582
return;
582583
auto Temp = MDNode::getTemporary(*Context, None);
@@ -1358,7 +1359,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
13581359
auto Prev = BR->getPrevious();
13591360
if (Prev && Prev->getOpCode() == OpLoopMerge) {
13601361
auto LM = static_cast<SPIRVLoopMerge *>(Prev);
1361-
setLLVMLoopMetadata(LM, BI);
1362+
setLLVMLoopMetadata<SPIRVLoopMerge>(LM, BI);
1363+
} else if (Prev && Prev->getOpCode() == OpLoopControlINTEL) {
1364+
auto LCI = static_cast<SPIRVLoopControlINTEL *>(Prev);
1365+
setLLVMLoopMetadata<SPIRVLoopControlINTEL>(LCI, BI);
13621366
}
13631367
return mapValue(BV, BI);
13641368
}
@@ -1372,7 +1376,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
13721376
auto Prev = BR->getPrevious();
13731377
if (Prev && Prev->getOpCode() == OpLoopMerge) {
13741378
auto LM = static_cast<SPIRVLoopMerge *>(Prev);
1375-
setLLVMLoopMetadata(LM, BC);
1379+
setLLVMLoopMetadata<SPIRVLoopMerge>(LM, BC);
1380+
} else if (Prev && Prev->getOpCode() == OpLoopControlINTEL) {
1381+
auto LCI = static_cast<SPIRVLoopControlINTEL *>(Prev);
1382+
setLLVMLoopMetadata<SPIRVLoopControlINTEL>(LCI, BC);
13761383
}
13771384
return mapValue(BV, BC);
13781385
}
@@ -1498,9 +1505,9 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
14981505

14991506
case OpVmeImageINTEL:
15001507
case OpLine:
1501-
case OpSelectionMerge: // OpenCL Compiler does not use this instruction
1502-
case OpLoopMerge: // Should be translated at OpBranch or OpBranchConditional
1503-
// cases
1508+
case OpSelectionMerge: // OpenCL Compiler does not use this instruction
1509+
case OpLoopMerge: // Should be translated at OpBranch or
1510+
case OpLoopControlINTEL: // OpBranchConditional cases
15041511
return nullptr;
15051512

15061513
case OpSwitch: {
@@ -1659,6 +1666,16 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
16591666
BV->getName(), BB));
16601667
}
16611668

1669+
case OpBitReverse: {
1670+
auto *BR = static_cast<SPIRVUnary *>(BV);
1671+
IntegerType *Int32Ty = IntegerType::get(*Context, 32);
1672+
Function *intr =
1673+
Intrinsic::getDeclaration(M, llvm::Intrinsic::bitreverse, Int32Ty);
1674+
auto *Call = CallInst::Create(intr, transValue(BR->getOperand(0), F, BB),
1675+
BR->getName(), BB);
1676+
return mapValue(BV, Call);
1677+
}
1678+
16621679
case OpFunctionCall: {
16631680
SPIRVFunctionCall *BC = static_cast<SPIRVFunctionCall *>(BV);
16641681
auto Call = CallInst::Create(transFunction(BC->getFunction()),
@@ -2493,21 +2510,21 @@ void SPIRVToLLVM::transIntelFPGADecorations(SPIRVValue *BV, Value *V) {
24932510
Builder.CreateCall(AnnotationFn, Args);
24942511
}
24952512
}
2496-
} else {
2497-
SmallString<256> AnnotStr;
2498-
generateIntelFPGAAnnotation(BV, AnnotStr);
2499-
if (!AnnotStr.empty()) {
2500-
auto *GS = Builder.CreateGlobalStringPtr(AnnotStr);
2501-
2502-
auto AnnotationFn =
2503-
llvm::Intrinsic::getDeclaration(M, Intrinsic::var_annotation);
2504-
2505-
llvm::Value *Args[] = {
2506-
Builder.CreateBitCast(V, Int8PtrTyPrivate, V->getName()),
2507-
Builder.CreateBitCast(GS, Int8PtrTyPrivate), UndefInt8Ptr,
2508-
UndefInt32};
2509-
Builder.CreateCall(AnnotationFn, Args);
2510-
}
2513+
}
2514+
2515+
SmallString<256> AnnotStr;
2516+
generateIntelFPGAAnnotation(BV, AnnotStr);
2517+
if (!AnnotStr.empty()) {
2518+
auto *GS = Builder.CreateGlobalStringPtr(AnnotStr);
2519+
2520+
auto AnnotationFn =
2521+
llvm::Intrinsic::getDeclaration(M, Intrinsic::var_annotation);
2522+
2523+
llvm::Value *Args[] = {
2524+
Builder.CreateBitCast(V, Int8PtrTyPrivate, V->getName()),
2525+
Builder.CreateBitCast(GS, Int8PtrTyPrivate), UndefInt8Ptr,
2526+
UndefInt32};
2527+
Builder.CreateCall(AnnotationFn, Args);
25112528
}
25122529
}
25132530
}

llvm-spirv/lib/SPIRV/SPIRVReader.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ class SPIRVToLLVM {
245245
BasicBlock *BB);
246246
Value *oclTransConstantPipeStorage(SPIRV::SPIRVConstantPipeStorage *BCPS);
247247
void setName(llvm::Value *V, SPIRVValue *BV);
248-
void setLLVMLoopMetadata(SPIRVLoopMerge *LM, BranchInst *BI);
248+
template <typename LoopInstType>
249+
void setLLVMLoopMetadata(LoopInstType *LM, BranchInst *BI);
249250
inline llvm::Metadata *getMetadataFromName(std::string Name);
250251
inline std::vector<llvm::Metadata *>
251252
getMetadataFromNameAndParameter(std::string Name, SPIRVWord Parameter);

llvm-spirv/lib/SPIRV/SPIRVToOCL.cpp

Lines changed: 0 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -362,119 +362,6 @@ std::string SPIRVToOCL::getGroupBuiltinPrefix(CallInst *CI) {
362362
return Prefix;
363363
}
364364

365-
Instruction *SPIRVToOCL::visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) {
366-
assert(CI->getCalledFunction() && "Unexpected indirect call");
367-
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
368-
Instruction *PInsertBefore = CI;
369-
370-
return mutateCallInstOCL(
371-
M, CI,
372-
[=](CallInst *, std::vector<Value *> &Args, Type *&RetTy) {
373-
auto Ptr = findFirstPtr(Args);
374-
auto Name = OCLSPIRVBuiltinMap::rmap(OC);
375-
auto NumOrder = getAtomicBuiltinNumMemoryOrderArgs(Name);
376-
auto ScopeIdx = Ptr + 1;
377-
auto OrderIdx = Ptr + 2;
378-
if (OC == OpAtomicIIncrement || OC == OpAtomicIDecrement) {
379-
// Since OpenCL 1.2 atomic_inc and atomic_dec builtins don't have,
380-
// memory scope and memory order syntax, and OpenCL 2.0 doesn't have
381-
// such builtins, therefore we translate these instructions to
382-
// atomic_fetch_add_explicit and atomic_fetch_sub_explicit OpenCL 2.0
383-
// builtins with "operand" argument = 1.
384-
Name = OCLSPIRVBuiltinMap::rmap(
385-
OC == OpAtomicIIncrement ? OpAtomicIAdd : OpAtomicISub);
386-
Type *ValueTy =
387-
cast<PointerType>(Args[Ptr]->getType())->getElementType();
388-
assert(ValueTy->isIntegerTy());
389-
Args.push_back(llvm::ConstantInt::get(ValueTy, 1));
390-
}
391-
if (auto *ScopeInt = dyn_cast_or_null<ConstantInt>(Args[ScopeIdx])) {
392-
Args[ScopeIdx] = mapUInt(M, ScopeInt, [](unsigned I) {
393-
return rmap<OCLScopeKind>(static_cast<Scope>(I));
394-
});
395-
} else {
396-
CallInst *TransCall = dyn_cast<CallInst>(Args[ScopeIdx]);
397-
Function *F = TransCall ? TransCall->getCalledFunction() : nullptr;
398-
if (F && F->getName().equals(kSPIRVName::TranslateOCLMemScope)) {
399-
// In case the SPIR-V module was created from an OpenCL program by
400-
// *this* SPIR-V generator, we know that the value passed to
401-
// __translate_ocl_memory_scope is what we should pass to the OpenCL
402-
// builtin now.
403-
Args[ScopeIdx] = TransCall->getArgOperand(0);
404-
} else {
405-
Args[ScopeIdx] = getOrCreateSwitchFunc(
406-
kSPIRVName::TranslateSPIRVMemScope, Args[ScopeIdx],
407-
OCLMemScopeMap::getRMap(), true /*IsReverse*/, None, CI, M);
408-
}
409-
}
410-
for (size_t I = 0; I < NumOrder; ++I) {
411-
if (auto OrderInt =
412-
dyn_cast_or_null<ConstantInt>(Args[OrderIdx + I])) {
413-
Args[OrderIdx + I] = mapUInt(M, OrderInt, [](unsigned Ord) {
414-
return mapSPIRVMemOrderToOCL(Ord);
415-
});
416-
} else {
417-
CallInst *TransCall = dyn_cast<CallInst>(Args[OrderIdx + I]);
418-
Function *F = TransCall ? TransCall->getCalledFunction() : nullptr;
419-
if (F && F->getName().equals(kSPIRVName::TranslateOCLMemOrder)) {
420-
// In case the SPIR-V module was created from an OpenCL program by
421-
// *this* SPIR-V generator, we know that the value passed to
422-
// __translate_ocl_memory_order is what we should pass to the
423-
// OpenCL builtin now.
424-
Args[OrderIdx + I] = TransCall->getArgOperand(0);
425-
} else {
426-
Args[OrderIdx + I] = getOrCreateSwitchFunc(
427-
kSPIRVName::TranslateSPIRVMemOrder, Args[OrderIdx + I],
428-
OCLMemOrderMap::getRMap(), true /*IsReverse*/, None, CI, M);
429-
}
430-
}
431-
}
432-
std::swap(Args[ScopeIdx], Args.back());
433-
if (OC == OpAtomicCompareExchange ||
434-
OC == OpAtomicCompareExchangeWeak) {
435-
// OpAtomicCompareExchange[Weak] semantics is different from
436-
// atomic_compare_exchange_[strong|weak] semantics as well as
437-
// arguments order.
438-
// OCL built-ins returns boolean value and stores a new/original
439-
// value by pointer passed as 2nd argument (aka expected) while SPIR-V
440-
// instructions returns this new/original value as a resulting value.
441-
AllocaInst *PExpected =
442-
new AllocaInst(CI->getType(), 0, "expected",
443-
&(*PInsertBefore->getParent()
444-
->getParent()
445-
->getEntryBlock()
446-
.getFirstInsertionPt()));
447-
PExpected->setAlignment(CI->getType()->getScalarSizeInBits() / 8);
448-
new StoreInst(Args[1], PExpected, PInsertBefore);
449-
unsigned AddrSpc = SPIRAS_Generic;
450-
Type *PtrTyAS =
451-
PExpected->getType()->getElementType()->getPointerTo(AddrSpc);
452-
Args[1] = CastInst::CreatePointerBitCastOrAddrSpaceCast(
453-
PExpected, PtrTyAS, PExpected->getName() + ".as", PInsertBefore);
454-
std::swap(Args[3], Args[4]);
455-
std::swap(Args[2], Args[3]);
456-
RetTy = Type::getInt1Ty(*Ctx);
457-
}
458-
return Name;
459-
},
460-
[=](CallInst *CI) -> Instruction * {
461-
if (OC == OpAtomicCompareExchange ||
462-
OC == OpAtomicCompareExchangeWeak) {
463-
// OCL built-ins atomic_compare_exchange_[strong|weak] return boolean
464-
// value. So, to obtain the same value as SPIR-V instruction is
465-
// returning it has to be loaded from the memory where 'expected'
466-
// value is stored. This memory must contain the needed value after a
467-
// call to OCL built-in is completed.
468-
LoadInst *POriginal =
469-
new LoadInst(CI->getArgOperand(1), "original", PInsertBefore);
470-
return POriginal;
471-
}
472-
// For other built-ins the return values match.
473-
return CI;
474-
},
475-
&Attrs);
476-
}
477-
478365
} // namespace SPIRV
479366

480367
ModulePass *llvm::createSPIRVToOCL(Module &M) {

llvm-spirv/lib/SPIRV/SPIRVToOCL.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,19 @@ class SPIRVToOCL : public ModulePass, public InstVisitor<SPIRVToOCL> {
101101
/// workgroup/subgroup scope enums.
102102
std::string getGroupBuiltinPrefix(CallInst *CI);
103103

104+
/// Transform __spirv_OpAtomicCompareExchange and
105+
/// __spirv_OpAtomicCompareExchangeWeak
106+
virtual Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI, Op OC) = 0;
107+
108+
/// Transform __spirv_OpAtomicIIncrement/OpAtomicIDecrement to:
109+
/// - OCL2.0: atomic_fetch_add_explicit/atomic_fetch_sub_explicit
110+
/// - OCL1.2: atomic_inc/atomic_dec
111+
virtual Instruction *visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) = 0;
112+
104113
/// Transform __spirv_Atomic* to atomic_*.
105114
/// __spirv_Atomic*(atomic_op, scope, sema, ops, ...) =>
106115
/// atomic_*(atomic_op, ops, ..., order(sema), map(scope))
107-
virtual Instruction *visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC);
116+
virtual Instruction *visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) = 0;
108117

109118
/// Transform __spirv_MemoryBarrier to:
110119
/// - OCL2.0: atomic_work_item_fence.__spirv_MemoryBarrier(scope, sema) =>
@@ -117,6 +126,13 @@ class SPIRVToOCL : public ModulePass, public InstVisitor<SPIRVToOCL> {
117126
/// - OCL1.2: barrier
118127
virtual void visitCallSPIRVControlBarrier(CallInst *CI) = 0;
119128

129+
/// Conduct generic mutations for all atomic builtins
130+
virtual CallInst *mutateCommonAtomicArguments(CallInst *CI, Op OC) = 0;
131+
132+
/// Transform __spirv_Opcode to ocl-version specific builtin name
133+
/// using separate maps for OpenCL 1.2 and OpenCL 2.0
134+
virtual Instruction *mutateAtomicName(CallInst *CI, Op OC) = 0;
135+
120136
static char ID;
121137

122138
protected:

0 commit comments

Comments
 (0)