Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -651,6 +651,19 @@ exceptions. T __builtin_elementwise_trunc(T x) return the integral value nearest to but no larger in floating point types magnitude than x + + T __builtin_elementwise_nearbyint(T x) round x to the nearest integer value in floating point format, floating point types + rounding halfway according to the current current rounding + direction. May not raise floating-point exceptions. This is + treated the same as ``__builtin_elementwise_rint`` unless + :ref:`FENV_ACCESS is enabled. `. + + T __builtin_elementwise_rint(T x) round x to the nearest integer value in floating point format, floating point types + rounding halfway cases according to the current rounding + direction. May raise floating-point exceptions. This is treated + the same as ``__builtin_elementwise_nearbyint`` unless + :ref:`FENV_ACCESS is enabled. `. + T __builtin_elementwise_canonicalize(T x) return the platform specific canonical encoding floating point types of a floating-point number T __builtin_elementwise_copysign(T x, T y) return the magnitude of x with the sign of y. floating point types Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -231,7 +231,12 @@ - Added ``__builtin_elementwise_round`` for builtin for floating point types. This allows access to ``llvm.round`` for arbitrary floating-point and vector of floating-point types. - +- Added ``__builtin_elementwise_rint`` for builtin for floating + point types. This allows access to ``llvm.rint`` for + arbitrary floating-point and vector of floating-point types. +- Added ``__builtin_elementwise_nearbyint`` for builtin for floating + point types. This allows access to ``llvm.nearbyint`` for + arbitrary floating-point and vector of floating-point types. New Compiler Flags ------------------ Index: clang/include/clang/Basic/Builtins.def =================================================================== --- clang/include/clang/Basic/Builtins.def +++ clang/include/clang/Basic/Builtins.def @@ -688,6 +688,8 @@ BUILTIN(__builtin_elementwise_log10, "v.", "nct") BUILTIN(__builtin_elementwise_roundeven, "v.", "nct") BUILTIN(__builtin_elementwise_round, "v.", "nct") +BUILTIN(__builtin_elementwise_rint, "v.", "nct") +BUILTIN(__builtin_elementwise_nearbyint, "v.", "nct") BUILTIN(__builtin_elementwise_sin, "v.", "nct") BUILTIN(__builtin_elementwise_trunc, "v.", "nct") BUILTIN(__builtin_elementwise_canonicalize, "v.", "nct") Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -3197,6 +3197,12 @@ case Builtin::BI__builtin_elementwise_round: return RValue::get(emitUnaryBuiltin(*this, E, llvm::Intrinsic::round, "elt.round")); + case Builtin::BI__builtin_elementwise_rint: + return RValue::get(emitUnaryBuiltin(*this, E, llvm::Intrinsic::rint, + "elt.rint")); + case Builtin::BI__builtin_elementwise_nearbyint: + return RValue::get(emitUnaryBuiltin(*this, E, llvm::Intrinsic::nearbyint, + "elt.nearbyint")); case Builtin::BI__builtin_elementwise_sin: return RValue::get( emitUnaryBuiltin(*this, E, llvm::Intrinsic::sin, "elt.sin")); Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -2637,6 +2637,8 @@ case Builtin::BI__builtin_elementwise_log10: case Builtin::BI__builtin_elementwise_roundeven: case Builtin::BI__builtin_elementwise_round: + case Builtin::BI__builtin_elementwise_rint: + case Builtin::BI__builtin_elementwise_nearbyint: case Builtin::BI__builtin_elementwise_sin: case Builtin::BI__builtin_elementwise_trunc: case Builtin::BI__builtin_elementwise_canonicalize: { Index: clang/test/CodeGen/builtins-elementwise-math.c =================================================================== --- clang/test/CodeGen/builtins-elementwise-math.c +++ clang/test/CodeGen/builtins-elementwise-math.c @@ -484,6 +484,38 @@ vf2 = __builtin_elementwise_round(vf1); } +void test_builtin_elementwise_rint(float f1, float f2, double d1, double d2, + float4 vf1, float4 vf2) { + // CHECK-LABEL: define void @test_builtin_elementwise_rint( + // CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4 + // CHECK-NEXT: call float @llvm.rint.f32(float [[F1]]) + f2 = __builtin_elementwise_rint(f1); + + // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8 + // CHECK-NEXT: call double @llvm.rint.f64(double [[D1]]) + d2 = __builtin_elementwise_rint(d1); + + // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16 + // CHECK-NEXT: call <4 x float> @llvm.rint.v4f32(<4 x float> [[VF1]]) + vf2 = __builtin_elementwise_rint(vf1); +} + +void test_builtin_elementwise_nearbyint(float f1, float f2, double d1, double d2, + float4 vf1, float4 vf2) { + // CHECK-LABEL: define void @test_builtin_elementwise_nearbyint( + // CHECK: [[F1:%.+]] = load float, ptr %f1.addr, align 4 + // CHECK-NEXT: call float @llvm.nearbyint.f32(float [[F1]]) + f2 = __builtin_elementwise_nearbyint(f1); + + // CHECK: [[D1:%.+]] = load double, ptr %d1.addr, align 8 + // CHECK-NEXT: call double @llvm.nearbyint.f64(double [[D1]]) + d2 = __builtin_elementwise_nearbyint(d1); + + // CHECK: [[VF1:%.+]] = load <4 x float>, ptr %vf1.addr, align 16 + // CHECK-NEXT: call <4 x float> @llvm.nearbyint.v4f32(<4 x float> [[VF1]]) + vf2 = __builtin_elementwise_nearbyint(vf1); +} + void test_builtin_elementwise_sin(float f1, float f2, double d1, double d2, float4 vf1, float4 vf2) { // CHECK-LABEL: define void @test_builtin_elementwise_sin( Index: clang/test/CodeGen/strictfp-elementwise-bulitins.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/strictfp-elementwise-bulitins.cpp @@ -0,0 +1,264 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fexperimental-strict-floating-point -frounding-math -ffp-exception-behavior=strict -O2 -emit-llvm -o - %s | FileCheck %s + +typedef float float2 __attribute__((ext_vector_type(2))); + +// Sanity check we're getting constrained ops for a non-builtin. +// CHECK-LABEL: define dso_local noundef double @_Z11strict_faddDv2_fS_ +// CHECK-SAME: (double noundef [[A_COERCE:%.*]], double noundef [[B_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[B_COERCE]] to <2 x float> +// CHECK-NEXT: [[ADD:%.*]] = tail call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[TMP0]], <2 x float> [[TMP1]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR4:[0-9]+]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x float> [[ADD]] to double +// CHECK-NEXT: ret double [[TMP2]] +// +float2 strict_fadd(float2 a, float2 b) { + return a + b; +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_absDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_ABS:%.*]] = tail call <2 x float> @llvm.fabs.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_ABS]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_abs(float2 a) { + return __builtin_elementwise_abs(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_maxDv2_fS_ +// CHECK-SAME: (double noundef [[A_COERCE:%.*]], double noundef [[B_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[B_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_MAX:%.*]] = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> [[TMP0]], <2 x float> [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x float> [[ELT_MAX]] to double +// CHECK-NEXT: ret double [[TMP2]] +// +float2 strict_elementwise_max(float2 a, float2 b) { + return __builtin_elementwise_max(a, b); +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_minDv2_fS_ +// CHECK-SAME: (double noundef [[A_COERCE:%.*]], double noundef [[B_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[B_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_MIN:%.*]] = tail call <2 x float> @llvm.minnum.v2f32(<2 x float> [[TMP0]], <2 x float> [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x float> [[ELT_MIN]] to double +// CHECK-NEXT: ret double [[TMP2]] +// +float2 strict_elementwise_min(float2 a, float2 b) { + return __builtin_elementwise_min(a, b); +} + +// CHECK-LABEL: define dso_local noundef double @_Z23strict_elementwise_ceilDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_CEIL:%.*]] = tail call <2 x float> @llvm.ceil.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_CEIL]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_ceil(float2 a) { + return __builtin_elementwise_ceil(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_cosDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_COS:%.*]] = tail call <2 x float> @llvm.cos.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_COS]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_cos(float2 a) { + return __builtin_elementwise_cos(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_expDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_EXP:%.*]] = tail call <2 x float> @llvm.exp.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_EXP]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_exp(float2 a) { + return __builtin_elementwise_exp(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z23strict_elementwise_exp2Dv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_EXP2:%.*]] = tail call <2 x float> @llvm.exp2.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_EXP2]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_exp2(float2 a) { + return __builtin_elementwise_exp2(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z24strict_elementwise_floorDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_FLOOR:%.*]] = tail call <2 x float> @llvm.floor.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_FLOOR]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_floor(float2 a) { + return __builtin_elementwise_floor(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_logDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_LOG:%.*]] = tail call <2 x float> @llvm.log.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_LOG]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_log(float2 a) { + return __builtin_elementwise_log(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z23strict_elementwise_log2Dv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_LOG2:%.*]] = tail call <2 x float> @llvm.log2.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_LOG2]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_log2(float2 a) { + return __builtin_elementwise_log2(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z24strict_elementwise_log10Dv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_LOG2:%.*]] = tail call <2 x float> @llvm.log2.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_LOG2]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_log10(float2 a) { + return __builtin_elementwise_log2(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z28strict_elementwise_roundevenDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_ROUNDEVEN:%.*]] = tail call <2 x float> @llvm.roundeven.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_ROUNDEVEN]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_roundeven(float2 a) { + return __builtin_elementwise_roundeven(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z24strict_elementwise_roundDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_ROUND:%.*]] = tail call <2 x float> @llvm.round.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_ROUND]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_round(float2 a) { + return __builtin_elementwise_round(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z23strict_elementwise_rintDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_RINT:%.*]] = tail call <2 x float> @llvm.rint.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_RINT]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_rint(float2 a) { + return __builtin_elementwise_rint(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z28strict_elementwise_nearbyintDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_NEARBYINT:%.*]] = tail call <2 x float> @llvm.nearbyint.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_NEARBYINT]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_nearbyint(float2 a) { + return __builtin_elementwise_nearbyint(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_sinDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_SIN:%.*]] = tail call <2 x float> @llvm.sin.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_SIN]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_sin(float2 a) { + return __builtin_elementwise_sin(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z24strict_elementwise_truncDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_TRUNC:%.*]] = tail call <2 x float> @llvm.trunc.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_TRUNC]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_trunc(float2 a) { + return __builtin_elementwise_trunc(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z31strict_elementwise_canonicalizeDv2_f +// CHECK-SAME: (double noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[ELT_TRUNC:%.*]] = tail call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[TMP0]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x float> [[ELT_TRUNC]] to double +// CHECK-NEXT: ret double [[TMP1]] +// +float2 strict_elementwise_canonicalize(float2 a) { + return __builtin_elementwise_canonicalize(a); +} + +// CHECK-LABEL: define dso_local noundef double @_Z27strict_elementwise_copysignDv2_fS_ +// CHECK-SAME: (double noundef [[A_COERCE:%.*]], double noundef [[B_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[B_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP2:%.*]] = tail call <2 x float> @llvm.copysign.v2f32(<2 x float> [[TMP0]], <2 x float> [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast <2 x float> [[TMP2]] to double +// CHECK-NEXT: ret double [[TMP3]] +// +float2 strict_elementwise_copysign(float2 a, float2 b) { + return __builtin_elementwise_copysign(a, b); +} + +// CHECK-LABEL: define dso_local noundef double @_Z22strict_elementwise_fmaDv2_fS_S_ +// CHECK-SAME: (double noundef [[A_COERCE:%.*]], double noundef [[B_COERCE:%.*]], double noundef [[C_COERCE:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[A_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[B_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP2:%.*]] = bitcast double [[C_COERCE]] to <2 x float> +// CHECK-NEXT: [[TMP3:%.*]] = tail call <2 x float> @llvm.fma.v2f32(<2 x float> [[TMP0]], <2 x float> [[TMP1]], <2 x float> [[TMP2]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP4:%.*]] = bitcast <2 x float> [[TMP3]] to double +// CHECK-NEXT: ret double [[TMP4]] +// +float2 strict_elementwise_fma(float2 a, float2 b, float2 c) { + return __builtin_elementwise_fma(a, b, c); +} + Index: clang/test/Sema/builtins-elementwise-math.c =================================================================== --- clang/test/Sema/builtins-elementwise-math.c +++ clang/test/Sema/builtins-elementwise-math.c @@ -460,7 +460,6 @@ } void test_builtin_elementwise_round(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) { - struct Foo s = __builtin_elementwise_round(f); // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'float'}} @@ -485,6 +484,56 @@ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}} } +void test_builtin_elementwise_rint(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) { + struct Foo s = __builtin_elementwise_rint(f); + // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'float'}} + + i = __builtin_elementwise_rint(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} + + i = __builtin_elementwise_rint(i); + // expected-error@-1 {{1st argument must be a floating point type (was 'int')}} + + i = __builtin_elementwise_rint(f, f); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} + + u = __builtin_elementwise_rint(u); + // expected-error@-1 {{1st argument must be a floating point type (was 'unsigned int')}} + + uv = __builtin_elementwise_rint(uv); + // expected-error@-1 {{1st argument must be a floating point type (was 'unsigned4' (vector of 4 'unsigned int' values))}} + + // FIXME: Error should not mention integer + _Complex float c1, c2; + c1 = __builtin_elementwise_rint(c1); + // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}} +} + +void test_builtin_elementwise_nearbyint(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) { + struct Foo s = __builtin_elementwise_nearbyint(f); + // expected-error@-1 {{initializing 'struct Foo' with an expression of incompatible type 'float'}} + + i = __builtin_elementwise_nearbyint(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} + + i = __builtin_elementwise_nearbyint(i); + // expected-error@-1 {{1st argument must be a floating point type (was 'int')}} + + i = __builtin_elementwise_nearbyint(f, f); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} + + u = __builtin_elementwise_nearbyint(u); + // expected-error@-1 {{1st argument must be a floating point type (was 'unsigned int')}} + + uv = __builtin_elementwise_nearbyint(uv); + // expected-error@-1 {{1st argument must be a floating point type (was 'unsigned4' (vector of 4 'unsigned int' values))}} + + // FIXME: Error should not mention integer + _Complex float c1, c2; + c1 = __builtin_elementwise_nearbyint(c1); + // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was '_Complex float')}} +} + void test_builtin_elementwise_sin(int i, float f, double d, float4 v, int3 iv, unsigned u, unsigned4 uv) { struct Foo s = __builtin_elementwise_sin(f);