[clang] [HLSL] Add matrix support for `sign` (PR #235542)
David Browne via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 25 17:41:23 PDT 2026
https://github.com/djb created https://github.com/llvm/llvm-project/pull/235542
Implement matrix support for `sign` and add matrix codegen and sema tests. Also fix a sema bug by rejecting boolean matrix and vector inputs to `__builtin_hlsl_elementwise_sign`, consistent with the builtin's rejection of scalar boolean inputs. Backend tests were not added as no modifications were made to either backend.
>From 42403aa2181c781f3fe8575c56e7a5e19d72998a Mon Sep 17 00:00:00 2001
From: David Browne <djb at users.noreply.github.com>
Date: Mon, 26 Oct 2026 00:53:23 +0100
Subject: [PATCH] add matrix support for sign
Implement matrix support for sign and add matrix codegen and sema
tests. Also fix a sema bug by rejecting boolean matrix and vector
inputs to __builtin_hlsl_elementwise_sign, consistent with the
builtin's rejection of scalar boolean inputs. Backend tests were not
added as no modifications were made to either backend.
---
clang/include/clang/Basic/HLSLIntrinsics.td | 1 -
clang/lib/AST/Type.cpp | 2 +
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 8 +--
clang/lib/Sema/SemaHLSL.cpp | 12 ++--
clang/test/CodeGenHLSL/builtins/sign_mat.hlsl | 60 +++++++++++++++++++
clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl | 9 ++-
.../SemaHLSL/BuiltIns/sign_mat-errors.hlsl | 13 ++++
7 files changed, 90 insertions(+), 15 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/builtins/sign_mat.hlsl
create mode 100644 clang/test/SemaHLSL/BuiltIns/sign_mat-errors.hlsl
diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
index fd59e3477b8c79..583917ca4030b5 100644
--- a/clang/include/clang/Basic/HLSLIntrinsics.td
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -1559,7 +1559,6 @@ def hlsl_sign : HLSLOneArgBuiltin<"sign", "__builtin_hlsl_elementwise_sign"> {
let ReturnType = VaryingShape<IntTy>;
let VaryingTypes = AllNumericTypes;
let VaryingLongVector = 1;
- let VaryingMatDims = [];
}
// Returns the sine of the input value, Val.
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 4c5f2f60a90005..8cbad334ebc467 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2245,6 +2245,8 @@ bool Type::hasAutoForTrailingReturnType() const {
bool Type::hasIntegerRepresentation() const {
if (const auto *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isIntegerType();
+ if (const auto *MT = dyn_cast<MatrixType>(CanonicalType))
+ return MT->getElementType()->isIntegerType();
if (CanonicalType->isSveVLSBuiltinType()) {
const auto *VT = cast<BuiltinType>(CanonicalType);
return VT->getKind() == BuiltinType::SveBool ||
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index fc422918499ed2..2281e96889a770 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -1751,12 +1751,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
auto *Arg0 = E->getArg(0);
Value *Op0 = EmitScalarExpr(Arg0);
llvm::Type *Xty = Op0->getType();
- llvm::Type *retType = llvm::Type::getInt32Ty(this->getLLVMContext());
- if (Xty->isVectorTy()) {
- auto *XVecTy = Arg0->getType()->castAs<VectorType>();
- retType = llvm::VectorType::get(
- retType, ElementCount::getFixed(XVecTy->getNumElements()));
- }
+ llvm::Type *retType = getAggregateType(
+ llvm::Type::getInt32Ty(this->getLLVMContext()), Arg0->getType());
assert((Arg0->getType()->hasFloatingRepresentation() ||
Arg0->getType()->hasIntegerRepresentation()) &&
"sign operand must have a float or int representation");
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f3fd1fb68c0727..e61d66833b7372 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3796,11 +3796,11 @@ static bool CheckNoDoubleVectors(Sema *S, SourceLocation Loc, int ArgOrdinal,
return false;
}
-static bool CheckFloatingOrIntRepresentation(Sema *S, SourceLocation Loc,
- int ArgOrdinal,
- clang::QualType PassedType) {
- if (!PassedType->hasIntegerRepresentation() &&
- !PassedType->hasFloatingRepresentation())
+static bool CheckFloatingOrNonBoolIntRepresentation(
+ Sema *S, SourceLocation Loc, int ArgOrdinal, clang::QualType PassedType) {
+ if (getScalarComponentType(PassedType)->isBooleanType() ||
+ (!PassedType->hasIntegerRepresentation() &&
+ !PassedType->hasFloatingRepresentation()))
return S->Diag(Loc, diag::err_builtin_invalid_arg_type)
<< ArgOrdinal << /* scalar or vector of */ 5 << /* integer */ 1
<< /* fp */ 1 << PassedType;
@@ -5146,7 +5146,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
- CheckFloatingOrIntRepresentation))
+ CheckFloatingOrNonBoolIntRepresentation))
return true;
SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().IntTy);
break;
diff --git a/clang/test/CodeGenHLSL/builtins/sign_mat.hlsl b/clang/test/CodeGenHLSL/builtins/sign_mat.hlsl
new file mode 100644
index 00000000000000..018ef3dbd6d8ae
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/sign_mat.hlsl
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type -fnative-int16-type \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
+// RUN: --check-prefixes=CHECK,NATIVE_HALF \
+// RUN: -DTARGET=dx -DFNATTRS="hidden noundef"
+// 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,NO_HALF \
+// RUN: -DTARGET=dx -DFNATTRS="hidden noundef"
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: spirv-unknown-vulkan-library %s -fnative-half-type -fnative-int16-type \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
+// RUN: --check-prefixes=CHECK,NATIVE_HALF \
+// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef"
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: spirv-unknown-vulkan-library %s -emit-llvm -disable-llvm-passes \
+// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
+// RUN: -DTARGET=spv -DFNATTRS="hidden spir_func noundef"
+
+// CHECK-LABEL: test_sign_half2x3
+// NATIVE_HALF: call <6 x i32> @llvm.[[TARGET]].sign.v6f16(<6 x half> %{{.*}})
+// NO_HALF: call <6 x i32> @llvm.[[TARGET]].sign.v6f32(<6 x float> %{{.*}})
+int2x3 test_sign_half2x3(half2x3 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_half3x4
+// NATIVE_HALF: call <12 x i32> @llvm.[[TARGET]].sign.v12f16(<12 x half> %{{.*}})
+// NO_HALF: call <12 x i32> @llvm.[[TARGET]].sign.v12f32(<12 x float> %{{.*}})
+int3x4 test_sign_half3x4(half3x4 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_half4x4
+// NATIVE_HALF: call <16 x i32> @llvm.[[TARGET]].sign.v16f16(<16 x half> %{{.*}})
+// NO_HALF: call <16 x i32> @llvm.[[TARGET]].sign.v16f32(<16 x float> %{{.*}})
+int4x4 test_sign_half4x4(half4x4 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_int2x3
+// CHECK: call <6 x i32> @llvm.[[TARGET]].sign.v6i32(<6 x i32> %{{.*}})
+int2x3 test_sign_int2x3(int2x3 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_int3x4
+// CHECK: call <12 x i32> @llvm.[[TARGET]].sign.v12i32(<12 x i32> %{{.*}})
+int3x4 test_sign_int3x4(int3x4 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_int4x4
+// CHECK: call <16 x i32> @llvm.[[TARGET]].sign.v16i32(<16 x i32> %{{.*}})
+int4x4 test_sign_int4x4(int4x4 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_uint2x3
+// CHECK: [[CMP:%.*]] = icmp eq <6 x i32> %{{.*}}, zeroinitializer
+// CHECK: %hlsl.sign = select <6 x i1> [[CMP]], <6 x i32> zeroinitializer, <6 x i32> splat (i32 1)
+int2x3 test_sign_uint2x3(uint2x3 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_uint3x4
+// CHECK: [[CMP:%.*]] = icmp eq <12 x i32> %{{.*}}, zeroinitializer
+// CHECK: %hlsl.sign = select <12 x i1> [[CMP]], <12 x i32> zeroinitializer, <12 x i32> splat (i32 1)
+int3x4 test_sign_uint3x4(uint3x4 p0) { return sign(p0); }
+
+// CHECK-LABEL: test_sign_uint4x4
+// CHECK: [[CMP:%.*]] = icmp eq <16 x i32> %{{.*}}, zeroinitializer
+// CHECK: %hlsl.sign = select <16 x i1> [[CMP]], <16 x i32> zeroinitializer, <16 x i32> splat (i32 1)
+int4x4 test_sign_uint4x4(uint4x4 p0) { return sign(p0); }
diff --git a/clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl
index 68583d10d12876..31a6368e3f779a 100644
--- a/clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/sign-errors.hlsl
@@ -10,7 +10,12 @@ bool2 test_too_many_arg(float2 p0) {
// expected-error at -1 {{too many arguments to function call, expected 1, have 2}}
}
-bool builtin_bool_to_float_type_promotion(bool p1) {
+bool builtin_sign_bool(bool p1) {
return __builtin_hlsl_elementwise_sign(p1);
- // expected-error at -1 {passing 'bool' to parameter of incompatible type 'float'}}
+ // expected-error at -1 {{1st argument must be a vector, integer or floating-point type (was 'bool')}}
+}
+
+int2 builtin_sign_bool2(bool2 p0) {
+ return __builtin_hlsl_elementwise_sign(p0);
+ // expected-error at -1 {{1st argument must be a scalar or vector of integer or floating-point types (was 'bool2' (aka 'vector<bool, 2>'))}}
}
diff --git a/clang/test/SemaHLSL/BuiltIns/sign_mat-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/sign_mat-errors.hlsl
new file mode 100644
index 00000000000000..5c0032b669069c
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/sign_mat-errors.hlsl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -emit-llvm-only -disable-llvm-passes -verify
+
+int2x2 test_too_many_arg(float2x2 p0) {
+ return __builtin_hlsl_elementwise_sign(p0, p0);
+ // expected-error at -1 2 {{cannot pass object of non-trivial type 'float2x2' (aka 'matrix<float, 2, 2>') through variadic function; call will abort at runtime}}
+ // expected-error at -2 {{too many arguments to function call, expected 1, have 2}}
+}
+
+int2x2 test_bool_matrix(bool2x2 p0) {
+ return __builtin_hlsl_elementwise_sign(p0);
+ // expected-error at -1 {{cannot pass object of non-trivial type 'bool2x2' (aka 'matrix<bool, 2, 2>') through variadic function; call will abort at runtime}}
+ // expected-error at -2 {{1st argument must be a scalar or vector of integer or floating-point types (was 'bool2x2' (aka 'matrix<bool, 2, 2>'))}}
+}
More information about the cfe-commits
mailing list