https://github.com/spall updated https://github.com/llvm/llvm-project/pull/123977
>From 50f8b16bf83d70cc37f2ac7e70c9195a4c4cda02 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Thu, 16 Jan 2025 01:32:25 +0000 Subject: [PATCH 01/10] wip --- clang/lib/CodeGen/CGExpr.cpp | 19 +++++++++++++++++++ clang/lib/CodeGen/CodeGenTypes.cpp | 6 ++++++ 2 files changed, 25 insertions(+) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 054f8d1eadb8c5..be8effb4dd40e7 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1986,6 +1986,10 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, if (const auto *ClangVecTy = Ty->getAs<VectorType>()) { // Boolean vectors use `iN` as storage type. if (ClangVecTy->isExtVectorBoolType()) { + if (getLangOpts().HLSL) { + llvm::Value *Value = Builder.CreateLoad(Addr, Volatile, "load_boolvec"); + return EmitFromMemory(Value, Ty); + } llvm::Type *ValTy = ConvertType(Ty); unsigned ValNumElems = cast<llvm::FixedVectorType>(ValTy)->getNumElements(); @@ -2064,6 +2068,9 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) { if (Ty->isExtVectorBoolType()) { llvm::Type *StoreTy = convertTypeForLoadStore(Ty, Value->getType()); + if (getLangOpts().HLSL) + return Builder.CreateZExt(Value, StoreTy); + // Expand to the memory bit width. unsigned MemNumElems = StoreTy->getPrimitiveSizeInBits(); // <N x i1> --> <P x i1>. @@ -2081,6 +2088,9 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) { llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { if (Ty->isExtVectorBoolType()) { const auto *RawIntTy = Value->getType(); + if (getLangOpts().HLSL) + return Builder.CreateTrunc(Value, ConvertType(Ty), "loadedv"); + // Bitcast iP --> <P x i1>. auto *PaddedVecTy = llvm::FixedVectorType::get( Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits()); @@ -2407,6 +2417,11 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, // Read/modify/write the vector, inserting the new element. llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddress(), Dst.isVolatileQualified()); + llvm::Type *OldVecTy = Vec->getType(); + if (getLangOpts().HLSL && Dst.getType()->isExtVectorBoolType()) + + Vec = Builder.CreateTrunc(Vec, ConvertType(Dst.getType()), "truncboolv"); + auto *IRStoreTy = dyn_cast<llvm::IntegerType>(Vec->getType()); if (IRStoreTy) { auto *IRVecTy = llvm::FixedVectorType::get( @@ -2420,6 +2435,10 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, // <N x i1> --> <iN>. Vec = Builder.CreateBitCast(Vec, IRStoreTy); } + + if (getLangOpts().HLSL && Dst.getType()->isExtVectorBoolType()) + Vec = Builder.CreateZExt(Vec, OldVecTy); + Builder.CreateStore(Vec, Dst.getVectorAddress(), Dst.isVolatileQualified()); return; diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 09191a4901f493..e7f280e3823a3f 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -112,6 +112,12 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { // Check for the boolean vector case. if (T->isExtVectorBoolType()) { auto *FixedVT = cast<llvm::FixedVectorType>(R); + + if (Context.getLangOpts().HLSL) { + llvm::Type *IRElemTy = ConvertTypeForMem(Context.BoolTy); + return llvm::FixedVectorType::get(IRElemTy, FixedVT->getNumElements()); + } + // Pad to at least one byte. uint64_t BytePadded = std::max<uint64_t>(FixedVT->getNumElements(), 8); return llvm::IntegerType::get(FixedVT->getContext(), BytePadded); >From b231f4e47ed263bf798455d8d303383caf1be635 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Thu, 16 Jan 2025 19:30:58 +0000 Subject: [PATCH 02/10] bool vector swizzle is allowed in hlsl --- clang/lib/Sema/SemaExprMember.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index d130e8b86bc56d..dcf7feab752b5e 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1697,7 +1697,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, QualType(), false); } - if (BaseType->isExtVectorBoolType()) { + if (BaseType->isExtVectorBoolType() && !S.Context.getLangOpts().HLSL) { // We disallow element access for ext_vector_type bool. There is no way to // materialize a reference to a vector element as a pointer (each element is // one bit in the vector). >From dd7e4595f47fb02fab4450e69a5ab07fd21f67d3 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Tue, 21 Jan 2025 16:50:33 +0000 Subject: [PATCH 03/10] swizzle tests for boolean vectors --- .../CodeGenHLSL/builtins/ScalarSwizzles.hlsl | 79 ++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl index 97711c9ee25a10..8e246959df94fe 100644 --- a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl @@ -11,13 +11,23 @@ int2 ToTwoInts(int V){ } // CHECK-LABEL: ToFourFloats -// [[splat:%.*]] = insertelement <1 x float> poison, float {{.*}}, i64 0 -// [[vec4:%.*]] = shufflevector <1 x float> [[splat]], <1 x float> poison, <4 x i32> zeroinitializer +// CHECK: [[splat:%.*]] = insertelement <1 x float> poison, float {{.*}}, i64 0 +// CHECK: [[vec4:%.*]] = shufflevector <1 x float> [[splat]], <1 x float> poison, <4 x i32> zeroinitializer // ret <4 x float> [[vec4]] float4 ToFourFloats(float V){ return V.rrrr; } +// CHECK-LABEL: ToFourBools +// CHECK: {{%.*}} = zext i1 {{.*}} to i32 +// CHECK: [[splat:%.*]] = insertelement <1 x i32> poison, i32 {{.*}}, i64 0 +// CHECK-NEXT: [[vec4:%.*]] = shufflevector <1 x i32> [[splat]], <1 x i32> poison, <4 x i32> zeroinitializer +// CHECK-NEXT: [[vec2Ret:%.*]] = trunc <4 x i32> [[vec4]] to <4 x i1> +// CHECK-NEXT: ret <4 x i1> [[vec2Ret]] +bool4 ToFourBools(bool V) { + return V.rrrr; +} + // CHECK-LABEL: FillOne // CHECK: [[vec1Ptr:%.*]] = alloca <1 x i32>, align 4 // CHECK: store <1 x i32> splat (i32 1), ptr [[vec1Ptr]], align 4 @@ -93,6 +103,17 @@ vector<float, 1> FillOneHalfFloat(){ return .5f.r; } +// CHECK-LABEL: FillTrue +// CHECK: [[Tmp:%.*]] = alloca <1 x i32>, align 1 +// CHECK-NEXT: store <1 x i1> splat (i1 true), ptr [[Tmp]], align 1 +// CHECK-NEXT: [[Vec1:%.*]] = load <1 x i32>, ptr [[Tmp]], align 1 +// CHECK-NEXT: [[Vec2:%.*]] = shufflevector <1 x i32> [[Vec1]], <1 x i32> poison, <2 x i32> zeroinitializer +// CHECK-NEXT: [[Vec2Ret:%.*]] = trunc <2 x i32> [[Vec2]] to <2 x i1> +// CHECK-NEXT: ret <2 x i1> [[Vec2Ret]] +bool2 FillTrue() { + return true.xx; +} + // The initial codegen for this case is correct but a bit odd. The IR optimizer // cleans this up very nicely. @@ -110,6 +131,24 @@ float2 HowManyFloats(float V) { return V.rr.rr; } +// CHECK-LABEL: HowManyBools +// CHECK: [[VAddr:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[Vec2Ptr:%.*]] = alloca <2 x i32>, align 1 +// CHECK-NEXT: [[Tmp:%.*]] = zext i1 {{.*}} to i32 +// CHECK-NEXT: store i32 [[Tmp]], ptr [[VAddr]], align 4 +// CHECK-NEXT: [[VVal:%.*]] = load i32, ptr [[VAddr]], align 4 +// CHECK-NEXT: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[VVal]], i64 0 +// CHECK-NEXT: [[Vec2:%.*]] = shufflevector <1 x i32> [[Splat]], <1 x i32> poison, <2 x i32> zeroinitializer +// CHECK-NEXT: [[Trunc:%.*]] = trunc <2 x i32> [[Vec2]] to <2 x i1> +// CHECK-NEXT: store <2 x i1> [[Trunc]], ptr [[Vec2Ptr]], align 1 +// CHECK-NEXT: [[V2:%.*]] = load <2 x i32>, ptr [[Vec2Ptr]], align 1 +// CHECK-NEXT: [[V3:%.*]] = shufflevector <2 x i32> [[V2]], <2 x i32> poison, <2 x i32> zeroinitializer +// CHECK-NEXT: [[LV1:%.*]] = trunc <2 x i32> [[V3]] to <2 x i1> +// CHECK-NEXT: ret <2 x i1> [[LV1]] +bool2 HowManyBools(bool V) { + return V.rr.rr; +} + // This codegen is gnarly because `1.l` is a double, so this creates double // vectors that need to be truncated down to floats. The optimizer cleans this // up nicely too. @@ -166,3 +205,39 @@ int AssignInt(int V){ X.x = V.x + V.x; return X; } + +// CHECK-LABEL: AssignBool +// CHECK: [[VAddr:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[XAddr:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[Zext:%.*]] = zext i1 %V to i32 +// CHECK-NEXT: store i32 [[Zext]], ptr [[VAddr]], align 4 +// CHECK-NEXT: [[X:%.*]] = load i32, ptr [[VAddr]], align 4 +// CHECK-NEXT: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[X]], i64 0 +// CHECK-NEXT: [[Y:%.*]] = extractelement <1 x i32> [[Splat]], i32 0 +// CHECK-NEXT: [[Z:%.*]] = trunc i32 [[Y]] to i1 +// CHECK-NEXT: [[A:%.*]] = zext i1 [[Z]] to i32 +// CHECK-NEXT: store i32 [[A]], ptr [[XAddr]], align 4 +// CHECK-NEXT: [[B:%.*]] = load i32, ptr [[VAddr]], align 4 +// CHECK-NEXT: [[Splat2:%.*]] = insertelement <1 x i32> poison, i32 [[B]], i64 0 +// CHECK-NEXT: [[C:%.*]] = extractelement <1 x i32> [[Splat2]], i32 0 +// CHECK-NEXT: [[D:%.*]] = trunc i32 [[C]] to i1 +// CHECK-NEXT: br i1 [[D]], label %lor.end, label %lor.rhs + +// CHECK: lor.rhs: +// CHECK-NEXT: [[E:%.*]] = load i32, ptr [[VAddr]], align 4 +// CHECK-NEXT: [[Splat3:%.*]] = insertelement <1 x i32> poison, i32 [[E]], i64 0 +// CHECK-NEXT: [[F:%.*]] = extractelement <1 x i32> [[Splat3]], i32 0 +// CHECK-NEXT: [[G:%.*]] = trunc i32 [[F]] to i1 +// CHECK-NEXT: br label %lor.end + +// CHECK: lor.end: +// CHECK-NEXT: [[H:%.*]] = phi i1 [ true, %entry ], [ [[G]], %lor.rhs ] +// CHECK-NEXT: store i1 [[H]], ptr [[XAddr]], align 4 +// CHECK-NEXT: [[I:%.*]] = load i32, ptr [[XAddr]], align 4 +// CHECK-NEXT: [[LoadV:%.*]] = trunc i32 [[I]] to i1 +// CHECK-NEXT: ret i1 [[LoadV]] +bool AssignBool(bool V) { + bool X = V.x; + X.x = V.x || V.x; + return X; +} >From 6734eedc466fc6202f7eb84484864d63dd0bb39d Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Tue, 21 Jan 2025 16:53:10 +0000 Subject: [PATCH 04/10] vector swizzle boolean vectors --- clang/lib/CodeGen/CGExpr.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index be8effb4dd40e7..331da27764df12 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2353,7 +2353,13 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { if (!ExprVT) { unsigned InIdx = getAccessedFieldNo(0, Elts); llvm::Value *Elt = llvm::ConstantInt::get(SizeTy, InIdx); - return RValue::get(Builder.CreateExtractElement(Vec, Elt)); + + llvm::Value *Element = Builder.CreateExtractElement(Vec, Elt); + + if (getLangOpts().HLSL && LV.getType()->isBooleanType()) + Element = Builder.CreateTrunc(Element, ConvertType(LV.getType())); + + return RValue::get(Element); } // Always use shuffle vector to try to retain the original program structure @@ -2364,6 +2370,10 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { Mask.push_back(getAccessedFieldNo(i, Elts)); Vec = Builder.CreateShuffleVector(Vec, Mask); + + if (getLangOpts().HLSL && LV.getType()->isExtVectorBoolType()) + Vec = EmitFromMemory(Vec, LV.getType()); + return RValue::get(Vec); } >From d9a4777cc755bdd9950e50f3f2bcf0a6f844a4a1 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Tue, 21 Jan 2025 18:17:07 +0000 Subject: [PATCH 05/10] fix test broken by changes --- .../standard_conversion_sequences.hlsl | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl index 1665a0260ab054..6770efefe94feb 100644 --- a/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl +++ b/clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl @@ -91,13 +91,12 @@ void l4_to_i2() { // CHECK-LABEL: i2_to_b2 // CHECK: [[l2:%.*]] = alloca <2 x i32> -// CHECK: [[b2:%.*]] = alloca i8 +// CHECK: [[b2:%.*]] = alloca <2 x i32> // CHECK: store <2 x i32> splat (i32 8), ptr [[i2]] // CHECK: [[veci2:%.*]] = load <2 x i32>, ptr [[i2]] // CHECK: [[vecb2:%.*]] = icmp ne <2 x i32> [[veci2]], zeroinitializer -// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecb2]], <2 x i1> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison> -// CHECK: [[i8:%.*]] = bitcast <8 x i1> [[vecb8]] to i8 -// CHECK: store i8 [[i8]], ptr [[b2]] +// CHECK: [[vecb8:%.*]] = zext <2 x i1> [[vecb2]] to <2 x i32> +// CHECK: store <2 x i32> [[vecb8]], ptr [[b2]] void i2_to_b2() { vector<int, 2> i2 = 8; vector<bool, 2> b2 = i2; @@ -105,14 +104,13 @@ void i2_to_b2() { // CHECK-LABEL: d4_to_b2 // CHECK: [[d4:%.*]] = alloca <4 x double> -// CHECK: [[b2:%.*]] = alloca i8 +// CHECK: [[b2:%.*]] = alloca <2 x i32> // CHECK: store <4 x double> splat (double 9.000000e+00), ptr [[d4]] // CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]] // CHECK: [[vecb4:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x double> [[vecd4]], zeroinitializer // CHECK: [[vecd2:%.*]] = shufflevector <4 x i1> [[vecb4]], <4 x i1> poison, <2 x i32> <i32 0, i32 1> -// CHECK: [[vecb8:%.*]] = shufflevector <2 x i1> [[vecd2]], <2 x i1> poison, <8 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison> -// CHECK: [[i8:%.*]] = bitcast <8 x i1> [[vecb8]] to i8 -// CHECK: store i8 [[i8]], ptr [[b2]] +// CHECK: [[vecb8:%.*]] = zext <2 x i1> [[vecd2]] to <2 x i32> +// CHECK: store <2 x i32> [[vecb8]], ptr [[b2]] void d4_to_b2() { vector<double,4> d4 = 9.0; vector<bool, 2> b2 = d4; >From e0638d10baadcf7793ed307a73e36f9159877c21 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Tue, 21 Jan 2025 18:18:59 +0000 Subject: [PATCH 06/10] actually make clang format happy --- clang/lib/CodeGen/CGExpr.cpp | 17 +++++++++-------- clang/lib/CodeGen/CodeGenTypes.cpp | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 331da27764df12..906876f1d878bd 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1987,8 +1987,8 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, // Boolean vectors use `iN` as storage type. if (ClangVecTy->isExtVectorBoolType()) { if (getLangOpts().HLSL) { - llvm::Value *Value = Builder.CreateLoad(Addr, Volatile, "load_boolvec"); - return EmitFromMemory(Value, Ty); + llvm::Value *Value = Builder.CreateLoad(Addr, Volatile, "load_boolvec"); + return EmitFromMemory(Value, Ty); } llvm::Type *ValTy = ConvertType(Ty); unsigned ValNumElems = @@ -2090,7 +2090,7 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { const auto *RawIntTy = Value->getType(); if (getLangOpts().HLSL) return Builder.CreateTrunc(Value, ConvertType(Ty), "loadedv"); - + // Bitcast iP --> <P x i1>. auto *PaddedVecTy = llvm::FixedVectorType::get( Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits()); @@ -2429,9 +2429,10 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, Dst.isVolatileQualified()); llvm::Type *OldVecTy = Vec->getType(); if (getLangOpts().HLSL && Dst.getType()->isExtVectorBoolType()) - - Vec = Builder.CreateTrunc(Vec, ConvertType(Dst.getType()), "truncboolv"); - + + Vec = + Builder.CreateTrunc(Vec, ConvertType(Dst.getType()), "truncboolv"); + auto *IRStoreTy = dyn_cast<llvm::IntegerType>(Vec->getType()); if (IRStoreTy) { auto *IRVecTy = llvm::FixedVectorType::get( @@ -2447,8 +2448,8 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, } if (getLangOpts().HLSL && Dst.getType()->isExtVectorBoolType()) - Vec = Builder.CreateZExt(Vec, OldVecTy); - + Vec = Builder.CreateZExt(Vec, OldVecTy); + Builder.CreateStore(Vec, Dst.getVectorAddress(), Dst.isVolatileQualified()); return; diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index e7f280e3823a3f..778161c6a5818e 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -112,12 +112,12 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { // Check for the boolean vector case. if (T->isExtVectorBoolType()) { auto *FixedVT = cast<llvm::FixedVectorType>(R); - + if (Context.getLangOpts().HLSL) { llvm::Type *IRElemTy = ConvertTypeForMem(Context.BoolTy); return llvm::FixedVectorType::get(IRElemTy, FixedVT->getNumElements()); } - + // Pad to at least one byte. uint64_t BytePadded = std::max<uint64_t>(FixedVT->getNumElements(), 8); return llvm::IntegerType::get(FixedVT->getContext(), BytePadded); >From 2e534a50c7059080b295a31d6cd8b4ac8072a688 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Wed, 22 Jan 2025 18:05:17 +0000 Subject: [PATCH 07/10] new test --- clang/test/CodeGenHLSL/BoolVector.hlsl | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 clang/test/CodeGenHLSL/BoolVector.hlsl diff --git a/clang/test/CodeGenHLSL/BoolVector.hlsl b/clang/test/CodeGenHLSL/BoolVector.hlsl new file mode 100644 index 00000000000000..16aa6c0e56cee4 --- /dev/null +++ b/clang/test/CodeGenHLSL/BoolVector.hlsl @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s + +// CHECK-LABEL: fn +// CHECK: [[B:%.*]] = alloca <2 x i32>, align 1 +// CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[B]], align 1 +// CHECK-NEXT: [[BoolVec:%.*]] = load <2 x i32>, ptr [[B]], align 1 +// CHECK-NEXT: [[L:%.*]] = trunc <2 x i32> [[BoolVec:%.*]] to <2 x i1> +// CHECK-NEXT: [[VecExt:%.*]] = extractelement <2 x i1> [[L]], i32 0 +// CHECK-NEXT: ret i1 [[VecExt]] +bool fn() { + bool2 B = {true,true}; + return B[0]; +} + +// CHECK-LABEL: fn2 +// CHECK: [[VAddr:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A:%.*]] = alloca <2 x i32>, align 1 +// CHECK-NEXT: [[StoreV:%.*]] = zext i1 {{.*}} to i32 +// CHECK-NEXT: store i32 [[StoreV]], ptr [[VAddr]], align 4 +// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[VAddr]], align 4 +// CHECK-NEXT: [[LoadV:%.*]] = trunc i32 [[L]] to i1 +// CHECK-NEXT: [[Vec:%.*]] = insertelement <2 x i1> poison, i1 [[LoadV]], i32 0 +// CHECK-NEXT: [[Vec1:%.*]] = insertelement <2 x i1> [[Vec]], i1 true, i32 1 +// CHECK-NEXT: [[Z:%.*]] = zext <2 x i1> [[Vec1]] to <2 x i32> +// CHECK-NEXT: store <2 x i32> [[Z]], ptr [[A]], align 1 +// CHECK-NEXT: [[LoadBV:%.*]] = load <2 x i32>, ptr [[A]], align 1 +// CHECK-NEXT: [[LoadV2:%.*]] = trunc <2 x i32> [[LoadBV]] to <2 x i1> +// CHECK-NEXT: ret <2 x i1> [[LoadV2]] +bool2 fn2(bool V) { + bool2 A = {V,true}; + return A; +} >From 793541d14300cdcedcebf4b18bd6e7373e1a2e70 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Fri, 31 Jan 2025 20:32:49 +0000 Subject: [PATCH 08/10] test with struct that contains bool vector. make sure bool vector in struct is a vector of i32. make sure constant struct has vector of i32 make clang format happy --- clang/lib/AST/ASTContext.cpp | 5 ++-- clang/lib/CodeGen/CGExprConstant.cpp | 9 ++++++ clang/test/CodeGenHLSL/BoolVector.hlsl | 38 ++++++++++++++++++++------ 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 155dbcfcaeed31..7aea590189766c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2016,8 +2016,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Vector: { const auto *VT = cast<VectorType>(T); TypeInfo EltInfo = getTypeInfo(VT->getElementType()); - Width = VT->isExtVectorBoolType() ? VT->getNumElements() - : EltInfo.Width * VT->getNumElements(); + Width = (VT->isExtVectorBoolType() && !getLangOpts().HLSL) + ? VT->getNumElements() + : EltInfo.Width * VT->getNumElements(); // Enforce at least byte size and alignment. Width = std::max<unsigned>(8, Width); Align = std::max<unsigned>(8, Width); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 655fc3dc954c81..afdc8c4a6cb985 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1984,6 +1984,15 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM, return Res; } + // In HLSL bool vectors are stored in memory as a vector of i32 + if (destType->isExtVectorBoolType() && CGM.getContext().getLangOpts().HLSL) { + llvm::Type *boolVecTy = CGM.getTypes().ConvertTypeForMem(destType); + llvm::Constant *Res = llvm::ConstantFoldCastOperand( + llvm::Instruction::ZExt, C, boolVecTy, CGM.getDataLayout()); + assert(Res && "Constant folding must succeed"); + return Res; + } + if (destType->isBitIntType()) { ConstantAggregateBuilder Builder(CGM); llvm::Type *LoadStoreTy = CGM.getTypes().convertTypeForLoadStore(destType); diff --git a/clang/test/CodeGenHLSL/BoolVector.hlsl b/clang/test/CodeGenHLSL/BoolVector.hlsl index 16aa6c0e56cee4..329f3c7e51b7a4 100644 --- a/clang/test/CodeGenHLSL/BoolVector.hlsl +++ b/clang/test/CodeGenHLSL/BoolVector.hlsl @@ -1,20 +1,27 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -// CHECK-LABEL: fn -// CHECK: [[B:%.*]] = alloca <2 x i32>, align 1 -// CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[B]], align 1 -// CHECK-NEXT: [[BoolVec:%.*]] = load <2 x i32>, ptr [[B]], align 1 +// CHECK: %struct.S = type { <2 x i32>, float } +// CHECK: [[ConstS:@.*]] = private unnamed_addr constant %struct.S { <2 x i32> splat (i32 1), float 1.000000e+00 }, align 8 +struct S { + bool2 bv; + float f; +}; + +// CHECK-LABEL: define noundef i1 {{.*}}fn1{{.*}} +// CHECK: [[B:%.*]] = alloca <2 x i32>, align 8 +// CHECK-NEXT: store <2 x i32> splat (i32 1), ptr [[B]], align 8 +// CHECK-NEXT: [[BoolVec:%.*]] = load <2 x i32>, ptr [[B]], align 8 // CHECK-NEXT: [[L:%.*]] = trunc <2 x i32> [[BoolVec:%.*]] to <2 x i1> // CHECK-NEXT: [[VecExt:%.*]] = extractelement <2 x i1> [[L]], i32 0 // CHECK-NEXT: ret i1 [[VecExt]] -bool fn() { +bool fn1() { bool2 B = {true,true}; return B[0]; } -// CHECK-LABEL: fn2 +// CHECK-LABEL: define noundef <2 x i1> {{.*}}fn2{{.*}} // CHECK: [[VAddr:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[A:%.*]] = alloca <2 x i32>, align 1 +// CHECK-NEXT: [[A:%.*]] = alloca <2 x i32>, align 8 // CHECK-NEXT: [[StoreV:%.*]] = zext i1 {{.*}} to i32 // CHECK-NEXT: store i32 [[StoreV]], ptr [[VAddr]], align 4 // CHECK-NEXT: [[L:%.*]] = load i32, ptr [[VAddr]], align 4 @@ -22,11 +29,24 @@ bool fn() { // CHECK-NEXT: [[Vec:%.*]] = insertelement <2 x i1> poison, i1 [[LoadV]], i32 0 // CHECK-NEXT: [[Vec1:%.*]] = insertelement <2 x i1> [[Vec]], i1 true, i32 1 // CHECK-NEXT: [[Z:%.*]] = zext <2 x i1> [[Vec1]] to <2 x i32> -// CHECK-NEXT: store <2 x i32> [[Z]], ptr [[A]], align 1 -// CHECK-NEXT: [[LoadBV:%.*]] = load <2 x i32>, ptr [[A]], align 1 +// CHECK-NEXT: store <2 x i32> [[Z]], ptr [[A]], align 8 +// CHECK-NEXT: [[LoadBV:%.*]] = load <2 x i32>, ptr [[A]], align 8 // CHECK-NEXT: [[LoadV2:%.*]] = trunc <2 x i32> [[LoadBV]] to <2 x i1> // CHECK-NEXT: ret <2 x i1> [[LoadV2]] bool2 fn2(bool V) { bool2 A = {V,true}; return A; } + +// CHECK-LABEL: define noundef i1 {{.*}}fn3{{.*}} +// CHECK: [[s:%.*]] = alloca %struct.S, align 8 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[s]], ptr align 8 [[ConstS]], i32 16, i1 false) +// CHECK-NEXT: [[BV:%.*]] = getelementptr inbounds nuw %struct.S, ptr [[s]], i32 0, i32 0 +// CHECK-NEXT: [[LBV:%.*]] = load <2 x i32>, ptr [[BV]], align 8 +// CHECK-NEXT: [[LV:%.*]] = trunc <2 x i32> [[LBV]] to <2 x i1> +// CHECK-NEXT: [[VX:%.*]] = extractelement <2 x i1> [[LV]], i32 0 +// CHECK-NEXT: ret i1 [[VX]] +bool fn3() { + S s = {{true,true}, 1.0}; + return s.bv[0]; +} >From 1fe0951164a4fbc50b99ee35dd4f37c59a6224db Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Fri, 31 Jan 2025 21:18:10 +0000 Subject: [PATCH 09/10] update test --- clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl index 8e246959df94fe..9c64ceb3089da5 100644 --- a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl @@ -104,9 +104,9 @@ vector<float, 1> FillOneHalfFloat(){ } // CHECK-LABEL: FillTrue -// CHECK: [[Tmp:%.*]] = alloca <1 x i32>, align 1 -// CHECK-NEXT: store <1 x i1> splat (i1 true), ptr [[Tmp]], align 1 -// CHECK-NEXT: [[Vec1:%.*]] = load <1 x i32>, ptr [[Tmp]], align 1 +// CHECK: [[Tmp:%.*]] = alloca <1 x i32>, align 4 +// CHECK-NEXT: store <1 x i1> splat (i1 true), ptr [[Tmp]], align 4 +// CHECK-NEXT: [[Vec1:%.*]] = load <1 x i32>, ptr [[Tmp]], align 4 // CHECK-NEXT: [[Vec2:%.*]] = shufflevector <1 x i32> [[Vec1]], <1 x i32> poison, <2 x i32> zeroinitializer // CHECK-NEXT: [[Vec2Ret:%.*]] = trunc <2 x i32> [[Vec2]] to <2 x i1> // CHECK-NEXT: ret <2 x i1> [[Vec2Ret]] @@ -133,15 +133,15 @@ float2 HowManyFloats(float V) { // CHECK-LABEL: HowManyBools // CHECK: [[VAddr:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[Vec2Ptr:%.*]] = alloca <2 x i32>, align 1 +// CHECK-NEXT: [[Vec2Ptr:%.*]] = alloca <2 x i32>, align 8 // CHECK-NEXT: [[Tmp:%.*]] = zext i1 {{.*}} to i32 // CHECK-NEXT: store i32 [[Tmp]], ptr [[VAddr]], align 4 // CHECK-NEXT: [[VVal:%.*]] = load i32, ptr [[VAddr]], align 4 // CHECK-NEXT: [[Splat:%.*]] = insertelement <1 x i32> poison, i32 [[VVal]], i64 0 // CHECK-NEXT: [[Vec2:%.*]] = shufflevector <1 x i32> [[Splat]], <1 x i32> poison, <2 x i32> zeroinitializer // CHECK-NEXT: [[Trunc:%.*]] = trunc <2 x i32> [[Vec2]] to <2 x i1> -// CHECK-NEXT: store <2 x i1> [[Trunc]], ptr [[Vec2Ptr]], align 1 -// CHECK-NEXT: [[V2:%.*]] = load <2 x i32>, ptr [[Vec2Ptr]], align 1 +// CHECK-NEXT: store <2 x i1> [[Trunc]], ptr [[Vec2Ptr]], align 8 +// CHECK-NEXT: [[V2:%.*]] = load <2 x i32>, ptr [[Vec2Ptr]], align 8 // CHECK-NEXT: [[V3:%.*]] = shufflevector <2 x i32> [[V2]], <2 x i32> poison, <2 x i32> zeroinitializer // CHECK-NEXT: [[LV1:%.*]] = trunc <2 x i32> [[V3]] to <2 x i1> // CHECK-NEXT: ret <2 x i1> [[LV1]] >From 505b17ba61867969bf3df3b47ed7db8a3f0c5d39 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Fri, 31 Jan 2025 23:37:55 +0000 Subject: [PATCH 10/10] test bool vector in array --- clang/test/CodeGenHLSL/BoolVector.hlsl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/clang/test/CodeGenHLSL/BoolVector.hlsl b/clang/test/CodeGenHLSL/BoolVector.hlsl index 329f3c7e51b7a4..ac2638963f70d4 100644 --- a/clang/test/CodeGenHLSL/BoolVector.hlsl +++ b/clang/test/CodeGenHLSL/BoolVector.hlsl @@ -2,6 +2,8 @@ // CHECK: %struct.S = type { <2 x i32>, float } // CHECK: [[ConstS:@.*]] = private unnamed_addr constant %struct.S { <2 x i32> splat (i32 1), float 1.000000e+00 }, align 8 +// CHECK: [[ConstArr:.*]] = private unnamed_addr constant [2 x <2 x i32>] [<2 x i32> splat (i32 1), <2 x i32> zeroinitializer], align 8 + struct S { bool2 bv; float f; @@ -50,3 +52,16 @@ bool fn3() { S s = {{true,true}, 1.0}; return s.bv[0]; } + +// CHECK-LABEL: define noundef i1 {{.*}}fn4{{.*}} +// CHECK: [[Arr:%.*]] = alloca [2 x <2 x i32>], align 8 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 8 [[Arr]], ptr align 8 [[ConstArr]], i32 16, i1 false) +// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x <2 x i32>], ptr [[Arr]], i32 0, i32 0 +// CHECK-NEXT: [[L:%.*]] = load <2 x i32>, ptr [[Idx]], align 8 +// CHECK-NEXT: [[LV:%.*]] = trunc <2 x i32> [[L]] to <2 x i1> +// CHECK-NEXT: [[VX:%.*]] = extractelement <2 x i1> [[LV]], i32 1 +// CHECK-NEXT: ret i1 [[VX]] +bool fn4() { + bool2 Arr[2] = {{true,true}, {false,false}}; + return Arr[0][1]; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits