1// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s --check-prefixes=CHECK,ALL 2// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -O3 -emit-llvm -finclude-default-header -o - %s | FileCheck %s --check-prefixes=OPT,ALL 3 4// Case 1: Simple floating integral conversion. 5// In this test case a float value is passed to an inout parameter taking an 6// integer. It is converted to an integer on call and converted back after the 7// function. 8 9// CHECK: define void {{.*}}trunc_Param{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) 10void trunc_Param(inout int X) {} 11 12// ALL-LABEL: define noundef nofpclass(nan inf) float {{.*}}case1 13// CHECK: [[F:%.*]] = alloca float 14// CHECK: [[ArgTmp:%.*]] = alloca i32 15// CHECK: [[FVal:%.*]] = load float, ptr {{.*}} 16// CHECK: [[IVal:%.*]] = fptosi float [[FVal]] to i32 17// CHECK: store i32 [[IVal]], ptr [[ArgTmp]] 18// CHECK: call void {{.*}}trunc_Param{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]]) 19// CHECK: [[IRet:%.*]] = load i32, ptr [[ArgTmp]] 20// CHECK: [[FRet:%.*]] = sitofp i32 [[IRet]] to float 21// CHECK: store float [[FRet]], ptr [[F]] 22// OPT: [[IVal:%.*]] = fptosi float {{.*}} to i32 23// OPT: [[FVal:%.*]] = sitofp i32 [[IVal]] to float 24// OPT: ret float [[FVal]] 25export float case1(float F) { 26 trunc_Param(F); 27 return F; 28} 29 30// Case 2: Uninitialized `out` parameters. 31// `out` parameters are not pre-initialized by the caller, so they are 32// uninitialized in the function. If they are not initialized before the 33// function returns the value is undefined. 34 35// CHECK: define void {{.*}}undef{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) 36void undef(out int Z) { } 37 38// ALL-LABEL: define noundef i32 {{.*}}case2 39// CHECK: [[V:%.*]] = alloca i32 40// CHECK: [[ArgTmp:%.*]] = alloca i32 41// CHECK-NOT: store {{.*}}, ptr [[ArgTmp]] 42// CHECK: call void {{.*}}unde{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]]) 43// CHECK-NOT: store {{.*}}, ptr [[ArgTmp]] 44// CHECK: [[Res:%.*]] = load i32, ptr [[ArgTmp]] 45// CHECK: store i32 [[Res]], ptr [[V]], align 4 46// OPT: ret i32 undef 47export int case2() { 48 int V; 49 undef(V); 50 return V; 51} 52 53// Case 3: Simple initialized `out` parameter. 54// This test should verify that an out parameter value is written to as 55// expected. 56 57// CHECK: define void {{.*}}zero{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) 58void zero(out int Z) { Z = 0; } 59 60// ALL-LABEL: define noundef i32 {{.*}}case3 61// CHECK: [[V:%.*]] = alloca i32 62// CHECK: [[ArgTmp:%.*]] = alloca i32 63// CHECK-NOT: store {{.*}}, ptr [[ArgTmp]] 64// CHECK: call void {{.*}}zero{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]]) 65// CHECK-NOT: store {{.*}}, ptr [[ArgTmp]] 66// CHECK: [[Res:%.*]] = load i32, ptr [[ArgTmp]] 67// CHECK: store i32 [[Res]], ptr [[V]], align 4 68// OPT: ret i32 0 69export int case3() { 70 int V; 71 zero(V); 72 return V; 73} 74 75// Case 4: Vector swizzle arguments. 76// Vector swizzles in HLSL produce lvalues, so they can be used as arguments to 77// inout parameters and the swizzle is reversed on writeback. 78 79// CHECK: define void {{.*}}funky{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}}) 80void funky(inout int3 X) { 81 X.x += 1; 82 X.y += 2; 83 X.z += 3; 84} 85 86// ALL-LABEL: define noundef {{.*}}<3 x i32> {{.*}}case4 87 88// This block initializes V = 0.xxx. 89// CHECK: [[V:%.*]] = alloca <3 x i32> 90// CHECK: [[ArgTmp:%.*]] = alloca <3 x i32> 91// CHECK: store <1 x i32> zeroinitializer, ptr [[ZeroPtr:%.*]] 92// CHECK: [[ZeroV1:%.*]] = load <1 x i32>, ptr [[ZeroPtr]] 93// CHECK: [[ZeroV3:%.*]] = shufflevector <1 x i32> [[ZeroV1]], <1 x i32> poison, <3 x i32> zeroinitializer 94// CHECK: store <3 x i32> [[ZeroV3]], ptr [[V]] 95 96// Shuffle the vector to the temporary. 97// CHECK: [[VVal:%.*]] = load <3 x i32>, ptr [[V]] 98// CHECK: [[Vyzx:%.*]] = shufflevector <3 x i32> [[VVal]], <3 x i32> poison, <3 x i32> <i32 1, i32 2, i32 0> 99// CHECK: store <3 x i32> [[Vyzx]], ptr [[ArgTmp]] 100 101// Call the function with the temporary. 102// CHECK: call void {{.*}}funky{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) [[ArgTmp]]) 103 104// Shuffle it back. 105// CHECK: [[RetVal:%.*]] = load <3 x i32>, ptr [[ArgTmp]] 106// CHECK: [[Vxyz:%.*]] = shufflevector <3 x i32> [[RetVal]], <3 x i32> poison, <3 x i32> <i32 2, i32 0, i32 1> 107// CHECK: store <3 x i32> [[Vxyz]], ptr [[V]] 108 109// OPT: ret <3 x i32> <i32 3, i32 1, i32 2> 110export int3 case4() { 111 int3 V = 0.xxx; 112 funky(V.yzx); 113 return V; 114} 115 116 117// Case 5: Straightforward inout of a scalar value. 118 119// CHECK: define void {{.*}}increment{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) {{%.*}}) 120void increment(inout int I) { 121 I += 1; 122} 123 124// ALL-LABEL: define noundef i32 {{.*}}case5 125 126// CHECK: [[I:%.*]] = alloca i32 127// CHECK: [[ArgTmp:%.*]] = alloca i32 128// CHECK: store i32 4, ptr [[I]] 129// CHECK: [[IInit:%.*]] = load i32, ptr [[I]] 130// CHECK: store i32 [[IInit:%.*]], ptr [[ArgTmp]], align 4 131// CHECK: call void {{.*}}increment{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[ArgTmp]]) 132// CHECK: [[RetVal:%.*]] = load i32, ptr [[ArgTmp]] 133// CHECK: store i32 [[RetVal]], ptr [[I]], align 4 134// OPT: ret i32 5 135export int case5() { 136 int I = 4; 137 increment(I); 138 return I; 139} 140 141// Case 6: Aggregate out parameters. 142struct S { 143 int X; 144 float Y; 145}; 146 147// CHECK: define void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) {{%.*}}) 148void init(out S s) { 149 s.X = 3; 150 s.Y = 4; 151} 152 153// ALL-LABEL: define noundef i32 {{.*}}case6 154 155// CHECK: [[S:%.*]] = alloca %struct.S 156// CHECK: [[Tmp:%.*]] = alloca %struct.S 157// CHECK: call void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) [[Tmp]]) 158// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[S]], ptr align 4 [[Tmp]], i32 8, i1 false) 159 160// OPT: ret i32 7 161export int case6() { 162 S s; 163 init(s); 164 return s.X + s.Y; 165} 166 167// Case 7: Aggregate inout parameters. 168struct R { 169 int X; 170 float Y; 171}; 172 173// CHECK: define void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) {{%.*}}) 174void init(inout R s) { 175 s.X = 3; 176 s.Y = 4; 177} 178 179// ALL-LABEL: define noundef i32 {{.*}}case7 180 181// CHECK: [[S:%.*]] = alloca %struct.R 182// CHECK: [[Tmp:%.*]] = alloca %struct.R 183// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[S]], i32 8, i1 false) 184// CHECK: call void {{.*}}init{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(8) [[Tmp]]) 185// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[S]], ptr align 4 [[Tmp]], i32 8, i1 false) 186 187// OPT: ret i32 7 188export int case7() { 189 R s; 190 init(s); 191 return s.X + s.Y; 192} 193 194 195// Case 8: Non-scalars with a cast expression. 196 197// CHECK: define void {{.*}}trunc_vec{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) {{%.*}}) 198void trunc_vec(inout int3 V) {} 199 200// ALL-LABEL: define noundef nofpclass(nan inf) <3 x float> {{.*}}case8 201 202// CHECK: [[V:%.*]] = alloca <3 x float> 203// CHECK: [[Tmp:%.*]] = alloca <3 x i32> 204// CHECK: [[FVal:%.*]] = load <3 x float>, ptr [[V]] 205// CHECK: [[IVal:%.*]] = fptosi <3 x float> [[FVal]] to <3 x i32> 206// CHECK: store <3 x i32> [[IVal]], ptr [[Tmp]] 207// CHECK: call void {{.*}}trunc_vec{{.*}}(ptr noalias noundef nonnull align 16 dereferenceable(16) [[Tmp]]) 208// CHECK: [[IRet:%.*]] = load <3 x i32>, ptr [[Tmp]] 209// CHECK: [[FRet:%.*]] = sitofp <3 x i32> [[IRet]] to <3 x float> 210// CHECK: store <3 x float> [[FRet]], ptr [[V]] 211 212// OPT: [[IVal:%.*]] = fptosi <3 x float> {{.*}} to <3 x i32> 213// OPT: [[FVal:%.*]] = sitofp <3 x i32> [[IVal]] to <3 x float> 214// OPT: ret <3 x float> [[FVal]] 215 216export float3 case8(float3 V) { 217 trunc_vec(V); 218 return V; 219} 220 221// Case 9: Side-effecting lvalue argument expression! 222 223void do_nothing(inout int V) {} 224 225// ALL-LABEL: define noundef i32 {{.*}}case9 226// CHECK: [[V:%.*]] = alloca i32 227// CHECK: [[Tmp:%.*]] = alloca i32 228// CHECK: store i32 0, ptr [[V]] 229// CHECK: [[VVal:%.*]] = load i32, ptr [[V]] 230// CHECK: [[VInc:%.*]] = add nsw i32 [[VVal]], 1 231// CHECK: store i32 [[VInc]], ptr [[V]] 232// CHECK: [[VArg:%.*]] = load i32, ptr [[V]] 233// CHECK-NOT: add 234// CHECK: store i32 [[VArg]], ptr [[Tmp]] 235// CHECK: call void {{.*}}do_nothing{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp]]) 236// CHECK: [[RetVal:%.*]] = load i32, ptr [[Tmp]] 237// CHECK: store i32 [[RetVal]], ptr [[V]] 238 239// OPT: ret i32 1 240export int case9() { 241 int V = 0; 242 do_nothing(++V); 243 return V; 244} 245 246// Case 10: Verify argument writeback ordering for aliasing arguments. 247 248void order_matters(inout int X, inout int Y) { 249 Y = 2; 250 X = 1; 251} 252 253// ALL-LABEL: define noundef i32 {{.*}}case10 254 255// CHECK: [[V:%.*]] = alloca i32 256// CHECK: [[Tmp0:%.*]] = alloca i32 257// CHECK: [[Tmp1:%.*]] = alloca i32 258// CHECK: store i32 0, ptr [[V]] 259// CHECK: [[VVal:%.*]] = load i32, ptr [[V]] 260// CHECK: store i32 [[VVal]], ptr [[Tmp0]] 261// CHECK: [[VVal:%.*]] = load i32, ptr [[V]] 262// CHECK: store i32 [[VVal]], ptr [[Tmp1]] 263// CHECK: call void {{.*}}order_matters{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp0]], ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp1]]) 264// CHECK: [[Arg1Val:%.*]] = load i32, ptr [[Tmp0]] 265// CHECK: store i32 [[Arg1Val]], ptr [[V]] 266// CHECK: [[Arg2Val:%.*]] = load i32, ptr [[Tmp1]] 267// CHECK: store i32 [[Arg2Val]], ptr [[V]] 268 269// OPT: ret i32 2 270export int case10() { 271 int V = 0; 272 order_matters(V, V); 273 return V; 274} 275 276// Case 11: Verify inout on bitfield lvalues 277 278struct B { 279 int X : 8; 280 int Y : 8; 281}; 282 283void setFour(inout int I) { 284 I = 4; 285} 286 287// ALL-LABEL: define {{.*}} i32 {{.*}}case11 288 289// CHECK: [[B:%.*]] = alloca %struct.B 290// CHECK: [[Tmp:%.*]] = alloca i32 291 292// CHECK: [[BFLoad:%.*]] = load i16, ptr [[B]] 293// CHECK: [[BFshl:%.*]] = shl i16 [[BFLoad]], 8 294// CHECK: [[BFashr:%.*]] = ashr i16 [[BFshl]], 8 295// CHECK: [[BFcast:%.*]] = sext i16 [[BFashr]] to i32 296// CHECK: store i32 [[BFcast]], ptr [[Tmp]] 297// CHECK: call void {{.*}}setFour{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp]]) 298// CHECK: [[RetVal:%.*]] = load i32, ptr [[Tmp]] 299// CHECK: [[TruncVal:%.*]] = trunc i32 [[RetVal]] to i16 300// CHECK: [[BFLoad:%.*]] = load i16, ptr [[B]] 301// CHECK: [[BFValue:%.*]] = and i16 [[TruncVal]], 255 302// CHECK: [[ZerodField:%.*]] = and i16 [[BFLoad]], -256 303// CHECK: [[BFSet:%.*]] = or i16 [[ZerodField]], [[BFValue]] 304// CHECK: store i16 [[BFSet]], ptr [[B]] 305 306// OPT: ret i32 8 307export int case11() { 308 B b = {1 , 2}; 309 setFour(b.X); 310 return b.X * b.Y; 311} 312 313// Case 12: Uninitialized out parameters are undefined 314 315void oops(out int X) {} 316// ALL-LABEL: define {{.*}} i32 {{.*}}case12 317 318// CHECK: [[V:%.*]] = alloca i32 319// CHECK: [[Tmp:%.*]] = alloca i32 320// CHECK-NOT: store {{.*}}, ptr [[Tmp]] 321// CHECK: call void {{.*}}oops{{.*}}(ptr noalias noundef nonnull align 4 dereferenceable(4) [[Tmp]]) 322// CHECK: [[ArgVal:%.*]] = load i32, ptr [[Tmp]] 323// CHECK: store i32 [[ArgVal]], ptr [[V]] 324 325// OPT: ret i32 undef 326export int case12() { 327 int V = 0; 328 oops(V); 329 return V; 330} 331