https://github.com/spall updated https://github.com/llvm/llvm-project/pull/107129
>From 3e0cd3c450eb4aa28742c4879733987e9e2692e7 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Wed, 28 Aug 2024 01:44:35 +0000 Subject: [PATCH 1/7] implement select intrinsic --- clang/include/clang/Basic/Builtins.td | 6 ++ clang/lib/CodeGen/CGBuiltin.cpp | 41 ++++++++++++ clang/lib/Headers/hlsl/hlsl_intrinsics.h | 24 +++++++ clang/lib/Sema/SemaHLSL.cpp | 84 ++++++++++++++++++++++++ 4 files changed, 155 insertions(+) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 8668b25661dec8..7e89f84319877b 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4751,6 +4751,12 @@ def HLSLSaturate : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLSelect : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_select"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + // Builtins for XRay. def XRayCustomEvent : Builtin { let Spellings = ["__xray_customevent"]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e4d169d2ad6030..7fe198c207ce22 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18695,6 +18695,47 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { CGM.getHLSLRuntime().getSaturateIntrinsic(), ArrayRef<Value *>{Op0}, nullptr, "hlsl.saturate"); } + case Builtin::BI__builtin_hlsl_select: { + Value *OpCond = EmitScalarExpr(E->getArg(0)); + Value *OpTrue = EmitScalarExpr(E->getArg(1)); + Value *OpFalse = EmitScalarExpr(E->getArg(2)); + llvm::Type *TCond = OpCond->getType(); + + // if cond is a bool emit a select instruction + if (TCond->isIntegerTy(1)) + return Builder.CreateSelect(OpCond, OpTrue, OpFalse); + + // if cond is a vector of bools lower to a shufflevector + // todo check if that true and false are vectors + // todo check that the size of true and false and cond are the same + if (TCond->isVectorTy() && + E->getArg(0)->getType()->getAs<VectorType>()->isBooleanType()) { + assert(OpTrue->getType()->isVectorTy() && OpFalse->getType()->isVectorTy() && + "Select's second and third operands must be vectors if first operand is a vector."); + + auto *VecTyTrue = E->getArg(1)->getType()->getAs<VectorType>(); + auto *VecTyFalse = E->getArg(2)->getType()->getAs<VectorType>(); + + assert(VecTyTrue->getElementType() == VecTyFalse->getElementType() && + "Select's second and third vectors need the same element types."); + + const unsigned N = VecTyTrue->getNumElements(); + assert(N == VecTyFalse->getNumElements() && + N == E->getArg(0)->getType()->getAs<VectorType>()->getNumElements() && + "Select requires vectors to be of the same size."); + + llvm::SmallVector<Value *> Mask; + for (unsigned I = 0; I < N; I++) { + Value *Index = ConstantInt::get(IntTy, I); + Value *IndexBool = Builder.CreateExtractElement(OpCond, Index); + Mask.push_back(Builder.CreateSelect(IndexBool, Index, ConstantInt::get(IntTy, I + N))); + } + + return Builder.CreateShuffleVector(OpTrue, OpFalse, BuildVector(Mask)); + } + + llvm_unreachable("Select requires a bool or vector of bools as its first operand."); + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { return EmitRuntimeCall(CGM.CreateRuntimeFunction( llvm::FunctionType::get(IntTy, {}, false), "__hlsl_wave_get_lane_index", diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 6d38b668fe770e..4319d9775c4bae 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1603,6 +1603,30 @@ double3 saturate(double3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_saturate) double4 saturate(double4); +//===----------------------------------------------------------------------===// +// select builtins +//===----------------------------------------------------------------------===// + +/// \fn T select(bool Cond, T TrueVal, T FalseVal) +/// \brief ternary operator. +/// \param Cond The Condition input value. +/// \param TrueVal The Value returned if Cond is true. +/// \param FalseVal The Value returned if Cond is false. + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) +template<typename T> +T select(bool, T, T); + +/// \fn vector<T,Sz> select(vector<bool,Sz> Conds, vector<T,Sz> TrueVals, vector<T,Sz>, FalseVals) +/// \brief ternary operator for vectors. All vectors must be the same size. +/// \param Conds The Condition input values. +/// \param TrueVals The vector values are chosen from when conditions are true. +/// \param FalseVals The vector values are chosen from when conditions are false. + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) +template<typename T, int Sz> +vector<T,Sz> select(vector<bool,Sz>, vector<T,Sz>, vector<T,Sz>); + //===----------------------------------------------------------------------===// // sin builtins //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index fabc6f32906b10..0da1d91ab7aa6b 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1512,6 +1512,66 @@ void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, TheCall->setType(ReturnType); } +bool CheckBoolSelect(Sema *S, CallExpr *TheCall) { + assert(TheCall->getNumArgs() == 3); + Expr *Arg1 = TheCall->getArg(1); + Expr *Arg2 = TheCall->getArg(2); + if(!S->Context.hasSameUnqualifiedType(Arg1->getType(), + Arg2->getType())) { + S->Diag(TheCall->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << Arg1->getType() << Arg2->getType() + << Arg1->getSourceRange() << Arg2->getSourceRange(); + return true; + } + + TheCall->setType(Arg1->getType()); + return false; +} + +bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { + assert(TheCall->getNumArgs() == 3); + Expr *Arg1 = TheCall->getArg(1); + Expr *Arg2 = TheCall->getArg(2); + if(!Arg1->getType()->isVectorType()) { + S->Diag(Arg1->getBeginLoc(), + diag::err_builtin_non_vector_type) + << "Second" << "__builtin_hlsl_select" << Arg1->getType() + << Arg1->getSourceRange(); + return true; + } + + if(!Arg2->getType()->isVectorType()) { + S->Diag(Arg2->getBeginLoc(), + diag::err_builtin_non_vector_type) + << "Third" << "__builtin_hlsl_select" << Arg2->getType() + << Arg2->getSourceRange(); + return true; + } + + if(!S->Context.hasSameUnqualifiedType(Arg1->getType(), + Arg2->getType())) { + S->Diag(TheCall->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << Arg1->getType() << Arg2->getType() + << Arg1->getSourceRange() << Arg2->getSourceRange(); + return true; + } + + // caller has checked that Arg0 is a vector. + // check all three args have the same length. + if(TheCall->getArg(0)->getType()->getAs<VectorType>()->getNumElements() != + Arg1->getType()->getAs<VectorType>()->getNumElements()) { + S->Diag(TheCall->getBeginLoc(), + diag::err_typecheck_vector_lengths_not_equal) + << TheCall->getArg(0)->getType() << Arg1->getType() + << TheCall->getArg(0)->getSourceRange() << Arg1->getSourceRange(); + return true; + } + + return false; +} + // Note: returning true in this case results in CheckBuiltinFunctionCall // returning an ExprError bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { @@ -1545,6 +1605,30 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; } case Builtin::BI__builtin_hlsl_elementwise_saturate: + case Builtin::BI__builtin_hlsl_select: { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + QualType ArgTy = TheCall->getArg(0)->getType(); + if (ArgTy->isBooleanType()) { + if (CheckBoolSelect(&SemaRef, TheCall)) + return true; + } else if (ArgTy->isVectorType() && + ArgTy->getAs<VectorType>()->getElementType()->isBooleanType()) { + if (CheckVectorSelect(&SemaRef, TheCall)) + return true; + } else { // first operand is not a bool or a vector of bools. + SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << TheCall->getArg(0)->getType() << SemaRef.Context.getBOOLType() + << 1 << 0 << 0; + SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_builtin_non_vector_type) + << "First" << "__builtin_hlsl_select" << TheCall->getArg(0)->getType() + << TheCall->getArg(0)->getSourceRange(); + return true; + } + break; + } case Builtin::BI__builtin_hlsl_elementwise_rcp: { if (CheckAllArgsHaveFloatRepresentation(&SemaRef, TheCall)) return true; >From 52f4f39e1d558ef8ab37e925db2a9aad1de87ce0 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Fri, 30 Aug 2024 21:49:20 +0000 Subject: [PATCH 2/7] tests for select intrinsic --- clang/test/CodeGenHLSL/builtins/select.hlsl | 76 ++++++++++++++++ .../test/SemaHLSL/BuiltIns/select-errors.hlsl | 90 +++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 clang/test/CodeGenHLSL/builtins/select.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/select-errors.hlsl diff --git a/clang/test/CodeGenHLSL/builtins/select.hlsl b/clang/test/CodeGenHLSL/builtins/select.hlsl new file mode 100644 index 00000000000000..eeafd8ea852ea3 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/select.hlsl @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ +// RUN: -o - | FileCheck %s --check-prefixes=CHECK + +// CHECK: %hlsl.select = select i1 +// CHECK: ret i32 %hlsl.select +int test_select_bool_int(bool cond0, int tVal, int fVal) { return select<int>(cond0, tVal, fVal); } + +// CHECK: %hlsl.select = select i1 +// CHECK: ret <2 x i32> %hlsl.select +vector<int,2> test_select_bool_vector(bool cond0, vector<int, 2> tVal, vector<int, 2> fVal) { return select<vector<int,2> >(cond0, tVal, fVal); } + +// CHECK: %4 = extractelement <1 x i1> %extractvec, i32 0 +// CHECK: %5 = extractelement <1 x i32> %2, i32 0 +// CHECK: %6 = extractelement <1 x i32> %3, i32 0 +// CHECK: %7 = select i1 %4, i32 %5, i32 %6 +// CHECK: %8 = insertelement <1 x i32> poison, i32 %7, i32 0 +// CHECK: ret <1 x i32> %8 +vector<int,1> test_select_vector_1(vector<bool,1> cond0, vector<int,1> tVals, vector<int,1> fVals) { return select<int,1>(cond0, tVals, fVals); } + +// CHECK: %4 = extractelement <2 x i1> %extractvec, i32 0 +// CHECK: %5 = extractelement <2 x i32> %2, i32 0 +// CHECK: %6 = extractelement <2 x i32> %3, i32 0 +// CHECK: %7 = select i1 %4, i32 %5, i32 %6 +// CHECK: %8 = insertelement <2 x i32> poison, i32 %7, i32 0 +// CHECK: %9 = extractelement <2 x i1> %extractvec, i32 1 +// CHECK: %10 = extractelement <2 x i32> %2, i32 1 +// CHECK: %11 = extractelement <2 x i32> %3, i32 1 +// CHECK: %12 = select i1 %9, i32 %10, i32 %11 +// CHECK: %13 = insertelement <2 x i32> %8, i32 %12, i32 1 +// CHECK: ret <2 x i32> %13 +vector<int,2> test_select_vector_2(vector<bool, 2> cond0, vector<int, 2> tVals, vector<int, 2> fVals) { return select<int,2>(cond0, tVals, fVals); } + +// CHECK: %4 = extractelement <3 x i1> %extractvec, i32 0 +// CHECK: %5 = extractelement <3 x i32> %2, i32 0 +// CHECK: %6 = extractelement <3 x i32> %3, i32 0 +// CHECK: %7 = select i1 %4, i32 %5, i32 %6 +// CHECK: %8 = insertelement <3 x i32> poison, i32 %7, i32 0 +// CHECK: %9 = extractelement <3 x i1> %extractvec, i32 1 +// CHECK: %10 = extractelement <3 x i32> %2, i32 1 +// CHECK: %11 = extractelement <3 x i32> %3, i32 1 +// CHECK: %12 = select i1 %9, i32 %10, i32 %11 +// CHECK: %13 = insertelement <3 x i32> %8, i32 %12, i32 1 +// CHECK: %14 = extractelement <3 x i1> %extractvec, i32 2 +// CHECK: %15 = extractelement <3 x i32> %2, i32 2 +// CHECK: %16 = extractelement <3 x i32> %3, i32 2 +// CHECK: %17 = select i1 %14, i32 %15, i32 %16 +// CHECK: %18 = insertelement <3 x i32> %13, i32 %17, i32 2 +// CHECK: ret <3 x i32> %18 +vector<int,3> test_select_vector_3(vector<bool, 3> cond0, vector<int, 3> tVals, vector<int, 3> fVals) { return select<int,3>(cond0, tVals, fVals); } + +// CHECK: %4 = extractelement <4 x i1> %extractvec, i32 0 +// CHECK: %5 = extractelement <4 x i32> %2, i32 0 +// CHECK: %6 = extractelement <4 x i32> %3, i32 0 +// CHECK: %7 = select i1 %4, i32 %5, i32 %6 +// CHECK: %8 = insertelement <4 x i32> poison, i32 %7, i32 0 +// CHECK: %9 = extractelement <4 x i1> %extractvec, i32 1 +// CHECK: %10 = extractelement <4 x i32> %2, i32 1 +// CHECK: %11 = extractelement <4 x i32> %3, i32 1 +// CHECK: %12 = select i1 %9, i32 %10, i32 %11 +// CHECK: %13 = insertelement <4 x i32> %8, i32 %12, i32 1 +// CHECK: %14 = extractelement <4 x i1> %extractvec, i32 2 +// CHECK: %15 = extractelement <4 x i32> %2, i32 2 +// CHECK: %16 = extractelement <4 x i32> %3, i32 2 +// CHECK: %17 = select i1 %14, i32 %15, i32 %16 +// CHECK: %18 = insertelement <4 x i32> %13, i32 %17, i32 2 +// CHECK: %19 = extractelement <4 x i1> %extractvec, i32 3 +// CHECK: %20 = extractelement <4 x i32> %2, i32 3 +// CHECK: %21 = extractelement <4 x i32> %3, i32 3 +// CHECK: %22 = select i1 %19, i32 %20, i32 %21 +// CHECK: %23 = insertelement <4 x i32> %18, i32 %22, i32 3 +// CHECK: ret <4 x i32> %23 +vector<int,4> test_select_vector_4(vector<bool, 4> cond0, vector<int, 4> tVals, vector<int, 4> fVals) { return select<int,4>(cond0, tVals, fVals); } + + + diff --git a/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl new file mode 100644 index 00000000000000..5637c5f8176e90 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify -verify-ignore-unexpected + +int test_no_arg() { + return select(); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 0 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 0 were provided}} +} + +int test_too_few_args(bool p0) { + return select(p0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} +} + +int test_too_many_args(bool p0, int t0, int f0, int g0) { + return select<int>(p0, t0, f0, g0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} +} + +int test_select_first_arg_wrong_type(vector<int,1> p0, int t0, int f0) { + return select(p0, t0, f0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: no known conversion from 'vector<int, 1>' (vector of 1 'int' value) to 'bool' for 1st argument}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could not match 'vector<T, Sz>' against 'int'}} +} + +vector<int,1> test_select_bool_vals_diff_vecs(bool p0, vector<int,1> t0, vector<int,2> f0) { + return select<vector<int,1> >(p0, t0, f0); + // expected-warning@-1 {{implicit conversion truncates vector: 'vector<int, 2>' (vector of 2 'int' values) to 'vector<int, 1>' (vector of 1 'int' value)}} +} + +vector<int,2> test_select_vector_vals_not_vecs(vector<bool,2> p0, int t0, int f0) { + return select(p0, t0, f0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could not match 'vector<T, Sz>' against 'int'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: no known conversion from 'vector<bool, 2>' (vector of 2 'bool' values) to 'bool' for 1st argument}} +} + +vector<int,1> test_select_vector_vals_wrong_size(vector<bool,2> p0, vector<int,1> t0, vector<int,2> f0) { + return select<int,1>(p0, t0, f0); // produce warnings + // expected-warning@-1 {{implicit conversion truncates vector: 'vector<bool, 2>' (vector of 2 'bool' values) to 'vector<bool, 1>' (vector of 1 'bool' value)}} + // expected-warning@-2 {{implicit conversion truncates vector: 'vector<int, 2>' (vector of 2 'int' values) to 'vector<int, 1>' (vector of 1 'int' value)}} +} + +// __builtin_hlsl_select tests +int test_select_builtin_wrong_arg_count(bool p0, int t0) { + return __builtin_hlsl_select(p0, t0); + // expected-error@-1 {{too few arguments to function call, expected 3, have 2}} +} + +// not a bool or a vector of bool. should be 2 errors. +int test_select_builtin_first_arg_wrong_type1(int p0, int t0, int f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{passing 'int' to parameter of incompatible type 'bool'}} + // expected-error@-2 {{First argument to __builtin_hlsl_select must be of vector type}} + } + +int test_select_builtin_first_arg_wrong_type2(vector<int,1> p0, int t0, int f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{passing 'vector<int, 1>' (vector of 1 'int' value) to parameter of incompatible type 'bool'}} + // expected-error@-2 {{First argument to __builtin_hlsl_select must be of vector type}} +} + +// if a bool last 2 args are of same type +int test_select_builtin_bool_incompatible_args(bool p0, int t0, double f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{arguments are of different types ('int' vs 'double')}} +} + +// if a vector second arg isnt a vector +vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, int t0, vector<int,2> f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{Second argument to __builtin_hlsl_select must be of vector type}} +} + +// if a vector third arg isn't a vector +vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, vector<int,2> t0, int f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{Third argument to __builtin_hlsl_select must be of vector type}} +} + +// if vector last 2 aren't same type (so both are vectors but wrong type) +vector<int,2> test_select_builtin_diff_types(vector<bool,1> p0, vector<int,1> t0, vector<float,1> f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{arguments are of different types ('vector<int, [...]>' vs 'vector<float, [...]>')}} +} \ No newline at end of file >From 7ff44a894c59c34d0aacba57d5eb2d6f63e9cf6f Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Fri, 30 Aug 2024 21:54:49 +0000 Subject: [PATCH 3/7] fix bugs revealed during testing --- clang/lib/CodeGen/CGBuiltin.cpp | 17 ++++++++++------- clang/lib/Headers/hlsl/hlsl_intrinsics.h | 4 ++-- clang/lib/Sema/SemaHLSL.cpp | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 7fe198c207ce22..1aaa668607dab0 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18703,13 +18703,13 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { // if cond is a bool emit a select instruction if (TCond->isIntegerTy(1)) - return Builder.CreateSelect(OpCond, OpTrue, OpFalse); + return Builder.CreateSelect(OpCond, OpTrue, OpFalse, "hlsl.select"); // if cond is a vector of bools lower to a shufflevector // todo check if that true and false are vectors // todo check that the size of true and false and cond are the same if (TCond->isVectorTy() && - E->getArg(0)->getType()->getAs<VectorType>()->isBooleanType()) { + E->getArg(0)->getType()->getAs<VectorType>()->getElementType()->isBooleanType()) { assert(OpTrue->getType()->isVectorTy() && OpFalse->getType()->isVectorTy() && "Select's second and third operands must be vectors if first operand is a vector."); @@ -18723,15 +18723,18 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { assert(N == VecTyFalse->getNumElements() && N == E->getArg(0)->getType()->getAs<VectorType>()->getNumElements() && "Select requires vectors to be of the same size."); - - llvm::SmallVector<Value *> Mask; + + llvm::Value *Result = llvm::PoisonValue::get(llvm::FixedVectorType::get(IntTy, N)); for (unsigned I = 0; I < N; I++) { Value *Index = ConstantInt::get(IntTy, I); Value *IndexBool = Builder.CreateExtractElement(OpCond, Index); - Mask.push_back(Builder.CreateSelect(IndexBool, Index, ConstantInt::get(IntTy, I + N))); + Value *TVal = Builder.CreateExtractElement(OpTrue, Index); + Value *FVal = Builder.CreateExtractElement(OpFalse, Index); + Value *IndexSelect = Builder.CreateSelect(IndexBool, TVal, FVal); + Result = Builder.CreateInsertElement(Result, IndexSelect, Index); } - - return Builder.CreateShuffleVector(OpTrue, OpFalse, BuildVector(Mask)); + + return Result; } llvm_unreachable("Select requires a bool or vector of bools as its first operand."); diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 4319d9775c4bae..da14e837f7bd0a 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1613,8 +1613,8 @@ double4 saturate(double4); /// \param TrueVal The Value returned if Cond is true. /// \param FalseVal The Value returned if Cond is false. +template <typename T> _HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) -template<typename T> T select(bool, T, T); /// \fn vector<T,Sz> select(vector<bool,Sz> Conds, vector<T,Sz> TrueVals, vector<T,Sz>, FalseVals) @@ -1623,8 +1623,8 @@ T select(bool, T, T); /// \param TrueVals The vector values are chosen from when conditions are true. /// \param FalseVals The vector values are chosen from when conditions are false. +template <typename T, int Sz> _HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) -template<typename T, int Sz> vector<T,Sz> select(vector<bool,Sz>, vector<T,Sz>, vector<T,Sz>); //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 0da1d91ab7aa6b..62c825c9c852a7 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1619,7 +1619,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } else { // first operand is not a bool or a vector of bools. SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), diag::err_typecheck_convert_incompatible) - << TheCall->getArg(0)->getType() << SemaRef.Context.getBOOLType() + << TheCall->getArg(0)->getType() << getASTContext().BoolTy << 1 << 0 << 0; SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), diag::err_builtin_non_vector_type) >From 735b0854659c734a9edc442ba6f20f11be2ee217 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Tue, 3 Sep 2024 21:53:43 +0000 Subject: [PATCH 4/7] move select case above saturate case so saturate falls through correctly. --- clang/lib/Sema/SemaHLSL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 62c825c9c852a7..b3b05db3b757b5 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1604,7 +1604,6 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; break; } - case Builtin::BI__builtin_hlsl_elementwise_saturate: case Builtin::BI__builtin_hlsl_select: { if (SemaRef.checkArgCount(TheCall, 3)) return true; @@ -1629,6 +1628,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } break; } + case Builtin::BI__builtin_hlsl_elementwise_saturate: case Builtin::BI__builtin_hlsl_elementwise_rcp: { if (CheckAllArgsHaveFloatRepresentation(&SemaRef, TheCall)) return true; >From f8f4a4e31aa4c49fc091a5b916013e6d66256ace Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Tue, 3 Sep 2024 22:00:15 +0000 Subject: [PATCH 5/7] remove no longer needed todo comments. --- clang/lib/CodeGen/CGBuiltin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 1aaa668607dab0..6709e15d383427 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -18706,8 +18706,6 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { return Builder.CreateSelect(OpCond, OpTrue, OpFalse, "hlsl.select"); // if cond is a vector of bools lower to a shufflevector - // todo check if that true and false are vectors - // todo check that the size of true and false and cond are the same if (TCond->isVectorTy() && E->getArg(0)->getType()->getAs<VectorType>()->getElementType()->isBooleanType()) { assert(OpTrue->getType()->isVectorTy() && OpFalse->getType()->isVectorTy() && >From 4803c5b111e989b6e50c1150609a03e3ecab7148 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Thu, 5 Sep 2024 18:22:04 +0000 Subject: [PATCH 6/7] address comments on PR. Simplify codegen of hlsl_select because llvm select instr already does exactly what we want. Add handling for aggregate types. --- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/lib/CodeGen/CGBuiltin.cpp | 70 ++++++------- clang/lib/CodeGen/CodeGenFunction.h | 3 +- clang/lib/Headers/hlsl/hlsl_intrinsics.h | 6 +- clang/lib/Sema/SemaHLSL.cpp | 59 ++++++----- clang/test/CodeGenHLSL/builtins/select.hlsl | 97 +++++++------------ .../test/SemaHLSL/BuiltIns/select-errors.hlsl | 97 +++++++++++++------ 7 files changed, 172 insertions(+), 163 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index dcb49d8a67604a..68c6993089dcb8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9206,6 +9206,9 @@ def err_typecheck_expect_scalar_operand : Error< "operand of type %0 where arithmetic or pointer type is required">; def err_typecheck_cond_incompatible_operands : Error< "incompatible operand types%diff{ ($ and $)|}0,1">; +def err_typecheck_expect_scalar_or_vector : Error< + "invalid operand of type %0 where %1 or " + "a vector of such type is required">; def err_typecheck_expect_flt_or_vector : Error< "invalid operand of type %0 where floating, complex or " "a vector of such types is required">; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 6709e15d383427..97e56b411bff46 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6241,8 +6241,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } // EmitHLSLBuiltinExpr will check getLangOpts().HLSL - if (Value *V = EmitHLSLBuiltinExpr(BuiltinID, E)) - return RValue::get(V); + if (Value *V = EmitHLSLBuiltinExpr(BuiltinID, E, ReturnValue)) { + switch (EvalKind) { + case TEK_Scalar: + if (V->getType()->isVoidTy()) + return RValue::get(nullptr); + return RValue::get(V); + case TEK_Aggregate: + return RValue::getAggregate(ReturnValue.getAddress(), + ReturnValue.isVolatile()); + case TEK_Complex: + llvm_unreachable("No current hlsl builtin returns complex"); + } + llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr"); + } if (getLangOpts().HIPStdPar && getLangOpts().CUDAIsDevice) return EmitHipStdParUnsupportedBuiltin(this, FD); @@ -18508,7 +18520,8 @@ Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) { } Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, - const CallExpr *E) { + const CallExpr *E, + ReturnValueSlot ReturnValue) { if (!getLangOpts().HLSL) return nullptr; @@ -18697,45 +18710,20 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { } case Builtin::BI__builtin_hlsl_select: { Value *OpCond = EmitScalarExpr(E->getArg(0)); - Value *OpTrue = EmitScalarExpr(E->getArg(1)); - Value *OpFalse = EmitScalarExpr(E->getArg(2)); - llvm::Type *TCond = OpCond->getType(); - - // if cond is a bool emit a select instruction - if (TCond->isIntegerTy(1)) - return Builder.CreateSelect(OpCond, OpTrue, OpFalse, "hlsl.select"); - - // if cond is a vector of bools lower to a shufflevector - if (TCond->isVectorTy() && - E->getArg(0)->getType()->getAs<VectorType>()->getElementType()->isBooleanType()) { - assert(OpTrue->getType()->isVectorTy() && OpFalse->getType()->isVectorTy() && - "Select's second and third operands must be vectors if first operand is a vector."); - - auto *VecTyTrue = E->getArg(1)->getType()->getAs<VectorType>(); - auto *VecTyFalse = E->getArg(2)->getType()->getAs<VectorType>(); - - assert(VecTyTrue->getElementType() == VecTyFalse->getElementType() && - "Select's second and third vectors need the same element types."); - - const unsigned N = VecTyTrue->getNumElements(); - assert(N == VecTyFalse->getNumElements() && - N == E->getArg(0)->getType()->getAs<VectorType>()->getNumElements() && - "Select requires vectors to be of the same size."); - - llvm::Value *Result = llvm::PoisonValue::get(llvm::FixedVectorType::get(IntTy, N)); - for (unsigned I = 0; I < N; I++) { - Value *Index = ConstantInt::get(IntTy, I); - Value *IndexBool = Builder.CreateExtractElement(OpCond, Index); - Value *TVal = Builder.CreateExtractElement(OpTrue, Index); - Value *FVal = Builder.CreateExtractElement(OpFalse, Index); - Value *IndexSelect = Builder.CreateSelect(IndexBool, TVal, FVal); - Result = Builder.CreateInsertElement(Result, IndexSelect, Index); - } - - return Result; - } + RValue RValTrue = EmitAnyExpr(E->getArg(1)); + Value *OpTrue = RValTrue.isScalar() ? RValTrue.getScalarVal() + : RValTrue.getAggregatePointer(E->getArg(1)->getType(), *this); + RValue RValFalse = EmitAnyExpr(E->getArg(2)); + Value *OpFalse = RValFalse.isScalar() ? RValFalse.getScalarVal() + : RValFalse.getAggregatePointer(E->getArg(2)->getType(), *this); - llvm_unreachable("Select requires a bool or vector of bools as its first operand."); + Value *SelectVal = Builder.CreateSelect(OpCond, OpTrue, OpFalse, + "hlsl.select"); + if (!RValTrue.isScalar()) + Builder.CreateStore(SelectVal, ReturnValue.getAddress(), + ReturnValue.isVolatile()); + + return SelectVal; } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { return EmitRuntimeCall(CGM.CreateRuntimeFunction( diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 368fc112187ffc..81a0b666183cc7 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4700,7 +4700,8 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E); - llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue); llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx, const CallExpr *E); llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E); diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index da14e837f7bd0a..d405d604cf2ab5 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1617,11 +1617,13 @@ template <typename T> _HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) T select(bool, T, T); -/// \fn vector<T,Sz> select(vector<bool,Sz> Conds, vector<T,Sz> TrueVals, vector<T,Sz>, FalseVals) +/// \fn vector<T,Sz> select(vector<bool,Sz> Conds, vector<T,Sz> TrueVals, +/// vector<T,Sz> FalseVals) /// \brief ternary operator for vectors. All vectors must be the same size. /// \param Conds The Condition input values. /// \param TrueVals The vector values are chosen from when conditions are true. -/// \param FalseVals The vector values are chosen from when conditions are false. +/// \param FalseVals The vector values are chosen from when conditions are +/// false. template <typename T, int Sz> _HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index b3b05db3b757b5..803d63e31b8321 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1512,7 +1512,24 @@ void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, TheCall->setType(ReturnType); } -bool CheckBoolSelect(Sema *S, CallExpr *TheCall) { +static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar, + unsigned ArgIndex) { + assert(TheCall->getNumArgs() >= ArgIndex); + QualType ArgType = TheCall->getArg(ArgIndex)->getType(); + auto *VTy = ArgType->getAs<VectorType>(); + // not the scalar or vector<scalar> + if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) || + (VTy && S->Context.hasSameUnqualifiedType(VTy->getElementType(), + Scalar)))) { + S->Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_typecheck_expect_scalar_or_vector) + << ArgType << Scalar; + return true; + } + return false; +} + +static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) { assert(TheCall->getNumArgs() == 3); Expr *Arg1 = TheCall->getArg(1); Expr *Arg2 = TheCall->getArg(2); @@ -1529,11 +1546,11 @@ bool CheckBoolSelect(Sema *S, CallExpr *TheCall) { return false; } -bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { +static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { assert(TheCall->getNumArgs() == 3); Expr *Arg1 = TheCall->getArg(1); Expr *Arg2 = TheCall->getArg(2); - if(!Arg1->getType()->isVectorType()) { + if (!Arg1->getType()->isVectorType()) { S->Diag(Arg1->getBeginLoc(), diag::err_builtin_non_vector_type) << "Second" << "__builtin_hlsl_select" << Arg1->getType() @@ -1541,7 +1558,7 @@ bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { return true; } - if(!Arg2->getType()->isVectorType()) { + if (!Arg2->getType()->isVectorType()) { S->Diag(Arg2->getBeginLoc(), diag::err_builtin_non_vector_type) << "Third" << "__builtin_hlsl_select" << Arg2->getType() @@ -1549,8 +1566,8 @@ bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { return true; } - if(!S->Context.hasSameUnqualifiedType(Arg1->getType(), - Arg2->getType())) { + if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), + Arg2->getType())) { S->Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_different_arg_types) << Arg1->getType() << Arg2->getType() @@ -1560,15 +1577,15 @@ bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { // caller has checked that Arg0 is a vector. // check all three args have the same length. - if(TheCall->getArg(0)->getType()->getAs<VectorType>()->getNumElements() != - Arg1->getType()->getAs<VectorType>()->getNumElements()) { + if (TheCall->getArg(0)->getType()->getAs<VectorType>()->getNumElements() != + Arg1->getType()->getAs<VectorType>()->getNumElements()) { S->Diag(TheCall->getBeginLoc(), diag::err_typecheck_vector_lengths_not_equal) << TheCall->getArg(0)->getType() << Arg1->getType() << TheCall->getArg(0)->getSourceRange() << Arg1->getSourceRange(); return true; } - + TheCall->setType(Arg1->getType()); return false; } @@ -1607,25 +1624,15 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__builtin_hlsl_select: { if (SemaRef.checkArgCount(TheCall, 3)) return true; + if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0)) + return true; QualType ArgTy = TheCall->getArg(0)->getType(); - if (ArgTy->isBooleanType()) { - if (CheckBoolSelect(&SemaRef, TheCall)) - return true; - } else if (ArgTy->isVectorType() && - ArgTy->getAs<VectorType>()->getElementType()->isBooleanType()) { - if (CheckVectorSelect(&SemaRef, TheCall)) - return true; - } else { // first operand is not a bool or a vector of bools. - SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << TheCall->getArg(0)->getType() << getASTContext().BoolTy - << 1 << 0 << 0; - SemaRef.Diag(TheCall->getArg(0)->getBeginLoc(), - diag::err_builtin_non_vector_type) - << "First" << "__builtin_hlsl_select" << TheCall->getArg(0)->getType() - << TheCall->getArg(0)->getSourceRange(); + if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall)) + return true; + auto *VTy = ArgTy->getAs<VectorType>(); + if (VTy && VTy->getElementType()->isBooleanType() && + CheckVectorSelect(&SemaRef, TheCall)) return true; - } break; } case Builtin::BI__builtin_hlsl_elementwise_saturate: diff --git a/clang/test/CodeGenHLSL/builtins/select.hlsl b/clang/test/CodeGenHLSL/builtins/select.hlsl index eeafd8ea852ea3..2d5a49ab2090b9 100644 --- a/clang/test/CodeGenHLSL/builtins/select.hlsl +++ b/clang/test/CodeGenHLSL/builtins/select.hlsl @@ -4,73 +4,42 @@ // CHECK: %hlsl.select = select i1 // CHECK: ret i32 %hlsl.select -int test_select_bool_int(bool cond0, int tVal, int fVal) { return select<int>(cond0, tVal, fVal); } +int test_select_bool_int(bool cond0, int tVal, int fVal) { + return select<int>(cond0, tVal, fVal); } +struct S { int a; }; // CHECK: %hlsl.select = select i1 -// CHECK: ret <2 x i32> %hlsl.select -vector<int,2> test_select_bool_vector(bool cond0, vector<int, 2> tVal, vector<int, 2> fVal) { return select<vector<int,2> >(cond0, tVal, fVal); } - -// CHECK: %4 = extractelement <1 x i1> %extractvec, i32 0 -// CHECK: %5 = extractelement <1 x i32> %2, i32 0 -// CHECK: %6 = extractelement <1 x i32> %3, i32 0 -// CHECK: %7 = select i1 %4, i32 %5, i32 %6 -// CHECK: %8 = insertelement <1 x i32> poison, i32 %7, i32 0 -// CHECK: ret <1 x i32> %8 -vector<int,1> test_select_vector_1(vector<bool,1> cond0, vector<int,1> tVals, vector<int,1> fVals) { return select<int,1>(cond0, tVals, fVals); } - -// CHECK: %4 = extractelement <2 x i1> %extractvec, i32 0 -// CHECK: %5 = extractelement <2 x i32> %2, i32 0 -// CHECK: %6 = extractelement <2 x i32> %3, i32 0 -// CHECK: %7 = select i1 %4, i32 %5, i32 %6 -// CHECK: %8 = insertelement <2 x i32> poison, i32 %7, i32 0 -// CHECK: %9 = extractelement <2 x i1> %extractvec, i32 1 -// CHECK: %10 = extractelement <2 x i32> %2, i32 1 -// CHECK: %11 = extractelement <2 x i32> %3, i32 1 -// CHECK: %12 = select i1 %9, i32 %10, i32 %11 -// CHECK: %13 = insertelement <2 x i32> %8, i32 %12, i32 1 -// CHECK: ret <2 x i32> %13 -vector<int,2> test_select_vector_2(vector<bool, 2> cond0, vector<int, 2> tVals, vector<int, 2> fVals) { return select<int,2>(cond0, tVals, fVals); } - -// CHECK: %4 = extractelement <3 x i1> %extractvec, i32 0 -// CHECK: %5 = extractelement <3 x i32> %2, i32 0 -// CHECK: %6 = extractelement <3 x i32> %3, i32 0 -// CHECK: %7 = select i1 %4, i32 %5, i32 %6 -// CHECK: %8 = insertelement <3 x i32> poison, i32 %7, i32 0 -// CHECK: %9 = extractelement <3 x i1> %extractvec, i32 1 -// CHECK: %10 = extractelement <3 x i32> %2, i32 1 -// CHECK: %11 = extractelement <3 x i32> %3, i32 1 -// CHECK: %12 = select i1 %9, i32 %10, i32 %11 -// CHECK: %13 = insertelement <3 x i32> %8, i32 %12, i32 1 -// CHECK: %14 = extractelement <3 x i1> %extractvec, i32 2 -// CHECK: %15 = extractelement <3 x i32> %2, i32 2 -// CHECK: %16 = extractelement <3 x i32> %3, i32 2 -// CHECK: %17 = select i1 %14, i32 %15, i32 %16 -// CHECK: %18 = insertelement <3 x i32> %13, i32 %17, i32 2 -// CHECK: ret <3 x i32> %18 -vector<int,3> test_select_vector_3(vector<bool, 3> cond0, vector<int, 3> tVals, vector<int, 3> fVals) { return select<int,3>(cond0, tVals, fVals); } +// CHECK: store ptr %hlsl.select +// CHECK: ret void +struct S test_select_infer(bool cond0, struct S tVal, struct S fVal) { + return select(cond0, tVal, fVal); } -// CHECK: %4 = extractelement <4 x i1> %extractvec, i32 0 -// CHECK: %5 = extractelement <4 x i32> %2, i32 0 -// CHECK: %6 = extractelement <4 x i32> %3, i32 0 -// CHECK: %7 = select i1 %4, i32 %5, i32 %6 -// CHECK: %8 = insertelement <4 x i32> poison, i32 %7, i32 0 -// CHECK: %9 = extractelement <4 x i1> %extractvec, i32 1 -// CHECK: %10 = extractelement <4 x i32> %2, i32 1 -// CHECK: %11 = extractelement <4 x i32> %3, i32 1 -// CHECK: %12 = select i1 %9, i32 %10, i32 %11 -// CHECK: %13 = insertelement <4 x i32> %8, i32 %12, i32 1 -// CHECK: %14 = extractelement <4 x i1> %extractvec, i32 2 -// CHECK: %15 = extractelement <4 x i32> %2, i32 2 -// CHECK: %16 = extractelement <4 x i32> %3, i32 2 -// CHECK: %17 = select i1 %14, i32 %15, i32 %16 -// CHECK: %18 = insertelement <4 x i32> %13, i32 %17, i32 2 -// CHECK: %19 = extractelement <4 x i1> %extractvec, i32 3 -// CHECK: %20 = extractelement <4 x i32> %2, i32 3 -// CHECK: %21 = extractelement <4 x i32> %3, i32 3 -// CHECK: %22 = select i1 %19, i32 %20, i32 %21 -// CHECK: %23 = insertelement <4 x i32> %18, i32 %22, i32 3 -// CHECK: ret <4 x i32> %23 -vector<int,4> test_select_vector_4(vector<bool, 4> cond0, vector<int, 4> tVals, vector<int, 4> fVals) { return select<int,4>(cond0, tVals, fVals); } +// CHECK: %hlsl.select = select i1 +// CHECK: ret <2 x i32> %hlsl.select +vector<int,2> test_select_bool_vector(bool cond0, vector<int, 2> tVal, + vector<int, 2> fVal) { + return select<vector<int,2> >(cond0, tVal, fVal); } +// CHECK: %hlsl.select = select <1 x i1> +// CHECK: ret <1 x i32> %hlsl.select +vector<int,1> test_select_vector_1(vector<bool,1> cond0, vector<int,1> tVals, + vector<int,1> fVals) { + return select<int,1>(cond0, tVals, fVals); } +// CHECK: %hlsl.select = select <2 x i1> +// CHECK: ret <2 x i32> %hlsl.select +vector<int,2> test_select_vector_2(vector<bool, 2> cond0, vector<int, 2> tVals, + vector<int, 2> fVals) { + return select<int,2>(cond0, tVals, fVals); } + +// CHECK: %hlsl.select = select <3 x i1> +// CHECK: ret <3 x i32> %hlsl.select +vector<int,3> test_select_vector_3(vector<bool, 3> cond0, vector<int, 3> tVals, + vector<int, 3> fVals) { + return select<int,3>(cond0, tVals, fVals); } + +// CHECK: %hlsl.select = select <4 x i1> +// CHECK: ret <4 x i32> %hlsl.select +int4 test_select_vector_4(bool4 cond0, int4 tVals, int4 fVals) { + return select(cond0, tVals, fVals); } diff --git a/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl index 5637c5f8176e90..68186b1b044a76 100644 --- a/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl @@ -1,68 +1,98 @@ -// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify -verify-ignore-unexpected +// RUN: %clang_cc1 -finclude-default-header +// -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only +// -disable-llvm-passes -verify -verify-ignore-unexpected int test_no_arg() { return select(); // expected-error@-1 {{no matching function for call to 'select'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 0 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 0 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template + // not viable: requires 3 arguments, but 0 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 0 were provided}} } int test_too_few_args(bool p0) { return select(p0); // expected-error@-1 {{no matching function for call to 'select'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 1 was provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 1 was provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 1 was provided}} } int test_too_many_args(bool p0, int t0, int f0, int g0) { return select<int>(p0, t0, f0, g0); // expected-error@-1 {{no matching function for call to 'select'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 3 arguments, but 4 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 4 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 4 were provided}} } int test_select_first_arg_wrong_type(vector<int,1> p0, int t0, int f0) { return select(p0, t0, f0); // expected-error@-1 {{no matching function for call to 'select'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: no known conversion from 'vector<int, 1>' (vector of 1 'int' value) to 'bool' for 1st argument}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could not match 'vector<T, Sz>' against 'int'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: no known conversion from 'vector<int, 1>' (vector of 1 'int' value) + // to 'bool' for 1st argument}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could + // not match 'vector<T, Sz>' against 'int'}} } -vector<int,1> test_select_bool_vals_diff_vecs(bool p0, vector<int,1> t0, vector<int,2> f0) { +vector<int,1> test_select_bool_vals_diff_vecs(bool p0, vector<int,1> t0, + vector<int,2> f0) { return select<vector<int,1> >(p0, t0, f0); - // expected-warning@-1 {{implicit conversion truncates vector: 'vector<int, 2>' (vector of 2 'int' values) to 'vector<int, 1>' (vector of 1 'int' value)}} + // expected-warning@-1 {{implicit conversion truncates vector: + // 'vector<int, 2>' (vector of 2 'int' values) to 'vector<int, 1>' + // (vector of 1 'int' value)}} } -vector<int,2> test_select_vector_vals_not_vecs(vector<bool,2> p0, int t0, int f0) { +vector<int,2> test_select_vector_vals_not_vecs(vector<bool,2> p0, int t0, + int f0) { return select(p0, t0, f0); // expected-error@-1 {{no matching function for call to 'select'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could not match 'vector<T, Sz>' against 'int'}} - // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: no known conversion from 'vector<bool, 2>' (vector of 2 'bool' values) to 'bool' for 1st argument}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: + // could not match 'vector<T, Sz>' against 'int'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: no known conversion from 'vector<bool, 2>' + // (vector of 2 'bool' values) to 'bool' for 1st argument}} } -vector<int,1> test_select_vector_vals_wrong_size(vector<bool,2> p0, vector<int,1> t0, vector<int,2> f0) { +vector<int,1> test_select_vector_vals_wrong_size(vector<bool,2> p0, + vector<int,1> t0, + vector<int,2> f0) { return select<int,1>(p0, t0, f0); // produce warnings - // expected-warning@-1 {{implicit conversion truncates vector: 'vector<bool, 2>' (vector of 2 'bool' values) to 'vector<bool, 1>' (vector of 1 'bool' value)}} - // expected-warning@-2 {{implicit conversion truncates vector: 'vector<int, 2>' (vector of 2 'int' values) to 'vector<int, 1>' (vector of 1 'int' value)}} + // expected-warning@-1 {{implicit conversion truncates vector: + // 'vector<bool, 2>' (vector of 2 'bool' values) to 'vector<bool, 1>' + // (vector of 1 'bool' value)}} + // expected-warning@-2 {{implicit conversion truncates vector: + // 'vector<int, 2>' (vector of 2 'int' values) to 'vector<int, 1>' + // (vector of 1 'int' value)}} } // __builtin_hlsl_select tests int test_select_builtin_wrong_arg_count(bool p0, int t0) { return __builtin_hlsl_select(p0, t0); - // expected-error@-1 {{too few arguments to function call, expected 3, have 2}} + // expected-error@-1 {{too few arguments to function call, expected 3, + // have 2}} } // not a bool or a vector of bool. should be 2 errors. int test_select_builtin_first_arg_wrong_type1(int p0, int t0, int f0) { return __builtin_hlsl_select(p0, t0, f0); - // expected-error@-1 {{passing 'int' to parameter of incompatible type 'bool'}} - // expected-error@-2 {{First argument to __builtin_hlsl_select must be of vector type}} + // expected-error@-1 {{passing 'int' to parameter of incompatible type + // 'bool'}} + // expected-error@-2 {{First argument to __builtin_hlsl_select must be of + // vector type}} } -int test_select_builtin_first_arg_wrong_type2(vector<int,1> p0, int t0, int f0) { +int test_select_builtin_first_arg_wrong_type2(vector<int,1> p0, int t0, + int f0) { return __builtin_hlsl_select(p0, t0, f0); - // expected-error@-1 {{passing 'vector<int, 1>' (vector of 1 'int' value) to parameter of incompatible type 'bool'}} - // expected-error@-2 {{First argument to __builtin_hlsl_select must be of vector type}} + // expected-error@-1 {{passing 'vector<int, 1>' (vector of 1 'int' value) to + // parameter of incompatible type 'bool'}} + // expected-error@-2 {{First argument to __builtin_hlsl_select must be of + // vector type}} } // if a bool last 2 args are of same type @@ -72,19 +102,28 @@ int test_select_builtin_bool_incompatible_args(bool p0, int t0, double f0) { } // if a vector second arg isnt a vector -vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, int t0, vector<int,2> f0) { +vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, + int t0, + vector<int,2> f0) { return __builtin_hlsl_select(p0, t0, f0); - // expected-error@-1 {{Second argument to __builtin_hlsl_select must be of vector type}} + // expected-error@-1 {{Second argument to __builtin_hlsl_select must be of + // vector type}} } // if a vector third arg isn't a vector -vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, vector<int,2> t0, int f0) { +vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, + vector<int,2> t0, + int f0) { return __builtin_hlsl_select(p0, t0, f0); - // expected-error@-1 {{Third argument to __builtin_hlsl_select must be of vector type}} + // expected-error@-1 {{Third argument to __builtin_hlsl_select must be of + // vector type}} } // if vector last 2 aren't same type (so both are vectors but wrong type) -vector<int,2> test_select_builtin_diff_types(vector<bool,1> p0, vector<int,1> t0, vector<float,1> f0) { +vector<int,2> test_select_builtin_diff_types(vector<bool,1> p0, + vector<int,1> t0, + vector<float,1> f0) { return __builtin_hlsl_select(p0, t0, f0); - // expected-error@-1 {{arguments are of different types ('vector<int, [...]>' vs 'vector<float, [...]>')}} + // expected-error@-1 {{arguments are of different types ('vector<int, [...]>' + // vs 'vector<float, [...]>')}} } \ No newline at end of file >From dc67f0c499a1751386c10a0f4a1f850da575e652 Mon Sep 17 00:00:00 2001 From: Sarah Spall <sp...@planetbauer.com> Date: Thu, 5 Sep 2024 20:53:39 +0000 Subject: [PATCH 7/7] remove use of vector from hlsl test code and use corresponding types such as int2 --- clang/test/CodeGenHLSL/builtins/select.hlsl | 14 ++++------ .../test/SemaHLSL/BuiltIns/select-errors.hlsl | 28 ++++++------------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/clang/test/CodeGenHLSL/builtins/select.hlsl b/clang/test/CodeGenHLSL/builtins/select.hlsl index 2d5a49ab2090b9..56457d82ec19e6 100644 --- a/clang/test/CodeGenHLSL/builtins/select.hlsl +++ b/clang/test/CodeGenHLSL/builtins/select.hlsl @@ -16,26 +16,22 @@ struct S test_select_infer(bool cond0, struct S tVal, struct S fVal) { // CHECK: %hlsl.select = select i1 // CHECK: ret <2 x i32> %hlsl.select -vector<int,2> test_select_bool_vector(bool cond0, vector<int, 2> tVal, - vector<int, 2> fVal) { - return select<vector<int,2> >(cond0, tVal, fVal); } +int2 test_select_bool_vector(bool cond0, int2 tVal, int2 fVal) { + return select<int2>(cond0, tVal, fVal); } // CHECK: %hlsl.select = select <1 x i1> // CHECK: ret <1 x i32> %hlsl.select -vector<int,1> test_select_vector_1(vector<bool,1> cond0, vector<int,1> tVals, - vector<int,1> fVals) { +int1 test_select_vector_2(bool1 cond0, int1 tVals, int1 fVals) { return select<int,1>(cond0, tVals, fVals); } // CHECK: %hlsl.select = select <2 x i1> // CHECK: ret <2 x i32> %hlsl.select -vector<int,2> test_select_vector_2(vector<bool, 2> cond0, vector<int, 2> tVals, - vector<int, 2> fVals) { +int2 test_select_vector_2(bool2 cond0, int2 tVals, int2 fVals) { return select<int,2>(cond0, tVals, fVals); } // CHECK: %hlsl.select = select <3 x i1> // CHECK: ret <3 x i32> %hlsl.select -vector<int,3> test_select_vector_3(vector<bool, 3> cond0, vector<int, 3> tVals, - vector<int, 3> fVals) { +int3 test_select_vector_3(bool3 cond0, int3 tVals, int3 fVals) { return select<int,3>(cond0, tVals, fVals); } // CHECK: %hlsl.select = select <4 x i1> diff --git a/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl index 68186b1b044a76..eeba500a1d5297 100644 --- a/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl @@ -29,7 +29,7 @@ int test_too_many_args(bool p0, int t0, int f0, int g0) { // viable: requires 3 arguments, but 4 were provided}} } -int test_select_first_arg_wrong_type(vector<int,1> p0, int t0, int f0) { +int test_select_first_arg_wrong_type(int1 p0, int t0, int f0) { return select(p0, t0, f0); // expected-error@-1 {{no matching function for call to 'select'}} // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not @@ -39,15 +39,14 @@ int test_select_first_arg_wrong_type(vector<int,1> p0, int t0, int f0) { // not match 'vector<T, Sz>' against 'int'}} } -vector<int,1> test_select_bool_vals_diff_vecs(bool p0, vector<int,1> t0, - vector<int,2> f0) { - return select<vector<int,1> >(p0, t0, f0); +int1 test_select_bool_vals_diff_vecs(bool p0, int1 t0, int1 f0) { + return select<int1>(p0, t0, f0); // expected-warning@-1 {{implicit conversion truncates vector: // 'vector<int, 2>' (vector of 2 'int' values) to 'vector<int, 1>' // (vector of 1 'int' value)}} } -vector<int,2> test_select_vector_vals_not_vecs(vector<bool,2> p0, int t0, +int2 test_select_vector_vals_not_vecs(bool2 p0, int t0, int f0) { return select(p0, t0, f0); // expected-error@-1 {{no matching function for call to 'select'}} @@ -58,9 +57,7 @@ vector<int,2> test_select_vector_vals_not_vecs(vector<bool,2> p0, int t0, // (vector of 2 'bool' values) to 'bool' for 1st argument}} } -vector<int,1> test_select_vector_vals_wrong_size(vector<bool,2> p0, - vector<int,1> t0, - vector<int,2> f0) { +int1 test_select_vector_vals_wrong_size(bool2 p0, int1 t0, int1 f0) { return select<int,1>(p0, t0, f0); // produce warnings // expected-warning@-1 {{implicit conversion truncates vector: // 'vector<bool, 2>' (vector of 2 'bool' values) to 'vector<bool, 1>' @@ -86,8 +83,7 @@ int test_select_builtin_first_arg_wrong_type1(int p0, int t0, int f0) { // vector type}} } -int test_select_builtin_first_arg_wrong_type2(vector<int,1> p0, int t0, - int f0) { +int test_select_builtin_first_arg_wrong_type2(int1 p0, int t0, int f0) { return __builtin_hlsl_select(p0, t0, f0); // expected-error@-1 {{passing 'vector<int, 1>' (vector of 1 'int' value) to // parameter of incompatible type 'bool'}} @@ -102,27 +98,21 @@ int test_select_builtin_bool_incompatible_args(bool p0, int t0, double f0) { } // if a vector second arg isnt a vector -vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, - int t0, - vector<int,2> f0) { +int2 test_select_builtin_second_arg_not_vector(bool2 p0, int t0, int2 f0) { return __builtin_hlsl_select(p0, t0, f0); // expected-error@-1 {{Second argument to __builtin_hlsl_select must be of // vector type}} } // if a vector third arg isn't a vector -vector<int,2> test_select_builtin_second_arg_not_vector(vector<bool,2> p0, - vector<int,2> t0, - int f0) { +int2 test_select_builtin_second_arg_not_vector(bool2 p0, int2 t0, int f0) { return __builtin_hlsl_select(p0, t0, f0); // expected-error@-1 {{Third argument to __builtin_hlsl_select must be of // vector type}} } // if vector last 2 aren't same type (so both are vectors but wrong type) -vector<int,2> test_select_builtin_diff_types(vector<bool,1> p0, - vector<int,1> t0, - vector<float,1> f0) { +int2 test_select_builtin_diff_types(bool1 p0, int1 t0, float1 f0) { return __builtin_hlsl_select(p0, t0, f0); // expected-error@-1 {{arguments are of different types ('vector<int, [...]>' // vs 'vector<float, [...]>')}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits