forked from OSchip/llvm-project
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:
parent
45a2a20384
commit
8eb018ab9c
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue