diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -643,6 +643,7 @@ BUILTIN(__builtin_alloca_with_align, "v*zIz", "Fn") BUILTIN(__builtin_call_with_static_chain, "v.", "nt") +BUILTIN(__builtin_elementwise_abs, "v.", "nct") BUILTIN(__builtin_elementwise_max, "v.", "nct") BUILTIN(__builtin_elementwise_min, "v.", "nct") diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8753,6 +8753,9 @@ def err_elementwise_math_invalid_arg_type: Error < "argument type %0 is not supported">; +def err_elementwise_math_invalid_arg_type_2: Error < + "argument must have a %0 type, but had a %1 type">; + def err_invalid_conversion_between_matrixes : Error< "conversion between matrix types%diff{ $ and $|}0,1 of different size is not allowed">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12712,8 +12712,10 @@ bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc); - ExprResult SemaBuiltinElementwiseMath(CallExpr *TheCall, - ExprResult CallResult); + ExprResult SemaBuiltinElementwiseMathOneArg(CallExpr *TheCall, + ExprResult CallResult); + ExprResult SemaBuiltinElementwiseMathTwoArgs(CallExpr *TheCall, + ExprResult CallResult); // Matrix builtin handling. ExprResult SemaBuiltinMatrixTranspose(CallExpr *TheCall, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3101,6 +3101,17 @@ return RValue::get(V); } + case Builtin::BI__builtin_elementwise_abs: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Result; + if (Op0->getType()->isIntOrIntVectorTy()) + Result = Builder.CreateBinaryIntrinsic( + llvm::Intrinsic::abs, Op0, Builder.getFalse(), nullptr, "elt.abs"); + else + Result = Builder.CreateUnaryIntrinsic(llvm::Intrinsic::fabs, Op0, nullptr, + "elt.abs"); + return RValue::get(Result); + } case Builtin::BI__builtin_elementwise_max: { Value *Op0 = EmitScalarExpr(E->getArg(0)); Value *Op1 = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1976,9 +1976,12 @@ break; } + case Builtin::BI__builtin_elementwise_abs: + return SemaBuiltinElementwiseMathOneArg(TheCall, TheCallResult); + case Builtin::BI__builtin_elementwise_min: case Builtin::BI__builtin_elementwise_max: - return SemaBuiltinElementwiseMath(TheCall, TheCallResult); + return SemaBuiltinElementwiseMathTwoArgs(TheCall, TheCallResult); case Builtin::BI__builtin_matrix_transpose: return SemaBuiltinMatrixTranspose(TheCall, TheCallResult); @@ -16653,8 +16656,32 @@ _2, _3, _4)); } -ExprResult Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall, - ExprResult CallResult) { +ExprResult Sema::SemaBuiltinElementwiseMathOneArg(CallExpr *TheCall, + ExprResult CallResult) { + if (checkArgCount(*this, TheCall, 1)) + return ExprError(); + + Expr *A = TheCall->getArg(0); + QualType TyA = A->getType(); + + if (!TyA->getAs() && !ConstantMatrixType::isValidElementType(TyA)) + return Diag(A->getBeginLoc(), diag::err_elementwise_math_invalid_arg_type) + << TyA; + + QualType EltTy = TyA; + if (auto *VecTy = EltTy->getAs()) + EltTy = VecTy->getElementType(); + if (EltTy->isUnsignedIntegerType()) + return Diag(A->getBeginLoc(), diag::err_elementwise_math_invalid_arg_type_2) + << "signed integer or floating point" + << "unsigned integer"; + + TheCall->setType(TyA); + return CallResult; +} + +ExprResult Sema::SemaBuiltinElementwiseMathTwoArgs(CallExpr *TheCall, + ExprResult CallResult) { if (checkArgCount(*this, TheCall, 2)) return ExprError(); diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c --- a/clang/test/CodeGen/builtins-elementwise-math.c +++ b/clang/test/CodeGen/builtins-elementwise-math.c @@ -4,10 +4,34 @@ typedef short int si8 __attribute__((ext_vector_type(8))); typedef unsigned int u4 __attribute__((ext_vector_type(4))); +void builtin_abs(float f1, float f2, double d1, double d2, float4 vf1, float4 vf2, si8 vi1, si8 vi2, long long int i1, long long int i2) { + // CHECK-LABEL: builtin_abs( + // CHECK: [[F1:%.+]] = load float, float* %f1.addr, align 4 + // CHECK-NEXT: call float @llvm.fabs.f32(float [[F1]]) + f2 = __builtin_elementwise_abs(f1); + + // CHECK: [[D1:%.+]] = load double, double* %d1.addr, align 8 + // CHECK-NEXT: call double @llvm.fabs.f64(double [[D1]]) + d2 = __builtin_elementwise_abs(d1); + + // CHECK: [[VF1:%.+]] = load <4 x float>, <4 x float>* %vf1.addr, align 16 + // CHECK-NEXT: call <4 x float> @llvm.fabs.v4f32(<4 x float> [[VF1]]) + vf2 = __builtin_elementwise_abs(vf1); + + // CHECK: [[I1:%.+]] = load i64, i64* %i1.addr, align 8 + // CHECK-NEXT: call i64 @llvm.abs.i64(i64 [[I1]], i1 false) + i2 = __builtin_elementwise_abs(i1); + + // CHECK: [[VI1:%.+]] = load <8 x i16>, <8 x i16>* %vi1.addr, align 16 + // CHECK-NEXT: call <8 x i16> @llvm.abs.v8i16(<8 x i16> [[VI1]], i1 false) + vi2 = __builtin_elementwise_abs(vi1); +} + void builtin_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, unsigned u1, unsigned u2, u4 vu1, u4 vu2) { // CHECK-LABEL: define void @builtin_max( + // CHECK: [[F1:%.+]] = load float, float* %f1.addr, align 4 // CHECK-NEXT: [[F2:%.+]] = load float, float* %f2.addr, align 4 // CHECK-NEXT: call float @llvm.maxnum.f32(float %0, float %1) diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c --- a/clang/test/Sema/builtins-elementwise-math.c +++ b/clang/test/Sema/builtins-elementwise-math.c @@ -2,11 +2,32 @@ typedef float float4 __attribute__((ext_vector_type(4))); typedef int int3 __attribute__((ext_vector_type(3))); +typedef unsigned unsigned4 __attribute__((ext_vector_type(4))); struct Foo { char *p; }; +void builtin_elementwise_abs(int i, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) { + struct Foo s = __builtin_elementwise_abs(i); + // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'int'}} + + i = __builtin_elementwise_abs(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} + + i = __builtin_elementwise_abs(i, i); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} + + i = __builtin_elementwise_abs(v); + // expected-error@-1 {{assigning to 'int' from incompatible type 'float4' (vector of 4 'float' values)}} + + u = __builtin_elementwise_abs(u); + // expected-error@-1 {{argument must have a signed integer or floating point type, but had a unsigned integer type}} + + uv = __builtin_elementwise_abs(uv); + // expected-error@-1 {{argument must have a signed integer or floating point type, but had a unsigned integer type}} +} + void builtin_elementwise_max(int i, double d, float4 v, int3 iv) { i = __builtin_elementwise_max(i, d); // expected-error@-1 {{argument types do not match, 'int' != 'double'}}