diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 962f5d8a517a..6324520350b8 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -854,12 +854,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Result.Val.getFloat())); } - // Math builtins have the same semantics as their math library twins. - // There are LLVM math intrinsics corresponding to math library functions - // except the intrinsic will never set errno while the math library might. - // Thus, we can transform math library and builtin calls to their - // semantically-equivalent LLVM intrinsic counterparts if the call is marked - // 'const' (it is known to never set errno). + // There are LLVM math intrinsics/instructions corresponding to math library + // functions except the LLVM op will never set errno while the math library + // might. Also, math builtins have the same semantics as their math library + // twins. Thus, we can transform math library and builtin calls to their + // LLVM counterparts if the call is marked 'const' (known to never set errno). if (FD->hasAttr()) { switch (BuiltinID) { case Builtin::BIceil: @@ -942,6 +941,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__builtin_fminl: return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::minnum)); + // fmod() is a special-case. It maps to the frem instruction rather than an + // LLVM intrinsic. + case Builtin::BIfmod: + case Builtin::BIfmodf: + case Builtin::BIfmodl: + case Builtin::BI__builtin_fmod: + case Builtin::BI__builtin_fmodf: + case Builtin::BI__builtin_fmodl: { + Value *Arg1 = EmitScalarExpr(E->getArg(0)); + Value *Arg2 = EmitScalarExpr(E->getArg(1)); + return RValue::get(Builder.CreateFRem(Arg1, Arg2, "fmod")); + } + case Builtin::BIlog: case Builtin::BIlogf: case Builtin::BIlogl: @@ -1067,14 +1079,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Result); } - case Builtin::BI__builtin_fmod: - case Builtin::BI__builtin_fmodf: - case Builtin::BI__builtin_fmodl: { - Value *Arg1 = EmitScalarExpr(E->getArg(0)); - Value *Arg2 = EmitScalarExpr(E->getArg(1)); - Value *Result = Builder.CreateFRem(Arg1, Arg2, "fmod"); - return RValue::get(Result); - } case Builtin::BI__builtin_conj: case Builtin::BI__builtin_conjf: case Builtin::BI__builtin_conjl: { diff --git a/clang/test/CodeGen/math-builtins.c b/clang/test/CodeGen/math-builtins.c index 805babe1cb0c..799d91b4ec00 100644 --- a/clang/test/CodeGen/math-builtins.c +++ b/clang/test/CodeGen/math-builtins.c @@ -6,12 +6,21 @@ // Test attributes and codegen of math builtins. void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) { + f = __builtin_fmod(f,f); f = __builtin_fmodf(f,f); f = __builtin_fmodl(f,f); + +// NO__ERRNO: frem double +// NO__ERRNO: frem float +// NO__ERRNO: frem x86_fp80 +// HAS_ERRNO: declare double @fmod(double, double) [[NOT_READNONE:#[0-9]+]] +// HAS_ERRNO: declare float @fmodf(float, float) [[NOT_READNONE]] +// HAS_ERRNO: declare x86_fp80 @fmodl(x86_fp80, x86_fp80) [[NOT_READNONE]] + __builtin_atan2(f,f); __builtin_atan2f(f,f) ; __builtin_atan2l(f, f); // NO__ERRNO: declare double @atan2(double, double) [[READNONE:#[0-9]+]] // NO__ERRNO: declare float @atan2f(float, float) [[READNONE]] // NO__ERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[READNONE]] -// HAS_ERRNO: declare double @atan2(double, double) [[NOT_READNONE:#[0-9]+]] +// HAS_ERRNO: declare double @atan2(double, double) [[NOT_READNONE]] // HAS_ERRNO: declare float @atan2f(float, float) [[NOT_READNONE]] // HAS_ERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NOT_READNONE]] @@ -33,13 +42,6 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) { // HAS_ERRNO: declare float @llvm.fabs.f32(float) [[READNONE_INTRINSIC]] // HAS_ERRNO: declare x86_fp80 @llvm.fabs.f80(x86_fp80) [[READNONE_INTRINSIC]] - __builtin_fmod(f,f); __builtin_fmodf(f,f); __builtin_fmodl(f,f); - -// NO__ERRNO-NOT: .fmod -// NO__ERRNO-NOT: @fmod -// HAS_ERRNO-NOT: .fmod -// HAS_ERRNO-NOT: @fmod - __builtin_frexp(f,i); __builtin_frexpf(f,i); __builtin_frexpl(f,i); // NO__ERRNO: declare double @frexp(double, i32*) [[NOT_READNONE:#[0-9]+]] diff --git a/clang/test/CodeGen/math-libcalls.c b/clang/test/CodeGen/math-libcalls.c index be9481cea459..39bcb4454d7c 100644 --- a/clang/test/CodeGen/math-libcalls.c +++ b/clang/test/CodeGen/math-libcalls.c @@ -6,12 +6,21 @@ // Test attributes and builtin codegen of math library calls. void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) { + f = fmod(f,f); f = fmodf(f,f); f = fmodl(f,f); + +// NO__ERRNO: frem double +// NO__ERRNO: frem float +// NO__ERRNO: frem x86_fp80 +// HAS_ERRNO: declare double @fmod(double, double) [[NOT_READNONE:#[0-9]+]] +// HAS_ERRNO: declare float @fmodf(float, float) [[NOT_READNONE]] +// HAS_ERRNO: declare x86_fp80 @fmodl(x86_fp80, x86_fp80) [[NOT_READNONE]] + atan2(f,f); atan2f(f,f) ; atan2l(f, f); // NO__ERRNO: declare double @atan2(double, double) [[READNONE:#[0-9]+]] // NO__ERRNO: declare float @atan2f(float, float) [[READNONE]] // NO__ERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[READNONE]] -// HAS_ERRNO: declare double @atan2(double, double) [[NOT_READNONE:#[0-9]+]] +// HAS_ERRNO: declare double @atan2(double, double) [[NOT_READNONE]] // HAS_ERRNO: declare float @atan2f(float, float) [[NOT_READNONE]] // HAS_ERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NOT_READNONE]] @@ -33,15 +42,6 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) { // HAS_ERRNO: declare float @llvm.fabs.f32(float) [[READNONE_INTRINSIC]] // HAS_ERRNO: declare x86_fp80 @llvm.fabs.f80(x86_fp80) [[READNONE_INTRINSIC]] - fmod(f,f); fmodf(f,f); fmodl(f,f); - -// NO__ERRNO: declare double @fmod(double, double) [[READNONE]] -// NO__ERRNO: declare float @fmodf(float, float) [[READNONE]] -// NO__ERRNO: declare x86_fp80 @fmodl(x86_fp80, x86_fp80) [[READNONE]] -// HAS_ERRNO: declare double @fmod(double, double) [[NOT_READNONE]] -// HAS_ERRNO: declare float @fmodf(float, float) [[NOT_READNONE]] -// HAS_ERRNO: declare x86_fp80 @fmodl(x86_fp80, x86_fp80) [[NOT_READNONE]] - frexp(f,i); frexpf(f,i); frexpl(f,i); // NO__ERRNO: declare double @frexp(double, i32*) [[NOT_READNONE:#[0-9]+]]