Skip to content

Commit 8280418

Browse files
AlexeySotkinvladimirlaz
authored andcommitted
Translate atomicrmw LLVM instruction to SPIR-V
atomicrmw with nand, fadd and fsub operation can't be represented in SPIR-V. Signed-off-by: Alexey Sotkin <alexey.sotkin@intel.com>
1 parent 36d69c7 commit 8280418

File tree

5 files changed

+145
-0
lines changed

5 files changed

+145
-0
lines changed

llvm-spirv/lib/SPIRV/OCLUtil.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "SPIRVInternal.h"
4343
#include "llvm/IR/DebugInfoMetadata.h"
4444
#include "llvm/IR/IRBuilder.h"
45+
#include "llvm/IR/Instructions.h"
4546
#include "llvm/Support/Path.h"
4647

4748
#include <functional>
@@ -984,6 +985,20 @@ template <> inline void SPIRVMap<std::string, Op, OCLOpaqueType>::init() {
984985
add("opencl.sampler_t", OpTypeSampler);
985986
}
986987

988+
typedef SPIRVMap<AtomicRMWInst::BinOp, Op> LLVMSPIRVAtomicRmwOpCodeMap;
989+
template <> inline void LLVMSPIRVAtomicRmwOpCodeMap::init() {
990+
add(llvm::AtomicRMWInst::Xchg, OpAtomicExchange);
991+
add(llvm::AtomicRMWInst::Add, OpAtomicIAdd);
992+
add(llvm::AtomicRMWInst::Sub, OpAtomicISub);
993+
add(llvm::AtomicRMWInst::And, OpAtomicAnd);
994+
add(llvm::AtomicRMWInst::Or, OpAtomicOr);
995+
add(llvm::AtomicRMWInst::Xor, OpAtomicXor);
996+
add(llvm::AtomicRMWInst::Max, OpAtomicSMax);
997+
add(llvm::AtomicRMWInst::Min, OpAtomicSMin);
998+
add(llvm::AtomicRMWInst::UMax, OpAtomicUMax);
999+
add(llvm::AtomicRMWInst::UMin, OpAtomicUMin);
1000+
}
1001+
9871002
} // namespace SPIRV
9881003

9891004
#endif // SPIRV_OCLUTIL_H

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,36 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
12231223
transValue(SF->getOperand(1), BB), Comp, BB));
12241224
}
12251225

1226+
if (AtomicRMWInst *ARMW = dyn_cast<AtomicRMWInst>(V)) {
1227+
AtomicRMWInst::BinOp Op = ARMW->getOperation();
1228+
if (!BM->getErrorLog().checkError(
1229+
!AtomicRMWInst::isFPOperation(Op) && Op != AtomicRMWInst::Nand,
1230+
SPIRVEC_InvalidInstruction,
1231+
OCLUtil::toString(V) + "\nAtomic " +
1232+
AtomicRMWInst::getOperationName(Op).str() +
1233+
" is not supported in SPIR-V!\n"))
1234+
return nullptr;
1235+
1236+
spv::Op OC = LLVMSPIRVAtomicRmwOpCodeMap::map(Op);
1237+
AtomicOrderingCABI Ordering = llvm::toCABI(ARMW->getOrdering());
1238+
auto MemSem = OCLMemOrderMap::map(static_cast<OCLMemOrderKind>(Ordering));
1239+
std::vector<Value *> Operands(4);
1240+
Operands[0] = ARMW->getPointerOperand();
1241+
// To get the memory scope argument we might use ARMW->getSyncScopeID(), but
1242+
// atomicrmw LLVM instruction is not aware of OpenCL(or SPIR-V) memory scope
1243+
// enumeration. And assuming the produced SPIR-V module will be consumed in
1244+
// an OpenCL environment, we can use the same memory scope as OpenCL atomic
1245+
// functions that don't have memory_scope argument i.e. memory_scope_device.
1246+
// See the OpenCL C specification p6.13.11. "Atomic Functions"
1247+
Operands[1] = getUInt32(M, spv::ScopeDevice);
1248+
Operands[2] = getUInt32(M, MemSem);
1249+
Operands[3] = ARMW->getValOperand();
1250+
std::vector<SPIRVId> Ops = BM->getIds(transValue(Operands, BB));
1251+
SPIRVType *Ty = transType(ARMW->getType());
1252+
1253+
return mapValue(V, BM->addInstTemplate(OC, Ops, BB, Ty));
1254+
}
1255+
12261256
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(V)) {
12271257
SPIRVValue *BV = transIntrinsicInst(II, BB);
12281258
return BV ? mapValue(V, BV) : nullptr;

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVErrorEnum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ _SPIRV_OP(InvalidBitWidth, "Invalid bit width in input:")
1212
_SPIRV_OP(InvalidModule, "Invalid SPIR-V module:")
1313
_SPIRV_OP(UnimplementedOpCode, "Unimplemented opcode")
1414
_SPIRV_OP(FunctionPointers, "Can't translate function pointer:\n")
15+
_SPIRV_OP(InvalidInstruction, "Can't translate llvm instruction:\n")

llvm-spirv/test/atomicrmw.ll

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
; RUN: llvm-as < %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -o %t.spv
3+
; RUN: spirv-val %t.spv
4+
; RUN: llvm-spirv -to-text %t.spv -o - | FileCheck %s
5+
6+
; CHECK: TypeInt [[Int:[0-9]+]] 32 0
7+
; CHECK-DAG: Constant [[Int]] [[Scope_Device:[0-9]+]] 1 {{$}}
8+
; CHECK-DAG: Constant [[Int]] [[MemSem_Relaxed:[0-9]+]] 0
9+
; CHECK-DAG: Constant [[Int]] [[MemSem_Acquire:[0-9]+]] 2
10+
; CHECK-DAG: Constant [[Int]] [[MemSem_Release:[0-9]+]] 4 {{$}}
11+
; CHECK-DAG: Constant [[Int]] [[MemSem_AcquireRelease:[0-9]+]] 8
12+
; CHECK-DAG: Constant [[Int]] [[MemSem_SequentiallyConsistent:[0-9]+]] 16
13+
; CHECK-DAG: Constant [[Int]] [[Value:[0-9]+]] 42
14+
; CHECK: TypeFloat [[Float:[0-9]+]] 32
15+
; CHECK: Variable {{[0-9]+}} [[Pointer:[0-9]+]]
16+
; CHECK: Variable {{[0-9]+}} [[FPPointer:[0-9]+]]
17+
; CHECK: Constant [[Float]] [[FPValue:[0-9]+]] 1109917696
18+
19+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
20+
target triple = "spir64"
21+
22+
@ui = common dso_local addrspace(1) global i32 0, align 4
23+
@f = common dso_local local_unnamed_addr addrspace(1) global float 0.000000e+00, align 4
24+
25+
; Function Attrs: nounwind
26+
define dso_local spir_func void @test_atomicrmw() local_unnamed_addr #0 {
27+
entry:
28+
%0 = atomicrmw xchg i32 addrspace(1)* @ui, i32 42 acq_rel
29+
; CHECK: AtomicExchange [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_AcquireRelease]] [[Value]]
30+
31+
%1 = atomicrmw xchg float addrspace(1)* @f, float 42.000000e+00 seq_cst
32+
; CHECK: AtomicExchange [[Float]] {{[0-9]+}} [[FPPointer]] [[Scope_Device]] [[MemSem_SequentiallyConsistent]] [[FPValue]]
33+
34+
%2 = atomicrmw add i32 addrspace(1)* @ui, i32 42 monotonic
35+
; CHECK: AtomicIAdd [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_Relaxed]] [[Value]]
36+
37+
%3 = atomicrmw sub i32 addrspace(1)* @ui, i32 42 acquire
38+
; CHECK: AtomicISub [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_Acquire]] [[Value]]
39+
40+
%4 = atomicrmw or i32 addrspace(1)* @ui, i32 42 release
41+
; CHECK: AtomicOr [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_Release]] [[Value]]
42+
43+
%5 = atomicrmw xor i32 addrspace(1)* @ui, i32 42 acq_rel
44+
; CHECK: AtomicXor [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_AcquireRelease]] [[Value]]
45+
46+
%6 = atomicrmw and i32 addrspace(1)* @ui, i32 42 seq_cst
47+
; CHECK: AtomicAnd [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_SequentiallyConsistent]] [[Value]]
48+
49+
%7 = atomicrmw max i32 addrspace(1)* @ui, i32 42 monotonic
50+
; CHECK: AtomicSMax [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_Relaxed]] [[Value]]
51+
52+
%8 = atomicrmw min i32 addrspace(1)* @ui, i32 42 acquire
53+
; CHECK: AtomicSMin [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_Acquire]] [[Value]]
54+
55+
%9 = atomicrmw umax i32 addrspace(1)* @ui, i32 42 release
56+
; CHECK: AtomicUMax [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_Release]] [[Value]]
57+
58+
%10 = atomicrmw umin i32 addrspace(1)* @ui, i32 42 acq_rel
59+
; CHECK: AtomicUMin [[Int]] {{[0-9]+}} [[Pointer]] [[Scope_Device]] [[MemSem_AcquireRelease]] [[Value]]
60+
61+
ret void
62+
}
63+
64+
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
65+
66+
!llvm.module.flags = !{!0}
67+
!llvm.ident = !{!1}
68+
69+
!0 = !{i32 1, !"wchar_size", i32 4}
70+
!1 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 20c5968e0953d978be4d9d1062801e8758c393b5)"}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; RUN: llvm-as < %s -o %t.bc
2+
; RUN: not --crash llvm-spirv %t.bc -o %t.spv 2>&1 | FileCheck %s
3+
4+
; CHECK: InvalidInstruction: Can't translate llvm instruction:
5+
; CHECK: atomicrmw nand i32 addrspace(1)* @ui, i32 42 acq_rel
6+
; CHECK: Atomic nand is not supported in SPIR-V!
7+
8+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
9+
target triple = "spir64"
10+
11+
@ui = common dso_local addrspace(1) global i32 0, align 4
12+
@f = common dso_local local_unnamed_addr addrspace(1) global float 0.000000e+00, align 4
13+
14+
; Function Attrs: nounwind
15+
define dso_local spir_func void @test_atomicrmw() local_unnamed_addr #0 {
16+
entry:
17+
%0 = atomicrmw nand i32 addrspace(1)* @ui, i32 42 acq_rel
18+
%1 = atomicrmw fadd float addrspace(1)* @f, float 42.000000e+00 seq_cst
19+
%2 = atomicrmw fsub float addrspace(1)* @f, float 42.000000e+00 seq_cst
20+
ret void
21+
}
22+
23+
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
24+
25+
!llvm.module.flags = !{!0}
26+
!llvm.ident = !{!1}
27+
28+
!0 = !{i32 1, !"wchar_size", i32 4}
29+
!1 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 20c5968e0953d978be4d9d1062801e8758c393b5)"}

0 commit comments

Comments
 (0)