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.

llvm-svn: 64689
This commit is contained in:
Daniel Dunbar 2009-02-16 22:43:43 +00:00
parent 45a2a20384
commit 8eb018ab9c
9 changed files with 96 additions and 7 deletions

View File

@ -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> {

View File

@ -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)
@ -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

View File

@ -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

View File

@ -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; }

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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);
}