BUILTIN(__builtin_atanh , "dd", "Fne")
BUILTIN(__builtin_atanhf, "ff", "Fne")
BUILTIN(__builtin_atanhl, "LdLd", "Fne")
-BUILTIN(__builtin_cbrt , "dd", "Fne")
-BUILTIN(__builtin_cbrtf, "ff", "Fne")
-BUILTIN(__builtin_cbrtl, "LdLd", "Fne")
+BUILTIN(__builtin_cbrt , "dd", "Fnc")
+BUILTIN(__builtin_cbrtf, "ff", "Fnc")
+BUILTIN(__builtin_cbrtl, "LdLd", "Fnc")
BUILTIN(__builtin_ceil , "dd" , "Fnc")
BUILTIN(__builtin_ceilf, "ff" , "Fnc")
BUILTIN(__builtin_ceill, "LdLd", "Fnc")
LIBBUILTIN(atanhf, "ff", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(atanhl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(cbrt, "dd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(cbrtf, "ff", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(cbrtl, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cbrt, "dd", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cbrtf, "ff", "fnc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cbrtl, "LdLd", "fnc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceil, "dd", "fnc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceilf, "ff", "fnc", "math.h", ALL_LANGUAGES)
case Builtin::BIfmal:
case Builtin::BI__builtin_fma:
case Builtin::BI__builtin_fmaf:
- case Builtin::BI__builtin_fmal: {
- // Rewrite fma to intrinsic.
- Value *FirstArg = EmitScalarExpr(E->getArg(0));
- llvm::Type *ArgType = FirstArg->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::fma, ArgType);
- return RValue::get(
- Builder.CreateCall(F, {FirstArg, EmitScalarExpr(E->getArg(1)),
- EmitScalarExpr(E->getArg(2))}));
- }
+ case Builtin::BI__builtin_fmal:
+ // A constant libcall or builtin is equivalent to the LLVM intrinsic.
+ if (FD->hasAttr<ConstAttr>())
+ return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma));
+ break;
case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
FD->getLocation()));
}
- // Mark const if we don't care about errno and that is the only
- // thing preventing the function from being const. This allows
- // IRgen to use LLVM intrinsics for such functions.
- if (!getLangOpts().MathErrno &&
- Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) {
- if (!FD->hasAttr<ConstAttr>())
+ // Mark const if we don't care about errno and that is the only thing
+ // preventing the function from being const. This allows IRgen to use LLVM
+ // intrinsics for such functions.
+ if (!getLangOpts().MathErrno && !FD->hasAttr<ConstAttr>() &&
+ Context.BuiltinInfo.isConstWithoutErrno(BuiltinID))
+ FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
+
+ // We make "fma" on GNU or Windows const because we know it does not set
+ // errno in those environments even though it could set errno based on the
+ // C standard.
+ const llvm::Triple &Trip = Context.getTargetInfo().getTriple();
+ if ((Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) &&
+ !FD->hasAttr<ConstAttr>()) {
+ switch (BuiltinID) {
+ case Builtin::BI__builtin_fma:
+ case Builtin::BI__builtin_fmaf:
+ case Builtin::BI__builtin_fmal:
+ case Builtin::BIfma:
+ case Builtin::BIfmaf:
+ case Builtin::BIfmal:
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
+ break;
+ default:
+ break;
+ }
}
-
+
if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) &&
!FD->hasAttr<ReturnsTwiceAttr>())
FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context,
// CHECK-YES-LABEL: define void @test_fma
// CHECK-NO-LABEL: define void @test_fma
void test_fma(float a0, double a1, long double a2) {
- // CHECK-YES: call float @llvm.fma.f32
+ // CHECK-YES: call float @fmaf
// CHECK-NO: call float @llvm.fma.f32
float l0 = fmaf(a0, a0, a0);
- // CHECK-YES: call double @llvm.fma.f64
+ // CHECK-YES: call double @fma
// CHECK-NO: call double @llvm.fma.f64
double l1 = fma(a1, a1, a1);
- // CHECK-YES: call x86_fp80 @llvm.fma.f80
+ // CHECK-YES: call x86_fp80 @fmal
// CHECK-NO: call x86_fp80 @llvm.fma.f80
long double l2 = fmal(a2, a2, a2);
}
-// CHECK-YES: declare float @llvm.fma.f32(float, float, float) [[NUW_RN:#[0-9]+]]
-// CHECK-YES: declare double @llvm.fma.f64(double, double, double) [[NUW_RN]]
-// CHECK-YES: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[NUW_RN]]
+// CHECK-YES: declare float @fmaf(float, float, float)
+// CHECK-YES: declare double @fma(double, double, double)
+// CHECK-YES: declare x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80)
// CHECK-NO: declare float @llvm.fma.f32(float, float, float) [[NUW_RN2:#[0-9]+]]
// CHECK-NO: declare double @llvm.fma.f64(double, double, double) [[NUW_RN2]]
// CHECK-NO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[NUW_RN2]]
// CHECK-YES-NOT: declare float @logf(float) [[NUW_RN]]
}
-// CHECK-YES: attributes [[NUW_RN]] = { nounwind readnone speculatable }
-
// CHECK-NO-DAG: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
// CHECK-NO-DAG: attributes [[NUW_RNI]] = { nounwind readnone speculatable }
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -w -S -o - -emit-llvm %s | FileCheck %s -check-prefix=NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -w -S -o - -emit-llvm -fmath-errno %s | FileCheck %s -check-prefix=HAS_ERRNO
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown-gnu -w -S -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_GNU
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -w -S -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_WIN
// Test attributes and codegen of math builtins.
// NO__ERRNO: declare double @cbrt(double) [[READNONE]]
// NO__ERRNO: declare float @cbrtf(float) [[READNONE]]
// NO__ERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[READNONE]]
-// HAS_ERRNO: declare double @cbrt(double) [[NOT_READNONE]]
-// HAS_ERRNO: declare float @cbrtf(float) [[NOT_READNONE]]
-// HAS_ERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[NOT_READNONE]]
+// HAS_ERRNO: declare double @cbrt(double) [[READNONE]]
+// HAS_ERRNO: declare float @cbrtf(float) [[READNONE]]
+// HAS_ERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[READNONE]]
__builtin_ceil(f); __builtin_ceilf(f); __builtin_ceill(f);
// NO__ERRNO: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC]]
// NO__ERRNO: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
// NO__ERRNO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
-// HAS_ERRNO: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC]]
-// HAS_ERRNO: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
-// HAS_ERRNO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @fma(double, double, double) [[NOT_READNONE]]
+// HAS_ERRNO: declare float @fmaf(float, float, float) [[NOT_READNONE]]
+// HAS_ERRNO: declare x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80) [[NOT_READNONE]]
+
+// On GNU or Win, fma never sets errno, so we can convert to the intrinsic.
+
+// HAS_ERRNO_GNU: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC:#[0-9]+]]
+// HAS_ERRNO_GNU: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO_GNU: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+
+// HAS_ERRNO_WIN: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC:#[0-9]+]]
+// HAS_ERRNO_WIN: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
+// Long double is just double on win, so no f80 use/declaration.
+// HAS_ERRNO_WIN-NOT: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80)
__builtin_fmax(f,f); __builtin_fmaxf(f,f); __builtin_fmaxl(f,f);
// HAS_ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} }
// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} }
+// HAS_ERRNO_GNU: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} }
+// HAS_ERRNO_WIN: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} }
+
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -w -S -o - -emit-llvm %s | FileCheck %s -check-prefix=NO__ERRNO
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -w -S -o - -emit-llvm -fmath-errno %s | FileCheck %s -check-prefix=HAS_ERRNO
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -w -S -o - -emit-llvm %s | FileCheck %s --check-prefix=NO__ERRNO
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -w -S -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown-gnu -w -S -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_GNU
+// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -w -S -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_WIN
// Test attributes and builtin codegen of math library calls.
// NO__ERRNO: declare double @cbrt(double) [[READNONE]]
// NO__ERRNO: declare float @cbrtf(float) [[READNONE]]
// NO__ERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[READNONE]]
-// HAS_ERRNO: declare double @cbrt(double) [[NOT_READNONE]]
-// HAS_ERRNO: declare float @cbrtf(float) [[NOT_READNONE]]
-// HAS_ERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[NOT_READNONE]]
+// HAS_ERRNO: declare double @cbrt(double) [[READNONE]]
+// HAS_ERRNO: declare float @cbrtf(float) [[READNONE]]
+// HAS_ERRNO: declare x86_fp80 @cbrtl(x86_fp80) [[READNONE]]
ceil(f); ceilf(f); ceill(f);
// NO__ERRNO: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC]]
// NO__ERRNO: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
// NO__ERRNO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
-// HAS_ERRNO: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC:#[0-9]+]]
-// HAS_ERRNO: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
-// HAS_ERRNO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+// HAS_ERRNO: declare double @fma(double, double, double) [[NOT_READNONE]]
+// HAS_ERRNO: declare float @fmaf(float, float, float) [[NOT_READNONE]]
+// HAS_ERRNO: declare x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80) [[NOT_READNONE]]
+
+// On GNU or Win, fma never sets errno, so we can convert to the intrinsic.
+
+// HAS_ERRNO_GNU: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC:#[0-9]+]]
+// HAS_ERRNO_GNU: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
+// HAS_ERRNO_GNU: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]
+
+// HAS_ERRNO_WIN: declare double @llvm.fma.f64(double, double, double) [[READNONE_INTRINSIC:#[0-9]+]]
+// HAS_ERRNO_WIN: declare float @llvm.fma.f32(float, float, float) [[READNONE_INTRINSIC]]
+// Long double is just double on win, so no f80 use/declaration.
+// HAS_ERRNO_WIN-NOT: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80)
fmax(f,f); fmaxf(f,f); fmaxl(f,f);
// HAS_ERRNO: attributes [[NOT_READNONE]] = { nounwind "correctly{{.*}} }
// HAS_ERRNO: attributes [[READNONE]] = { {{.*}}readnone{{.*}} }
// HAS_ERRNO: attributes [[READONLY]] = { {{.*}}readonly{{.*}} }
-// HAS_ERRNO: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} }
+// HAS_ERRNO_GNU: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} }
+// HAS_ERRNO_WIN: attributes [[READNONE_INTRINSIC]] = { {{.*}}readnone{{.*}} }