Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions clang/include/clang/Basic/Builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringTable.h"
#include "llvm/TargetParser/Triple.h"
#include <cstring>

// VC++ defines 'alloca' as an object-like macro, which interferes with our
Expand Down Expand Up @@ -405,6 +406,22 @@ class Context {
return strchr(getAttributesString(ID), 'g') != nullptr;
}

/// Determine whether we can generate LLVM intrinsics for the given
/// builtin ID, based on whether it has side effects such as setting errno.
///
/// \param BuiltinID The builtin ID to check.
/// \param Trip The target triple.
/// \param ErrnoOverwritten Indicates whether the errno setting behavior
/// has been overwritten via '#pragma float_control(precise, on/off)'.
/// \param MathErrnoEnabled Indicates whether math-errno is enabled on
/// command line.
/// \param HasOptNoneAttr True iff 'attribute__((optnone))' is used.
/// \param IsOptimizationEnabled True iff the optimization level is not 'O0'.
bool shouldGenerateFPMathIntrinsic(unsigned BuiltinID, llvm::Triple Trip,
std::optional<bool> ErrnoOverwritten,
bool MathErrnoEnabled, bool HasOptNoneAttr,
bool IsOptimizationEnabled) const;

const char *getRequiredFeatures(unsigned ID) const;

unsigned getRequiredVectorWidth(unsigned ID) const;
Expand Down
90 changes: 90 additions & 0 deletions clang/lib/Basic/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,96 @@ static bool builtinIsSupported(const llvm::StringTable &Strings,
return true;
}

static bool isBuiltinConstForTriple(unsigned BuiltinID, llvm::Triple Trip) {
// There's a special case with the fma builtins where they are always const
// if the target environment is GNU or the target is OS is Windows and we're
// targeting the MSVCRT.dll environment.
// FIXME: This list can be become outdated. Need to find a way to get it some
// other way.
switch (BuiltinID) {
case Builtin::BI__builtin_fma:
case Builtin::BI__builtin_fmaf:
case Builtin::BI__builtin_fmal:
case Builtin::BI__builtin_fmaf16:
case Builtin::BIfma:
case Builtin::BIfmaf:
case Builtin::BIfmal: {
if (Trip.isGNUEnvironment() || Trip.isOSMSVCRT())
return true;
break;
}
default:
break;
}

return false;
}

bool Builtin::Context::shouldGenerateFPMathIntrinsic(
unsigned BuiltinID, llvm::Triple Trip, std::optional<bool> ErrnoOverwritten,
bool MathErrnoEnabled, bool HasOptNoneAttr,
bool IsOptimizationEnabled) const {

// True if we are compiling at -O2 and errno has been disabled
// using the '#pragma float_control(precise, off)', and
// attribute opt-none hasn't been seen.
bool ErrnoOverridenToFalseWithOpt = ErrnoOverwritten.has_value() &&
!ErrnoOverwritten.value() &&
!HasOptNoneAttr && IsOptimizationEnabled;

// 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).
// In case FP exceptions are enabled, the experimental versions of the
// intrinsics model those.
bool ConstAlways =
isConst(BuiltinID) || isBuiltinConstForTriple(BuiltinID, Trip);

bool ConstWithoutErrnoAndExceptions =
isConstWithoutErrnoAndExceptions(BuiltinID);
bool ConstWithoutExceptions = isConstWithoutExceptions(BuiltinID);

// ConstAttr is enabled in fast-math mode. In fast-math mode, math-errno is
// disabled.
// Math intrinsics are generated only when math-errno is disabled. Any pragmas
// or attributes that affect math-errno should prevent or allow math
// intrinsics to be generated. Intrinsics are generated:
// 1- In fast math mode, unless math-errno is overriden
// via '#pragma float_control(precise, on)', or via an
// 'attribute__((optnone))'.
// 2- If math-errno was enabled on command line but overriden
// to false via '#pragma float_control(precise, off))' and
// 'attribute__((optnone))' hasn't been used.
// 3- If we are compiling with optimization and errno has been disabled
// via '#pragma float_control(precise, off)', and
// 'attribute__((optnone))' hasn't been used.

bool ConstWithoutErrnoOrExceptions =
ConstWithoutErrnoAndExceptions || ConstWithoutExceptions;
bool GenerateIntrinsics =
(ConstAlways && !HasOptNoneAttr) ||
(!MathErrnoEnabled &&
!(ErrnoOverwritten.has_value() && ErrnoOverwritten.value()) &&
!HasOptNoneAttr);
if (!GenerateIntrinsics) {
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions && !ConstWithoutErrnoAndExceptions;
if (!GenerateIntrinsics)
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions &&
(!MathErrnoEnabled &&
!(ErrnoOverwritten.has_value() && ErrnoOverwritten.value()) &&
!HasOptNoneAttr);
if (!GenerateIntrinsics)
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions && ErrnoOverridenToFalseWithOpt;
}

return GenerateIntrinsics;
}

/// initializeBuiltins - Mark the identifiers for all the builtins with their
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
/// such.
Expand Down
84 changes: 7 additions & 77 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2640,84 +2640,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// fast-math which implies math-errno.
bool OptNone = CurFuncDecl && CurFuncDecl->hasAttr<OptimizeNoneAttr>();

// True if we are compiling at -O2 and errno has been disabled
// using the '#pragma float_control(precise, off)', and
// attribute opt-none hasn't been seen.
bool ErrnoOverridenToFalseWithOpt =
ErrnoOverriden.has_value() && !ErrnoOverriden.value() && !OptNone &&
CGM.getCodeGenOpts().OptimizationLevel != 0;

// 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).
// In case FP exceptions are enabled, the experimental versions of the
// intrinsics model those.
bool ConstAlways =
getContext().BuiltinInfo.isConst(BuiltinID);

// There's a special case with the fma builtins where they are always const
// if the target environment is GNU or the target is OS is Windows and we're
// targeting the MSVCRT.dll environment.
// FIXME: This list can be become outdated. Need to find a way to get it some
// other way.
switch (BuiltinID) {
case Builtin::BI__builtin_fma:
case Builtin::BI__builtin_fmaf:
case Builtin::BI__builtin_fmal:
case Builtin::BI__builtin_fmaf16:
case Builtin::BIfma:
case Builtin::BIfmaf:
case Builtin::BIfmal: {
auto &Trip = CGM.getTriple();
if (Trip.isGNUEnvironment() || Trip.isOSMSVCRT())
ConstAlways = true;
break;
}
default:
break;
}
bool IsOptimizationEnabled = CGM.getCodeGenOpts().OptimizationLevel != 0;

bool GenerateFPMathIntrinsics =
getContext().BuiltinInfo.shouldGenerateFPMathIntrinsic(
BuiltinID, CGM.getTriple(), ErrnoOverriden, getLangOpts().MathErrno,
OptNone, IsOptimizationEnabled);

bool ConstWithoutErrnoAndExceptions =
getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
bool ConstWithoutExceptions =
getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID);

// ConstAttr is enabled in fast-math mode. In fast-math mode, math-errno is
// disabled.
// Math intrinsics are generated only when math-errno is disabled. Any pragmas
// or attributes that affect math-errno should prevent or allow math
// intrinsics to be generated. Intrinsics are generated:
// 1- In fast math mode, unless math-errno is overriden
// via '#pragma float_control(precise, on)', or via an
// 'attribute__((optnone))'.
// 2- If math-errno was enabled on command line but overriden
// to false via '#pragma float_control(precise, off))' and
// 'attribute__((optnone))' hasn't been used.
// 3- If we are compiling with optimization and errno has been disabled
// via '#pragma float_control(precise, off)', and
// 'attribute__((optnone))' hasn't been used.

bool ConstWithoutErrnoOrExceptions =
ConstWithoutErrnoAndExceptions || ConstWithoutExceptions;
bool GenerateIntrinsics =
(ConstAlways && !OptNone) ||
(!getLangOpts().MathErrno &&
!(ErrnoOverriden.has_value() && ErrnoOverriden.value()) && !OptNone);
if (!GenerateIntrinsics) {
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions && !ConstWithoutErrnoAndExceptions;
if (!GenerateIntrinsics)
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions &&
(!getLangOpts().MathErrno &&
!(ErrnoOverriden.has_value() && ErrnoOverriden.value()) && !OptNone);
if (!GenerateIntrinsics)
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions && ErrnoOverridenToFalseWithOpt;
}
if (GenerateIntrinsics) {
if (GenerateFPMathIntrinsics) {
switch (BuiltinIDIfNoAsmLabel) {
case Builtin::BIacos:
case Builtin::BIacosf:
Expand Down