-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang] Add __builtin_(elementwise|reduce)_(max|min)imum #110198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-hlsl @llvm/pr-subscribers-clang-codegen Author: Francis Visoiu Mistrih (francisvm) ChangesWe have the LLVM intrinsics, and we're missing the clang builtins to be used directly in code that needs to make the distinction in NaN semantics. Patch is 22.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/110198.diff 11 Files Affected:
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 0c6b9b1b8f9ce4..9b4c3e2ab4b5ef 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -706,6 +706,12 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
representable values for the signed/unsigned integer type.
T __builtin_elementwise_sub_sat(T x, T y) return the difference of x and y, clamped to the range of integer types
representable values for the signed/unsigned integer type.
+ T __builtin_elementwise_maximum(T x, T y) return x or y, whichever is larger. If exactly one argument is integer and floating point types
+ a NaN, return the other argument. If both arguments are NaNs,
+ return a NaN.
+ T __builtin_elementwise_minimum(T x, T y) return x or y, whichever is smaller. If exactly one argument is integer and floating point types
+ a NaN, return the other argument. If both arguments are NaNs,
+ return a NaN.
=========================================== ================================================================ =========================================
@@ -745,6 +751,10 @@ Let ``VT`` be a vector type and ``ET`` the element type of ``VT``.
ET __builtin_reduce_and(VT a) & integer types
ET __builtin_reduce_or(VT a) \| integer types
ET __builtin_reduce_xor(VT a) ^ integer types
+ ET __builtin_reduce_maximum(VT a) return the largest element of the vector. If the vector floating point types
+ contains a NaN, return NaN.
+ ET __builtin_reduce_minimum(VT a) return the smallest element of the vector. If the vector floating point types
+ contains a NaN, return NaN.
======================================= ================================================================ ==================================
Matrix Types
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 33791270800c9d..d26f5b9a6c8bdc 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1268,6 +1268,18 @@ def ElementwiseMin : Builtin {
let Prototype = "void(...)";
}
+def ElementwiseMaximum : Builtin {
+ let Spellings = ["__builtin_elementwise_maximum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def ElementwiseMinimum : Builtin {
+ let Spellings = ["__builtin_elementwise_minimum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
def ElementwiseCeil : Builtin {
let Spellings = ["__builtin_elementwise_ceil"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
@@ -1436,6 +1448,18 @@ def ReduceMin : Builtin {
let Prototype = "void(...)";
}
+def ReduceMaximum : Builtin {
+ let Spellings = ["__builtin_reduce_maximum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def ReduceMinimum : Builtin {
+ let Spellings = ["__builtin_reduce_minimum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
def ReduceXor : Builtin {
let Spellings = ["__builtin_reduce_xor"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f3d5d4c56606cc..4f598f7517cf23 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12216,7 +12216,8 @@ def err_builtin_invalid_arg_type: Error <
"a floating point type|"
"a vector of integers|"
"an unsigned integer|"
- "an 'int'}1 (was %2)">;
+ "an 'int'|"
+ "a vector of floating points}1 (was %2)">;
def err_builtin_matrix_disabled: Error<
"matrix types extension is disabled. Pass -fenable-matrix to enable it">;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 9033cd1ccd781d..0ab8068bb936f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3960,6 +3960,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Result);
}
+ case Builtin::BI__builtin_elementwise_maximum: {
+ Value *Op0 = EmitScalarExpr(E->getArg(0));
+ Value *Op1 = EmitScalarExpr(E->getArg(1));
+ Value *Result = Builder.CreateBinaryIntrinsic(
+ llvm::Intrinsic::maximum, Op0, Op1, nullptr, "elt.maximum");
+ return RValue::get(Result);
+ }
+
+ case Builtin::BI__builtin_elementwise_minimum: {
+ Value *Op0 = EmitScalarExpr(E->getArg(0));
+ Value *Op1 = EmitScalarExpr(E->getArg(1));
+ Value *Result = Builder.CreateBinaryIntrinsic(
+ llvm::Intrinsic::minimum, Op0, Op1, nullptr, "elt.minimum");
+ return RValue::get(Result);
+ }
+
case Builtin::BI__builtin_reduce_max: {
auto GetIntrinsicID = [this](QualType QT) {
if (auto *VecTy = QT->getAs<VectorType>())
@@ -4013,6 +4029,29 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(emitBuiltinWithOneOverloadedType<1>(
*this, E, llvm::Intrinsic::vector_reduce_and, "rdx.and"));
+ case Builtin::BI__builtin_reduce_maximum: {
+ auto GetIntrinsicID = [](QualType QT) {
+ if (auto *VecTy = QT->getAs<VectorType>())
+ QT = VecTy->getElementType();
+ assert(QT->isFloatingType() && "must have a float here");
+ return llvm::Intrinsic::vector_reduce_fmaximum;
+ };
+ return RValue::get(emitBuiltinWithOneOverloadedType<1>(
+ *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.maximum"));
+ }
+
+ case Builtin::BI__builtin_reduce_minimum: {
+ auto GetIntrinsicID = [](QualType QT) {
+ if (auto *VecTy = QT->getAs<VectorType>())
+ QT = VecTy->getElementType();
+ assert(QT->isFloatingType() && "must have a float here");
+ return llvm::Intrinsic::vector_reduce_fminimum;
+ };
+
+ return RValue::get(emitBuiltinWithOneOverloadedType<1>(
+ *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.minimum"));
+ }
+
case Builtin::BI__builtin_matrix_transpose: {
auto *MatrixTy = E->getArg(0)->getType()->castAs<ConstantMatrixType>();
Value *MatValue = EmitScalarExpr(E->getArg(0));
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index af1dc21594da8a..c798fe950c4f27 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2755,6 +2755,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
// These builtins restrict the element type to floating point
// types only, and take in two arguments.
+ case Builtin::BI__builtin_elementwise_minimum:
+ case Builtin::BI__builtin_elementwise_maximum:
case Builtin::BI__builtin_elementwise_pow: {
if (BuiltinElementwiseMath(TheCall))
return ExprError();
@@ -2867,6 +2869,29 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(ElTy);
break;
}
+ case Builtin::BI__builtin_reduce_maximum:
+ case Builtin::BI__builtin_reduce_minimum: {
+ if (PrepareBuiltinReduceMathOneArgCall(TheCall))
+ return ExprError();
+
+ const Expr *Arg = TheCall->getArg(0);
+ const auto *TyA = Arg->getType()->getAs<VectorType>();
+
+ QualType ElTy;
+ if (TyA)
+ ElTy = TyA->getElementType();
+ else if (Arg->getType()->isSizelessVectorType())
+ ElTy = Arg->getType()->getSizelessVectorEltType(Context);
+
+ if (ElTy.isNull() || !ElTy->isFloatingType()) {
+ Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << 1 << /* vector of floating points */ 9 << Arg->getType();
+ return ExprError();
+ }
+
+ TheCall->setType(ElTy);
+ break;
+ }
// These builtins support vectors of integers only.
// TODO: ADD/MUL should support floating-point types.
diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c
index 7e094a52653ef0..4a02b2f6467c34 100644
--- a/clang/test/CodeGen/builtins-elementwise-math.c
+++ b/clang/test/CodeGen/builtins-elementwise-math.c
@@ -169,6 +169,82 @@ void test_builtin_elementwise_sub_sat(float f1, float f2, double d1, double d2,
i1 = __builtin_elementwise_sub_sat(1, 'a');
}
+void test_builtin_elementwise_maximum(float f1, float f2, double d1, double d2,
+ float4 vf1, float4 vf2, long long int i1,
+ long long int i2, si8 vi1, si8 vi2,
+ unsigned u1, unsigned u2, u4 vu1, u4 vu2,
+ _BitInt(31) bi1, _BitInt(31) bi2,
+ unsigned _BitInt(55) bu1, unsigned _BitInt(55) bu2) {
+ // CHECK-LABEL: define void @test_builtin_elementwise_maximum(
+ // CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
+ // CHECK-NEXT: [[F2:%.+]] = load float, ptr %f2.addr, align 4
+ // CHECK-NEXT: call float @llvm.maximum.f32(float [[F1]], float [[F2]])
+ f1 = __builtin_elementwise_maximum(f1, f2);
+
+ // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
+ // CHECK-NEXT: [[D2:%.+]] = load double, ptr %d2.addr, align 8
+ // CHECK-NEXT: call double @llvm.maximum.f64(double [[D1]], double [[D2]])
+ d1 = __builtin_elementwise_maximum(d1, d2);
+
+ // CHECK: [[D2:%.+]] = load double, ptr %d2.addr, align 8
+ // CHECK-NEXT: call double @llvm.maximum.f64(double 2.000000e+01, double [[D2]])
+ d1 = __builtin_elementwise_maximum(20.0, d2);
+
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.maximum.v4f32(<4 x float> [[VF1]], <4 x float> [[VF2]])
+ vf1 = __builtin_elementwise_maximum(vf1, vf2);
+
+ // CHECK: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.maximum.v4f32(<4 x float> [[CVF1]], <4 x float> [[VF2]])
+ const float4 cvf1 = vf1;
+ vf1 = __builtin_elementwise_maximum(cvf1, vf2);
+
+ // CHECK: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.maximum.v4f32(<4 x float> [[VF2]], <4 x float> [[CVF1]])
+ vf1 = __builtin_elementwise_maximum(vf2, cvf1);
+}
+
+void test_builtin_elementwise_minimum(float f1, float f2, double d1, double d2,
+ float4 vf1, float4 vf2, long long int i1,
+ long long int i2, si8 vi1, si8 vi2,
+ unsigned u1, unsigned u2, u4 vu1, u4 vu2,
+ _BitInt(31) bi1, _BitInt(31) bi2,
+ unsigned _BitInt(55) bu1, unsigned _BitInt(55) bu2) {
+ // CHECK-LABEL: define void @test_builtin_elementwise_minimum(
+ // CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
+ // CHECK-NEXT: [[F2:%.+]] = load float, ptr %f2.addr, align 4
+ // CHECK-NEXT: call float @llvm.minimum.f32(float [[F1]], float [[F2]])
+ f1 = __builtin_elementwise_minimum(f1, f2);
+
+ // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
+ // CHECK-NEXT: [[D2:%.+]] = load double, ptr %d2.addr, align 8
+ // CHECK-NEXT: call double @llvm.minimum.f64(double [[D1]], double [[D2]])
+ d1 = __builtin_elementwise_minimum(d1, d2);
+
+ // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
+ // CHECK-NEXT: call double @llvm.minimum.f64(double [[D1]], double 2.000000e+00)
+ d1 = __builtin_elementwise_minimum(d1, 2.0);
+
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.minimum.v4f32(<4 x float> [[VF1]], <4 x float> [[VF2]])
+ vf1 = __builtin_elementwise_minimum(vf1, vf2);
+
+ // CHECK: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.minimum.v4f32(<4 x float> [[CVF1]], <4 x float> [[VF2]])
+ const float4 cvf1 = vf1;
+ vf1 = __builtin_elementwise_minimum(cvf1, vf2);
+
+ // CHECK: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.minimum.v4f32(<4 x float> [[VF2]], <4 x float> [[CVF1]])
+ vf1 = __builtin_elementwise_minimum(vf2, cvf1);
+}
+
void test_builtin_elementwise_max(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2, long long int i1,
long long int i2, si8 vi1, si8 vi2,
diff --git a/clang/test/CodeGen/builtins-reduction-math.c b/clang/test/CodeGen/builtins-reduction-math.c
index acafe9222d59fd..e12fd729c84c0b 100644
--- a/clang/test/CodeGen/builtins-reduction-math.c
+++ b/clang/test/CodeGen/builtins-reduction-math.c
@@ -138,6 +138,30 @@ void test_builtin_reduce_and(si8 vi1, u4 vu1) {
unsigned r3 = __builtin_reduce_and(vu1);
}
+void test_builtin_reduce_maximum(float4 vf1) {
+ // CHECK-LABEL: define void @test_builtin_reduce_maximum(
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> [[VF1]])
+ float r1 = __builtin_reduce_maximum(vf1);
+
+ // CHECK: [[VF1_AS1:%.+]] = load <4 x float>, ptr addrspace(1) @vf1_as_one, align 16
+ // CHECK-NEXT: [[RDX1:%.+]] = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> [[VF1_AS1]])
+ // CHECK-NEXT: fpext float [[RDX1]] to double
+ const double r4 = __builtin_reduce_maximum(vf1_as_one);
+}
+
+void test_builtin_reduce_minimum(float4 vf1) {
+ // CHECK-LABEL: define void @test_builtin_reduce_minimum(
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> [[VF1]])
+ float r1 = __builtin_reduce_minimum(vf1);
+
+ // CHECK: [[VF1_AS1:%.+]] = load <4 x float>, ptr addrspace(1) @vf1_as_one, align 16
+ // CHECK-NEXT: [[RDX1:%.+]] = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> [[VF1_AS1]])
+ // CHECK-NEXT: fpext float [[RDX1]] to double
+ const double r4 = __builtin_reduce_minimum(vf1_as_one);
+}
+
#if defined(__ARM_FEATURE_SVE)
#include <arm_sve.h>
diff --git a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
index 55ba17a1955800..dc5674ddab233c 100644
--- a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
+++ b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
@@ -47,6 +47,26 @@ float4 strict_elementwise_min(float4 a, float4 b) {
return __builtin_elementwise_min(a, b);
}
+// CHECK-LABEL: define dso_local noundef <4 x float> @_Z26strict_elementwise_maximumDv4_fS_
+// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[ELT_MAXIMUM:%.*]] = tail call <4 x float> @llvm.maximum.v4f32(<4 x float> [[A]], <4 x float> [[B]]) #[[ATTR4]]
+// CHECK-NEXT: ret <4 x float> [[ELT_MAXIMUM]]
+//
+float4 strict_elementwise_maximum(float4 a, float4 b) {
+ return __builtin_elementwise_maximum(a, b);
+}
+
+// CHECK-LABEL: define dso_local noundef <4 x float> @_Z26strict_elementwise_minimumDv4_fS_
+// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[ELT_MINIMUM:%.*]] = tail call <4 x float> @llvm.minimum.v4f32(<4 x float> [[A]], <4 x float> [[B]]) #[[ATTR4]]
+// CHECK-NEXT: ret <4 x float> [[ELT_MINIMUM]]
+//
+float4 strict_elementwise_minimum(float4 a, float4 b) {
+ return __builtin_elementwise_minimum(a, b);
+}
+
// CHECK-LABEL: define dso_local noundef <4 x float> @_Z23strict_elementwise_ceilDv4_f
// CHECK-SAME: (<4 x float> noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
// CHECK-NEXT: entry:
diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c
index 1727be1d6286d5..6960b5cc77e545 100644
--- a/clang/test/Sema/builtins-elementwise-math.c
+++ b/clang/test/Sema/builtins-elementwise-math.c
@@ -273,6 +273,74 @@ void test_builtin_elementwise_min(int i, short s, double d, float4 v, int3 iv, u
// expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}}
}
+void test_builtin_elementwise_maximum(int i, short s, float f, double d, float4 v, int3 iv, unsigned3 uv, int *p) {
+ i = __builtin_elementwise_maximum(p, d);
+ // expected-error@-1 {{arguments are of different types ('int *' vs 'double')}}
+
+ struct Foo foo = __builtin_elementwise_maximum(d, d);
+ // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'double'}}
+
+ i = __builtin_elementwise_maximum(i);
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 1}}
+
+ i = __builtin_elementwise_maximum();
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 0}}
+
+ i = __builtin_elementwise_maximum(i, i, i);
+ // expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
+
+ i = __builtin_elementwise_maximum(v, iv);
+ // expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'int3' (vector of 3 'int' values))}}
+
+ i = __builtin_elementwise_maximum(uv, iv);
+ // expected-error@-1 {{arguments are of different types ('unsigned3' (vector of 3 'unsigned int' values) vs 'int3' (vector of 3 'int' values))}}
+
+ d = __builtin_elementwise_maximum(d, f);
+
+ v = __builtin_elementwise_maximum(v, v);
+
+ int A[10];
+ A = __builtin_elementwise_maximum(A, A);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'int *')}}
+
+ _Complex float c1, c2;
+ c1 = __builtin_elementwise_maximum(c1, c2);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}}
+}
+
+void test_builtin_elementwise_minimum(int i, short s, float f, double d, float4 v, int3 iv, unsigned3 uv, int *p) {
+ i = __builtin_elementwise_minimum(p, d);
+ // expected-error@-1 {{arguments are of different types ('int *' vs 'double')}}
+
+ struct Foo foo = __builtin_elementwise_minimum(d, d);
+ // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'double'}}
+
+ i = __builtin_elementwise_minimum(i);
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 1}}
+
+ i = __builtin_elementwise_minimum();
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 0}}
+
+ i = __builtin_elementwise_minimum(i, i, i);
+ // expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
+
+ i = __builtin_elementwise_minimum(v, iv);
+ // expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'int3' (vector of 3 'int' values))}}
+
+ i = __builtin_elementwise_minimum(uv, iv);
+ // expected-error@-1 {{arguments are of different types ('unsigned3' (vector of 3 'unsigned int' values) vs 'int3' (vector of 3 'int' values))}}
+
+ d = __builtin_elementwise_minimum(f, d);
+
+ int A[10];
+ A = __builtin_elementwise_minimum(A, A);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'int *')}}
+
+ _Complex float c1, c2;
+ c1 = __builtin_elementwise_minimum(c1, c2);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}}
+}
+
voi...
[truncated]
|
@llvm/pr-subscribers-clang Author: Francis Visoiu Mistrih (francisvm) ChangesWe have the LLVM intrinsics, and we're missing the clang builtins to be used directly in code that needs to make the distinction in NaN semantics. Patch is 22.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/110198.diff 11 Files Affected:
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 0c6b9b1b8f9ce4..9b4c3e2ab4b5ef 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -706,6 +706,12 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
representable values for the signed/unsigned integer type.
T __builtin_elementwise_sub_sat(T x, T y) return the difference of x and y, clamped to the range of integer types
representable values for the signed/unsigned integer type.
+ T __builtin_elementwise_maximum(T x, T y) return x or y, whichever is larger. If exactly one argument is integer and floating point types
+ a NaN, return the other argument. If both arguments are NaNs,
+ return a NaN.
+ T __builtin_elementwise_minimum(T x, T y) return x or y, whichever is smaller. If exactly one argument is integer and floating point types
+ a NaN, return the other argument. If both arguments are NaNs,
+ return a NaN.
=========================================== ================================================================ =========================================
@@ -745,6 +751,10 @@ Let ``VT`` be a vector type and ``ET`` the element type of ``VT``.
ET __builtin_reduce_and(VT a) & integer types
ET __builtin_reduce_or(VT a) \| integer types
ET __builtin_reduce_xor(VT a) ^ integer types
+ ET __builtin_reduce_maximum(VT a) return the largest element of the vector. If the vector floating point types
+ contains a NaN, return NaN.
+ ET __builtin_reduce_minimum(VT a) return the smallest element of the vector. If the vector floating point types
+ contains a NaN, return NaN.
======================================= ================================================================ ==================================
Matrix Types
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 33791270800c9d..d26f5b9a6c8bdc 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1268,6 +1268,18 @@ def ElementwiseMin : Builtin {
let Prototype = "void(...)";
}
+def ElementwiseMaximum : Builtin {
+ let Spellings = ["__builtin_elementwise_maximum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def ElementwiseMinimum : Builtin {
+ let Spellings = ["__builtin_elementwise_minimum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
def ElementwiseCeil : Builtin {
let Spellings = ["__builtin_elementwise_ceil"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
@@ -1436,6 +1448,18 @@ def ReduceMin : Builtin {
let Prototype = "void(...)";
}
+def ReduceMaximum : Builtin {
+ let Spellings = ["__builtin_reduce_maximum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def ReduceMinimum : Builtin {
+ let Spellings = ["__builtin_reduce_minimum"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
def ReduceXor : Builtin {
let Spellings = ["__builtin_reduce_xor"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f3d5d4c56606cc..4f598f7517cf23 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12216,7 +12216,8 @@ def err_builtin_invalid_arg_type: Error <
"a floating point type|"
"a vector of integers|"
"an unsigned integer|"
- "an 'int'}1 (was %2)">;
+ "an 'int'|"
+ "a vector of floating points}1 (was %2)">;
def err_builtin_matrix_disabled: Error<
"matrix types extension is disabled. Pass -fenable-matrix to enable it">;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 9033cd1ccd781d..0ab8068bb936f7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3960,6 +3960,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Result);
}
+ case Builtin::BI__builtin_elementwise_maximum: {
+ Value *Op0 = EmitScalarExpr(E->getArg(0));
+ Value *Op1 = EmitScalarExpr(E->getArg(1));
+ Value *Result = Builder.CreateBinaryIntrinsic(
+ llvm::Intrinsic::maximum, Op0, Op1, nullptr, "elt.maximum");
+ return RValue::get(Result);
+ }
+
+ case Builtin::BI__builtin_elementwise_minimum: {
+ Value *Op0 = EmitScalarExpr(E->getArg(0));
+ Value *Op1 = EmitScalarExpr(E->getArg(1));
+ Value *Result = Builder.CreateBinaryIntrinsic(
+ llvm::Intrinsic::minimum, Op0, Op1, nullptr, "elt.minimum");
+ return RValue::get(Result);
+ }
+
case Builtin::BI__builtin_reduce_max: {
auto GetIntrinsicID = [this](QualType QT) {
if (auto *VecTy = QT->getAs<VectorType>())
@@ -4013,6 +4029,29 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(emitBuiltinWithOneOverloadedType<1>(
*this, E, llvm::Intrinsic::vector_reduce_and, "rdx.and"));
+ case Builtin::BI__builtin_reduce_maximum: {
+ auto GetIntrinsicID = [](QualType QT) {
+ if (auto *VecTy = QT->getAs<VectorType>())
+ QT = VecTy->getElementType();
+ assert(QT->isFloatingType() && "must have a float here");
+ return llvm::Intrinsic::vector_reduce_fmaximum;
+ };
+ return RValue::get(emitBuiltinWithOneOverloadedType<1>(
+ *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.maximum"));
+ }
+
+ case Builtin::BI__builtin_reduce_minimum: {
+ auto GetIntrinsicID = [](QualType QT) {
+ if (auto *VecTy = QT->getAs<VectorType>())
+ QT = VecTy->getElementType();
+ assert(QT->isFloatingType() && "must have a float here");
+ return llvm::Intrinsic::vector_reduce_fminimum;
+ };
+
+ return RValue::get(emitBuiltinWithOneOverloadedType<1>(
+ *this, E, GetIntrinsicID(E->getArg(0)->getType()), "rdx.minimum"));
+ }
+
case Builtin::BI__builtin_matrix_transpose: {
auto *MatrixTy = E->getArg(0)->getType()->castAs<ConstantMatrixType>();
Value *MatValue = EmitScalarExpr(E->getArg(0));
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index af1dc21594da8a..c798fe950c4f27 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2755,6 +2755,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
// These builtins restrict the element type to floating point
// types only, and take in two arguments.
+ case Builtin::BI__builtin_elementwise_minimum:
+ case Builtin::BI__builtin_elementwise_maximum:
case Builtin::BI__builtin_elementwise_pow: {
if (BuiltinElementwiseMath(TheCall))
return ExprError();
@@ -2867,6 +2869,29 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(ElTy);
break;
}
+ case Builtin::BI__builtin_reduce_maximum:
+ case Builtin::BI__builtin_reduce_minimum: {
+ if (PrepareBuiltinReduceMathOneArgCall(TheCall))
+ return ExprError();
+
+ const Expr *Arg = TheCall->getArg(0);
+ const auto *TyA = Arg->getType()->getAs<VectorType>();
+
+ QualType ElTy;
+ if (TyA)
+ ElTy = TyA->getElementType();
+ else if (Arg->getType()->isSizelessVectorType())
+ ElTy = Arg->getType()->getSizelessVectorEltType(Context);
+
+ if (ElTy.isNull() || !ElTy->isFloatingType()) {
+ Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << 1 << /* vector of floating points */ 9 << Arg->getType();
+ return ExprError();
+ }
+
+ TheCall->setType(ElTy);
+ break;
+ }
// These builtins support vectors of integers only.
// TODO: ADD/MUL should support floating-point types.
diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c
index 7e094a52653ef0..4a02b2f6467c34 100644
--- a/clang/test/CodeGen/builtins-elementwise-math.c
+++ b/clang/test/CodeGen/builtins-elementwise-math.c
@@ -169,6 +169,82 @@ void test_builtin_elementwise_sub_sat(float f1, float f2, double d1, double d2,
i1 = __builtin_elementwise_sub_sat(1, 'a');
}
+void test_builtin_elementwise_maximum(float f1, float f2, double d1, double d2,
+ float4 vf1, float4 vf2, long long int i1,
+ long long int i2, si8 vi1, si8 vi2,
+ unsigned u1, unsigned u2, u4 vu1, u4 vu2,
+ _BitInt(31) bi1, _BitInt(31) bi2,
+ unsigned _BitInt(55) bu1, unsigned _BitInt(55) bu2) {
+ // CHECK-LABEL: define void @test_builtin_elementwise_maximum(
+ // CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
+ // CHECK-NEXT: [[F2:%.+]] = load float, ptr %f2.addr, align 4
+ // CHECK-NEXT: call float @llvm.maximum.f32(float [[F1]], float [[F2]])
+ f1 = __builtin_elementwise_maximum(f1, f2);
+
+ // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
+ // CHECK-NEXT: [[D2:%.+]] = load double, ptr %d2.addr, align 8
+ // CHECK-NEXT: call double @llvm.maximum.f64(double [[D1]], double [[D2]])
+ d1 = __builtin_elementwise_maximum(d1, d2);
+
+ // CHECK: [[D2:%.+]] = load double, ptr %d2.addr, align 8
+ // CHECK-NEXT: call double @llvm.maximum.f64(double 2.000000e+01, double [[D2]])
+ d1 = __builtin_elementwise_maximum(20.0, d2);
+
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.maximum.v4f32(<4 x float> [[VF1]], <4 x float> [[VF2]])
+ vf1 = __builtin_elementwise_maximum(vf1, vf2);
+
+ // CHECK: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.maximum.v4f32(<4 x float> [[CVF1]], <4 x float> [[VF2]])
+ const float4 cvf1 = vf1;
+ vf1 = __builtin_elementwise_maximum(cvf1, vf2);
+
+ // CHECK: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.maximum.v4f32(<4 x float> [[VF2]], <4 x float> [[CVF1]])
+ vf1 = __builtin_elementwise_maximum(vf2, cvf1);
+}
+
+void test_builtin_elementwise_minimum(float f1, float f2, double d1, double d2,
+ float4 vf1, float4 vf2, long long int i1,
+ long long int i2, si8 vi1, si8 vi2,
+ unsigned u1, unsigned u2, u4 vu1, u4 vu2,
+ _BitInt(31) bi1, _BitInt(31) bi2,
+ unsigned _BitInt(55) bu1, unsigned _BitInt(55) bu2) {
+ // CHECK-LABEL: define void @test_builtin_elementwise_minimum(
+ // CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
+ // CHECK-NEXT: [[F2:%.+]] = load float, ptr %f2.addr, align 4
+ // CHECK-NEXT: call float @llvm.minimum.f32(float [[F1]], float [[F2]])
+ f1 = __builtin_elementwise_minimum(f1, f2);
+
+ // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
+ // CHECK-NEXT: [[D2:%.+]] = load double, ptr %d2.addr, align 8
+ // CHECK-NEXT: call double @llvm.minimum.f64(double [[D1]], double [[D2]])
+ d1 = __builtin_elementwise_minimum(d1, d2);
+
+ // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
+ // CHECK-NEXT: call double @llvm.minimum.f64(double [[D1]], double 2.000000e+00)
+ d1 = __builtin_elementwise_minimum(d1, 2.0);
+
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.minimum.v4f32(<4 x float> [[VF1]], <4 x float> [[VF2]])
+ vf1 = __builtin_elementwise_minimum(vf1, vf2);
+
+ // CHECK: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.minimum.v4f32(<4 x float> [[CVF1]], <4 x float> [[VF2]])
+ const float4 cvf1 = vf1;
+ vf1 = __builtin_elementwise_minimum(cvf1, vf2);
+
+ // CHECK: [[VF2:%.+]] = load <4 x float>, ptr %vf2.addr, align 16
+ // CHECK-NEXT: [[CVF1:%.+]] = load <4 x float>, ptr %cvf1, align 16
+ // CHECK-NEXT: call <4 x float> @llvm.minimum.v4f32(<4 x float> [[VF2]], <4 x float> [[CVF1]])
+ vf1 = __builtin_elementwise_minimum(vf2, cvf1);
+}
+
void test_builtin_elementwise_max(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2, long long int i1,
long long int i2, si8 vi1, si8 vi2,
diff --git a/clang/test/CodeGen/builtins-reduction-math.c b/clang/test/CodeGen/builtins-reduction-math.c
index acafe9222d59fd..e12fd729c84c0b 100644
--- a/clang/test/CodeGen/builtins-reduction-math.c
+++ b/clang/test/CodeGen/builtins-reduction-math.c
@@ -138,6 +138,30 @@ void test_builtin_reduce_and(si8 vi1, u4 vu1) {
unsigned r3 = __builtin_reduce_and(vu1);
}
+void test_builtin_reduce_maximum(float4 vf1) {
+ // CHECK-LABEL: define void @test_builtin_reduce_maximum(
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> [[VF1]])
+ float r1 = __builtin_reduce_maximum(vf1);
+
+ // CHECK: [[VF1_AS1:%.+]] = load <4 x float>, ptr addrspace(1) @vf1_as_one, align 16
+ // CHECK-NEXT: [[RDX1:%.+]] = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> [[VF1_AS1]])
+ // CHECK-NEXT: fpext float [[RDX1]] to double
+ const double r4 = __builtin_reduce_maximum(vf1_as_one);
+}
+
+void test_builtin_reduce_minimum(float4 vf1) {
+ // CHECK-LABEL: define void @test_builtin_reduce_minimum(
+ // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
+ // CHECK-NEXT: call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> [[VF1]])
+ float r1 = __builtin_reduce_minimum(vf1);
+
+ // CHECK: [[VF1_AS1:%.+]] = load <4 x float>, ptr addrspace(1) @vf1_as_one, align 16
+ // CHECK-NEXT: [[RDX1:%.+]] = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> [[VF1_AS1]])
+ // CHECK-NEXT: fpext float [[RDX1]] to double
+ const double r4 = __builtin_reduce_minimum(vf1_as_one);
+}
+
#if defined(__ARM_FEATURE_SVE)
#include <arm_sve.h>
diff --git a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
index 55ba17a1955800..dc5674ddab233c 100644
--- a/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
+++ b/clang/test/CodeGen/strictfp-elementwise-bulitins.cpp
@@ -47,6 +47,26 @@ float4 strict_elementwise_min(float4 a, float4 b) {
return __builtin_elementwise_min(a, b);
}
+// CHECK-LABEL: define dso_local noundef <4 x float> @_Z26strict_elementwise_maximumDv4_fS_
+// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[ELT_MAXIMUM:%.*]] = tail call <4 x float> @llvm.maximum.v4f32(<4 x float> [[A]], <4 x float> [[B]]) #[[ATTR4]]
+// CHECK-NEXT: ret <4 x float> [[ELT_MAXIMUM]]
+//
+float4 strict_elementwise_maximum(float4 a, float4 b) {
+ return __builtin_elementwise_maximum(a, b);
+}
+
+// CHECK-LABEL: define dso_local noundef <4 x float> @_Z26strict_elementwise_minimumDv4_fS_
+// CHECK-SAME: (<4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[ELT_MINIMUM:%.*]] = tail call <4 x float> @llvm.minimum.v4f32(<4 x float> [[A]], <4 x float> [[B]]) #[[ATTR4]]
+// CHECK-NEXT: ret <4 x float> [[ELT_MINIMUM]]
+//
+float4 strict_elementwise_minimum(float4 a, float4 b) {
+ return __builtin_elementwise_minimum(a, b);
+}
+
// CHECK-LABEL: define dso_local noundef <4 x float> @_Z23strict_elementwise_ceilDv4_f
// CHECK-SAME: (<4 x float> noundef [[A:%.*]]) local_unnamed_addr #[[ATTR2]] {
// CHECK-NEXT: entry:
diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c
index 1727be1d6286d5..6960b5cc77e545 100644
--- a/clang/test/Sema/builtins-elementwise-math.c
+++ b/clang/test/Sema/builtins-elementwise-math.c
@@ -273,6 +273,74 @@ void test_builtin_elementwise_min(int i, short s, double d, float4 v, int3 iv, u
// expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}}
}
+void test_builtin_elementwise_maximum(int i, short s, float f, double d, float4 v, int3 iv, unsigned3 uv, int *p) {
+ i = __builtin_elementwise_maximum(p, d);
+ // expected-error@-1 {{arguments are of different types ('int *' vs 'double')}}
+
+ struct Foo foo = __builtin_elementwise_maximum(d, d);
+ // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'double'}}
+
+ i = __builtin_elementwise_maximum(i);
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 1}}
+
+ i = __builtin_elementwise_maximum();
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 0}}
+
+ i = __builtin_elementwise_maximum(i, i, i);
+ // expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
+
+ i = __builtin_elementwise_maximum(v, iv);
+ // expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'int3' (vector of 3 'int' values))}}
+
+ i = __builtin_elementwise_maximum(uv, iv);
+ // expected-error@-1 {{arguments are of different types ('unsigned3' (vector of 3 'unsigned int' values) vs 'int3' (vector of 3 'int' values))}}
+
+ d = __builtin_elementwise_maximum(d, f);
+
+ v = __builtin_elementwise_maximum(v, v);
+
+ int A[10];
+ A = __builtin_elementwise_maximum(A, A);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'int *')}}
+
+ _Complex float c1, c2;
+ c1 = __builtin_elementwise_maximum(c1, c2);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}}
+}
+
+void test_builtin_elementwise_minimum(int i, short s, float f, double d, float4 v, int3 iv, unsigned3 uv, int *p) {
+ i = __builtin_elementwise_minimum(p, d);
+ // expected-error@-1 {{arguments are of different types ('int *' vs 'double')}}
+
+ struct Foo foo = __builtin_elementwise_minimum(d, d);
+ // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'double'}}
+
+ i = __builtin_elementwise_minimum(i);
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 1}}
+
+ i = __builtin_elementwise_minimum();
+ // expected-error@-1 {{too few arguments to function call, expected 2, have 0}}
+
+ i = __builtin_elementwise_minimum(i, i, i);
+ // expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
+
+ i = __builtin_elementwise_minimum(v, iv);
+ // expected-error@-1 {{arguments are of different types ('float4' (vector of 4 'float' values) vs 'int3' (vector of 3 'int' values))}}
+
+ i = __builtin_elementwise_minimum(uv, iv);
+ // expected-error@-1 {{arguments are of different types ('unsigned3' (vector of 3 'unsigned int' values) vs 'int3' (vector of 3 'int' values))}}
+
+ d = __builtin_elementwise_minimum(f, d);
+
+ int A[10];
+ A = __builtin_elementwise_minimum(A, A);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'int *')}}
+
+ _Complex float c1, c2;
+ c1 = __builtin_elementwise_minimum(c1, c2);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}}
+}
+
voi...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
e42a4a9
to
511cfd9
Compare
511cfd9
to
8b53cbb
Compare
af6d6b8
to
840989c
Compare
840989c
to
cd66c08
Compare
cd66c08
to
a97d39c
Compare
We have the LLVM intrinsics, and we're missing the clang builtins to be used directly in code that needs to make the distinction in NaN semantics.
a97d39c
to
4813faa
Compare
@francisvm See: #110187 (comment) |
Looks like this breaks check-clang: http://45.33.8.238/linux/149333/step_6.txt Please take a look and revert for now if it takes a while to fix. |
I just pushed a fix for the test: 793ded7 |
Thank you @tex3d, sorry about that! |
Unfortunately, I didn't see your revert, and my pull didn't show any changes from main before I quickly committed the test change. So my test change would also break the build with your revert. So I reverted the test change just now! Revert: 5d308af. |
You should be able to re-land your change if you add the test fix to it. |
Oh dang. That's why I didn't see an update. Because the revert wasn't pushed to llvm/main, it was a revert on another repo. Looks like I could re-apply the test fix again unless you're planning on doing a revert on llvm/main. |
Yes, |
But IIUC, the diagnostic message change from this PR might be unintentional. The expected error message in 793ded7 doesn't align to the error message from other tests in the same file. Should that be addressed? |
Test fix has re-landed: fea18af. |
The other error messages in the file are now different because the path taken for the one arg intrinsic is different (calling It would be nice to fix these somehow, but I don't know if that should be part of landing this PR. I didn't like that wording in the diagnostic for multiple reasons (vector, integer or floating point??), but there wasn't a clear fix that wouldn't have broader impact, so I avoided rocking the boat here. I think it would be great to have a cleaner diagnostic and a better function structure for this code, but that probably makes more sense as a separate cleanup step at this point. Honestly, this code makes me wish there was a more regular structure to defining and applying needed constraints here. It currently feels a bit convoluted and messy. What do you think? |
I totally agree with you @tex3d, I wish we could add these constraints somewhere in |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/153/builds/10649 Here is the relevant piece of the build log for the reference
|
We have the LLVM intrinsics, and we're missing the clang builtins to be used directly in code that needs to make the distinction in NaN semantics.
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/56/builds/8882 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/60/builds/9156 Here is the relevant piece of the build log for the reference
|
We have the LLVM intrinsics, and we're missing the clang builtins to be used directly in code that needs to make the distinction in NaN semantics.