Skip to content

Commit

Permalink
Fix translation of 64-bit atomics to OpenCL 1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexeySotkin authored and svenvh committed Aug 27, 2019
1 parent e692372 commit 10dee68
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 25 deletions.
2 changes: 1 addition & 1 deletion lib/SPIRV/OCLUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ template <> inline void SPIRVMap<std::string, Op, SPIRVInstruction>::init() {
}

template <> inline void SPIRVMap<std::string, Op, OCL12Builtin>::init() {
#define _SPIRV_OP(x, y) add("atomic_" #x, Op##y);
#define _SPIRV_OP(x, y) add(#x, Op##y);
_SPIRV_OP(add, AtomicIAdd)
_SPIRV_OP(sub, AtomicISub)
_SPIRV_OP(xchg, AtomicExchange)
Expand Down
59 changes: 35 additions & 24 deletions lib/SPIRV/SPIRVToOCL12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@ class SPIRVToOCL12 : public SPIRVToOCL {
Instruction *visitCallSPIRVAtomicUMinUMax(CallInst *CI, Op OC);

/// Transform __spirv_OpAtomicLoad to atomic_add(*ptr, 0)
Instruction *visitCallSPIRVAtomicLoad(CallInst *CI, Op OC);
Instruction *visitCallSPIRVAtomicLoad(CallInst *CI);

/// Transform __spirv_OpAtomicStore to atomic_xchg(*ptr, value)
Instruction *visitCallSPIRVAtomicStore(CallInst *CI, Op OC);
Instruction *visitCallSPIRVAtomicStore(CallInst *CI);

/// Transform __spirv_OpAtomicFlagClear to atomic_xchg(*ptr, 0)
/// with ignoring the result
Instruction *visitCallSPIRVAtomicFlagClear(CallInst *CI, Op OC);
Instruction *visitCallSPIRVAtomicFlagClear(CallInst *CI);

/// Transform __spirv_OpAtomicFlagTestAndTest to
/// (bool)atomic_xchg(*ptr, 1)
Instruction *visitCallSPIRVAtomicFlagTestAndSet(CallInst *CI, Op OC);
Instruction *visitCallSPIRVAtomicFlagTestAndSet(CallInst *CI);

/// Transform __spirv_OpAtomicCompareExchange and
/// __spirv_OpAtomicCompareExchangeWeak into atomic_cmpxchg. There is no
Expand All @@ -97,15 +97,19 @@ class SPIRVToOCL12 : public SPIRVToOCL {

/// Transform atomic builtin name into correct ocl-dependent name
Instruction *mutateAtomicName(CallInst *CI, Op OC) override;

/// Transform SPIR-V atomic instruction opcode into OpenCL 1.2 builtin name.
/// Depending on the type, the return name starts with "atomic_" for 32-bit
/// types or with "atom_" for 64-bit types, as specified by
/// cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics extensions.
std::string mapAtomicName(Op OC, Type *Ty);
};

bool SPIRVToOCL12::runOnModule(Module &Module) {
M = &Module;
Ctx = &M->getContext();
visit(*M);

translateMangledAtomicTypeName();

eraseUselessFunctions(&Module);

LLVM_DEBUG(dbgs() << "After SPIRVToOCL12:\n" << *M);
Expand Down Expand Up @@ -186,7 +190,7 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) {
M, CI,
[=](CallInst *, std::vector<Value *> &Args) {
Args.resize(1);
return OCLSPIRVBuiltinMap::rmap(OC);
return mapAtomicName(OC, CI->getType());
},
&Attrs);
}
Expand All @@ -205,7 +209,7 @@ CallInst *SPIRVToOCL12::mutateCommonAtomicArguments(CallInst *CI, Op OC) {
auto StartIdx = Ptr + 1;
auto StopIdx = StartIdx + ArgsToRemove;
Args.erase(Args.begin() + StartIdx, Args.begin() + StopIdx);
return OCL12SPIRVBuiltinMap::rmap(OC);
return mapAtomicName(OC, CI->getType());
},
&Attrs);
}
Expand All @@ -217,13 +221,13 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicUMinUMax(CallInst *CI, Op OC) {
[=](CallInst *, std::vector<Value *> &Args) {
std::swap(Args[1], Args[3]);
Args.resize(2);
return OCL12SPIRVBuiltinMap::rmap(OC == OpAtomicUMin ? OpAtomicSMin
: OpAtomicSMax);
return mapAtomicName(OC == OpAtomicUMin ? OpAtomicSMin : OpAtomicSMax,
CI->getType());
},
&Attrs);
}

Instruction *SPIRVToOCL12::visitCallSPIRVAtomicLoad(CallInst *CI, Op OC) {
Instruction *SPIRVToOCL12::visitCallSPIRVAtomicLoad(CallInst *CI) {
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
return mutateCallInstOCL(
M, CI,
Expand All @@ -233,12 +237,12 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicLoad(CallInst *CI, Op OC) {
// Emit this builtin via call of atomic_add(*p, 0).
Type *ptrElemTy = Args[0]->getType()->getPointerElementType();
Args.push_back(Constant::getNullValue(ptrElemTy));
return OCL12SPIRVBuiltinMap::rmap(OpAtomicIAdd);
return mapAtomicName(OpAtomicIAdd, ptrElemTy);
},
&Attrs);
}

Instruction *SPIRVToOCL12::visitCallSPIRVAtomicStore(CallInst *CI, Op OC) {
Instruction *SPIRVToOCL12::visitCallSPIRVAtomicStore(CallInst *CI) {
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
return mutateCallInstOCL(
M, CI,
Expand All @@ -248,34 +252,33 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicStore(CallInst *CI, Op OC) {
// The type of the value pointed to by Pointer (1st argument)
// must be the same as Result Type.
RetTy = Args[0]->getType()->getPointerElementType();
return OCL12SPIRVBuiltinMap::rmap(OpAtomicExchange);
return mapAtomicName(OpAtomicExchange, RetTy);
},
[=](CallInst *CI) -> Instruction * { return CI; }, &Attrs);
}

Instruction *SPIRVToOCL12::visitCallSPIRVAtomicFlagClear(CallInst *CI, Op OC) {
Instruction *SPIRVToOCL12::visitCallSPIRVAtomicFlagClear(CallInst *CI) {
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
return mutateCallInstOCL(
M, CI,
[=](CallInst *, std::vector<Value *> &Args, Type *&RetTy) {
Args.resize(1);
Args.push_back(getInt32(M, 0));
RetTy = Type::getInt32Ty(M->getContext());
return OCL12SPIRVBuiltinMap::rmap(OpAtomicExchange);
return mapAtomicName(OpAtomicExchange, RetTy);
},
[=](CallInst *CI) -> Instruction * { return CI; }, &Attrs);
}

Instruction *SPIRVToOCL12::visitCallSPIRVAtomicFlagTestAndSet(CallInst *CI,
Op OC) {
Instruction *SPIRVToOCL12::visitCallSPIRVAtomicFlagTestAndSet(CallInst *CI) {
AttributeList Attrs = CI->getCalledFunction()->getAttributes();
return mutateCallInstOCL(
M, CI,
[=](CallInst *, std::vector<Value *> &Args, Type *&RetTy) {
Args.resize(1);
Args.push_back(getInt32(M, 1));
RetTy = Type::getInt32Ty(M->getContext());
return OCL12SPIRVBuiltinMap::rmap(OpAtomicExchange);
return mapAtomicName(OpAtomicExchange, RetTy);
},
[=](CallInst *CI) -> Instruction * {
return BitCastInst::Create(Instruction::Trunc, CI,
Expand All @@ -295,7 +298,9 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicCmpExchg(CallInst *CI, Op OC) {
// has Value and Comparator in different order than ocl functions
// both of them are translated into atomic_cmpxchg
std::swap(Args[1], Args[2]);
return OCL12SPIRVBuiltinMap::rmap(OpAtomicCompareExchange);
// Type of return value, pointee of the pointer operand, other operands,
// all match, and should be integer scalar types.
return mapAtomicName(OpAtomicCompareExchange, CI->getType());
},
&Attrs);
}
Expand All @@ -304,16 +309,16 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) {
Instruction *NewCI = nullptr;
switch (OC) {
case OpAtomicLoad:
NewCI = visitCallSPIRVAtomicLoad(CI, OC);
NewCI = visitCallSPIRVAtomicLoad(CI);
break;
case OpAtomicStore:
NewCI = visitCallSPIRVAtomicStore(CI, OC);
NewCI = visitCallSPIRVAtomicStore(CI);
break;
case OpAtomicFlagClear:
NewCI = visitCallSPIRVAtomicFlagClear(CI, OC);
NewCI = visitCallSPIRVAtomicFlagClear(CI);
break;
case OpAtomicFlagTestAndSet:
NewCI = visitCallSPIRVAtomicFlagTestAndSet(CI, OC);
NewCI = visitCallSPIRVAtomicFlagTestAndSet(CI);
break;
case OpAtomicUMin:
case OpAtomicUMax:
Expand All @@ -340,6 +345,12 @@ Instruction *SPIRVToOCL12::mutateAtomicName(CallInst *CI, Op OC) {
&Attrs);
}

std::string SPIRVToOCL12::mapAtomicName(Op OC, Type *Ty) {
std::string Prefix = Ty->isIntegerTy(64) ? kOCLBuiltinName::AtomPrefix
: kOCLBuiltinName::AtomicPrefix;
return Prefix += OCL12SPIRVBuiltinMap::rmap(OC);
}

} // namespace SPIRV

INITIALIZE_PASS(SPIRVToOCL12, "spvtoocl12",
Expand Down
83 changes: 83 additions & 0 deletions test/transcoding/atomics_int64.spt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
119734787 65536 393230 34 0
2 Capability Addresses
2 Capability Linkage
2 Capability Kernel
2 Capability Int64
2 Capability Int64Atomics
2 Capability GenericPointer
5 ExtInstImport 1 "OpenCL.std"
3 MemoryModel 1 2
3 Source 3 200000
5 Decorate 8 LinkageAttributes "foo" Export
4 TypeInt 3 64 0
4 TypeInt 5 32 0
4 Constant 5 17 1
4 Constant 5 18 16
2 TypeVoid 2
4 TypePointer 4 8 3
4 TypePointer 6 8 5
9 TypeFunction 7 2 4 4 6 3 3 3
2 TypeBool 32


5 Function 2 8 0 7
3 FunctionParameter 4 9
3 FunctionParameter 4 10
3 FunctionParameter 6 11
3 FunctionParameter 3 12
3 FunctionParameter 3 13
3 FunctionParameter 3 14

2 Label 15
6 AtomicLoad 3 16 9 17 18
5 AtomicStore 9 17 18 12
7 AtomicExchange 3 19 9 17 18 12
9 AtomicCompareExchange 3 20 9 17 18 18 12 14
6 AtomicIIncrement 3 21 9 17 18
6 AtomicIDecrement 3 22 9 17 18
7 AtomicIAdd 3 23 9 17 18 12
7 AtomicISub 3 24 9 17 18 12
7 AtomicSMin 3 25 9 17 18 12
7 AtomicUMin 3 26 10 17 18 13
7 AtomicSMax 3 27 9 17 18 12
7 AtomicUMax 3 28 10 17 18 13
7 AtomicAnd 3 29 9 17 18 12
7 AtomicOr 3 30 9 17 18 12
7 AtomicXor 3 31 9 17 18 12
6 AtomicFlagTestAndSet 32 33 11 17 18
4 AtomicFlagClear 11 17 18
1 Return

1 FunctionEnd

; RUN: llvm-spirv --to-binary %s -o %t.spv
; RUN: spirv-val %t.spv
; RUN: llvm-spirv --spirv-ocl-builtins-version=CL1.2 -r %t.spv -o - | llvm-dis -o %t.ll
; RUN: FileCheck %s < %t.ll

; OpAtomicLoad is emulated via atom_add(*p, 0)
; CHECK: call spir_func i64 @_Z8atom_add

; OpAtomicStore is emulated via atom_xchg(*p, val)
; CHECK: call spir_func i64 @_Z9atom_xchg

; CHECK: call spir_func i64 @_Z9atom_xchg
; CHECK: call spir_func i64 @_Z12atom_cmpxchg
; CHECK: call spir_func i64 @_Z8atom_inc
; CHECK: call spir_func i64 @_Z8atom_dec
; CHECK: call spir_func i64 @_Z8atom_add
; CHECK: call spir_func i64 @_Z8atom_sub
; CHECK: call spir_func i64 @_Z8atom_min
; CHECK: call spir_func i64 @_Z8atom_min
; CHECK: call spir_func i64 @_Z8atom_max
; CHECK: call spir_func i64 @_Z8atom_max
; CHECK: call spir_func i64 @_Z8atom_and
; CHECK: call spir_func i64 @_Z7atom_or
; CHECK: call spir_func i64 @_Z8atom_xor

; OpAtomicFlagTestAndSet is emulated via atomic_xchg(*p, 1)
; CHECK: call spir_func i32 @_Z11atomic_xchg

; OpAtomicFlagClear is emulated via atomic_xchg(*p, 0)
; CHECK: call spir_func i32 @_Z11atomic_xchg

0 comments on commit 10dee68

Please sign in to comment.