https://github.com/llvm-beanz updated https://github.com/llvm/llvm-project/pull/163857
>From 490971d23eb067f7a2e3d2ca8b4e2f53bb3fe13f Mon Sep 17 00:00:00 2001 From: Chris Bieneman <[email protected]> Date: Thu, 16 Oct 2025 15:18:39 -0500 Subject: [PATCH 1/2] [HLSL] Convert vectors to bool for unary ! HLSL extends C++'s requirement that unary `!` apply to boolean arguments and produces boolean results to apply to vectors. This change implements implicit conversion for non-boolean vector operands to boolean vectors. I've noted this behavior in the issue tracking writing the HLSL specification section on unary operators (https://github.com/microsoft/hlsl-specs/issues/686). Fixes #162913 --- clang/lib/Sema/SemaExpr.cpp | 14 +++++ .../CodeGenHLSL/Operators/logical-not.hlsl | 33 ++++++++++++ .../test/SemaHLSL/Operators/logical-not.hlsl | 53 +++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 clang/test/CodeGenHLSL/Operators/logical-not.hlsl create mode 100644 clang/test/SemaHLSL/Operators/logical-not.hlsl diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3e0e9bb5e39e5..e42d30cb5acc8 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15944,6 +15944,20 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } + } else if (Context.getLangOpts().HLSL && resultType->isVectorType() && + !resultType->hasBooleanRepresentation()) { + // HLSL unary logical not behaves like C++, which states that the + // operand is onverted to bool and the result is bool, however HLSL + // extends this property to vectors. + const VectorType *VTy = resultType->castAs<VectorType>(); + resultType = + Context.getExtVectorType(Context.BoolTy, VTy->getNumElements()); + + Input = ImpCastExprToType( + Input.get(), resultType, + ScalarTypeToBooleanCastKind(VTy->getElementType())) + .get(); + break; } else if (resultType->isExtVectorType()) { if (Context.getLangOpts().OpenCL && Context.getLangOpts().getOpenCLCompatibleVersion() < 120) { diff --git a/clang/test/CodeGenHLSL/Operators/logical-not.hlsl b/clang/test/CodeGenHLSL/Operators/logical-not.hlsl new file mode 100644 index 0000000000000..0f9d0677d8610 --- /dev/null +++ b/clang/test/CodeGenHLSL/Operators/logical-not.hlsl @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -disable-llvm-passes -emit-llvm -finclude-default-header -fnative-half-type -o - %s | FileCheck %s + +// CHECK-LABEL: case1 +// CHECK: [[ToBool:%.*]] = icmp ne <2 x i32> {{.*}}, zeroinitializer +// CHECK-NEXT: [[BoolCmp:%.*]] = icmp eq <2 x i1> [[ToBool]], zeroinitializer +// CHECK-NEXT: {{.*}} = zext <2 x i1> [[BoolCmp]] to <2 x i32> +export uint32_t2 case1(uint32_t2 b) { + return !b; +} + +// CHECK-LABEL: case2 +// CHECK: [[ToBool:%.*]] = icmp ne <3 x i32> {{.*}}, zeroinitializer +// CHECK-NEXT: [[BoolCmp:%.*]] = icmp eq <3 x i1> [[ToBool]], zeroinitializer +// CHECK-NEXT: {{.*}} = zext <3 x i1> [[BoolCmp]] to <3 x i32> +export int32_t3 case2(int32_t3 b) { + return !b; +} + +// CHECK-LABEL: case3 +// CHECK: [[ToBool:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une half {{.*}}, 0xH0000 +// CHECK-NEXT: [[BoolCmp:%.*]] = xor i1 [[ToBool]], true +// CHECK-NEXT: {{.*}} = uitofp i1 [[BoolCmp]] to half +export float16_t case3(float16_t b) { + return !b; +} + +// CHECK-LABEL: case4 +// CHECK: [[ToBool:%.*]] = fcmp reassoc nnan ninf nsz arcp afn une <4 x float> {{.*}}, zeroinitializer +// CHECK-NEXT: [[BoolCmp:%.*]] = icmp eq <4 x i1> [[ToBool]], zeroinitializer +// CHECK-NEXT: {{.*}} = uitofp <4 x i1> [[BoolCmp]] to <4 x float> +export float4 case4(float4 b) { + return !b; +} diff --git a/clang/test/SemaHLSL/Operators/logical-not.hlsl b/clang/test/SemaHLSL/Operators/logical-not.hlsl new file mode 100644 index 0000000000000..d06ca3982be05 --- /dev/null +++ b/clang/test/SemaHLSL/Operators/logical-not.hlsl @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -ast-dump -ast-dump-filter=case | FileCheck %s + +// CHECK-LABEL: FunctionDecl {{.*}} used case1 'uint32_t2 (uint32_t2)' +// CHECK-NEXT: ParmVarDecl {{.*}} used b 'uint32_t2':'vector<uint32_t, 2>' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ReturnStmt +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<uint32_t, 2>' <IntegralCast> +// CHECK-NEXT: UnaryOperator {{.*}} 'vector<bool, 2>' prefix '!' cannot overflow +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 2>' <IntegralToBoolean> +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint32_t2':'vector<uint32_t, 2>' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'uint32_t2':'vector<uint32_t, 2>' lvalue ParmVar {{.*}} 'b' 'uint32_t2':'vector<uint32_t, 2>' +export uint32_t2 case1(uint32_t2 b) { + return !b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} used case2 'int32_t3 (int32_t3)' +// CHECK-NEXT: ParmVarDecl {{.*}} used b 'int32_t3':'vector<int32_t, 3>' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ReturnStmt +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int32_t, 3>' <IntegralCast> +// CHECK-NEXT: UnaryOperator {{.*}} 'vector<bool, 3>' prefix '!' cannot overflow +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 3>' <IntegralToBoolean> +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int32_t3':'vector<int32_t, 3>' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'int32_t3':'vector<int32_t, 3>' lvalue ParmVar {{.*}} 'b' 'int32_t3':'vector<int32_t, 3>' +export int32_t3 case2(int32_t3 b) { + return !b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} used case3 'float16_t (float16_t)' +// CHECK-NEXT: ParmVarDecl {{.*}} used b 'float16_t':'half' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ReturnStmt +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float16_t':'half' <IntegralToFloating> +// CHECK-NEXT: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <FloatingToBoolean> +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float16_t':'half' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'float16_t':'half' lvalue ParmVar {{.*}} 'b' 'float16_t':'half' +export float16_t case3(float16_t b) { + return !b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} used case4 'float4 (float4)' +// CHECK-NEXT: ParmVarDecl {{.*}} used b 'float4':'vector<float, 4>' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ReturnStmt +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 4>' <IntegralToFloating> +// CHECK-NEXT: UnaryOperator {{.*}} 'vector<bool, 4>' prefix '!' cannot overflow +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<bool, 4>' <FloatingToBoolean> +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4':'vector<float, 4>' <LValueToRValue> +// CHECK-NEXT: DeclRefExpr {{.*}} 'float4':'vector<float, 4>' lvalue ParmVar {{.*}} 'b' 'float4':'vector<float, 4>' +export float4 case4(float4 b) { + return !b; +} >From ceb43aa604a5074359d02c31e4ec8e0f53d4cbbe Mon Sep 17 00:00:00 2001 From: Chris B <[email protected]> Date: Thu, 16 Oct 2025 16:28:09 -0500 Subject: [PATCH 2/2] Update clang/lib/Sema/SemaExpr.cpp Co-authored-by: Farzon Lotfi <[email protected]> --- clang/lib/Sema/SemaExpr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e42d30cb5acc8..83c5e285550b5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15947,7 +15947,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } else if (Context.getLangOpts().HLSL && resultType->isVectorType() && !resultType->hasBooleanRepresentation()) { // HLSL unary logical not behaves like C++, which states that the - // operand is onverted to bool and the result is bool, however HLSL + // operand is converted to bool and the result is bool, however HLSL // extends this property to vectors. const VectorType *VTy = resultType->castAs<VectorType>(); resultType = _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
