Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,8 @@ of different sizes and signs is forbidden in binary and ternary builtins.
T __builtin_elementwise_exp(T x) returns the base-e exponential, e^x, of the specified value floating point types
T __builtin_elementwise_exp2(T x) returns the base-2 exponential, 2^x, of the specified value floating point types
T __builtin_elementwise_exp10(T x) returns the base-10 exponential, 10^x, of the specified value floating point types
T __builtin_elementwise_ldexp(T x, IntT y) returns the product of x and 2 raised to the power y. T: floating point types,
y must be an integer type matching the shape of x. IntT: integer types

T __builtin_elementwise_sqrt(T x) return the square root of a floating-point number floating point types
T __builtin_elementwise_roundeven(T x) round x to the nearest integer value in floating point format, floating point types
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ C23 Feature Support

Non-comprehensive list of changes in this release
-------------------------------------------------
- Added ``__builtin_elementwise_ldexp``.

- Added ``__builtin_elementwise_fshl`` and ``__builtin_elementwise_fshr``.

- ``__builtin_elementwise_abs`` can now be used in constant expression.
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1418,6 +1418,12 @@ def ElementwiseExp10 : Builtin {
let Prototype = "void(...)";
}

def ElementwiseLdexp : Builtin {
let Spellings = ["__builtin_elementwise_ldexp"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}

def ElementwiseFloor : Builtin {
let Spellings = ["__builtin_elementwise_floor"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3992,6 +3992,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_elementwise_exp10:
return RValue::get(emitBuiltinWithOneOverloadedType<1>(
*this, E, Intrinsic::exp10, "elt.exp10"));
case Builtin::BI__builtin_elementwise_ldexp: {
Value *Src = EmitScalarExpr(E->getArg(0));
Value *Exp = EmitScalarExpr(E->getArg(1));
Value *Result = Builder.CreateLdexp(Src, Exp, {}, "elt.ldexp");
return RValue::get(Result);
}
case Builtin::BI__builtin_elementwise_log:
return RValue::get(emitBuiltinWithOneOverloadedType<1>(
*this, E, Intrinsic::log, "elt.log"));
Expand Down
64 changes: 52 additions & 12 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2609,6 +2609,18 @@ static ExprResult BuiltinInvoke(Sema &S, CallExpr *TheCall) {
Args.drop_front(), TheCall->getRParenLoc());
}

// Performs a similar job to Sema::UsualUnaryConversions, but without any
// implicit promotion of integral/enumeration types.
static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
// First, convert to an r-value.
ExprResult Res = S.DefaultFunctionArrayLvalueConversion(E);
if (Res.isInvalid())
return ExprError();

// Promote floating-point types.
return S.UsualUnaryFPConversions(Res.get());
}

ExprResult
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
Expand Down Expand Up @@ -3273,6 +3285,46 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;

case Builtin::BI__builtin_elementwise_ldexp: {
if (checkArgCount(TheCall, 2))
return ExprError();

ExprResult A = BuiltinVectorMathConversions(*this, TheCall->getArg(0));
if (A.isInvalid())
return ExprError();
QualType TyA = A.get()->getType();
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
EltwiseBuiltinArgTyRestriction::FloatTy, 1))
return ExprError();

ExprResult Exp = UsualUnaryConversions(TheCall->getArg(1));
if (Exp.isInvalid())
return ExprError();
QualType TyExp = Exp.get()->getType();
if (checkMathBuiltinElementType(*this, Exp.get()->getBeginLoc(), TyExp,
EltwiseBuiltinArgTyRestriction::IntegerTy,
2))
return ExprError();

// Check the two arguments are either scalars or vectors of equal length.
const auto *Vec0 = TyA->getAs<VectorType>();
const auto *Vec1 = TyExp->getAs<VectorType>();
unsigned Arg0Length = Vec0 ? Vec0->getNumElements() : 0;
unsigned Arg1Length = Vec1 ? Vec1->getNumElements() : 0;
if (Arg0Length != Arg1Length) {
Diag(Exp.get()->getBeginLoc(),
diag::err_typecheck_vector_lengths_not_equal)
<< TyA << TyExp << A.get()->getSourceRange()
<< Exp.get()->getSourceRange();
return ExprError();
}

TheCall->setArg(0, A.get());
TheCall->setArg(1, Exp.get());
TheCall->setType(TyA);
break;
}

// These builtins restrict the element type to floating point
// types only, and take in two arguments.
case Builtin::BI__builtin_elementwise_minnum:
Expand Down Expand Up @@ -15992,18 +16044,6 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) {
_2, _3, _4));
}

// Performs a similar job to Sema::UsualUnaryConversions, but without any
// implicit promotion of integral/enumeration types.
static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
// First, convert to an r-value.
ExprResult Res = S.DefaultFunctionArrayLvalueConversion(E);
if (Res.isInvalid())
return ExprError();

// Promote floating-point types.
return S.UsualUnaryFPConversions(Res.get());
}

bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
if (checkArgCount(TheCall, 1))
Expand Down
31 changes: 31 additions & 0 deletions clang/test/CodeGen/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ typedef half half2 __attribute__((ext_vector_type(2)));
typedef float float2 __attribute__((ext_vector_type(2)));
typedef float float4 __attribute__((ext_vector_type(4)));
typedef short int si8 __attribute__((ext_vector_type(8)));
typedef int int4 __attribute__((ext_vector_type(4)));
typedef unsigned int u4 __attribute__((ext_vector_type(4)));
typedef double double2 __attribute__((ext_vector_type(2)));
typedef double double3 __attribute__((ext_vector_type(3)));
Expand Down Expand Up @@ -729,6 +730,36 @@ void test_builtin_elementwise_exp10(float f1, float f2, double d1, double d2,
vf2 = __builtin_elementwise_exp10(vf1);
}

void test_builtin_elementwise_ldexp(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2, int i1, int4 vi1, short s1, long l1) {
// CHECK-LABEL: define void @test_builtin_elementwise_ldexp(
// CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4
// CHECK: [[I1:%.+]] = load i32, ptr %i1.addr, align 4
// CHECK-NEXT: call float @llvm.ldexp.f32.i32(float [[F1]], i32 [[I1]])
f2 = __builtin_elementwise_ldexp(f1, i1);

// CHECK: [[F2:%.+]] = load float, ptr %f1.addr, align 4
// CHECK: [[S1:%.+]] = load i16, ptr %s1.addr, align 2
// CHECK: [[Ext1:%.+]] = sext i16 [[S1]] to i32
// CHECK-NEXT: call float @llvm.ldexp.f32.i32(float [[F2]], i32 [[Ext1]])
f2 = __builtin_elementwise_ldexp(f1, s1);

// CHECK: [[F3:%.+]] = load float, ptr %f1.addr, align 4
// CHECK: [[L1:%.+]] = load i64, ptr %l1.addr, align 8
// CHECK-NEXT: call float @llvm.ldexp.f32.i64(float [[F3]], i64 [[L1]])
f2 = __builtin_elementwise_ldexp(f1, l1);

// CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8
// CHECK: [[I2:%.+]] = load i32, ptr %i1.addr, align 4
// CHECK-NEXT: call double @llvm.ldexp.f64.i32(double [[D1]], i32 [[I2]])
d2 = __builtin_elementwise_ldexp(d1, i1);

// CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16
// CHECK: [[VI1:%.+]] = load <4 x i32>, ptr %vi1.addr, align 16
// CHECK-NEXT: call <4 x float> @llvm.ldexp.v4f32.v4i32(<4 x float> [[VF1]], <4 x i32> [[VI1]])
vf2 = __builtin_elementwise_ldexp(vf1, vi1);
}

void test_builtin_elementwise_floor(float f1, float f2, double d1, double d2,
float4 vf1, float4 vf2) {
// CHECK-LABEL: define void @test_builtin_elementwise_floor(
Expand Down
36 changes: 36 additions & 0 deletions clang/test/Sema/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,42 @@ void test_builtin_elementwise_exp10(int i, float f, double d, float4 v, int3 iv,
// expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'unsigned4' (vector of 4 'unsigned int' values))}}
}

void test_builtin_elementwise_ldexp(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) {

struct Foo s = __builtin_elementwise_ldexp(f, i);
// expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'float'}}

f = __builtin_elementwise_ldexp();
// expected-error@-1 {{too few arguments to function call, expected 2, have 0}}

f = __builtin_elementwise_ldexp(f);
// expected-error@-1 {{too few arguments to function call, expected 2, have 1}}

f = __builtin_elementwise_ldexp(f, i, i);
// expected-error@-1 {{too many arguments to function call, expected 2, have 3}}

f = __builtin_elementwise_ldexp(i, i);
// expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'int')}}

f = __builtin_elementwise_ldexp(f, f);
// expected-error@-1 {{2nd argument must be a scalar or vector of integer types (was 'float')}}

f = __builtin_elementwise_ldexp(v, iv);
// expected-error@-1 {{vector operands do not have the same number of elements ('float4' (vector of 4 'float' values) and 'int3' (vector of 3 'int' values))}}

v = __builtin_elementwise_ldexp(v, i);
// expected-error@-1 {{vector operands do not have the same number of elements ('float4' (vector of 4 'float' values) and 'int')}}

v = __builtin_elementwise_ldexp(f, iv);
// expected-error@-1 {{vector operands do not have the same number of elements ('float' and 'int3' (vector of 3 'int' values))}}

f = __builtin_elementwise_ldexp(u, i);
// expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'unsigned int')}}

f = __builtin_elementwise_ldexp(uv, i);
// expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'unsigned4' (vector of 4 'unsigned int' values))}}
}

void test_builtin_elementwise_floor(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) {

struct Foo s = __builtin_elementwise_floor(f);
Expand Down