1; RUN: opt -S -dxil-op-lower %s | FileCheck %s 2 3target triple = "dxil-pc-shadermodel6.6-compute" 4 5declare void @scalar_user(float) 6declare void @vector_user(<4 x float>) 7declare void @check_user(i1) 8 9define void @loadv4f32() { 10 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 11 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 12 %buffer = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0) 13 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_0_0_0( 14 i32 0, i32 0, i32 1, i32 0, i1 false) 15 16 ; The temporary casts should all have been cleaned up 17 ; CHECK-NOT: %dx.resource.casthandle 18 19 ; CHECK: [[DATA0:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle [[HANDLE]], i32 0, i32 undef) #[[#ATTR:]] 20 %load0 = call {<4 x float>, i1} @llvm.dx.resource.load.typedbuffer( 21 target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 0) 22 %data0 = extractvalue {<4 x float>, i1} %load0, 0 23 24 ; The extract order depends on the users, so don't enforce that here. 25 ; CHECK-DAG: [[VAL0_0:%.*]] = extractvalue %dx.types.ResRet.f32 [[DATA0]], 0 26 %data0_0 = extractelement <4 x float> %data0, i32 0 27 ; CHECK-DAG: [[VAL0_2:%.*]] = extractvalue %dx.types.ResRet.f32 [[DATA0]], 2 28 %data0_2 = extractelement <4 x float> %data0, i32 2 29 30 ; If all of the uses are extracts, we skip creating a vector 31 ; CHECK-NOT: insertelement 32 ; CHECK-DAG: call void @scalar_user(float [[VAL0_0]]) 33 ; CHECK-DAG: call void @scalar_user(float [[VAL0_2]]) 34 call void @scalar_user(float %data0_0) 35 call void @scalar_user(float %data0_2) 36 37 ; CHECK: [[DATA4:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle [[HANDLE]], i32 4, i32 undef) #[[#ATTR]] 38 %load4 = call {<4 x float>, i1} @llvm.dx.resource.load.typedbuffer( 39 target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 4) 40 %data4 = extractvalue {<4 x float>, i1} %load4, 0 41 42 ; CHECK: extractvalue %dx.types.ResRet.f32 [[DATA4]], 0 43 ; CHECK: extractvalue %dx.types.ResRet.f32 [[DATA4]], 1 44 ; CHECK: extractvalue %dx.types.ResRet.f32 [[DATA4]], 2 45 ; CHECK: extractvalue %dx.types.ResRet.f32 [[DATA4]], 3 46 ; CHECK: insertelement <4 x float> undef 47 ; CHECK: insertelement <4 x float> 48 ; CHECK: insertelement <4 x float> 49 ; CHECK: insertelement <4 x float> 50 call void @vector_user(<4 x float> %data4) 51 52 ; CHECK: [[DATA12:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle [[HANDLE]], i32 12, i32 undef) #[[#ATTR]] 53 %load12 = call {<4 x float>, i1} @llvm.dx.resource.load.typedbuffer( 54 target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 12) 55 %data12 = extractvalue {<4 x float>, i1} %load12, 0 56 57 ; CHECK: [[DATA12_3:%.*]] = extractvalue %dx.types.ResRet.f32 [[DATA12]], 3 58 %data12_3 = extractelement <4 x float> %data12, i32 3 59 60 ; If there are a mix of users we need the vector, but extracts are direct 61 ; CHECK: call void @scalar_user(float [[DATA12_3]]) 62 call void @scalar_user(float %data12_3) 63 call void @vector_user(<4 x float> %data12) 64 65 ret void 66} 67 68define void @index_dynamic(i32 %bufindex, i32 %elemindex) { 69 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 70 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 71 %buffer = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0) 72 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_0_0_0( 73 i32 0, i32 0, i32 1, i32 0, i1 false) 74 75 ; CHECK: [[LOAD:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle [[HANDLE]], i32 %bufindex, i32 undef) #[[#ATTR]] 76 %load = call {<4 x float>, i1} @llvm.dx.resource.load.typedbuffer( 77 target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 %bufindex) 78 %data = extractvalue {<4 x float>, i1} %load, 0 79 80 ; CHECK: [[ALLOCA:%.*]] = alloca [4 x float] 81 ; CHECK: [[V0:%.*]] = extractvalue %dx.types.ResRet.f32 [[LOAD]], 0 82 ; CHECK: [[A0:%.*]] = getelementptr inbounds [4 x float], ptr [[ALLOCA]], i32 0, i32 0 83 ; CHECK: store float [[V0]], ptr [[A0]] 84 ; CHECK: [[V1:%.*]] = extractvalue %dx.types.ResRet.f32 [[LOAD]], 1 85 ; CHECK: [[A1:%.*]] = getelementptr inbounds [4 x float], ptr [[ALLOCA]], i32 0, i32 1 86 ; CHECK: store float [[V1]], ptr [[A1]] 87 ; CHECK: [[V2:%.*]] = extractvalue %dx.types.ResRet.f32 [[LOAD]], 2 88 ; CHECK: [[A2:%.*]] = getelementptr inbounds [4 x float], ptr [[ALLOCA]], i32 0, i32 2 89 ; CHECK: store float [[V2]], ptr [[A2]] 90 ; CHECK: [[V3:%.*]] = extractvalue %dx.types.ResRet.f32 [[LOAD]], 3 91 ; CHECK: [[A3:%.*]] = getelementptr inbounds [4 x float], ptr [[ALLOCA]], i32 0, i32 3 92 ; CHECK: store float [[V3]], ptr [[A3]] 93 ; 94 ; CHECK: [[PTR:%.*]] = getelementptr inbounds [4 x float], ptr [[ALLOCA]], i32 0, i32 %elemindex 95 ; CHECK: [[X:%.*]] = load float, ptr [[PTR]] 96 %x = extractelement <4 x float> %data, i32 %elemindex 97 98 ; CHECK: call void @scalar_user(float [[X]]) 99 call void @scalar_user(float %x) 100 101 ret void 102} 103 104define void @loadf32() { 105 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 106 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 107 %buffer = call target("dx.TypedBuffer", float, 0, 0, 0) 108 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_0_0_0( 109 i32 0, i32 0, i32 1, i32 0, i1 false) 110 111 ; CHECK: [[DATA0:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle [[HANDLE]], i32 0, i32 undef) #[[#ATTR]] 112 %load0 = call {float, i1} @llvm.dx.resource.load.typedbuffer( 113 target("dx.TypedBuffer", float, 0, 0, 0) %buffer, i32 0) 114 %data0 = extractvalue {float, i1} %load0, 0 115 116 ; CHECK: [[VAL0:%.*]] = extractvalue %dx.types.ResRet.f32 [[DATA0]], 0 117 ; CHECK: call void @scalar_user(float [[VAL0]]) 118 call void @scalar_user(float %data0) 119 120 ret void 121} 122 123define void @loadv2f32() { 124 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 125 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 126 %buffer = call target("dx.TypedBuffer", <2 x float>, 0, 0, 0) 127 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v2f32_0_0_0( 128 i32 0, i32 0, i32 1, i32 0, i1 false) 129 130 ; CHECK: [[DATA0:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle [[HANDLE]], i32 0, i32 undef) #[[#ATTR]] 131 %data0 = call {<2 x float>, i1} @llvm.dx.resource.load.typedbuffer( 132 target("dx.TypedBuffer", <2 x float>, 0, 0, 0) %buffer, i32 0) 133 134 ret void 135} 136 137define void @loadv4f32_checkbit() { 138 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 139 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 140 %buffer = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0) 141 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_0_0_0( 142 i32 0, i32 0, i32 1, i32 0, i1 false) 143 144 ; CHECK: [[DATA0:%.*]] = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle [[HANDLE]], i32 0, i32 undef) #[[#ATTR]] 145 %data0 = call {<4 x float>, i1} @llvm.dx.resource.load.typedbuffer.f32( 146 target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %buffer, i32 0) 147 148 ; CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.f32 [[DATA0]], 4 149 ; CHECK: [[MAPPED:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) #[[#ATTR]] 150 %check = extractvalue {<4 x float>, i1} %data0, 1 151 152 ; CHECK: call void @check_user(i1 [[MAPPED]]) 153 call void @check_user(i1 %check) 154 155 ret void 156} 157 158define void @loadv4i32() { 159 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 160 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 161 %buffer = call target("dx.TypedBuffer", <4 x i32>, 0, 0, 0) 162 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4i32_0_0_0( 163 i32 0, i32 0, i32 1, i32 0, i1 false) 164 165 ; CHECK: [[DATA0:%.*]] = call %dx.types.ResRet.i32 @dx.op.bufferLoad.i32(i32 68, %dx.types.Handle [[HANDLE]], i32 0, i32 undef) #[[#ATTR]] 166 %data0 = call {<4 x i32>, i1} @llvm.dx.resource.load.typedbuffer( 167 target("dx.TypedBuffer", <4 x i32>, 0, 0, 0) %buffer, i32 0) 168 169 ret void 170} 171 172define void @loadv4f16() { 173 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 174 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 175 %buffer = call target("dx.TypedBuffer", <4 x half>, 0, 0, 0) 176 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f16_0_0_0( 177 i32 0, i32 0, i32 1, i32 0, i1 false) 178 179 ; CHECK: [[DATA0:%.*]] = call %dx.types.ResRet.f16 @dx.op.bufferLoad.f16(i32 68, %dx.types.Handle [[HANDLE]], i32 0, i32 undef) #[[#ATTR]] 180 %data0 = call {<4 x half>, i1} @llvm.dx.resource.load.typedbuffer( 181 target("dx.TypedBuffer", <4 x half>, 0, 0, 0) %buffer, i32 0) 182 183 ret void 184} 185 186define void @loadv4i16() { 187 ; CHECK: [[BIND:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, 188 ; CHECK: [[HANDLE:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BIND]] 189 %buffer = call target("dx.TypedBuffer", <4 x i16>, 0, 0, 0) 190 @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4i16_0_0_0( 191 i32 0, i32 0, i32 1, i32 0, i1 false) 192 193 ; CHECK: [[DATA0:%.*]] = call %dx.types.ResRet.i16 @dx.op.bufferLoad.i16(i32 68, %dx.types.Handle [[HANDLE]], i32 0, i32 undef) #[[#ATTR]] 194 %data0 = call {<4 x i16>, i1} @llvm.dx.resource.load.typedbuffer( 195 target("dx.TypedBuffer", <4 x i16>, 0, 0, 0) %buffer, i32 0) 196 197 ret void 198} 199 200; CHECK: attributes #[[#ATTR]] = {{{.*}} memory(read) {{.*}}} 201