329 lines · plain
1// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \2// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \3// RUN: -o - | FileCheck %s4 5// CHECK-LABEL: ToTwoInts6// CHECK: [[splat:%.*]] = insertelement <1 x i32> poison, i32 {{.*}}, i64 07// CHECK: [[vec2:%.*]] = shufflevector <1 x i32> [[splat]], <1 x i32> poison, <2 x i32> zeroinitializer8// CHECK: ret <2 x i32> [[vec2]]9int2 ToTwoInts(int V){10 return V.xx;11}12 13// CHECK-LABEL: ToFourFloats14// CHECK: [[splat:%.*]] = insertelement <1 x float> poison, float {{.*}}, i64 015// CHECK: [[vec4:%.*]] = shufflevector <1 x float> [[splat]], <1 x float> poison, <4 x i32> zeroinitializer16// ret <4 x float> [[vec4]]17float4 ToFourFloats(float V){18 return V.rrrr;19}20 21// CHECK-LABEL: ToFourBools22// CHECK: {{%.*}} = zext i1 {{.*}} to i3223// CHECK: [[splat:%.*]] = insertelement <1 x i32> poison, i32 {{.*}}, i64 024// CHECK-NEXT: [[vec4:%.*]] = shufflevector <1 x i32> [[splat]], <1 x i32> poison, <4 x i32> zeroinitializer25// CHECK-NEXT: [[vec2Ret:%.*]] = trunc <4 x i32> [[vec4]] to <4 x i1>26// CHECK-NEXT: ret <4 x i1> [[vec2Ret]]27bool4 ToFourBools(bool V) {28 return V.rrrr;29}30 31// CHECK-LABEL: FillOne32// CHECK: [[vec1Ptr:%.*]] = alloca <1 x i32>, align 433// CHECK: store <1 x i32> splat (i32 1), ptr [[vec1Ptr]], align 434// CHECK: [[vec1:%.*]] = load <1 x i32>, ptr [[vec1Ptr]], align 435// CHECK: [[vec2:%.*]] = shufflevector <1 x i32> [[vec1]], <1 x i32> poison, <2 x i32> zeroinitializer36// CHECK: ret <2 x i32> [[vec2]]37int2 FillOne(){38 return 1.xx;39}40 41// CHECK-LABEL: FillOneUnsigned42// CHECK: [[vec1Ptr:%.*]] = alloca <1 x i32>, align 443// CHECK: store <1 x i32> splat (i32 1), ptr [[vec1Ptr]], align 444// CHECK: [[vec1:%.*]] = load <1 x i32>, ptr [[vec1Ptr]], align 445// CHECK: [[vec3:%.*]] = shufflevector <1 x i32> [[vec1]], <1 x i32> poison, <3 x i32> zeroinitializer46// CHECK: ret <3 x i32> [[vec3]]47uint3 FillOneUnsigned(){48 return 1u.xxx;49}50 51// CHECK-LABEL: FillOneUnsignedLong52// CHECK: [[vec1Ptr:%.*]] = alloca <1 x i64>, align 853// CHECK: store <1 x i64> splat (i64 1), ptr [[vec1Ptr]], align 854// CHECK: [[vec1:%.*]] = load <1 x i64>, ptr [[vec1Ptr]], align 855// CHECK: [[vec4:%.*]] = shufflevector <1 x i64> [[vec1]], <1 x i64> poison, <4 x i32> zeroinitializer56// CHECK: ret <4 x i64> [[vec4]]57vector<uint64_t,4> FillOneUnsignedLong(){58 return 1ul.xxxx;59}60 61// CHECK-LABEL: FillTwoPointFive62// CHECK: [[vec1Ptr:%.*]] = alloca <1 x double>, align 863// CHECK: store <1 x double> splat (double 2.500000e+00), ptr [[vec1Ptr]], align 864// CHECK: [[vec1:%.*]] = load <1 x double>, ptr [[vec1Ptr]], align 865// CHECK: [[vec2:%.*]] = shufflevector <1 x double> [[vec1]], <1 x double> poison, <2 x i32> zeroinitializer66// CHECK: ret <2 x double> [[vec2]]67double2 FillTwoPointFive(){68 return 2.5l.rr;69}70 71// CHECK-LABEL: FillOneHalf72// CHECK: [[vec1Ptr:%.*]] = alloca <1 x double>, align 873// CHECK: store <1 x double> splat (double 5.000000e-01), ptr [[vec1Ptr]], align 874// CHECK: [[vec1:%.*]] = load <1 x double>, ptr [[vec1Ptr]], align 875// CHECK: [[vec3:%.*]] = shufflevector <1 x double> [[vec1]], <1 x double> poison, <3 x i32> zeroinitializer76// CHECK: ret <3 x double> [[vec3]]77double3 FillOneHalf(){78 return .5l.rrr;79}80 81// CHECK-LABEL: FillTwoPointFiveFloat82// CHECK: [[vec1Ptr:%.*]] = alloca <1 x float>, align 483// CHECK: store <1 x float> splat (float 2.500000e+00), ptr [[vec1Ptr]], align 484// CHECK: [[vec1:%.*]] = load <1 x float>, ptr [[vec1Ptr]], align 485// CHECK: [[vec4:%.*]] = shufflevector <1 x float> [[vec1]], <1 x float> poison, <4 x i32> zeroinitializer86// CHECK: ret <4 x float> [[vec4]]87float4 FillTwoPointFiveFloat(){88 return 2.5f.rrrr;89}90 91// The initial codegen for this case is correct but a bit odd. The IR optimizer92// cleans this up very nicely.93 94// CHECK-LABEL: FillOneHalfFloat95// CHECK: [[vec1Ptr:%.*]] = alloca <1 x float>, align 496// CHECK: store <1 x float> splat (float 5.000000e-01), ptr [[vec1Ptr]], align 497// CHECK: [[vec1:%.*]] = load <1 x float>, ptr [[vec1Ptr]], align 498// CHECK: [[el0:%.*]] = extractelement <1 x float> [[vec1]], i32 099// CHECK: [[vec1Splat:%.*]] = insertelement <1 x float> poison, float [[el0]], i64 0100// CHECK: [[vec1Ret:%.*]] = shufflevector <1 x float> [[vec1Splat]], <1 x float> poison, <1 x i32> zeroinitializer101// CHECK: ret <1 x float> [[vec1Ret]]102vector<float, 1> FillOneHalfFloat(){103 return .5f.r;104}105 106// CHECK-LABEL: FillTrue107// CHECK: [[Tmp:%.*]] = alloca <1 x i32>, align 4108// CHECK-NEXT: store <1 x i32> splat (i32 1), ptr [[Tmp]], align 4109// CHECK-NEXT: [[Vec1:%.*]] = load <1 x i32>, ptr [[Tmp]], align 4110// CHECK-NEXT: [[Vec2:%.*]] = shufflevector <1 x i32> [[Vec1]], <1 x i32> poison, <2 x i32> zeroinitializer111// CHECK-NEXT: [[Vec2Ret:%.*]] = trunc <2 x i32> [[Vec2]] to <2 x i1>112// CHECK-NEXT: ret <2 x i1> [[Vec2Ret]]113bool2 FillTrue() {114 return true.xx;115}116 117// The initial codegen for this case is correct but a bit odd. The IR optimizer118// cleans this up very nicely.119 120// CHECK-LABEL: HowManyFloats121// CHECK: [[VAddr:%.*]] = alloca float, align 4122// CHECK: [[vec2Ptr:%.*]] = alloca <2 x float>, align 8123// CHECK: [[VVal:%.*]] = load float, ptr [[VAddr]], align 4124// CHECK: [[splat:%.*]] = insertelement <1 x float> poison, float [[VVal]], i64 0125// CHECK: [[vec2:%.*]] = shufflevector <1 x float> [[splat]], <1 x float> poison, <2 x i32> zeroinitializer126// CHECK: store <2 x float> [[vec2]], ptr [[vec2Ptr]], align 8127// CHECK: [[vec2:%.*]] = load <2 x float>, ptr [[vec2Ptr]], align 8128// CHECK: [[vec2Res:%.*]] = shufflevector <2 x float> [[vec2]], <2 x float> poison, <2 x i32> zeroinitializer129// CHECK: ret <2 x float> [[vec2Res]]130float2 HowManyFloats(float V) {131 return V.rr.rr;132}133 134// CHECK-LABEL: HowManyBools135// CHECK: [[VAddr:%.*]] = alloca i32, align 4136// CHECK-NEXT: [[Vec2Ptr:%.*]] = alloca <2 x i32>, align 8137// CHECK-NEXT: [[Tmp:%.*]] = zext i1 {{.*}} to i32138// CHECK-NEXT: store i32 [[Tmp]], ptr [[VAddr]], align 4139// CHECK-NEXT: [[VVal:%.*]] = load i32, ptr [[VAddr]], align 4140// CHECK-NEXT: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[VVal]], i64 0141// CHECK-NEXT: [[Vec2:%.*]] = shufflevector <1 x i32> [[Splat]], <1 x i32> poison, <2 x i32> zeroinitializer142// CHECK-NEXT: [[Trunc:%.*]] = trunc <2 x i32> [[Vec2]] to <2 x i1>143// CHECK-NEXT: [[Ext:%.*]] = zext <2 x i1> [[Trunc]] to <2 x i32>144// CHECK-NEXT: store <2 x i32> [[Ext]], ptr [[Vec2Ptr]], align 8145// CHECK-NEXT: [[V2:%.*]] = load <2 x i32>, ptr [[Vec2Ptr]], align 8146// CHECK-NEXT: [[V3:%.*]] = shufflevector <2 x i32> [[V2]], <2 x i32> poison, <2 x i32> zeroinitializer147// CHECK-NEXT: [[LV1:%.*]] = trunc <2 x i32> [[V3]] to <2 x i1>148// CHECK-NEXT: ret <2 x i1> [[LV1]]149bool2 HowManyBools(bool V) {150 return V.rr.rr;151}152 153// This codegen is gnarly because `1.l` is a double, so this creates double154// vectors that need to be truncated down to floats. The optimizer cleans this155// up nicely too.156 157// CHECK-LABEL: AllRighty158// CHECK: [[Tmp:%.*]] = alloca <1 x double>, align 8159// CHECK: store <1 x double> splat (double 1.000000e+00), ptr [[Tmp]], align 8160// CHECK: [[vec1:%.*]] = load <1 x double>, ptr [[Tmp]], align 8161// CHECK: [[vec3:%.*]] = shufflevector <1 x double> [[vec1]], <1 x double> poison, <3 x i32> zeroinitializer162// CHECK: [[vec3f:%.*]] = fptrunc reassoc nnan ninf nsz arcp afn <3 x double> [[vec3]] to <3 x float>163// CHECK: ret <3 x float> [[vec3f]]164 165float3 AllRighty() {166 return 1.l.rrr;167}168 169// CHECK-LABEL: AllRighty2170// CHECK: [[vec1Ptr:%.*]] = alloca <1 x float>, align 4171// CHECK: store <1 x float> splat (float 1.000000e+00), ptr [[vec1Ptr]], align 4172// CHECK: [[vec1:%.*]] = load <1 x float>, ptr [[vec1Ptr]], align 4173// CHECK: [[vec3:%.*]] = shufflevector <1 x float> [[vec1]], <1 x float> poison, <3 x i32>174// CHECK: ret <3 x float> [[vec3]]175 176float3 AllRighty2() {177 return 1..rrr;178}179 180// CHECK-LABEL: AssignInt181// CHECK: [[VAddr:%.*]] = alloca i32, align 4182// CHECK: [[XAddr:%.*]] = alloca i32, align 4183 184// Load V into a vector, then extract V out and store it to X.185// CHECK: [[V:%.*]] = load i32, ptr [[VAddr]], align 4186// CHECK: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[V]], i64 0187// CHECK: [[VExtVal:%.*]] = extractelement <1 x i32> [[Splat]], i32 0188// CHECK: store i32 [[VExtVal]], ptr [[XAddr]], align 4189 190// Load V into two separate vectors, then add the extracted X components.191// CHECK: [[V:%.*]] = load i32, ptr [[VAddr]], align 4192// CHECK: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[V]], i64 0193// CHECK: [[LHS:%.*]] = extractelement <1 x i32> [[Splat]], i32 0194 195// CHECK: [[V:%.*]] = load i32, ptr [[VAddr]], align 4196// CHECK: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[V]], i64 0197// CHECK: [[RHS:%.*]] = extractelement <1 x i32> [[Splat]], i32 0198 199// CHECK: [[Sum:%.*]] = add nsw i32 [[LHS]], [[RHS]]200// CHECK: store i32 [[Sum]], ptr [[XAddr]], align 4201// CHECK: [[X:%.*]] = load i32, ptr [[XAddr]], align 4202// CHECK: ret i32 [[X]]203 204int AssignInt(int V){205 int X = V.x;206 X.x = V.x + V.x;207 return X;208}209 210// CHECK-LABEL: AssignBool211// CHECK: [[VAddr:%.*]] = alloca i32, align 4212// CHECK-NEXT: [[XAddr:%.*]] = alloca i32, align 4213// CHECK-NEXT: [[Zext:%.*]] = zext i1 %V to i32214// CHECK-NEXT: store i32 [[Zext]], ptr [[VAddr]], align 4215// CHECK-NEXT: [[X:%.*]] = load i32, ptr [[VAddr]], align 4216// CHECK-NEXT: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[X]], i64 0217// CHECK-NEXT: [[Y:%.*]] = extractelement <1 x i32> [[Splat]], i32 0218// CHECK-NEXT: [[Z:%.*]] = trunc i32 [[Y]] to i1219// CHECK-NEXT: [[A:%.*]] = zext i1 [[Z]] to i32220// CHECK-NEXT: store i32 [[A]], ptr [[XAddr]], align 4221// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[VAddr]], align 4222// CHECK-NEXT: [[Splat2:%.*]] = insertelement <1 x i32> poison, i32 [[B]], i64 0223// CHECK-NEXT: [[C:%.*]] = extractelement <1 x i32> [[Splat2]], i32 0224// CHECK-NEXT: [[D:%.*]] = trunc i32 [[C]] to i1225// CHECK-NEXT: br i1 [[D]], label %lor.end, label %lor.rhs226 227// CHECK: lor.rhs:228// CHECK-NEXT: [[E:%.*]] = load i32, ptr [[VAddr]], align 4229// CHECK-NEXT: [[Splat3:%.*]] = insertelement <1 x i32> poison, i32 [[E]], i64 0230// CHECK-NEXT: [[F:%.*]] = extractelement <1 x i32> [[Splat3]], i32 0231// CHECK-NEXT: [[G:%.*]] = trunc i32 [[F]] to i1232// CHECK-NEXT: br label %lor.end233 234// CHECK: lor.end:235// CHECK-NEXT: [[H:%.*]] = phi i1 [ true, %entry ], [ [[G]], %lor.rhs ]236// CHECK-NEXT: [[J:%.*]] = zext i1 %9 to i32237// CHECK-NEXT: store i32 [[J]], ptr [[XAddr]], align 4238// CHECK-NEXT: [[I:%.*]] = load i32, ptr [[XAddr]], align 4239// CHECK-NEXT: [[LoadV:%.*]] = trunc i32 [[I]] to i1240// CHECK-NEXT: ret i1 [[LoadV]]241bool AssignBool(bool V) {242 bool X = V.x;243 X.x = V.x || V.x;244 return X;245}246 247// CHECK-LABEL: AssignBool2248// CHECK: [[VAdddr:%.*]] = alloca i32, align 4249// CHECK-NEXT: [[X:%.*]] = alloca <2 x i32>, align 8250// CHECK-NEXT: [[Tmp:%.*]] = alloca <1 x i32>, align 4251// CHECK-NEXT: [[SV:%.*]] = zext i1 %V to i32252// CHECK-NEXT: store i32 [[SV]], ptr [[VAddr]], align 4253// CHECK-NEXT: store <1 x i32> splat (i32 1), ptr [[Tmp]], align 4254// CHECK-NEXT: [[Y:%.*]] = load <1 x i32>, ptr [[Tmp]], align 4255// CHECK-NEXT: [[Z:%.*]] = shufflevector <1 x i32> [[Y]], <1 x i32> poison, <2 x i32> zeroinitializer256// CHECK-NEXT: [[LV:%.*]] = trunc <2 x i32> [[Z]] to <2 x i1>257// CHECK-NEXT: [[A:%.*]] = zext <2 x i1> [[LV]] to <2 x i32>258// CHECK-NEXT: store <2 x i32> [[A]], ptr [[X]], align 8259// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[VAddr]], align 4260// CHECK-NEXT: [[LV1:%.*]] = trunc i32 [[B]] to i1261// CHECK-NEXT: [[D:%.*]] = zext i1 [[LV1]] to i32262// CHECK-NEXT: [[C:%.*]] = getelementptr <2 x i32>, ptr [[X]], i32 0, i32 1263// CHECK-NEXT: store i32 [[D]], ptr [[C]], align 4264// CHECK-NEXT: ret void265void AssignBool2(bool V) {266 bool2 X = true.xx;267 X.y = V;268}269 270// CHECK-LABEL: AssignBool3271// CHECK: [[VAddr:%.*]] = alloca <2 x i32>, align 8272// CHECK-NEXT: [[X:%.*]] = alloca <2 x i32>, align 8273// CHECK-NEXT: [[Y:%.*]] = zext <2 x i1> %V to <2 x i32>274// CHECK-NEXT: store <2 x i32> [[Y]], ptr [[VAddr]], align 8275// CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[X]], align 8276// CHECK-NEXT: [[Z:%.*]] = load <2 x i32>, ptr [[VAddr]], align 8277// CHECK-NEXT: [[LV:%.*]] = trunc <2 x i32> [[Z]] to <2 x i1>278// CHECK-NEXT: [[B:%.*]] = zext <2 x i1> [[LV]] to <2 x i32>279// CHECK-NEXT: [[V1:%.*]] = extractelement <2 x i32> [[B]], i32 0280// CHECK-NEXT: store i32 [[V1]], ptr [[X]], align 4281// CHECK-NEXT: [[V2:%.*]] = extractelement <2 x i32> [[B]], i32 1282// CHECK-NEXT: [[X2:%.*]] = getelementptr <2 x i32>, ptr [[X]], i32 0, i32 1283// CHECK-NEXT: store i32 [[V2]], ptr [[X2]], align 4284// CHECK-NEXT: ret void285 286void AssignBool3(bool2 V) {287 bool2 X = {true,true};288 X.xy = V;289}290 291// CHECK-LABEL: AccessBools292// CHECK: [[X:%.*]] = alloca <4 x i32>, align 16293// CHECK-NEXT: [[Tmp:%.*]] = alloca <1 x i32>, align 4294// CHECK-NEXT: store <1 x i32> splat (i32 1), ptr [[Tmp]], align 4295// CHECK-NEXT: [[Y:%.*]] = load <1 x i32>, ptr [[Tmp]], align 4296// CHECK-NEXT: [[Z:%.*]] = shufflevector <1 x i32> [[Y]], <1 x i32> poison, <4 x i32> zeroinitializer297// CHECK-NEXT: [[LV:%.*]] = trunc <4 x i32> [[Z]] to <4 x i1>298// CHECK-NEXT: [[A:%.*]] = zext <4 x i1> [[LV]] to <4 x i32>299// CHECK-NEXT: store <4 x i32> [[A]], ptr [[X]], align 16300// CHECK-NEXT: [[B:%.*]] = load <4 x i32>, ptr [[X]], align 16301// CHECK-NEXT: [[C:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> poison, <2 x i32> <i32 2, i32 3>302// CHECK-NEXT: [[LV1:%.*]] = trunc <2 x i32> [[C]] to <2 x i1>303// CHECK-NEXT: ret <2 x i1> [[LV1]]304bool2 AccessBools() {305 bool4 X = true.xxxx;306 return X.zw;307}308 309// CHECK-LABEL: define hidden void {{.*}}BoolSizeMismatch{{.*}}310// CHECK: [[B:%.*]] = alloca <4 x i32>, align 16311// CHECK-NEXT: [[Tmp:%.*]] = alloca <1 x i32>, align 4312// CHECK-NEXT: store <4 x i32> splat (i32 1), ptr [[B]], align 16313// CHECK-NEXT: store <1 x i32> zeroinitializer, ptr [[Tmp]], align 4314// CHECK-NEXT: [[L0:%.*]] = load <1 x i32>, ptr [[Tmp]], align 4315// CHECK-NEXT: [[L1:%.*]] = shufflevector <1 x i32> [[L0]], <1 x i32> poison, <3 x i32> zeroinitializer316// CHECK-NEXT: [[TruncV:%.*]] = trunc <3 x i32> [[L1]] to <3 x i1>317// CHECK-NEXT: [[L2:%.*]] = zext <3 x i1> [[TruncV]] to <3 x i32>318// CHECK-NEXT: [[V1:%.*]] = extractelement <3 x i32> [[L2]], i32 0319// CHECK-NEXT: store i32 [[V1]], ptr %B, align 4320// CHECK-NEXT: [[V2:%.*]] = extractelement <3 x i32> [[L2]], i32 1321// CHECK-NEXT: [[B2:%.*]] = getelementptr <4 x i32>, ptr %B, i32 0, i32 1322// CHECK-NEXT: store i32 [[V2]], ptr [[B2]], align 4323// CHECK-NEXT: [[V3:%.*]] = extractelement <3 x i32> [[L2]], i32 2324// CHECK-NEXT: [[B3:%.*]] = getelementptr <4 x i32>, ptr %B, i32 0, i32 2325void BoolSizeMismatch() {326 bool4 B = {true,true,true,true};327 B.xyz = false.xxx;328}329