diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-02-16 22:43:43 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-02-16 22:43:43 +0000 |
commit | ef2abfee3ea16ec74942dc09e9e425f46aeb2582 (patch) | |
tree | a1fd544522e1d5e2708b9b2a6df1704a0734d0bd | |
parent | f592c929bd1f083abcc8199b24bb825fdd28df1c (diff) |
Support IRgen of sqrt -> llvm.sqrt, pow -> llvm.pow.
- Define pow[lf]?, sqrt[lf]? as builtins.
- Add -fmath-errno option which binds to LangOptions.MathErrno
- Add new builtin flag Builtin::Context::isConstWithoutErrno for
functions which can be marked as const if errno isn't respected for
math functions. Sema automatically marks these functions as const
when they are defined, if MathErrno=0.
- IRgen uses const attribute on sqrt and pow library functions to
decide if it can use the llvm intrinsic.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64689 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | Driver/clang.cpp | 12 | ||||
-rw-r--r-- | include/clang/AST/Builtins.def | 12 | ||||
-rw-r--r-- | include/clang/AST/Builtins.h | 8 | ||||
-rw-r--r-- | include/clang/Basic/LangOptions.h | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGBuiltin.cpp | 31 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 9 | ||||
-rw-r--r-- | test/CodeGen/libcalls.c | 22 |
9 files changed, 96 insertions, 7 deletions
diff --git a/Driver/clang.cpp b/Driver/clang.cpp index d1ef871d6a..d0b3dafb31 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -213,9 +213,14 @@ InheritanceViewCls("cxx-inheritance-view", //===----------------------------------------------------------------------===// static llvm::cl::opt<bool> Freestanding("ffreestanding", - llvm::cl::desc("Assert that the compiler takes place in a " + llvm::cl::desc("Assert that the compilation takes place in a " "freestanding environment")); +static llvm::cl::opt<bool> +MathErrno("fmath-errno", + llvm::cl::desc("Require math functions to respect errno."), + llvm::cl::init(true)); + //===----------------------------------------------------------------------===// // Analyzer Options. //===----------------------------------------------------------------------===// @@ -647,6 +652,8 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK, if (Freestanding) Options.Freestanding = 1; + Options.MathErrno = MathErrno; + // Override the default runtime if the user requested it. if (NeXTRuntime) Options.NeXTRuntime = 1; @@ -1238,8 +1245,7 @@ static void ParseFile(Preprocessor &PP, MinimalAction *PA) { //===----------------------------------------------------------------------===// static llvm::cl::opt<bool> -OptSize("Os", - llvm::cl::desc("Optimize for size")); +OptSize("Os", llvm::cl::desc("Optimize for size")); // It might be nice to add bounds to the CommandLine library directly. struct OptLevelParser : public llvm::cl::parser<unsigned> { diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def index bdcdab15b4..94696e8174 100644 --- a/include/clang/AST/Builtins.def +++ b/include/clang/AST/Builtins.def @@ -63,6 +63,7 @@ // P:N: -> similar to the p:N: attribute, but the function is like vprintf // in that it accepts its arguments as a va_list rather than // through an ellipsis +// e -> const, but only when -fmath-errno=0 // FIXME: gcc has nonnull #if defined(BUILTIN) && !defined(LIBBUILTIN) @@ -176,7 +177,7 @@ BUILTIN(__sync_fetch_and_min,"ii*i", "n") BUILTIN(__sync_fetch_and_max,"ii*i", "n") BUILTIN(__sync_fetch_and_umin,"UiUi*Ui", "n") BUILTIN(__sync_fetch_and_umax,"UiUi*Ui", "n") -BUILTIN(__sync_fetch_and_and,"ii*i", "n") +BUILTIN(__sync_fetch_and_and,"ii*i", "n") BUILTIN(__sync_fetch_and_or,"ii*i", "n") BUILTIN(__sync_fetch_and_xor,"ii*i", "n") BUILTIN(__sync_lock_test_and_set,"ii*i", "n") @@ -216,5 +217,14 @@ LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h") // FIXME: asprintf and vasprintf aren't C99 functions. Should they be // target-specific builtins, perhaps? +// Builtin math library functions +LIBBUILTIN(pow, "ddd", "fe", "math.h") +LIBBUILTIN(powl, "LdLdLd", "fe", "math.h") +LIBBUILTIN(powf, "fff", "fe", "math.h") + +LIBBUILTIN(sqrt, "dd", "fe", "math.h") +LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h") +LIBBUILTIN(sqrtf, "ff", "fe", "math.h") + #undef BUILTIN #undef LIBBUILTIN diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h index 6af8d750a4..ad71375eba 100644 --- a/include/clang/AST/Builtins.h +++ b/include/clang/AST/Builtins.h @@ -105,6 +105,14 @@ public: return strpbrk(GetRecord(ID).Type, "Aa") != 0; } + /// isConstWithoutErrno - Return true if this function has no side + /// effects and doesn't read memory, except for possibly errno. Such + /// functions can be const when the MathErrno lang option is + /// disabled. + bool isConstWithoutErrno(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'e') != 0; + } + /// GetBuiltinType - Return the type for the specified builtin. enum GetBuiltinTypeError { GE_None, //< No error diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 12fffb332d..0124b04aa9 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -54,6 +54,9 @@ public: unsigned Blocks : 1; // block extension to C unsigned EmitAllDecls : 1; // Emit all declarations, even if // they are unused. + unsigned MathErrno : 1; // Math functions must respect errno + // (modulo the platform support). + private: unsigned GC : 2; // Objective-C Garbage Collection modes. We declare // this enum as unsigned because MSVC insists on making enums @@ -76,6 +79,7 @@ public: ThreadsafeStatics = 0; Blocks = 0; EmitAllDecls = 0; + MathErrno = 1; } GCMode getGCMode() const { return (GCMode) GC; } diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index b990c19995..6e59226a6e 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -36,7 +36,8 @@ static RValue EmitBinaryAtomic(CodeGenFunction& CFG, CFG.EmitScalarExpr(E->getArg(1)))); } -RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { +RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, + unsigned BuiltinID, const CallExpr *E) { // See if we can constant fold this builtin. If so, don't emit it at all. Expr::EvalResult Result; if (E->Evaluate(Result, CGM.getContext())) { @@ -324,6 +325,34 @@ RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { } case Builtin::BI__sync_lock_test_and_set: return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); + + + // Library functions with special handling. + + case Builtin::BIsqrt: + case Builtin::BIsqrtf: + case Builtin::BIsqrtl: { + // Rewrite sqrt to intrinsic if allowed. + if (!FD->getAttr<ConstAttr>()) + break; + Value *Arg0 = EmitScalarExpr(E->getArg(0)); + const llvm::Type *ArgType = Arg0->getType(); + Value *F = CGM.getIntrinsic(Intrinsic::sqrt, &ArgType, 1); + return RValue::get(Builder.CreateCall(F, Arg0, "tmp")); + } + + case Builtin::BIpow: + case Builtin::BIpowf: + case Builtin::BIpowl: { + // Rewrite sqrt to intrinsic if allowed. + if (!FD->getAttr<ConstAttr>()) + break; + Value *Base = EmitScalarExpr(E->getArg(0)); + Value *Exponent = EmitScalarExpr(E->getArg(1)); + const llvm::Type *ArgType = Base->getType(); + Value *F = CGM.getIntrinsic(Intrinsic::pow, &ArgType, 1); + return RValue::get(Builder.CreateCall2(F, Base, Exponent, "tmp")); + } } // If this is an alias for a libm function (e.g. __builtin_sin) turn it into diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 4dc8a9e1d4..b151dd2102 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -969,7 +969,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const FunctionDecl *FDecl = dyn_cast<const FunctionDecl>(DRExpr->getDecl())) if (unsigned builtinID = FDecl->getBuiltinID(getContext())) - return EmitBuiltinExpr(builtinID, E); + return EmitBuiltinExpr(FDecl, builtinID, E); if (E->getCallee()->getType()->isBlockPointerType()) return EmitBlockCallExpr(E); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 5f42a429e0..7f36c71ab6 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -631,7 +631,8 @@ public: CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); - RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + RValue EmitBuiltinExpr(const FunctionDecl *FD, + unsigned BuiltinID, const CallExpr *E); RValue EmitBlockCallExpr(const CallExpr *E); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2692cd99db..4f8b245ef3 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2956,6 +2956,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (!FD->getAttr<FormatAttr>()) FD->addAttr(new FormatAttr("printf", FormatIdx + 1, FormatIdx + 2)); } + + // 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 (!getLangOptions().MathErrno && + Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) { + if (!FD->getAttr<ConstAttr>()) + FD->addAttr(new ConstAttr()); + } } IdentifierInfo *Name = FD->getIdentifier(); diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c new file mode 100644 index 0000000000..9224fe10c7 --- /dev/null +++ b/test/CodeGen/libcalls.c @@ -0,0 +1,22 @@ +// RUN: clang -fmath-errno=1 -emit-llvm -o %t %s && +// RUN: grep "declare " %t | count 6 && +// RUN: grep "declare " %t | grep "@llvm." | count 1 && +// RUN: clang -fmath-errno=0 -emit-llvm -o %t %s && +// RUN: grep "declare " %t | count 6 && +// RUN: grep "declare " %t | grep -v "@llvm." | count 0 + +// IRgen only pays attention to const; it should always call llvm for +// this. +float sqrtf(float) __attribute__((const)); + +void test_sqrt(float a0, double a1, long double a2) { + float l0 = sqrtf(a0); + double l1 = sqrt(a1); + long double l2 = sqrtl(a2); +} + +void test_pow(float a0, double a1, long double a2) { + float l0 = powf(a0, a0); + double l1 = pow(a1, a1); + long double l2 = powl(a2, a2); +} |