1; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s 2; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} 3 4; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s 5; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} 6 7; CHECK-DAG: OpName [[ADD:%.*]] "test_add" 8; CHECK-DAG: OpName [[SUB:%.*]] "test_sub" 9; CHECK-DAG: OpName [[MIN:%.*]] "test_min" 10; CHECK-DAG: OpName [[MAX:%.*]] "test_max" 11; CHECK-DAG: OpName [[UMIN:%.*]] "test_umin" 12; CHECK-DAG: OpName [[UMAX:%.*]] "test_umax" 13; CHECK-DAG: OpName [[AND:%.*]] "test_and" 14; CHECK-DAG: OpName [[OR:%.*]] "test_or" 15; CHECK-DAG: OpName [[XOR:%.*]] "test_xor" 16 17; CHECK-DAG: [[I32Ty:%.*]] = OpTypeInt 32 0 18; CHECK-DAG: [[PtrI32Ty:%.*]] = OpTypePointer Function [[I32Ty]] 19; CHECK-DAG: [[I64Ty:%.*]] = OpTypeInt 64 0 20; CHECK-DAG: [[PtrI64Ty:%.*]] = OpTypePointer Generic [[I64Ty]] 21; CHECK-DAG: [[CROSSDEVICESCOPE:%.*]] = OpConstantNull [[I32Ty]] 22; CHECK-DAG: [[DEVICESCOPE:%.*]] = OpConstant [[I32Ty]] 1 23;; "monotonic" maps to the relaxed memory semantics, encoded with constant 0 24 25; CHECK: [[ADD]] = OpFunction [[I32Ty]] 26; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 27; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 28; CHECK-NEXT: OpLabel 29; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 30; CHECK-NEXT: OpReturnValue [[R]] 31; CHECK-NEXT: OpFunctionEnd 32define i32 @test_add(i32* %ptr, i32 %val) { 33 %r = atomicrmw add i32* %ptr, i32 %val monotonic 34 ret i32 %r 35} 36 37; CHECK: [[SUB]] = OpFunction [[I32Ty]] 38; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 39; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 40; CHECK-NEXT: OpLabel 41; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 42; CHECK-NEXT: OpReturnValue [[R]] 43; CHECK-NEXT: OpFunctionEnd 44define i32 @test_sub(i32* %ptr, i32 %val) { 45 %r = atomicrmw sub i32* %ptr, i32 %val monotonic 46 ret i32 %r 47} 48 49; CHECK: [[MIN]] = OpFunction [[I32Ty]] 50; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 51; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 52; CHECK-NEXT: OpLabel 53; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 54; CHECK-NEXT: OpReturnValue [[R]] 55; CHECK-NEXT: OpFunctionEnd 56define i32 @test_min(i32* %ptr, i32 %val) { 57 %r = atomicrmw min i32* %ptr, i32 %val monotonic 58 ret i32 %r 59} 60 61; CHECK: [[MAX]] = OpFunction [[I32Ty]] 62; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 63; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 64; CHECK-NEXT: OpLabel 65; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 66; CHECK-NEXT: OpReturnValue [[R]] 67; CHECK-NEXT: OpFunctionEnd 68define i32 @test_max(i32* %ptr, i32 %val) { 69 %r = atomicrmw max i32* %ptr, i32 %val monotonic 70 ret i32 %r 71} 72 73; CHECK: [[UMIN]] = OpFunction [[I32Ty]] 74; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 75; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 76; CHECK-NEXT: OpLabel 77; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 78; CHECK-NEXT: OpReturnValue [[R]] 79; CHECK-NEXT: OpFunctionEnd 80define i32 @test_umin(i32* %ptr, i32 %val) { 81 %r = atomicrmw umin i32* %ptr, i32 %val monotonic 82 ret i32 %r 83} 84 85; CHECK: [[UMAX]] = OpFunction [[I32Ty]] 86; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 87; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 88; CHECK-NEXT: OpLabel 89; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 90; CHECK-NEXT: OpReturnValue [[R]] 91; CHECK-NEXT: OpFunctionEnd 92define i32 @test_umax(i32* %ptr, i32 %val) { 93 %r = atomicrmw umax i32* %ptr, i32 %val monotonic 94 ret i32 %r 95} 96 97; CHECK: [[AND]] = OpFunction [[I32Ty]] 98; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 99; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 100; CHECK-NEXT: OpLabel 101; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 102; CHECK-NEXT: OpReturnValue [[R]] 103; CHECK-NEXT: OpFunctionEnd 104define i32 @test_and(i32* %ptr, i32 %val) { 105 %r = atomicrmw and i32* %ptr, i32 %val monotonic 106 ret i32 %r 107} 108 109; CHECK: [[OR]] = OpFunction [[I32Ty]] 110; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 111; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 112; CHECK-NEXT: OpLabel 113; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 114; CHECK-NEXT: OpReturnValue [[R]] 115; CHECK-NEXT: OpFunctionEnd 116define i32 @test_or(i32* %ptr, i32 %val) { 117 %r = atomicrmw or i32* %ptr, i32 %val monotonic 118 ret i32 %r 119} 120 121; CHECK: [[XOR]] = OpFunction [[I32Ty]] 122; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter [[PtrI32Ty]] 123; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter [[I32Ty]] 124; CHECK-NEXT: OpLabel 125; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[A]] [[CROSSDEVICESCOPE]] {{.+}} [[B]] 126; CHECK-NEXT: OpReturnValue [[R]] 127; CHECK-NEXT: OpFunctionEnd 128define i32 @test_xor(i32* %ptr, i32 %val) { 129 %r = atomicrmw xor i32* %ptr, i32 %val monotonic 130 ret i32 %r 131} 132 133; CHECK: OpFunction 134; CHECK-NEXT: [[Arg1:%.*]] = OpFunctionParameter [[PtrI64Ty]] 135; CHECK-NEXT: [[Arg2:%.*]] = OpFunctionParameter [[I64Ty]] 136; CHECK-NEXT: OpLabel 137; CHECK-NEXT: OpAtomicSMin [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]] 138; CHECK-NEXT: OpAtomicSMax [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]] 139; CHECK-NEXT: OpAtomicUMin [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]] 140; CHECK-NEXT: OpAtomicUMax [[I64Ty]] [[Arg1]] [[DEVICESCOPE]] {{.+}} [[Arg2]] 141; CHECK-NEXT: OpReturn 142; CHECK-NEXT: OpFunctionEnd 143define dso_local spir_kernel void @test_wrappers(ptr addrspace(4) %arg, i64 %val) { 144 %r1 = call spir_func i64 @__spirv_AtomicSMin(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val) 145 %r2 = call spir_func i64 @__spirv_AtomicSMax(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val) 146 %r3 = call spir_func i64 @__spirv_AtomicUMin(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val) 147 %r4 = call spir_func i64 @__spirv_AtomicUMax(ptr addrspace(4) %arg, i32 1, i32 0, i64 %val) 148 ret void 149} 150 151declare dso_local spir_func i64 @__spirv_AtomicSMin(ptr addrspace(4), i32, i32, i64) 152declare dso_local spir_func i64 @__spirv_AtomicSMax(ptr addrspace(4), i32, i32, i64) 153declare dso_local spir_func i64 @__spirv_AtomicUMin(ptr addrspace(4), i32, i32, i64) 154declare dso_local spir_func i64 @__spirv_AtomicUMax(ptr addrspace(4), i32, i32, i64) 155