blob: e2a2aa71b880b3b8a366c1363e3784e8d2e42b67 [file] [log] [blame]
//===- LangOptions.h - C Language Family Language Options -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Defines the clang::LangOptions interface.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_LANGOPTIONS_H
#define LLVM_CLANG_BASIC_LANGOPTIONS_H
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangStandard.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/TargetCXXABI.h"
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>
#include <string>
#include <vector>
namespace clang {
/// In the Microsoft ABI, this controls the placement of virtual displacement
/// members used to implement virtual inheritance.
enum class MSVtorDispMode { Never, ForVBaseOverride, ForVFTable };
/// Shader programs run in specific pipeline stages.
/// The order of these values matters, and must be kept in sync with the
/// Triple Environment enum in llvm::Triple. The ordering is enforced in
/// static_asserts in Triple.cpp and in clang/Basic/HLSLRuntime.h.
enum class ShaderStage {
Pixel = 0,
Vertex,
Geometry,
Hull,
Domain,
Compute,
Library,
RayGeneration,
Intersection,
AnyHit,
ClosestHit,
Miss,
Callable,
Mesh,
Amplification,
Invalid,
};
enum class PointerAuthenticationMode : unsigned {
None,
Strip,
SignAndStrip,
SignAndAuth
};
/// Bitfields of LangOptions, split out from LangOptions in order to ensure that
/// this large collection of bitfields is a trivial class type.
class LangOptionsBase {
friend class CompilerInvocation;
friend class CompilerInvocationBase;
public:
using Visibility = clang::Visibility;
using RoundingMode = llvm::RoundingMode;
enum GCMode { NonGC, GCOnly, HybridGC };
enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq };
// Automatic variables live on the stack, and when trivial they're usually
// uninitialized because it's undefined behavior to use them without
// initializing them.
enum class TrivialAutoVarInitKind { Uninitialized, Zero, Pattern };
enum SignedOverflowBehaviorTy {
// Default C standard behavior.
SOB_Undefined,
// -fwrapv
SOB_Defined,
// -ftrapv
SOB_Trapping
};
// FIXME: Unify with TUKind.
enum CompilingModuleKind {
/// Not compiling a module interface at all.
CMK_None,
/// Compiling a module from a module map.
CMK_ModuleMap,
/// Compiling a module header unit.
CMK_HeaderUnit,
/// Compiling a C++ modules interface unit.
CMK_ModuleInterface,
};
enum PragmaMSPointersToMembersKind {
PPTMK_BestCase,
PPTMK_FullGeneralitySingleInheritance,
PPTMK_FullGeneralityMultipleInheritance,
PPTMK_FullGeneralityVirtualInheritance
};
using MSVtorDispMode = clang::MSVtorDispMode;
enum DefaultCallingConvention {
DCC_None,
DCC_CDecl,
DCC_FastCall,
DCC_StdCall,
DCC_VectorCall,
DCC_RegCall,
DCC_RtdCall
};
enum AddrSpaceMapMangling { ASMM_Target, ASMM_On, ASMM_Off };
// Corresponds to _MSC_VER
enum MSVCMajorVersion {
MSVC2010 = 1600,
MSVC2012 = 1700,
MSVC2013 = 1800,
MSVC2015 = 1900,
MSVC2017 = 1910,
MSVC2017_5 = 1912,
MSVC2017_7 = 1914,
MSVC2019 = 1920,
MSVC2019_5 = 1925,
MSVC2019_8 = 1928,
MSVC2022_3 = 1933,
};
enum SYCLMajorVersion {
SYCL_None,
SYCL_2017,
SYCL_2020,
// The "default" SYCL version to be used when none is specified on the
// frontend command line.
SYCL_Default = SYCL_2020
};
enum HLSLLangStd {
HLSL_Unset = 0,
HLSL_2015 = 2015,
HLSL_2016 = 2016,
HLSL_2017 = 2017,
HLSL_2018 = 2018,
HLSL_2021 = 2021,
HLSL_202x = 2029,
};
/// Clang versions with different platform ABI conformance.
enum class ClangABI {
/// Attempt to be ABI-compatible with code generated by Clang 3.8.x
/// (SVN r257626). This causes <1 x long long> to be passed in an
/// integer register instead of an SSE register on x64_64.
Ver3_8,
/// Attempt to be ABI-compatible with code generated by Clang 4.0.x
/// (SVN r291814). This causes move operations to be ignored when
/// determining whether a class type can be passed or returned directly.
Ver4,
/// Attempt to be ABI-compatible with code generated by Clang 6.0.x
/// (SVN r321711). This causes determination of whether a type is
/// standard-layout to ignore collisions between empty base classes
/// and between base classes and member subobjects, which affects
/// whether we reuse base class tail padding in some ABIs.
Ver6,
/// Attempt to be ABI-compatible with code generated by Clang 7.0.x
/// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be
/// compatible with __alignof (i.e., return the preferred alignment)
/// rather than returning the required alignment.
Ver7,
/// Attempt to be ABI-compatible with code generated by Clang 9.0.x
/// (SVN r351319). This causes vectors of __int128 to be passed in memory
/// instead of passing in multiple scalar registers on x86_64 on Linux and
/// NetBSD.
Ver9,
/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
/// vector member on the stack instead of using registers, to not properly
/// mangle substitutions for template names in some cases, and to mangle
/// declaration template arguments without a cast to the parameter type
/// even when that can lead to mangling collisions.
Ver11,
/// Attempt to be ABI-compatible with code generated by Clang 12.0.x
/// (git 8e464dd76bef). This causes clang to mangle lambdas within
/// global-scope inline variables incorrectly.
Ver12,
/// Attempt to be ABI-compatible with code generated by Clang 14.0.x.
/// This causes clang to:
/// - mangle dependent nested names incorrectly.
/// - make trivial only those defaulted copy constructors with a
/// parameter-type-list equivalent to the parameter-type-list of an
/// implicit declaration.
Ver14,
/// Attempt to be ABI-compatible with code generated by Clang 15.0.x.
/// This causes clang to:
/// - Reverse the implementation for DR692, DR1395 and DR1432.
/// - pack non-POD members of packed structs.
/// - consider classes with defaulted special member functions non-pod.
Ver15,
/// Attempt to be ABI-compatible with code generated by Clang 17.0.x.
/// This causes clang to revert some fixes to its implementation of the
/// Itanium name mangling scheme, with the consequence that overloaded
/// function templates are mangled the same if they differ only by:
/// - constraints
/// - whether a non-type template parameter has a deduced type
/// - the parameter list of a template template parameter
Ver17,
/// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
/// This causes clang to revert some fixes to the mangling of lambdas
/// in the initializers of members of local classes.
Ver18,
/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
};
enum class CoreFoundationABI {
/// No interoperability ABI has been specified
Unspecified,
/// CoreFoundation does not have any language interoperability
Standalone,
/// Interoperability with the ObjectiveC runtime
ObjectiveC,
/// Interoperability with the latest known version of the Swift runtime
Swift,
/// Interoperability with the Swift 5.0 runtime
Swift5_0,
/// Interoperability with the Swift 4.2 runtime
Swift4_2,
/// Interoperability with the Swift 4.1 runtime
Swift4_1,
};
enum FPModeKind {
// Disable the floating point pragma
FPM_Off,
// Enable the floating point pragma
FPM_On,
// Aggressively fuse FP ops (E.g. FMA) disregarding pragmas.
FPM_Fast,
// Aggressively fuse FP ops and honor pragmas.
FPM_FastHonorPragmas
};
/// Possible floating point exception behavior.
enum FPExceptionModeKind {
/// Assume that floating-point exceptions are masked.
FPE_Ignore,
/// Transformations do not cause new exceptions but may hide some.
FPE_MayTrap,
/// Strictly preserve the floating-point exception semantics.
FPE_Strict,
/// Used internally to represent initial unspecified value.
FPE_Default
};
/// Possible float expression evaluation method choices.
enum FPEvalMethodKind {
/// The evaluation method cannot be determined or is inconsistent for this
/// target.
FEM_Indeterminable = -1,
/// Use the declared type for fp arithmetic.
FEM_Source = 0,
/// Use the type double for fp arithmetic.
FEM_Double = 1,
/// Use extended type for fp arithmetic.
FEM_Extended = 2,
/// Used only for FE option processing; this is only used to indicate that
/// the user did not specify an explicit evaluation method on the command
/// line and so the target should be queried for its default evaluation
/// method instead.
FEM_UnsetOnCommandLine = 3
};
enum ExcessPrecisionKind { FPP_Standard, FPP_Fast, FPP_None };
/// Possible exception handling behavior.
enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm };
enum class LaxVectorConversionKind {
/// Permit no implicit vector bitcasts.
None,
/// Permit vector bitcasts between integer vectors with different numbers
/// of elements but the same total bit-width.
Integer,
/// Permit vector bitcasts between all vectors with the same total
/// bit-width.
All,
};
enum class AltivecSrcCompatKind {
// All vector compares produce scalars except vector pixel and vector bool.
// The types vector pixel and vector bool return vector results.
Mixed,
// All vector compares produce vector results as in GCC.
GCC,
// All vector compares produce scalars as in XL.
XL,
// Default clang behaviour.
Default = Mixed,
};
enum class SignReturnAddressScopeKind {
/// No signing for any function.
None,
/// Sign the return address of functions that spill LR.
NonLeaf,
/// Sign the return address of all functions,
All
};
enum class SignReturnAddressKeyKind {
/// Return address signing uses APIA key.
AKey,
/// Return address signing uses APIB key.
BKey
};
enum class ThreadModelKind {
/// POSIX Threads.
POSIX,
/// Single Threaded Environment.
Single
};
enum class ExtendArgsKind {
/// Integer arguments are sign or zero extended to 32/64 bits
/// during default argument promotions.
ExtendTo32,
ExtendTo64
};
enum class GPUDefaultStreamKind {
/// Legacy default stream
Legacy,
/// Per-thread default stream
PerThread,
};
enum class DefaultVisiblityExportMapping {
None,
/// map only explicit default visibilities to exported
Explicit,
/// map all default visibilities to exported
All,
};
enum class VisibilityForcedKinds {
/// Force hidden visibility
ForceHidden,
/// Force protected visibility
ForceProtected,
/// Force default visibility
ForceDefault,
/// Don't alter the visibility
Source,
};
enum class VisibilityFromDLLStorageClassKinds {
/// Keep the IR-gen assigned visibility.
Keep,
/// Override the IR-gen assigned visibility with default visibility.
Default,
/// Override the IR-gen assigned visibility with hidden visibility.
Hidden,
/// Override the IR-gen assigned visibility with protected visibility.
Protected,
};
enum class StrictFlexArraysLevelKind {
/// Any trailing array member is a FAM.
Default = 0,
/// Any trailing array member of undefined, 0, or 1 size is a FAM.
OneZeroOrIncomplete = 1,
/// Any trailing array member of undefined or 0 size is a FAM.
ZeroOrIncomplete = 2,
/// Any trailing array member of undefined size is a FAM.
IncompleteOnly = 3,
};
/// Controls the various implementations for complex multiplication and
// division.
enum ComplexRangeKind {
/// Implementation of complex division and multiplication using a call to
/// runtime library functions(generally the case, but the BE might
/// sometimes replace the library call if it knows enough about the
/// potential range of the inputs). Overflow and non-finite values are
/// handled by the library implementation. This is the default value.
CX_Full,
/// Implementation of complex division offering an improved handling
/// for overflow in intermediate calculations with no special handling for
/// NaN and infinite values.
CX_Improved,
/// Implementation of complex division using algebraic formulas at
/// higher precision. Overflow is handled. Non-finite values are handled in
/// some cases. If the target hardware does not have native support for a
/// higher precision data type, an implementation for the complex operation
/// will be used to provide improved guards against intermediate overflow,
/// but overflow and underflow may still occur in some cases. NaN and
/// infinite values are not handled.
CX_Promoted,
/// Implementation of complex division and multiplication using
/// algebraic formulas at source precision. No special handling to avoid
/// overflow. NaN and infinite values are not handled.
CX_Basic,
/// No range rule is enabled.
CX_None
};
// Define simple language options (with no accessors).
#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
protected:
// Define language options of enumeration type. These are private, and will
// have accessors (below).
#define LANGOPT(Name, Bits, Default, Description)
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
LLVM_PREFERRED_TYPE(Type) \
unsigned Name : Bits;
#include "clang/Basic/LangOptions.def"
};
/// Keeps track of the various options that can be
/// enabled, which controls the dialect of C or C++ that is accepted.
class LangOptions : public LangOptionsBase {
public:
/// The used language standard.
LangStandard::Kind LangStd;
/// Set of enabled sanitizers.
SanitizerSet Sanitize;
/// Is at least one coverage instrumentation type enabled.
bool SanitizeCoverage = false;
/// Paths to files specifying which objects
/// (files, functions, variables) should not be instrumented.
std::vector<std::string> NoSanitizeFiles;
/// Paths to the XRay "always instrument" files specifying which
/// objects (files, functions, variables) should be imbued with the XRay
/// "always instrument" attribute.
/// WARNING: This is a deprecated field and will go away in the future.
std::vector<std::string> XRayAlwaysInstrumentFiles;
/// Paths to the XRay "never instrument" files specifying which
/// objects (files, functions, variables) should be imbued with the XRay
/// "never instrument" attribute.
/// WARNING: This is a deprecated field and will go away in the future.
std::vector<std::string> XRayNeverInstrumentFiles;
/// Paths to the XRay attribute list files, specifying which objects
/// (files, functions, variables) should be imbued with the appropriate XRay
/// attribute(s).
std::vector<std::string> XRayAttrListFiles;
/// Paths to special case list files specifying which entities
/// (files, functions) should or should not be instrumented.
std::vector<std::string> ProfileListFiles;
clang::ObjCRuntime ObjCRuntime;
CoreFoundationABI CFRuntime = CoreFoundationABI::Unspecified;
std::string ObjCConstantStringClass;
/// The name of the handler function to be called when -ftrapv is
/// specified.
///
/// If none is specified, abort (GCC-compatible behaviour).
std::string OverflowHandler;
/// The module currently being compiled as specified by -fmodule-name.
std::string ModuleName;
/// The name of the current module, of which the main source file
/// is a part. If CompilingModule is set, we are compiling the interface
/// of this module, otherwise we are compiling an implementation file of
/// it. This starts as ModuleName in case -fmodule-name is provided and
/// changes during compilation to reflect the current module.
std::string CurrentModule;
/// The names of any features to enable in module 'requires' decls
/// in addition to the hard-coded list in Module.cpp and the target features.
///
/// This list is sorted.
std::vector<std::string> ModuleFeatures;
/// Options for parsing comments.
CommentOptions CommentOpts;
/// A list of all -fno-builtin-* function names (e.g., memset).
std::vector<std::string> NoBuiltinFuncs;
/// A prefix map for __FILE__, __BASE_FILE__ and __builtin_FILE().
std::map<std::string, std::string, std::greater<std::string>> MacroPrefixMap;
/// Triples of the OpenMP targets that the host code codegen should
/// take into account in order to generate accurate offloading descriptors.
std::vector<llvm::Triple> OMPTargetTriples;
/// Name of the IR file that contains the result of the OpenMP target
/// host code generation.
std::string OMPHostIRFile;
/// The user provided compilation unit ID, if non-empty. This is used to
/// externalize static variables which is needed to support accessing static
/// device variables in host code for single source offloading languages
/// like CUDA/HIP.
std::string CUID;
/// C++ ABI to compile with, if specified by the frontend through -fc++-abi=.
/// This overrides the default ABI used by the target.
std::optional<TargetCXXABI::Kind> CXXABI;
/// Indicates whether the front-end is explicitly told that the
/// input is a header file (i.e. -x c-header).
bool IsHeaderFile = false;
/// The default stream kind used for HIP kernel launching.
GPUDefaultStreamKind GPUDefaultStream;
/// The seed used by the randomize structure layout feature.
std::string RandstructSeed;
/// Indicates whether to use target's platform-specific file separator when
/// __FILE__ macro is used and when concatenating filename with directory or
/// to use build environment environment's platform-specific file separator.
///
/// The plaform-specific path separator is the backslash(\) for Windows and
/// forward slash (/) elsewhere.
bool UseTargetPathSeparator = false;
// Indicates whether we should keep all nullptr checks for pointers
// received as a result of a standard operator new (-fcheck-new)
bool CheckNew = false;
// In OpenACC mode, contains a user provided override for the _OPENACC macro.
// This exists so that we can override the macro value and test our incomplete
// implementation on real-world examples.
std::string OpenACCMacroOverride;
LangOptions();
/// Set language defaults for the given input language and
/// language standard in the given LangOptions object.
///
/// \param Opts - The LangOptions object to set up.
/// \param Lang - The input language.
/// \param T - The target triple.
/// \param Includes - If the language requires extra headers to be implicitly
/// included, they will be appended to this list.
/// \param LangStd - The input language standard.
static void
setLangDefaults(LangOptions &Opts, Language Lang, const llvm::Triple &T,
std::vector<std::string> &Includes,
LangStandard::Kind LangStd = LangStandard::lang_unspecified);
// Define accessors/mutators for language options of enumeration type.
#define LANGOPT(Name, Bits, Default, Description)
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Type get##Name() const { return static_cast<Type>(Name); } \
void set##Name(Type Value) { Name = static_cast<unsigned>(Value); }
#include "clang/Basic/LangOptions.def"
/// Are we compiling a module?
bool isCompilingModule() const {
return getCompilingModule() != CMK_None;
}
/// Are we compiling a module implementation?
bool isCompilingModuleImplementation() const {
return !isCompilingModule() && !ModuleName.empty();
}
/// Do we need to track the owning module for a local declaration?
bool trackLocalOwningModule() const {
return isCompilingModule() || ModulesLocalVisibility;
}
bool isSignedOverflowDefined() const {
return getSignedOverflowBehavior() == SOB_Defined;
}
bool isSubscriptPointerArithmetic() const {
return ObjCRuntime.isSubscriptPointerArithmetic() &&
!ObjCSubscriptingLegacyRuntime;
}
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const {
return MSCompatibilityVersion >= MajorVersion * 100000U;
}
/// Reset all of the options that are not considered when building a
/// module.
void resetNonModularOptions();
/// Is this a libc/libm function that is no longer recognized as a
/// builtin because a -fno-builtin-* option has been specified?
bool isNoBuiltinFunc(StringRef Name) const;
/// True if any ObjC types may have non-trivial lifetime qualifiers.
bool allowsNonTrivialObjCLifetimeQualifiers() const {
return ObjCAutoRefCount || ObjCWeak;
}
bool assumeFunctionsAreConvergent() const {
return ConvergentFunctions;
}
/// Return the OpenCL C or C++ version as a VersionTuple.
VersionTuple getOpenCLVersionTuple() const;
/// Return the OpenCL version that kernel language is compatible with
unsigned getOpenCLCompatibleVersion() const;
/// Return the OpenCL C or C++ for OpenCL language name and version
/// as a string.
std::string getOpenCLVersionString() const;
/// Returns true if functions without prototypes or functions with an
/// identifier list (aka K&R C functions) are not allowed.
bool requiresStrictPrototypes() const {
return CPlusPlus || C23 || DisableKNRFunctions;
}
/// Returns true if implicit function declarations are allowed in the current
/// language mode.
bool implicitFunctionsAllowed() const {
return !requiresStrictPrototypes() && !OpenCL;
}
/// Returns true if the language supports calling the 'atexit' function.
bool hasAtExit() const { return !(OpenMP && OpenMPIsTargetDevice); }
/// Returns true if implicit int is part of the language requirements.
bool isImplicitIntRequired() const { return !CPlusPlus && !C99; }
/// Returns true if implicit int is supported at all.
bool isImplicitIntAllowed() const { return !CPlusPlus && !C23; }
/// Check if return address signing is enabled.
bool hasSignReturnAddress() const {
return getSignReturnAddressScope() != SignReturnAddressScopeKind::None;
}
/// Check if return address signing uses AKey.
bool isSignReturnAddressWithAKey() const {
return getSignReturnAddressKey() == SignReturnAddressKeyKind::AKey;
}
/// Check if leaf functions are also signed.
bool isSignReturnAddressScopeAll() const {
return getSignReturnAddressScope() == SignReturnAddressScopeKind::All;
}
bool hasSjLjExceptions() const {
return getExceptionHandling() == ExceptionHandlingKind::SjLj;
}
bool hasSEHExceptions() const {
return getExceptionHandling() == ExceptionHandlingKind::WinEH;
}
bool hasDWARFExceptions() const {
return getExceptionHandling() == ExceptionHandlingKind::DwarfCFI;
}
bool hasWasmExceptions() const {
return getExceptionHandling() == ExceptionHandlingKind::Wasm;
}
bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
bool hasDefaultVisibilityExportMapping() const {
return getDefaultVisibilityExportMapping() !=
DefaultVisiblityExportMapping::None;
}
bool isExplicitDefaultVisibilityExportMapping() const {
return getDefaultVisibilityExportMapping() ==
DefaultVisiblityExportMapping::Explicit;
}
bool isAllDefaultVisibilityExportMapping() const {
return getDefaultVisibilityExportMapping() ==
DefaultVisiblityExportMapping::All;
}
bool hasGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() !=
VisibilityForcedKinds::Source;
}
bool hasDefaultGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() ==
VisibilityForcedKinds::ForceDefault;
}
bool hasProtectedGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() ==
VisibilityForcedKinds::ForceProtected;
}
bool hasHiddenGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() ==
VisibilityForcedKinds::ForceHidden;
}
/// Remap path prefix according to -fmacro-prefix-path option.
void remapPathPrefix(SmallVectorImpl<char> &Path) const;
RoundingMode getDefaultRoundingMode() const {
return RoundingMath ? RoundingMode::Dynamic
: RoundingMode::NearestTiesToEven;
}
FPExceptionModeKind getDefaultExceptionMode() const {
FPExceptionModeKind EM = getFPExceptionMode();
if (EM == FPExceptionModeKind::FPE_Default)
return FPExceptionModeKind::FPE_Ignore;
return EM;
}
};
/// Floating point control options
class FPOptionsOverride;
class FPOptions {
public:
// We start by defining the layout.
using storage_type = uint32_t;
using RoundingMode = llvm::RoundingMode;
static constexpr unsigned StorageBitSize = 8 * sizeof(storage_type);
// Define a fake option named "First" so that we have a PREVIOUS even for the
// real first option.
static constexpr storage_type FirstShift = 0, FirstWidth = 0;
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
static constexpr storage_type NAME##Shift = \
PREVIOUS##Shift + PREVIOUS##Width; \
static constexpr storage_type NAME##Width = WIDTH; \
static constexpr storage_type NAME##Mask = ((1 << NAME##Width) - 1) \
<< NAME##Shift;
#include "clang/Basic/FPOptions.def"
static constexpr storage_type TotalWidth = 0
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) +WIDTH
#include "clang/Basic/FPOptions.def"
;
static_assert(TotalWidth <= StorageBitSize, "Too short type for FPOptions");
private:
storage_type Value;
FPOptionsOverride getChangesSlow(const FPOptions &Base) const;
public:
FPOptions() : Value(0) {
setFPContractMode(LangOptions::FPM_Off);
setConstRoundingMode(RoundingMode::Dynamic);
setSpecifiedExceptionMode(LangOptions::FPE_Default);
}
explicit FPOptions(const LangOptions &LO) {
Value = 0;
// The language fp contract option FPM_FastHonorPragmas has the same effect
// as FPM_Fast in frontend. For simplicity, use FPM_Fast uniformly in
// frontend.
auto LangOptContractMode = LO.getDefaultFPContractMode();
if (LangOptContractMode == LangOptions::FPM_FastHonorPragmas)
LangOptContractMode = LangOptions::FPM_Fast;
setFPContractMode(LangOptContractMode);
setRoundingMath(LO.RoundingMath);
setConstRoundingMode(LangOptions::RoundingMode::Dynamic);
setSpecifiedExceptionMode(LO.getFPExceptionMode());
setAllowFPReassociate(LO.AllowFPReassoc);
setNoHonorNaNs(LO.NoHonorNaNs);
setNoHonorInfs(LO.NoHonorInfs);
setNoSignedZero(LO.NoSignedZero);
setAllowReciprocal(LO.AllowRecip);
setAllowApproxFunc(LO.ApproxFunc);
if (getFPContractMode() == LangOptions::FPM_On &&
getRoundingMode() == llvm::RoundingMode::Dynamic &&
getExceptionMode() == LangOptions::FPE_Strict)
// If the FP settings are set to the "strict" model, then
// FENV access is set to true. (ffp-model=strict)
setAllowFEnvAccess(true);
else
setAllowFEnvAccess(LangOptions::FPM_Off);
setComplexRange(LO.getComplexRange());
}
bool allowFPContractWithinStatement() const {
return getFPContractMode() == LangOptions::FPM_On;
}
void setAllowFPContractWithinStatement() {
setFPContractMode(LangOptions::FPM_On);
}
bool allowFPContractAcrossStatement() const {
return getFPContractMode() == LangOptions::FPM_Fast;
}
void setAllowFPContractAcrossStatement() {
setFPContractMode(LangOptions::FPM_Fast);
}
bool isFPConstrained() const {
return getRoundingMode() != llvm::RoundingMode::NearestTiesToEven ||
getExceptionMode() != LangOptions::FPE_Ignore ||
getAllowFEnvAccess();
}
RoundingMode getRoundingMode() const {
RoundingMode RM = getConstRoundingMode();
if (RM == RoundingMode::Dynamic) {
// C23: 7.6.2p3 If the FE_DYNAMIC mode is specified and FENV_ACCESS is
// "off", the translator may assume that the default rounding mode is in
// effect.
if (!getAllowFEnvAccess() && !getRoundingMath())
RM = RoundingMode::NearestTiesToEven;
}
return RM;
}
LangOptions::FPExceptionModeKind getExceptionMode() const {
LangOptions::FPExceptionModeKind EM = getSpecifiedExceptionMode();
if (EM == LangOptions::FPExceptionModeKind::FPE_Default) {
if (getAllowFEnvAccess())
return LangOptions::FPExceptionModeKind::FPE_Strict;
else
return LangOptions::FPExceptionModeKind::FPE_Ignore;
}
return EM;
}
bool operator==(FPOptions other) const { return Value == other.Value; }
/// Return the default value of FPOptions that's used when trailing
/// storage isn't required.
static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO);
storage_type getAsOpaqueInt() const { return Value; }
static FPOptions getFromOpaqueInt(storage_type Value) {
FPOptions Opts;
Opts.Value = Value;
return Opts;
}
/// Return difference with the given option set.
FPOptionsOverride getChangesFrom(const FPOptions &Base) const;
void applyChanges(FPOptionsOverride FPO);
// We can define most of the accessors automatically:
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
TYPE get##NAME() const { \
return static_cast<TYPE>((Value & NAME##Mask) >> NAME##Shift); \
} \
void set##NAME(TYPE value) { \
Value = (Value & ~NAME##Mask) | (storage_type(value) << NAME##Shift); \
}
#include "clang/Basic/FPOptions.def"
LLVM_DUMP_METHOD void dump();
};
/// Represents difference between two FPOptions values.
///
/// The effect of language constructs changing the set of floating point options
/// is usually a change of some FP properties while leaving others intact. This
/// class describes such changes by keeping information about what FP options
/// are overridden.
///
/// The integral set of FP options, described by the class FPOptions, may be
/// represented as a default FP option set, defined by language standard and
/// command line options, with the overrides introduced by pragmas.
///
/// The is implemented as a value of the new FPOptions plus a mask showing which
/// fields are actually set in it.
class FPOptionsOverride {
FPOptions Options = FPOptions::getFromOpaqueInt(0);
FPOptions::storage_type OverrideMask = 0;
public:
using RoundingMode = llvm::RoundingMode;
/// The type suitable for storing values of FPOptionsOverride. Must be twice
/// as wide as bit size of FPOption.
using storage_type = uint64_t;
static_assert(sizeof(storage_type) >= 2 * sizeof(FPOptions::storage_type),
"Too short type for FPOptionsOverride");
/// Bit mask selecting bits of OverrideMask in serialized representation of
/// FPOptionsOverride.
static constexpr storage_type OverrideMaskBits =
(static_cast<storage_type>(1) << FPOptions::StorageBitSize) - 1;
FPOptionsOverride() {}
FPOptionsOverride(const LangOptions &LO)
: Options(LO), OverrideMask(OverrideMaskBits) {}
FPOptionsOverride(FPOptions FPO)
: Options(FPO), OverrideMask(OverrideMaskBits) {}
FPOptionsOverride(FPOptions FPO, FPOptions::storage_type Mask)
: Options(FPO), OverrideMask(Mask) {}
bool requiresTrailingStorage() const { return OverrideMask != 0; }
void setAllowFPContractWithinStatement() {
setFPContractModeOverride(LangOptions::FPM_On);
}
void setAllowFPContractAcrossStatement() {
setFPContractModeOverride(LangOptions::FPM_Fast);
}
void setDisallowFPContract() {
setFPContractModeOverride(LangOptions::FPM_Off);
}
void setFPPreciseEnabled(bool Value) {
setAllowFPReassociateOverride(!Value);
setNoHonorNaNsOverride(!Value);
setNoHonorInfsOverride(!Value);
setNoSignedZeroOverride(!Value);
setAllowReciprocalOverride(!Value);
setAllowApproxFuncOverride(!Value);
setMathErrnoOverride(Value);
if (Value)
/* Precise mode implies fp_contract=on and disables ffast-math */
setAllowFPContractWithinStatement();
else
/* Precise mode disabled sets fp_contract=fast and enables ffast-math */
setAllowFPContractAcrossStatement();
}
void setDisallowOptimizations() {
setFPPreciseEnabled(true);
setDisallowFPContract();
}
storage_type getAsOpaqueInt() const {
return (static_cast<storage_type>(Options.getAsOpaqueInt())
<< FPOptions::StorageBitSize) |
OverrideMask;
}
static FPOptionsOverride getFromOpaqueInt(storage_type I) {
FPOptionsOverride Opts;
Opts.OverrideMask = I & OverrideMaskBits;
Opts.Options = FPOptions::getFromOpaqueInt(I >> FPOptions::StorageBitSize);
return Opts;
}
FPOptions applyOverrides(FPOptions Base) {
FPOptions Result =
FPOptions::getFromOpaqueInt((Base.getAsOpaqueInt() & ~OverrideMask) |
(Options.getAsOpaqueInt() & OverrideMask));
return Result;
}
FPOptions applyOverrides(const LangOptions &LO) {
return applyOverrides(FPOptions(LO));
}
bool operator==(FPOptionsOverride other) const {
return Options == other.Options && OverrideMask == other.OverrideMask;
}
bool operator!=(FPOptionsOverride other) const { return !(*this == other); }
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
bool has##NAME##Override() const { \
return OverrideMask & FPOptions::NAME##Mask; \
} \
TYPE get##NAME##Override() const { \
assert(has##NAME##Override()); \
return Options.get##NAME(); \
} \
void clear##NAME##Override() { \
/* Clear the actual value so that we don't have spurious differences when \
* testing equality. */ \
Options.set##NAME(TYPE(0)); \
OverrideMask &= ~FPOptions::NAME##Mask; \
} \
void set##NAME##Override(TYPE value) { \
Options.set##NAME(value); \
OverrideMask |= FPOptions::NAME##Mask; \
}
#include "clang/Basic/FPOptions.def"
LLVM_DUMP_METHOD void dump();
};
inline FPOptionsOverride FPOptions::getChangesFrom(const FPOptions &Base) const {
if (Value == Base.Value)
return FPOptionsOverride();
return getChangesSlow(Base);
}
inline void FPOptions::applyChanges(FPOptionsOverride FPO) {
*this = FPO.applyOverrides(*this);
}
/// Describes the kind of translation unit being processed.
enum TranslationUnitKind {
/// The translation unit is a complete translation unit.
TU_Complete,
/// The translation unit is a prefix to a translation unit, and is
/// not complete.
TU_Prefix,
/// The translation unit is a clang module.
TU_ClangModule,
/// The translation unit is a is a complete translation unit that we might
/// incrementally extend later.
TU_Incremental
};
} // namespace clang
#endif // LLVM_CLANG_BASIC_LANGOPTIONS_H