; RUN: llvm-as %s -o %t.bc ; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_shader_atomic_float_add -o %t.spv ; RUN: spirv-val %t.spv ; RUN: llvm-spirv %t.spv -to-text -o %t.spt ; RUN: FileCheck < %t.spt %s -check-prefix=CHECK-SPIRV ; RUN: llvm-spirv %t.spv -r --spirv-target-env=CL2.0 -o - | llvm-dis -o %t.rev.ll ; RUN: FileCheck < %t.rev.ll %s -check-prefix=CHECK-LLVM ; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_EXT_shader_atomic_float_add,+SPV_KHR_untyped_pointers -o %t.spv ; RUN: spirv-val %t.spv ; RUN: llvm-spirv %t.spv -to-text -o %t.spt ; RUN: FileCheck < %t.spt %s -check-prefix=CHECK-SPIRV ; RUN: llvm-spirv %t.spv -r --spirv-target-env=CL2.0 -o - | llvm-dis -o %t.rev.ll ; RUN: FileCheck < %t.rev.ll %s -check-prefix=CHECK-LLVM target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" target triple = "spir64" @j = local_unnamed_addr addrspace(1) global i32 0, align 4 ; SPIRV scopes ; 0 - ScopeCrossDevice (all svm devices) ; 1 - ScopeDevice ; 2 - ScopeWorkGroup ; 3 - ScopeSubgroup ; 4 - ScopeInvocation (mapped from work item) ; OCL scopes ; 0 - work_item ; 1 - work_group ; 2 - device ; 3 - all_svm_devices ; 4 - sub_group ; CHECK-SPIRV-DAG: Constant [[#]] [[#ConstInt0:]] 0 ; CHECK-SPIRV-DAG: Constant [[#]] [[#ConstInt2:]] 2 ; CHECK-SPIRV-DAG: Constant [[#]] [[#SCPrivate:]] 16 ; CHECK-SPIRV-DAG: Constant [[#]] [[#ConstInt1:]] 1 ; CHECK-SPIRV-DAG: Constant [[#]] [[#ConstInt3:]] 3 ; CHECK-SPIRV-DAG: Constant [[#]] [[#ConstInt4:]] 4 ; CHECK-SPIRV-DAG: Constant [[#]] [[#Const2Power30:]] 1073741824 ; CHECK-SPIRV-DAG: Constant [[#]] [[#ConstInt42:]] 42 ; Note: Storage class bits (SCGlobal, SCLocal, etc.) are not added for plain LLVM IR atomics ; Only OpenCL builtin atomics get the storage class memory semantics bits from the patch ; AtomicLoad ResTypeId ResId PtrId MemScopeId MemSemanticsId ; Note: Plain LLVM atomic loads don't get storage class bits added (only OpenCL builtins do) ; These use SCPrivate (16) which is SequentiallyConsistent without storage class bits ; CHECK-SPIRV: AtomicLoad [[#]] [[#]] [[#]] [[#ConstInt2]] [[#SCPrivate]] ; CHECK-SPIRV: AtomicLoad [[#]] [[#]] [[#]] [[#ConstInt1]] [[#SCPrivate]] ; CHECK-SPIRV: AtomicLoad [[#]] [[#]] [[#]] [[#ConstInt0]] [[#SCPrivate]] ; CHECK-SPIRV: AtomicLoad [[#]] [[#]] [[#]] [[#ConstInt3]] [[#SCPrivate]] ; CHECK-LLVM: call spir_func i32 @_Z20atomic_load_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr{{.*}}, i32 5, i32 1) ; CHECK-LLVM: call spir_func i32 @_Z20atomic_load_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr{{.*}}, i32 5, i32 2) ; CHECK-LLVM: call spir_func i32 @_Z20atomic_load_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr{{.*}}, i32 5, i32 3) ; CHECK-LLVM: call spir_func i32 @_Z20atomic_load_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr{{.*}}, i32 5, i32 4) define dso_local void @fi1(ptr addrspace(4) captures(none) noundef readonly %i) local_unnamed_addr #0 { entry: %0 = load atomic i32, ptr addrspace(4) %i syncscope("workgroup") seq_cst, align 4 %1 = load atomic i32, ptr addrspace(4) %i syncscope("device") seq_cst, align 4 %2 = load atomic i32, ptr addrspace(4) %i seq_cst, align 4 %3 = load atomic i32, ptr addrspace(4) %i syncscope("subgroup") seq_cst, align 4 ret void } ; AtomicStore PtrId MemScopeId MemSemanticsId ValueId ; Plain LLVM IR store atomic instructions don't get storage class bits ; CHECK-SPIRV: AtomicStore [[#]] [[#ConstInt3]] [[#SCPrivate]] [[#ConstInt1]] ; CHECK-SPIRV: AtomicStore [[#]] [[#ConstInt2]] [[#SCPrivate]] [[#ConstInt1]] ; CHECK-LLVM: call spir_func void @_Z21atomic_store_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(ptr{{.*}}, i32 5, i32 4) ; CHECK-LLVM: call spir_func void @_Z21atomic_store_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(ptr{{.*}}, i32 5, i32 1) define dso_local void @test_addr(ptr addrspace(1) captures(none) noundef writeonly %ig, ptr addrspace(3) captures(none) noundef writeonly %il) local_unnamed_addr #0 { entry: store atomic i32 1, ptr addrspace(1) %ig syncscope("subgroup") seq_cst, align 4 store atomic i32 1, ptr addrspace(3) %il syncscope("workgroup") seq_cst, align 4 ret void } ; Atomic* ResTypeId ResId PtrId MemScopeId MemSemanticsId ValueId ; CHECK-SPIRV: AtomicAnd [[#]] [[#]] [[#]] [[#ConstInt4]] [[#SCPrivate]] [[#ConstInt1]] ; CHECK-SPIRV: AtomicSMin [[#]] [[#]] [[#]] [[#ConstInt0]] [[#SCPrivate]] [[#ConstInt1]] ; CHECK-SPIRV: AtomicSMax [[#]] [[#]] [[#]] [[#ConstInt0]] [[#SCPrivate]] [[#ConstInt1]] ; CHECK-SPIRV: AtomicUMin [[#]] [[#]] [[#]] [[#ConstInt2]] [[#SCPrivate]] [[#ConstInt1]] ; CHECK-SPIRV: AtomicUMax [[#]] [[#]] [[#]] [[#ConstInt2]] [[#SCPrivate]] [[#ConstInt1]] ; CHECK-LLVM: call spir_func i32 @_Z25atomic_fetch_and_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(ptr{{.*}}, i32 1, i32 5, i32 0) ; CHECK-LLVM: call spir_func i32 @_Z25atomic_fetch_min_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(ptr{{.*}}, i32 1, i32 5, i32 3) ; CHECK-LLVM: call spir_func i32 @_Z25atomic_fetch_max_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(ptr{{.*}}, i32 1, i32 5, i32 3) ; CHECK-LLVM: call spir_func i32 @_Z25atomic_fetch_min_explicitPU3AS4VU7_Atomicjj12memory_order12memory_scope(ptr{{.*}}, i32 1, i32 5, i32 1) ; CHECK-LLVM: call spir_func i32 @_Z25atomic_fetch_max_explicitPU3AS4VU7_Atomicjj12memory_order12memory_scope(ptr{{.*}}, i32 1, i32 5, i32 1) define dso_local void @fi3(ptr captures(none) noundef %i, ptr captures(none) noundef %ui) local_unnamed_addr #0 { entry: %0 = atomicrmw and ptr %i, i32 1 syncscope("singlethread") seq_cst, align 4 %1 = atomicrmw min ptr %i, i32 1 seq_cst, align 4 %2 = atomicrmw max ptr %i, i32 1 syncscope("wrong_scope") seq_cst, align 4 %3 = atomicrmw umin ptr %ui, i32 1 syncscope("workgroup") seq_cst, align 4 %4 = atomicrmw umax ptr %ui, i32 1 syncscope("workgroup") seq_cst, align 4 ret void } ; AtomicCompareExchange ResTypeId ResId PtrId MemScopeId MemSemEqualId MemSemUnequalId ValueId ComparatorId ; CHECK-SPIRV: AtomicCompareExchange [[#]] [[#]] [[#]] [[#ConstInt2]] [[#ConstInt2]] [[#ConstInt2]] [[#ConstInt1]] [[#ConstInt0]] ; CHECK-LLVM: call spir_func i1 @_Z39atomic_compare_exchange_strong_explicitPU3AS4VU7_AtomiciPU3AS4ii12memory_orderS4_12memory_scope(ptr{{.*}}, ptr{{.*}}, i32 1, i32 2, i32 2, i32 1) define dso_local zeroext i1 @fi4(ptr captures(none) noundef %i) local_unnamed_addr #0 { entry: %0 = cmpxchg ptr %i, i32 0, i32 1 syncscope("workgroup") acquire acquire, align 4 %1 = extractvalue { i32, i1 } %0, 1 ret i1 %1 } ; AtomicExchange ResTypeId ResId PtrId MemScopeId MemSemanticsId ValueId ; CHECK-SPIRV: AtomicExchange [[#]] [[#]] [[#]] [[#ConstInt2]] [[#SCPrivate]] [[#Const2Power30]] ; CHECK-LLVM: call spir_func i32 @_Z24atomic_exchange_explicitPU3AS4VU7_Atomicii12memory_order12memory_scope(ptr{{.*}}, i32 1073741824, i32 5, i32 1) define dso_local float @ff3(ptr captures(none) noundef %d) local_unnamed_addr #0 { entry: %0 = atomicrmw xchg ptr %d, i32 1073741824 syncscope("workgroup") seq_cst, align 4 %1 = bitcast i32 %0 to float ret float %1 } ; AtomicFAddEXT ResTypeId ResId PtrId MemScopeId MemSemanticsId ValueId ; Plain LLVM atomicrmw fadd doesn't get storage class bits ; CHECK-SPIRV: AtomicFAddEXT [[#]] [[#]] [[#]] [[#ConstInt2]] [[#ConstInt0]] [[#]] ; CHECK-LLVM: call spir_func float @_Z25atomic_fetch_add_explicitPU3AS4VU7_Atomicff12memory_order12memory_scope(ptr{{.*}}, i32 0, i32 1) define dso_local float @ff4(ptr addrspace(1) captures(none) noundef %d, float noundef %a) local_unnamed_addr #0 { entry: %0 = atomicrmw fadd ptr addrspace(1) %d, float %a syncscope("workgroup") monotonic, align 4 ret float %0 } ; ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) ; define dso_local void @atomic_init_foo() local_unnamed_addr #1 { ; entry: ; store i32 42, ptr addrspace(1) @j, align 4 ; ret void ; } ; Store PtrId ObjId MemOps+ ; CHECK-SPIRV: Store [[#]] [[#ConstInt42]] ; CHECK-LLVM: store i32 42, ptr addrspace(1) @j define dso_local void @atomic_init_foo() local_unnamed_addr #1 { entry: tail call spir_func void @_Z11atomic_initPU3AS4VU7_Atomicff(ptr addrspace(1) @j, i32 42) ret void } ; Function Attrs: convergent declare spir_func void @_Z11atomic_initPU3AS4VU7_Atomicff(ptr addrspace(1), i32) local_unnamed_addr attributes #0 = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) "no-trapping-math"="true" "stack-protector-buffer-size"="8" } attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) "no-trapping-math"="true" "stack-protector-buffer-size"="8" } attributes #2 = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) "no-trapping-math"="true" "stack-protector-buffer-size"="8" } !llvm.module.flags = !{!1} !opencl.ocl.version = !{!2} !llvm.ident = !{!3} !1 = !{i32 1, !"wchar_size", i32 4} !2 = !{i32 2, i32 0} !3 = !{!"clang version 18.0.0 (https://github.com/llvm/llvm-project.git 7ce613fc77af092dd6e9db71ce3747b75bc5616e)"} !4 = !{!5, !5, i64 0} !5 = !{!"omnipotent char", !6, i64 0} !6 = !{!"Simple C/C++ TBAA"}