diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/Basic/Builtins.def | 12 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 32 | ||||
| -rw-r--r-- | clang/test/CodeGen/libcalls.c | 14 | ||||
| -rw-r--r-- | clang/test/CodeGen/math-builtins.c | 28 | ||||
| -rw-r--r-- | clang/test/CodeGen/math-libcalls.c | 32 | 
6 files changed, 87 insertions, 45 deletions
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 34ffd8d8138..56b1e67e2df 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -165,9 +165,9 @@ BUILTIN(__builtin_atanl, "LdLd", "Fne")  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(atanh, "dd", "fne", "math.h", ALL_LANGUAGES)  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) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 2d1b4f40dc5..4c5e3a4bf19 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2109,15 +2109,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,    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: diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ab1a66ad8fb..14dcce48d29 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12838,15 +12838,33 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {                                                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, diff --git a/clang/test/CodeGen/libcalls.c b/clang/test/CodeGen/libcalls.c index 0a1bcc605ca..3cf86d36a24 100644 --- a/clang/test/CodeGen/libcalls.c +++ b/clang/test/CodeGen/libcalls.c @@ -58,22 +58,22 @@ void test_pow(float a0, double a1, long double a2) {  // 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 @@ void test_builtins(double d, float f, long double ld) {  // 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 } diff --git a/clang/test/CodeGen/math-builtins.c b/clang/test/CodeGen/math-builtins.c index cb9b5974584..fb494f2e1f5 100644 --- a/clang/test/CodeGen/math-builtins.c +++ b/clang/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 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {  // 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 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {  // 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 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {  // 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{{.*}} } + diff --git a/clang/test/CodeGen/math-libcalls.c b/clang/test/CodeGen/math-libcalls.c index fcb54ed8d9f..129b86527d5 100644 --- a/clang/test/CodeGen/math-libcalls.c +++ b/clang/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 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {  // 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 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {  // 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 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {  // 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{{.*}} }  | 

