Index: cfe/trunk/include/clang/Basic/Builtins.def =================================================================== --- cfe/trunk/include/clang/Basic/Builtins.def +++ cfe/trunk/include/clang/Basic/Builtins.def @@ -165,9 +165,9 @@ 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") @@ -1040,9 +1040,9 @@ 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) Index: cfe/trunk/lib/CodeGen/CGBuiltin.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp @@ -2109,15 +2109,11 @@ 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()) + return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma)); + break; case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -12838,15 +12838,33 @@ 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()) + // 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() && + 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()) { + 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()) FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context, Index: cfe/trunk/test/CodeGen/libcalls.c =================================================================== --- cfe/trunk/test/CodeGen/libcalls.c +++ cfe/trunk/test/CodeGen/libcalls.c @@ -58,22 +58,22 @@ // 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]] @@ -123,7 +123,5 @@ // 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 } Index: cfe/trunk/test/CodeGen/math-builtins.c =================================================================== --- cfe/trunk/test/CodeGen/math-builtins.c +++ cfe/trunk/test/CodeGen/math-builtins.c @@ -1,5 +1,7 @@ // 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. @@ -175,9 +177,9 @@ // 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); @@ -274,9 +276,20 @@ // 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); @@ -558,3 +571,6 @@ // 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{{.*}} } + Index: cfe/trunk/test/CodeGen/math-libcalls.c =================================================================== --- cfe/trunk/test/CodeGen/math-libcalls.c +++ cfe/trunk/test/CodeGen/math-libcalls.c @@ -1,5 +1,7 @@ -// 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. @@ -145,9 +147,9 @@ // 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); @@ -244,9 +246,20 @@ // 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); @@ -528,5 +541,6 @@ // 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{{.*}} }