https://github.com/DanielKristofKiss updated https://github.com/llvm/llvm-project/pull/83277
>From c421b6b9c167e82cedc5db2a67f47d3ba12deba9 Mon Sep 17 00:00:00 2001 From: Daniel Kiss <daniel.k...@arm.com> Date: Wed, 28 Feb 2024 15:18:31 +0100 Subject: [PATCH 1/6] Add branch protection attributes to the defaults. These attributes are no longer inherited from the module flags, therefore need to be added for synthetic functions. --- clang/lib/CodeGen/CGCall.cpp | 16 ++++++++++ .../CodeGenCXX/arm64-generated-fn-attr.cpp | 30 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 13f68237b464d..5b59c77353675 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2022,6 +2022,22 @@ static void getTrivialDefaultFunctionAttributes( std::tie(Var, Value) = Attr.split('='); FuncAttrs.addAttribute(Var, Value); } + + TargetInfo::BranchProtectionInfo BPI(LangOpts); + + if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { + FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr()); + FuncAttrs.addAttribute( + "sign-return-address-key", + BPI.SignKey == LangOptions::SignReturnAddressKeyKind::AKey ? "a_key" + : "b_key"); + } + if (BPI.BranchTargetEnforcement) + FuncAttrs.addAttribute("branch-target-enforcement", "true"); + if (BPI.BranchProtectionPAuthLR) + FuncAttrs.addAttribute("branch-protection-pauth-lr", "true"); + if (BPI.GuardedControlStack) + FuncAttrs.addAttribute("guarded-control-stack", "true"); } /// Merges `target-features` from \TargetOpts and \F, and sets the result in diff --git a/clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp b/clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp new file mode 100644 index 0000000000000..8daf44abd4f91 --- /dev/null +++ b/clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple aarch64-none-none -mbranch-target-enforce -msign-return-address=all -fcxx-exceptions -fexceptions -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK + +// Check that functions generated by clang have the correct attributes + +class Example { +public: + Example(); + int fn(); +}; + +// Initialization of var1 causes __cxx_global_var_init and __tls_init to be generated +thread_local Example var1; +extern thread_local Example var2; +extern void fn(); + +int testfn() noexcept { + // Calling fn in a noexcept function causes __clang_call_terminate to be generated + fn(); + // Use of var1 and var2 causes TLS wrapper functions to be generated + return var1.fn() + var2.fn(); +} + +// CHECK: define {{.*}} @__cxx_global_var_init() [[ATTR1:#[0-9]+]] +// CHECK: define {{.*}} @__clang_call_terminate({{.*}}) [[ATTR2:#[0-9]+]] +// CHECK: define {{.*}} @_ZTW4var1() [[ATTR1]] +// CHECK: define {{.*}} @_ZTW4var2() [[ATTR1]] +// CHECK: define {{.*}} @__tls_init() [[ATTR1]] + +// CHECK: attributes [[ATTR1]] = { {{.*}}"branch-target-enforcement"="true"{{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key" +// CHECK: attributes [[ATTR2]] = { {{.*}}"branch-target-enforcement"="true"{{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key" >From 3e46bfa6bcd8a0cce142a4e1254c89ff68174117 Mon Sep 17 00:00:00 2001 From: Daniel Kiss <daniel.k...@arm.com> Date: Wed, 28 Feb 2024 17:38:49 +0100 Subject: [PATCH 2/6] fixup! [Clang][Arm][AArch64] Add branch protection attributes to the defaults. --- clang/lib/CodeGen/CGCall.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 5b59c77353675..58ccd3d181ccd 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2027,10 +2027,7 @@ static void getTrivialDefaultFunctionAttributes( if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr()); - FuncAttrs.addAttribute( - "sign-return-address-key", - BPI.SignKey == LangOptions::SignReturnAddressKeyKind::AKey ? "a_key" - : "b_key"); + FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr()); } if (BPI.BranchTargetEnforcement) FuncAttrs.addAttribute("branch-target-enforcement", "true"); >From 054515d8b3b50b3efc792db9dfe4c9e61fa2507d Mon Sep 17 00:00:00 2001 From: Daniel Kiss <daniel.k...@arm.com> Date: Mon, 4 Mar 2024 17:31:31 +0100 Subject: [PATCH 3/6] Move TargetInfo changes over. Dropping restrictions on the member functions. --- clang/include/clang/Basic/TargetInfo.h | 43 +++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 7682f84e491c7..9eeeecd68147f 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -31,7 +31,9 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Frontend/OpenMP/OMPGridValues.h" +#include "llvm/IR/Attributes.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" @@ -1368,15 +1370,14 @@ class TargetInfo : public TransferrableTargetInfo, return StringRef(); } - struct BranchProtectionInfo { + class BranchProtectionInfo { + public: LangOptions::SignReturnAddressScopeKind SignReturnAddr; LangOptions::SignReturnAddressKeyKind SignKey; bool BranchTargetEnforcement; bool BranchProtectionPAuthLR; bool GuardedControlStack; - BranchProtectionInfo() = default; - const char *getSignReturnAddrStr() const { switch (SignReturnAddr) { case LangOptions::SignReturnAddressScopeKind::None: @@ -1388,7 +1389,6 @@ class TargetInfo : public TransferrableTargetInfo, } llvm_unreachable("Unexpected SignReturnAddressScopeKind"); } - const char *getSignKeyStr() const { switch (SignKey) { case LangOptions::SignReturnAddressKeyKind::AKey: @@ -1398,6 +1398,41 @@ class TargetInfo : public TransferrableTargetInfo, } llvm_unreachable("Unexpected SignReturnAddressKeyKind"); } + + BranchProtectionInfo() = default; + BranchProtectionInfo(const LangOptions &LangOpts) { + SignReturnAddr = + LangOpts.hasSignReturnAddress() + ? (LangOpts.isSignReturnAddressScopeAll() + ? LangOptions::SignReturnAddressScopeKind::All + : LangOptions::SignReturnAddressScopeKind::NonLeaf) + : LangOptions::SignReturnAddressScopeKind::None; + SignKey = LangOpts.isSignReturnAddressWithAKey() + ? LangOptions::SignReturnAddressKeyKind::AKey + : LangOptions::SignReturnAddressKeyKind::BKey; + BranchTargetEnforcement = LangOpts.BranchTargetEnforcement; + BranchProtectionPAuthLR = LangOpts.BranchProtectionPAuthLR; + GuardedControlStack = LangOpts.GuardedControlStack; + } + + void setFnAttributes(llvm::Function &F) { + llvm::AttrBuilder FuncAttrs(F.getContext()); + setFnAttributes(FuncAttrs); + F.addFnAttrs(FuncAttrs); + } + + void setFnAttributes(llvm::AttrBuilder &FuncAttrs) { + if (SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { + FuncAttrs.addAttribute("sign-return-address", getSignReturnAddrStr()); + FuncAttrs.addAttribute("sign-return-address-key", getSignKeyStr()); + } + if (BranchTargetEnforcement) + FuncAttrs.addAttribute("branch-target-enforcement", "true"); + if (BranchProtectionPAuthLR) + FuncAttrs.addAttribute("branch-protection-pauth-lr", "true"); + if (GuardedControlStack) + FuncAttrs.addAttribute("guarded-control-stack", "true"); + } }; /// Determine if the Architecture in this TargetInfo supports branch >From 23490c21d4c49b8ec9ba653380af90b33989dfa4 Mon Sep 17 00:00:00 2001 From: Daniel Kiss <daniel.k...@arm.com> Date: Mon, 4 Mar 2024 17:32:41 +0100 Subject: [PATCH 4/6] Simplify the code. --- clang/lib/CodeGen/CGCall.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 58ccd3d181ccd..8f13b84908805 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2024,17 +2024,7 @@ static void getTrivialDefaultFunctionAttributes( } TargetInfo::BranchProtectionInfo BPI(LangOpts); - - if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { - FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr()); - FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr()); - } - if (BPI.BranchTargetEnforcement) - FuncAttrs.addAttribute("branch-target-enforcement", "true"); - if (BPI.BranchProtectionPAuthLR) - FuncAttrs.addAttribute("branch-protection-pauth-lr", "true"); - if (BPI.GuardedControlStack) - FuncAttrs.addAttribute("guarded-control-stack", "true"); + BPI.setFnAttributes(FuncAttrs); } /// Merges `target-features` from \TargetOpts and \F, and sets the result in >From e216b669622662cf28ecbd3f597fb8bb7cca9bf9 Mon Sep 17 00:00:00 2001 From: Daniel Kiss <daniel.k...@arm.com> Date: Mon, 4 Mar 2024 17:32:59 +0100 Subject: [PATCH 5/6] Simplify the test invocation --- clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp b/clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp index 8daf44abd4f91..de35c32e9c18a 100644 --- a/clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp +++ b/clang/test/CodeGenCXX/arm64-generated-fn-attr.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple aarch64-none-none -mbranch-target-enforce -msign-return-address=all -fcxx-exceptions -fexceptions -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK +// RUN: %clang_cc1 -triple aarch64 -mbranch-target-enforce -msign-return-address=all -fcxx-exceptions -fexceptions -emit-llvm %s -o - | FileCheck %s // Check that functions generated by clang have the correct attributes >From 787e05968ccb3829bd5c27fdbbf7b338c3bf5359 Mon Sep 17 00:00:00 2001 From: Daniel Kiss <daniel.k...@arm.com> Date: Wed, 10 Jul 2024 16:36:54 +0200 Subject: [PATCH 6/6] Delete clang/include/clang/Basic/TargetInfo.h drop empty line change --- clang/include/clang/Basic/TargetInfo.h | 1883 ------------------------ 1 file changed, 1883 deletions(-) delete mode 100644 clang/include/clang/Basic/TargetInfo.h diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h deleted file mode 100644 index 8eb05d82d2da6..0000000000000 --- a/clang/include/clang/Basic/TargetInfo.h +++ /dev/null @@ -1,1883 +0,0 @@ -//===--- TargetInfo.h - Expose information about the target -----*- 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::TargetInfo interface. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_BASIC_TARGETINFO_H -#define LLVM_CLANG_BASIC_TARGETINFO_H - -#include "clang/Basic/AddressSpaces.h" -#include "clang/Basic/BitmaskEnum.h" -#include "clang/Basic/CodeGenOptions.h" -#include "clang/Basic/LLVM.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/Specifiers.h" -#include "clang/Basic/TargetCXXABI.h" -#include "clang/Basic/TargetOptions.h" -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/Frontend/OpenMP/OMPGridValues.h" -#include "llvm/IR/Attributes.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/VersionTuple.h" -#include "llvm/TargetParser/Triple.h" -#include <cassert> -#include <optional> -#include <string> -#include <utility> -#include <vector> - -namespace llvm { -struct fltSemantics; -} - -namespace clang { -class DiagnosticsEngine; -class LangOptions; -class CodeGenOptions; -class MacroBuilder; - -/// Contains information gathered from parsing the contents of TargetAttr. -struct ParsedTargetAttr { - std::vector<std::string> Features; - StringRef CPU; - StringRef Tune; - StringRef BranchProtection; - StringRef Duplicate; - bool operator ==(const ParsedTargetAttr &Other) const { - return Duplicate == Other.Duplicate && CPU == Other.CPU && - Tune == Other.Tune && BranchProtection == Other.BranchProtection && - Features == Other.Features; - } -}; - -namespace Builtin { struct Info; } - -enum class FloatModeKind { - NoFloat = 0, - Half = 1 << 0, - Float = 1 << 1, - Double = 1 << 2, - LongDouble = 1 << 3, - Float128 = 1 << 4, - Ibm128 = 1 << 5, - LLVM_MARK_AS_BITMASK_ENUM(Ibm128) -}; - -/// Fields controlling how types are laid out in memory; these may need to -/// be copied for targets like AMDGPU that base their ABIs on an auxiliary -/// CPU target. -struct TransferrableTargetInfo { - unsigned char PointerWidth, PointerAlign; - unsigned char BoolWidth, BoolAlign; - unsigned char IntWidth, IntAlign; - unsigned char HalfWidth, HalfAlign; - unsigned char BFloat16Width, BFloat16Align; - unsigned char FloatWidth, FloatAlign; - unsigned char DoubleWidth, DoubleAlign; - unsigned char LongDoubleWidth, LongDoubleAlign, Float128Align, Ibm128Align; - unsigned char LargeArrayMinWidth, LargeArrayAlign; - unsigned char LongWidth, LongAlign; - unsigned char LongLongWidth, LongLongAlign; - unsigned char Int128Align; - - // This is an optional parameter for targets that - // don't use 'LongLongAlign' for '_BitInt' max alignment - std::optional<unsigned> BitIntMaxAlign; - - // Fixed point bit widths - unsigned char ShortAccumWidth, ShortAccumAlign; - unsigned char AccumWidth, AccumAlign; - unsigned char LongAccumWidth, LongAccumAlign; - unsigned char ShortFractWidth, ShortFractAlign; - unsigned char FractWidth, FractAlign; - unsigned char LongFractWidth, LongFractAlign; - - // If true, unsigned fixed point types have the same number of fractional bits - // as their signed counterparts, forcing the unsigned types to have one extra - // bit of padding. Otherwise, unsigned fixed point types have - // one more fractional bit than its corresponding signed type. This is false - // by default. - bool PaddingOnUnsignedFixedPoint; - - // Fixed point integral and fractional bit sizes - // Saturated types share the same integral/fractional bits as their - // corresponding unsaturated types. - // For simplicity, the fractional bits in a _Fract type will be one less the - // width of that _Fract type. This leaves all signed _Fract types having no - // padding and unsigned _Fract types will only have 1 bit of padding after the - // sign if PaddingOnUnsignedFixedPoint is set. - unsigned char ShortAccumScale; - unsigned char AccumScale; - unsigned char LongAccumScale; - - unsigned char DefaultAlignForAttributeAligned; - unsigned char MinGlobalAlign; - - unsigned short SuitableAlign; - unsigned short NewAlign; - unsigned MaxVectorAlign; - unsigned MaxTLSAlign; - - const llvm::fltSemantics *HalfFormat, *BFloat16Format, *FloatFormat, - *DoubleFormat, *LongDoubleFormat, *Float128Format, *Ibm128Format; - - ///===---- Target Data Type Query Methods -------------------------------===// - enum IntType { - NoInt = 0, - SignedChar, - UnsignedChar, - SignedShort, - UnsignedShort, - SignedInt, - UnsignedInt, - SignedLong, - UnsignedLong, - SignedLongLong, - UnsignedLongLong - }; - -protected: - IntType SizeType, IntMaxType, PtrDiffType, IntPtrType, WCharType, WIntType, - Char16Type, Char32Type, Int64Type, Int16Type, SigAtomicType, - ProcessIDType; - - /// Whether Objective-C's built-in boolean type should be signed char. - /// - /// Otherwise, when this flag is not set, the normal built-in boolean type is - /// used. - LLVM_PREFERRED_TYPE(bool) - unsigned UseSignedCharForObjCBool : 1; - - /// Control whether the alignment of bit-field types is respected when laying - /// out structures. If true, then the alignment of the bit-field type will be - /// used to (a) impact the alignment of the containing structure, and (b) - /// ensure that the individual bit-field will not straddle an alignment - /// boundary. - LLVM_PREFERRED_TYPE(bool) - unsigned UseBitFieldTypeAlignment : 1; - - /// Whether zero length bitfields (e.g., int : 0;) force alignment of - /// the next bitfield. - /// - /// If the alignment of the zero length bitfield is greater than the member - /// that follows it, `bar', `bar' will be aligned as the type of the - /// zero-length bitfield. - LLVM_PREFERRED_TYPE(bool) - unsigned UseZeroLengthBitfieldAlignment : 1; - - /// Whether zero length bitfield alignment is respected if they are the - /// leading members. - LLVM_PREFERRED_TYPE(bool) - unsigned UseLeadingZeroLengthBitfield : 1; - - /// Whether explicit bit field alignment attributes are honored. - LLVM_PREFERRED_TYPE(bool) - unsigned UseExplicitBitFieldAlignment : 1; - - /// If non-zero, specifies a fixed alignment value for bitfields that follow - /// zero length bitfield, regardless of the zero length bitfield type. - unsigned ZeroLengthBitfieldBoundary; - - /// If non-zero, specifies a maximum alignment to truncate alignment - /// specified in the aligned attribute of a static variable to this value. - unsigned MaxAlignedAttribute; -}; - -/// OpenCL type kinds. -enum OpenCLTypeKind : uint8_t { - OCLTK_Default, - OCLTK_ClkEvent, - OCLTK_Event, - OCLTK_Image, - OCLTK_Pipe, - OCLTK_Queue, - OCLTK_ReserveID, - OCLTK_Sampler, -}; - -/// Exposes information about the current target. -/// -class TargetInfo : public TransferrableTargetInfo, - public RefCountedBase<TargetInfo> { - std::shared_ptr<TargetOptions> TargetOpts; - llvm::Triple Triple; -protected: - // Target values set by the ctor of the actual target implementation. Default - // values are specified by the TargetInfo constructor. - bool BigEndian; - bool TLSSupported; - bool VLASupported; - bool NoAsmVariants; // True if {|} are normal characters. - bool HasLegalHalfType; // True if the backend supports operations on the half - // LLVM IR type. - bool HalfArgsAndReturns; - bool HasFloat128; - bool HasFloat16; - bool HasBFloat16; - bool HasFullBFloat16; // True if the backend supports native bfloat16 - // arithmetic. Used to determine excess precision - // support in the frontend. - bool HasIbm128; - bool HasLongDouble; - bool HasFPReturn; - bool HasStrictFP; - - unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; - std::string DataLayoutString; - const char *UserLabelPrefix; - const char *MCountName; - unsigned char RegParmMax, SSERegParmMax; - TargetCXXABI TheCXXABI; - const LangASMap *AddrSpaceMap; - - mutable StringRef PlatformName; - mutable VersionTuple PlatformMinVersion; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasAlignMac68kSupport : 1; - LLVM_PREFERRED_TYPE(FloatModeKind) - unsigned RealTypeUsesObjCFPRetMask : llvm::BitWidth<FloatModeKind>; - LLVM_PREFERRED_TYPE(bool) - unsigned ComplexLongDoubleUsesFP2Ret : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasBuiltinMSVaList : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned IsRenderScriptTarget : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasAArch64SVETypes : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasRISCVVTypes : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned AllowAMDGPUUnsafeFPAtomics : 1; - - LLVM_PREFERRED_TYPE(bool) - unsigned HasUnalignedAccess : 1; - - unsigned ARMCDECoprocMask : 8; - - unsigned MaxOpenCLWorkGroupSize; - - std::optional<unsigned> MaxBitIntWidth; - - std::optional<llvm::Triple> DarwinTargetVariantTriple; - - // TargetInfo Constructor. Default initializes all fields. - TargetInfo(const llvm::Triple &T); - - // UserLabelPrefix must match DL's getGlobalPrefix() when interpreted - // as a DataLayout object. - void resetDataLayout(StringRef DL, const char *UserLabelPrefix = ""); - - // Target features that are read-only and should not be disabled/enabled - // by command line options. Such features are for emitting predefined - // macros or checking availability of builtin functions and can be omitted - // in function attributes in IR. - llvm::StringSet<> ReadOnlyFeatures; - -public: - /// Construct a target for the given options. - /// - /// \param Opts - The options to use to initialize the target. The target may - /// modify the options to canonicalize the target feature information to match - /// what the backend expects. - static TargetInfo * - CreateTargetInfo(DiagnosticsEngine &Diags, - const std::shared_ptr<TargetOptions> &Opts); - - virtual ~TargetInfo(); - - /// Retrieve the target options. - TargetOptions &getTargetOpts() const { - assert(TargetOpts && "Missing target options"); - return *TargetOpts; - } - - /// The different kinds of __builtin_va_list types defined by - /// the target implementation. - enum BuiltinVaListKind { - /// typedef char* __builtin_va_list; - CharPtrBuiltinVaList = 0, - - /// typedef void* __builtin_va_list; - VoidPtrBuiltinVaList, - - /// __builtin_va_list as defined by the AArch64 ABI - /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf - AArch64ABIBuiltinVaList, - - /// __builtin_va_list as defined by the PNaCl ABI: - /// http://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Machine-Types - PNaClABIBuiltinVaList, - - /// __builtin_va_list as defined by the Power ABI: - /// https://www.power.org - /// /resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Embedded.pdf - PowerABIBuiltinVaList, - - /// __builtin_va_list as defined by the x86-64 ABI: - /// http://refspecs.linuxbase.org/elf/x86_64-abi-0.21.pdf - X86_64ABIBuiltinVaList, - - /// __builtin_va_list as defined by ARM AAPCS ABI - /// http://infocenter.arm.com - // /help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf - AAPCSABIBuiltinVaList, - - // typedef struct __va_list_tag - // { - // long __gpr; - // long __fpr; - // void *__overflow_arg_area; - // void *__reg_save_area; - // } va_list[1]; - SystemZBuiltinVaList, - - // typedef struct __va_list_tag { - // void *__current_saved_reg_area_pointer; - // void *__saved_reg_area_end_pointer; - // void *__overflow_area_pointer; - //} va_list; - HexagonBuiltinVaList - }; - -protected: - /// Specify if mangling based on address space map should be used or - /// not for language specific address spaces - bool UseAddrSpaceMapMangling; - -public: - IntType getSizeType() const { return SizeType; } - IntType getSignedSizeType() const { - switch (SizeType) { - case UnsignedShort: - return SignedShort; - case UnsignedInt: - return SignedInt; - case UnsignedLong: - return SignedLong; - case UnsignedLongLong: - return SignedLongLong; - default: - llvm_unreachable("Invalid SizeType"); - } - } - IntType getIntMaxType() const { return IntMaxType; } - IntType getUIntMaxType() const { - return getCorrespondingUnsignedType(IntMaxType); - } - IntType getPtrDiffType(LangAS AddrSpace) const { - return AddrSpace == LangAS::Default ? PtrDiffType - : getPtrDiffTypeV(AddrSpace); - } - IntType getUnsignedPtrDiffType(LangAS AddrSpace) const { - return getCorrespondingUnsignedType(getPtrDiffType(AddrSpace)); - } - IntType getIntPtrType() const { return IntPtrType; } - IntType getUIntPtrType() const { - return getCorrespondingUnsignedType(IntPtrType); - } - IntType getWCharType() const { return WCharType; } - IntType getWIntType() const { return WIntType; } - IntType getChar16Type() const { return Char16Type; } - IntType getChar32Type() const { return Char32Type; } - IntType getInt64Type() const { return Int64Type; } - IntType getUInt64Type() const { - return getCorrespondingUnsignedType(Int64Type); - } - IntType getInt16Type() const { return Int16Type; } - IntType getUInt16Type() const { - return getCorrespondingUnsignedType(Int16Type); - } - IntType getSigAtomicType() const { return SigAtomicType; } - IntType getProcessIDType() const { return ProcessIDType; } - - static IntType getCorrespondingUnsignedType(IntType T) { - switch (T) { - case SignedChar: - return UnsignedChar; - case SignedShort: - return UnsignedShort; - case SignedInt: - return UnsignedInt; - case SignedLong: - return UnsignedLong; - case SignedLongLong: - return UnsignedLongLong; - default: - llvm_unreachable("Unexpected signed integer type"); - } - } - - /// In the event this target uses the same number of fractional bits for its - /// unsigned types as it does with its signed counterparts, there will be - /// exactly one bit of padding. - /// Return true if unsigned fixed point types have padding for this target. - bool doUnsignedFixedPointTypesHavePadding() const { - return PaddingOnUnsignedFixedPoint; - } - - /// Return the width (in bits) of the specified integer type enum. - /// - /// For example, SignedInt -> getIntWidth(). - unsigned getTypeWidth(IntType T) const; - - /// Return integer type with specified width. - virtual IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const; - - /// Return the smallest integer type with at least the specified width. - virtual IntType getLeastIntTypeByWidth(unsigned BitWidth, - bool IsSigned) const; - - /// Return floating point type with specified width. On PPC, there are - /// three possible types for 128-bit floating point: "PPC double-double", - /// IEEE 754R quad precision, and "long double" (which under the covers - /// is represented as one of those two). At this time, there is no support - /// for an explicit "PPC double-double" type (i.e. __ibm128) so we only - /// need to differentiate between "long double" and IEEE quad precision. - FloatModeKind getRealTypeByWidth(unsigned BitWidth, - FloatModeKind ExplicitType) const; - - /// Return the alignment (in bits) of the specified integer type enum. - /// - /// For example, SignedInt -> getIntAlign(). - unsigned getTypeAlign(IntType T) const; - - /// Returns true if the type is signed; false otherwise. - static bool isTypeSigned(IntType T); - - /// Return the width of pointers on this target, for the - /// specified address space. - uint64_t getPointerWidth(LangAS AddrSpace) const { - return AddrSpace == LangAS::Default ? PointerWidth - : getPointerWidthV(AddrSpace); - } - uint64_t getPointerAlign(LangAS AddrSpace) const { - return AddrSpace == LangAS::Default ? PointerAlign - : getPointerAlignV(AddrSpace); - } - - /// Return the maximum width of pointers on this target. - virtual uint64_t getMaxPointerWidth() const { - return PointerWidth; - } - - /// Get integer value for null pointer. - /// \param AddrSpace address space of pointee in source language. - virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; } - - /// Return the size of '_Bool' and C++ 'bool' for this target, in bits. - unsigned getBoolWidth() const { return BoolWidth; } - - /// Return the alignment of '_Bool' and C++ 'bool' for this target. - unsigned getBoolAlign() const { return BoolAlign; } - - unsigned getCharWidth() const { return 8; } // FIXME - unsigned getCharAlign() const { return 8; } // FIXME - - /// Return the size of 'signed short' and 'unsigned short' for this - /// target, in bits. - unsigned getShortWidth() const { return 16; } // FIXME - - /// Return the alignment of 'signed short' and 'unsigned short' for - /// this target. - unsigned getShortAlign() const { return 16; } // FIXME - - /// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for - /// this target, in bits. - unsigned getIntWidth() const { return IntWidth; } - unsigned getIntAlign() const { return IntAlign; } - - /// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long' - /// for this target, in bits. - unsigned getLongWidth() const { return LongWidth; } - unsigned getLongAlign() const { return LongAlign; } - - /// getLongLongWidth/Align - Return the size of 'signed long long' and - /// 'unsigned long long' for this target, in bits. - unsigned getLongLongWidth() const { return LongLongWidth; } - unsigned getLongLongAlign() const { return LongLongAlign; } - - /// getInt128Align() - Returns the alignment of Int128. - unsigned getInt128Align() const { return Int128Align; } - - /// getBitIntMaxAlign() - Returns the maximum possible alignment of - /// '_BitInt' and 'unsigned _BitInt'. - unsigned getBitIntMaxAlign() const { - return BitIntMaxAlign.value_or(LongLongAlign); - } - - /// getBitIntAlign/Width - Return aligned size of '_BitInt' and - /// 'unsigned _BitInt' for this target, in bits. - unsigned getBitIntWidth(unsigned NumBits) const { - return llvm::alignTo(NumBits, getBitIntAlign(NumBits)); - } - unsigned getBitIntAlign(unsigned NumBits) const { - return std::clamp<unsigned>(llvm::PowerOf2Ceil(NumBits), getCharWidth(), - getBitIntMaxAlign()); - } - - /// getShortAccumWidth/Align - Return the size of 'signed short _Accum' and - /// 'unsigned short _Accum' for this target, in bits. - unsigned getShortAccumWidth() const { return ShortAccumWidth; } - unsigned getShortAccumAlign() const { return ShortAccumAlign; } - - /// getAccumWidth/Align - Return the size of 'signed _Accum' and - /// 'unsigned _Accum' for this target, in bits. - unsigned getAccumWidth() const { return AccumWidth; } - unsigned getAccumAlign() const { return AccumAlign; } - - /// getLongAccumWidth/Align - Return the size of 'signed long _Accum' and - /// 'unsigned long _Accum' for this target, in bits. - unsigned getLongAccumWidth() const { return LongAccumWidth; } - unsigned getLongAccumAlign() const { return LongAccumAlign; } - - /// getShortFractWidth/Align - Return the size of 'signed short _Fract' and - /// 'unsigned short _Fract' for this target, in bits. - unsigned getShortFractWidth() const { return ShortFractWidth; } - unsigned getShortFractAlign() const { return ShortFractAlign; } - - /// getFractWidth/Align - Return the size of 'signed _Fract' and - /// 'unsigned _Fract' for this target, in bits. - unsigned getFractWidth() const { return FractWidth; } - unsigned getFractAlign() const { return FractAlign; } - - /// getLongFractWidth/Align - Return the size of 'signed long _Fract' and - /// 'unsigned long _Fract' for this target, in bits. - unsigned getLongFractWidth() const { return LongFractWidth; } - unsigned getLongFractAlign() const { return LongFractAlign; } - - /// getShortAccumScale/IBits - Return the number of fractional/integral bits - /// in a 'signed short _Accum' type. - unsigned getShortAccumScale() const { return ShortAccumScale; } - unsigned getShortAccumIBits() const { - return ShortAccumWidth - ShortAccumScale - 1; - } - - /// getAccumScale/IBits - Return the number of fractional/integral bits - /// in a 'signed _Accum' type. - unsigned getAccumScale() const { return AccumScale; } - unsigned getAccumIBits() const { return AccumWidth - AccumScale - 1; } - - /// getLongAccumScale/IBits - Return the number of fractional/integral bits - /// in a 'signed long _Accum' type. - unsigned getLongAccumScale() const { return LongAccumScale; } - unsigned getLongAccumIBits() const { - return LongAccumWidth - LongAccumScale - 1; - } - - /// getUnsignedShortAccumScale/IBits - Return the number of - /// fractional/integral bits in a 'unsigned short _Accum' type. - unsigned getUnsignedShortAccumScale() const { - return PaddingOnUnsignedFixedPoint ? ShortAccumScale : ShortAccumScale + 1; - } - unsigned getUnsignedShortAccumIBits() const { - return PaddingOnUnsignedFixedPoint - ? getShortAccumIBits() - : ShortAccumWidth - getUnsignedShortAccumScale(); - } - - /// getUnsignedAccumScale/IBits - Return the number of fractional/integral - /// bits in a 'unsigned _Accum' type. - unsigned getUnsignedAccumScale() const { - return PaddingOnUnsignedFixedPoint ? AccumScale : AccumScale + 1; - } - unsigned getUnsignedAccumIBits() const { - return PaddingOnUnsignedFixedPoint ? getAccumIBits() - : AccumWidth - getUnsignedAccumScale(); - } - - /// getUnsignedLongAccumScale/IBits - Return the number of fractional/integral - /// bits in a 'unsigned long _Accum' type. - unsigned getUnsignedLongAccumScale() const { - return PaddingOnUnsignedFixedPoint ? LongAccumScale : LongAccumScale + 1; - } - unsigned getUnsignedLongAccumIBits() const { - return PaddingOnUnsignedFixedPoint - ? getLongAccumIBits() - : LongAccumWidth - getUnsignedLongAccumScale(); - } - - /// getShortFractScale - Return the number of fractional bits - /// in a 'signed short _Fract' type. - unsigned getShortFractScale() const { return ShortFractWidth - 1; } - - /// getFractScale - Return the number of fractional bits - /// in a 'signed _Fract' type. - unsigned getFractScale() const { return FractWidth - 1; } - - /// getLongFractScale - Return the number of fractional bits - /// in a 'signed long _Fract' type. - unsigned getLongFractScale() const { return LongFractWidth - 1; } - - /// getUnsignedShortFractScale - Return the number of fractional bits - /// in a 'unsigned short _Fract' type. - unsigned getUnsignedShortFractScale() const { - return PaddingOnUnsignedFixedPoint ? getShortFractScale() - : getShortFractScale() + 1; - } - - /// getUnsignedFractScale - Return the number of fractional bits - /// in a 'unsigned _Fract' type. - unsigned getUnsignedFractScale() const { - return PaddingOnUnsignedFixedPoint ? getFractScale() : getFractScale() + 1; - } - - /// getUnsignedLongFractScale - Return the number of fractional bits - /// in a 'unsigned long _Fract' type. - unsigned getUnsignedLongFractScale() const { - return PaddingOnUnsignedFixedPoint ? getLongFractScale() - : getLongFractScale() + 1; - } - - /// Determine whether the __int128 type is supported on this target. - virtual bool hasInt128Type() const { - return (getPointerWidth(LangAS::Default) >= 64) || - getTargetOpts().ForceEnableInt128; - } // FIXME - - /// Determine whether the _BitInt type is supported on this target. This - /// limitation is put into place for ABI reasons. - /// FIXME: _BitInt is a required type in C23, so there's not much utility in - /// asking whether the target supported it or not; I think this should be - /// removed once backends have been alerted to the type and have had the - /// chance to do implementation work if needed. - virtual bool hasBitIntType() const { - return false; - } - - // Different targets may support a different maximum width for the _BitInt - // type, depending on what operations are supported. - virtual size_t getMaxBitIntWidth() const { - // Consider -fexperimental-max-bitint-width= first. - if (MaxBitIntWidth) - return std::min<size_t>(*MaxBitIntWidth, llvm::IntegerType::MAX_INT_BITS); - - // FIXME: this value should be llvm::IntegerType::MAX_INT_BITS, which is - // maximum bit width that LLVM claims its IR can support. However, most - // backends currently have a bug where they only support float to int - // conversion (and vice versa) on types that are <= 128 bits and crash - // otherwise. We're setting the max supported value to 128 to be - // conservative. - return 128; - } - - /// Determine whether _Float16 is supported on this target. - virtual bool hasLegalHalfType() const { return HasLegalHalfType; } - - /// Whether half args and returns are supported. - virtual bool allowHalfArgsAndReturns() const { return HalfArgsAndReturns; } - - /// Determine whether the __float128 type is supported on this target. - virtual bool hasFloat128Type() const { return HasFloat128; } - - /// Determine whether the _Float16 type is supported on this target. - virtual bool hasFloat16Type() const { return HasFloat16; } - - /// Determine whether the _BFloat16 type is supported on this target. - virtual bool hasBFloat16Type() const { - return HasBFloat16 || HasFullBFloat16; - } - - /// Determine whether the BFloat type is fully supported on this target, i.e - /// arithemtic operations. - virtual bool hasFullBFloat16Type() const { return HasFullBFloat16; } - - /// Determine whether the __ibm128 type is supported on this target. - virtual bool hasIbm128Type() const { return HasIbm128; } - - /// Determine whether the long double type is supported on this target. - virtual bool hasLongDoubleType() const { return HasLongDouble; } - - /// Determine whether return of a floating point value is supported - /// on this target. - virtual bool hasFPReturn() const { return HasFPReturn; } - - /// Determine whether constrained floating point is supported on this target. - virtual bool hasStrictFP() const { return HasStrictFP; } - - /// Return the alignment that is the largest alignment ever used for any - /// scalar/SIMD data type on the target machine you are compiling for - /// (including types with an extended alignment requirement). - unsigned getSuitableAlign() const { return SuitableAlign; } - - /// Return the default alignment for __attribute__((aligned)) on - /// this target, to be used if no alignment value is specified. - unsigned getDefaultAlignForAttributeAligned() const { - return DefaultAlignForAttributeAligned; - } - - /// getMinGlobalAlign - Return the minimum alignment of a global variable, - /// unless its alignment is explicitly reduced via attributes. If \param - /// HasNonWeakDef is true, this concerns a VarDecl which has a definition - /// in current translation unit and that is not weak. - virtual unsigned getMinGlobalAlign(uint64_t Size, bool HasNonWeakDef) const { - return MinGlobalAlign; - } - - /// Return the largest alignment for which a suitably-sized allocation with - /// '::operator new(size_t)' is guaranteed to produce a correctly-aligned - /// pointer. - unsigned getNewAlign() const { - return NewAlign ? NewAlign : std::max(LongDoubleAlign, LongLongAlign); - } - - /// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in - /// bits. - unsigned getWCharWidth() const { return getTypeWidth(WCharType); } - unsigned getWCharAlign() const { return getTypeAlign(WCharType); } - - /// getChar16Width/Align - Return the size of 'char16_t' for this target, in - /// bits. - unsigned getChar16Width() const { return getTypeWidth(Char16Type); } - unsigned getChar16Align() const { return getTypeAlign(Char16Type); } - - /// getChar32Width/Align - Return the size of 'char32_t' for this target, in - /// bits. - unsigned getChar32Width() const { return getTypeWidth(Char32Type); } - unsigned getChar32Align() const { return getTypeAlign(Char32Type); } - - /// getHalfWidth/Align/Format - Return the size/align/format of 'half'. - unsigned getHalfWidth() const { return HalfWidth; } - unsigned getHalfAlign() const { return HalfAlign; } - const llvm::fltSemantics &getHalfFormat() const { return *HalfFormat; } - - /// getFloatWidth/Align/Format - Return the size/align/format of 'float'. - unsigned getFloatWidth() const { return FloatWidth; } - unsigned getFloatAlign() const { return FloatAlign; } - const llvm::fltSemantics &getFloatFormat() const { return *FloatFormat; } - - /// getBFloat16Width/Align/Format - Return the size/align/format of '__bf16'. - unsigned getBFloat16Width() const { return BFloat16Width; } - unsigned getBFloat16Align() const { return BFloat16Align; } - const llvm::fltSemantics &getBFloat16Format() const { return *BFloat16Format; } - - /// getDoubleWidth/Align/Format - Return the size/align/format of 'double'. - unsigned getDoubleWidth() const { return DoubleWidth; } - unsigned getDoubleAlign() const { return DoubleAlign; } - const llvm::fltSemantics &getDoubleFormat() const { return *DoubleFormat; } - - /// getLongDoubleWidth/Align/Format - Return the size/align/format of 'long - /// double'. - unsigned getLongDoubleWidth() const { return LongDoubleWidth; } - unsigned getLongDoubleAlign() const { return LongDoubleAlign; } - const llvm::fltSemantics &getLongDoubleFormat() const { - return *LongDoubleFormat; - } - - /// getFloat128Width/Align/Format - Return the size/align/format of - /// '__float128'. - unsigned getFloat128Width() const { return 128; } - unsigned getFloat128Align() const { return Float128Align; } - const llvm::fltSemantics &getFloat128Format() const { - return *Float128Format; - } - - /// getIbm128Width/Align/Format - Return the size/align/format of - /// '__ibm128'. - unsigned getIbm128Width() const { return 128; } - unsigned getIbm128Align() const { return Ibm128Align; } - const llvm::fltSemantics &getIbm128Format() const { return *Ibm128Format; } - - /// Return the mangled code of long double. - virtual const char *getLongDoubleMangling() const { return "e"; } - - /// Return the mangled code of __float128. - virtual const char *getFloat128Mangling() const { return "g"; } - - /// Return the mangled code of __ibm128. - virtual const char *getIbm128Mangling() const { - llvm_unreachable("ibm128 not implemented on this target"); - } - - /// Return the mangled code of bfloat. - virtual const char *getBFloat16Mangling() const { return "DF16b"; } - - /// Return the value for the C99 FLT_EVAL_METHOD macro. - virtual LangOptions::FPEvalMethodKind getFPEvalMethod() const { - return LangOptions::FPEvalMethodKind::FEM_Source; - } - - virtual bool supportSourceEvalMethod() const { return true; } - - // getLargeArrayMinWidth/Align - Return the minimum array size that is - // 'large' and its alignment. - unsigned getLargeArrayMinWidth() const { return LargeArrayMinWidth; } - unsigned getLargeArrayAlign() const { return LargeArrayAlign; } - - /// Return the maximum width lock-free atomic operation which will - /// ever be supported for the given target - unsigned getMaxAtomicPromoteWidth() const { return MaxAtomicPromoteWidth; } - /// Return the maximum width lock-free atomic operation which can be - /// inlined given the supported features of the given target. - unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; } - /// Set the maximum inline or promote width lock-free atomic operation - /// for the given target. - virtual void setMaxAtomicWidth() {} - /// Returns true if the given target supports lock-free atomic - /// operations at the specified width and alignment. - virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits, - uint64_t AlignmentInBits) const { - return AtomicSizeInBits <= AlignmentInBits && - AtomicSizeInBits <= getMaxAtomicInlineWidth() && - (AtomicSizeInBits <= getCharWidth() || - llvm::isPowerOf2_64(AtomicSizeInBits / getCharWidth())); - } - - /// Return the maximum vector alignment supported for the given target. - unsigned getMaxVectorAlign() const { return MaxVectorAlign; } - - unsigned getMaxOpenCLWorkGroupSize() const { return MaxOpenCLWorkGroupSize; } - - /// Return the alignment (in bits) of the thrown exception object. This is - /// only meaningful for targets that allocate C++ exceptions in a system - /// runtime, such as those using the Itanium C++ ABI. - virtual unsigned getExnObjectAlignment() const { - // Itanium says that an _Unwind_Exception has to be "double-word" - // aligned (and thus the end of it is also so-aligned), meaning 16 - // bytes. Of course, that was written for the actual Itanium, - // which is a 64-bit platform. Classically, the ABI doesn't really - // specify the alignment on other platforms, but in practice - // libUnwind declares the struct with __attribute__((aligned)), so - // we assume that alignment here. (It's generally 16 bytes, but - // some targets overwrite it.) - return getDefaultAlignForAttributeAligned(); - } - - /// Return the size of intmax_t and uintmax_t for this target, in bits. - unsigned getIntMaxTWidth() const { - return getTypeWidth(IntMaxType); - } - - // Return the size of unwind_word for this target. - virtual unsigned getUnwindWordWidth() const { - return getPointerWidth(LangAS::Default); - } - - /// Return the "preferred" register width on this target. - virtual unsigned getRegisterWidth() const { - // Currently we assume the register width on the target matches the pointer - // width, we can introduce a new variable for this if/when some target wants - // it. - return PointerWidth; - } - - /// Return true iff unaligned accesses are a single instruction (rather than - /// a synthesized sequence). - bool hasUnalignedAccess() const { return HasUnalignedAccess; } - - /// Return true iff unaligned accesses are cheap. This affects placement and - /// size of bitfield loads/stores. (Not the ABI-mandated placement of - /// the bitfields themselves.) - bool hasCheapUnalignedBitFieldAccess() const { - // Simply forward to the unaligned access getter. - return hasUnalignedAccess(); - } - - /// \brief Returns the default value of the __USER_LABEL_PREFIX__ macro, - /// which is the prefix given to user symbols by default. - /// - /// On most platforms this is "", but it is "_" on some. - const char *getUserLabelPrefix() const { return UserLabelPrefix; } - - /// Returns the name of the mcount instrumentation function. - const char *getMCountName() const { - return MCountName; - } - - /// Check if the Objective-C built-in boolean type should be signed - /// char. - /// - /// Otherwise, if this returns false, the normal built-in boolean type - /// should also be used for Objective-C. - bool useSignedCharForObjCBool() const { - return UseSignedCharForObjCBool; - } - void noSignedCharForObjCBool() { - UseSignedCharForObjCBool = false; - } - - /// Check whether the alignment of bit-field types is respected - /// when laying out structures. - bool useBitFieldTypeAlignment() const { - return UseBitFieldTypeAlignment; - } - - /// Check whether zero length bitfields should force alignment of - /// the next member. - bool useZeroLengthBitfieldAlignment() const { - return UseZeroLengthBitfieldAlignment; - } - - /// Check whether zero length bitfield alignment is respected if they are - /// leading members. - bool useLeadingZeroLengthBitfield() const { - return UseLeadingZeroLengthBitfield; - } - - /// Get the fixed alignment value in bits for a member that follows - /// a zero length bitfield. - unsigned getZeroLengthBitfieldBoundary() const { - return ZeroLengthBitfieldBoundary; - } - - /// Get the maximum alignment in bits for a static variable with - /// aligned attribute. - unsigned getMaxAlignedAttribute() const { return MaxAlignedAttribute; } - - /// Check whether explicit bitfield alignment attributes should be - // honored, as in "__attribute__((aligned(2))) int b : 1;". - bool useExplicitBitFieldAlignment() const { - return UseExplicitBitFieldAlignment; - } - - /// Check whether this target support '\#pragma options align=mac68k'. - bool hasAlignMac68kSupport() const { - return HasAlignMac68kSupport; - } - - /// Return the user string for the specified integer type enum. - /// - /// For example, SignedShort -> "short". - static const char *getTypeName(IntType T); - - /// Return the constant suffix for the specified integer type enum. - /// - /// For example, SignedLong -> "L". - const char *getTypeConstantSuffix(IntType T) const; - - /// Return the printf format modifier for the specified - /// integer type enum. - /// - /// For example, SignedLong -> "l". - static const char *getTypeFormatModifier(IntType T); - - /// Check whether the given real type should use the "fpret" flavor of - /// Objective-C message passing on this target. - bool useObjCFPRetForRealType(FloatModeKind T) const { - return (int)((FloatModeKind)RealTypeUsesObjCFPRetMask & T); - } - - /// Check whether _Complex long double should use the "fp2ret" flavor - /// of Objective-C message passing on this target. - bool useObjCFP2RetForComplexLongDouble() const { - return ComplexLongDoubleUsesFP2Ret; - } - - /// Check whether llvm intrinsics such as llvm.convert.to.fp16 should be used - /// to convert to and from __fp16. - /// FIXME: This function should be removed once all targets stop using the - /// conversion intrinsics. - virtual bool useFP16ConversionIntrinsics() const { - return true; - } - - /// Specify if mangling based on address space map should be used or - /// not for language specific address spaces - bool useAddressSpaceMapMangling() const { - return UseAddrSpaceMapMangling; - } - - ///===---- Other target property query methods --------------------------===// - - /// Appends the target-specific \#define values for this - /// target set to the specified buffer. - virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const = 0; - - - /// Return information about target-specific builtins for - /// the current primary target, and info about which builtins are non-portable - /// across the current set of primary and secondary targets. - virtual ArrayRef<Builtin::Info> getTargetBuiltins() const = 0; - - /// Returns target-specific min and max values VScale_Range. - virtual std::optional<std::pair<unsigned, unsigned>> - getVScaleRange(const LangOptions &LangOpts) const { - return std::nullopt; - } - /// The __builtin_clz* and __builtin_ctz* built-in - /// functions are specified to have undefined results for zero inputs, but - /// on targets that support these operations in a way that provides - /// well-defined results for zero without loss of performance, it is a good - /// idea to avoid optimizing based on that undef behavior. - virtual bool isCLZForZeroUndef() const { return true; } - - /// Returns the kind of __builtin_va_list type that should be used - /// with this target. - virtual BuiltinVaListKind getBuiltinVaListKind() const = 0; - - /// Returns whether or not type \c __builtin_ms_va_list type is - /// available on this target. - bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; } - - /// Returns true for RenderScript. - bool isRenderScriptTarget() const { return IsRenderScriptTarget; } - - /// Returns whether or not the AArch64 SVE built-in types are - /// available on this target. - bool hasAArch64SVETypes() const { return HasAArch64SVETypes; } - - /// Returns whether or not the RISC-V V built-in types are - /// available on this target. - bool hasRISCVVTypes() const { return HasRISCVVTypes; } - - /// Returns whether or not the AMDGPU unsafe floating point atomics are - /// allowed. - bool allowAMDGPUUnsafeFPAtomics() const { return AllowAMDGPUUnsafeFPAtomics; } - - /// For ARM targets returns a mask defining which coprocessors are configured - /// as Custom Datapath. - uint32_t getARMCDECoprocMask() const { return ARMCDECoprocMask; } - - /// Returns whether the passed in string is a valid clobber in an - /// inline asm statement. - /// - /// This is used by Sema. - bool isValidClobber(StringRef Name) const; - - /// Returns whether the passed in string is a valid register name - /// according to GCC. - /// - /// This is used by Sema for inline asm statements. - virtual bool isValidGCCRegisterName(StringRef Name) const; - - /// Returns the "normalized" GCC register name. - /// - /// ReturnCannonical true will return the register name without any additions - /// such as "{}" or "%" in it's canonical form, for example: - /// ReturnCanonical = true and Name = "rax", will return "ax". - StringRef getNormalizedGCCRegisterName(StringRef Name, - bool ReturnCanonical = false) const; - - virtual bool isSPRegName(StringRef) const { return false; } - - /// Extracts a register from the passed constraint (if it is a - /// single-register constraint) and the asm label expression related to a - /// variable in the input or output list of an inline asm statement. - /// - /// This function is used by Sema in order to diagnose conflicts between - /// the clobber list and the input/output lists. - virtual StringRef getConstraintRegister(StringRef Constraint, - StringRef Expression) const { - return ""; - } - - struct ConstraintInfo { - enum { - CI_None = 0x00, - CI_AllowsMemory = 0x01, - CI_AllowsRegister = 0x02, - CI_ReadWrite = 0x04, // "+r" output constraint (read and write). - CI_HasMatchingInput = 0x08, // This output operand has a matching input. - CI_ImmediateConstant = 0x10, // This operand must be an immediate constant - CI_EarlyClobber = 0x20, // "&" output constraint (early clobber). - }; - unsigned Flags; - int TiedOperand; - struct { - int Min; - int Max; - bool isConstrained; - } ImmRange; - llvm::SmallSet<int, 4> ImmSet; - - std::string ConstraintStr; // constraint: "=rm" - std::string Name; // Operand name: [foo] with no []'s. - public: - ConstraintInfo(StringRef ConstraintStr, StringRef Name) - : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), - Name(Name.str()) { - ImmRange.Min = ImmRange.Max = 0; - ImmRange.isConstrained = false; - } - - const std::string &getConstraintStr() const { return ConstraintStr; } - const std::string &getName() const { return Name; } - bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; } - bool earlyClobber() { return (Flags & CI_EarlyClobber) != 0; } - bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; } - bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; } - - /// Return true if this output operand has a matching - /// (tied) input operand. - bool hasMatchingInput() const { return (Flags & CI_HasMatchingInput) != 0; } - - /// Return true if this input operand is a matching - /// constraint that ties it to an output operand. - /// - /// If this returns true then getTiedOperand will indicate which output - /// operand this is tied to. - bool hasTiedOperand() const { return TiedOperand != -1; } - unsigned getTiedOperand() const { - assert(hasTiedOperand() && "Has no tied operand!"); - return (unsigned)TiedOperand; - } - - bool requiresImmediateConstant() const { - return (Flags & CI_ImmediateConstant) != 0; - } - bool isValidAsmImmediate(const llvm::APInt &Value) const { - if (!ImmSet.empty()) - return Value.isSignedIntN(32) && ImmSet.contains(Value.getZExtValue()); - return !ImmRange.isConstrained || - (Value.sge(ImmRange.Min) && Value.sle(ImmRange.Max)); - } - - void setIsReadWrite() { Flags |= CI_ReadWrite; } - void setEarlyClobber() { Flags |= CI_EarlyClobber; } - void setAllowsMemory() { Flags |= CI_AllowsMemory; } - void setAllowsRegister() { Flags |= CI_AllowsRegister; } - void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } - void setRequiresImmediate(int Min, int Max) { - Flags |= CI_ImmediateConstant; - ImmRange.Min = Min; - ImmRange.Max = Max; - ImmRange.isConstrained = true; - } - void setRequiresImmediate(llvm::ArrayRef<int> Exacts) { - Flags |= CI_ImmediateConstant; - for (int Exact : Exacts) - ImmSet.insert(Exact); - } - void setRequiresImmediate(int Exact) { - Flags |= CI_ImmediateConstant; - ImmSet.insert(Exact); - } - void setRequiresImmediate() { - Flags |= CI_ImmediateConstant; - } - - /// Indicate that this is an input operand that is tied to - /// the specified output operand. - /// - /// Copy over the various constraint information from the output. - void setTiedOperand(unsigned N, ConstraintInfo &Output) { - Output.setHasMatchingInput(); - Flags = Output.Flags; - TiedOperand = N; - // Don't copy Name or constraint string. - } - }; - - /// Validate register name used for global register variables. - /// - /// This function returns true if the register passed in RegName can be used - /// for global register variables on this target. In addition, it returns - /// true in HasSizeMismatch if the size of the register doesn't match the - /// variable size passed in RegSize. - virtual bool validateGlobalRegisterVariable(StringRef RegName, - unsigned RegSize, - bool &HasSizeMismatch) const { - HasSizeMismatch = false; - return true; - } - - // validateOutputConstraint, validateInputConstraint - Checks that - // a constraint is valid and provides information about it. - // FIXME: These should return a real error instead of just true/false. - bool validateOutputConstraint(ConstraintInfo &Info) const; - bool validateInputConstraint(MutableArrayRef<ConstraintInfo> OutputConstraints, - ConstraintInfo &info) const; - - virtual bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap, - StringRef /*Constraint*/, - unsigned /*Size*/) const { - return true; - } - - virtual bool validateInputSize(const llvm::StringMap<bool> &FeatureMap, - StringRef /*Constraint*/, - unsigned /*Size*/) const { - return true; - } - virtual bool - validateConstraintModifier(StringRef /*Constraint*/, - char /*Modifier*/, - unsigned /*Size*/, - std::string &/*SuggestedModifier*/) const { - return true; - } - virtual bool - validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const = 0; - - bool resolveSymbolicName(const char *&Name, - ArrayRef<ConstraintInfo> OutputConstraints, - unsigned &Index) const; - - // Constraint parm will be left pointing at the last character of - // the constraint. In practice, it won't be changed unless the - // constraint is longer than one character. - virtual std::string convertConstraint(const char *&Constraint) const { - // 'p' defaults to 'r', but can be overridden by targets. - if (*Constraint == 'p') - return std::string("r"); - return std::string(1, *Constraint); - } - - /// Replace some escaped characters with another string based on - /// target-specific rules - virtual std::optional<std::string> handleAsmEscapedChar(char C) const { - return std::nullopt; - } - - /// Returns a string of target-specific clobbers, in LLVM format. - virtual std::string_view getClobbers() const = 0; - - /// Returns true if NaN encoding is IEEE 754-2008. - /// Only MIPS allows a different encoding. - virtual bool isNan2008() const { - return true; - } - - /// Returns the target triple of the primary target. - const llvm::Triple &getTriple() const { - return Triple; - } - - /// Returns the target ID if supported. - virtual std::optional<std::string> getTargetID() const { - return std::nullopt; - } - - const char *getDataLayoutString() const { - assert(!DataLayoutString.empty() && "Uninitialized DataLayout!"); - return DataLayoutString.c_str(); - } - - struct GCCRegAlias { - const char * const Aliases[5]; - const char * const Register; - }; - - struct AddlRegName { - const char * const Names[5]; - const unsigned RegNum; - }; - - /// Does this target support "protected" visibility? - /// - /// Any target which dynamic libraries will naturally support - /// something like "default" (meaning that the symbol is visible - /// outside this shared object) and "hidden" (meaning that it isn't) - /// visibilities, but "protected" is really an ELF-specific concept - /// with weird semantics designed around the convenience of dynamic - /// linker implementations. Which is not to suggest that there's - /// consistent target-independent semantics for "default" visibility - /// either; the entire thing is pretty badly mangled. - virtual bool hasProtectedVisibility() const { return true; } - - /// Does this target aim for semantic compatibility with - /// Microsoft C++ code using dllimport/export attributes? - virtual bool shouldDLLImportComdatSymbols() const { - return getTriple().isWindowsMSVCEnvironment() || - getTriple().isWindowsItaniumEnvironment() || getTriple().isPS(); - } - - // Does this target have PS4 specific dllimport/export handling? - virtual bool hasPS4DLLImportExport() const { - return getTriple().isPS() || - // Windows Itanium support allows for testing the SCEI flavour of - // dllimport/export handling on a Windows system. - (getTriple().isWindowsItaniumEnvironment() && - getTriple().getVendor() == llvm::Triple::SCEI); - } - - /// Set forced language options. - /// - /// Apply changes to the target information with respect to certain - /// language options which change the target configuration and adjust - /// the language based on the target options where applicable. - virtual void adjust(DiagnosticsEngine &Diags, LangOptions &Opts); - - /// Initialize the map with the default set of target features for the - /// CPU this should include all legal feature strings on the target. - /// - /// \return False on error (invalid features). - virtual bool initFeatureMap(llvm::StringMap<bool> &Features, - DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeatureVec) const; - - /// Get the ABI currently in use. - virtual StringRef getABI() const { return StringRef(); } - - /// Get the C++ ABI currently in use. - TargetCXXABI getCXXABI() const { - return TheCXXABI; - } - - /// Target the specified CPU. - /// - /// \return False on error (invalid CPU name). - virtual bool setCPU(const std::string &Name) { - return false; - } - - /// Fill a SmallVectorImpl with the valid values to setCPU. - virtual void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {} - - /// Fill a SmallVectorImpl with the valid values for tuning CPU. - virtual void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const { - fillValidCPUList(Values); - } - - /// Determine whether this TargetInfo supports the given CPU name. - virtual bool isValidCPUName(StringRef Name) const { - return true; - } - - /// Determine whether this TargetInfo supports the given CPU name for - /// tuning. - virtual bool isValidTuneCPUName(StringRef Name) const { - return isValidCPUName(Name); - } - - virtual ParsedTargetAttr parseTargetAttr(StringRef Str) const; - - /// Determine whether this TargetInfo supports tune in target attribute. - virtual bool supportsTargetAttributeTune() const { - return false; - } - - /// Use the specified ABI. - /// - /// \return False on error (invalid ABI name). - virtual bool setABI(const std::string &Name) { - return false; - } - - /// Use the specified unit for FP math. - /// - /// \return False on error (invalid unit name). - virtual bool setFPMath(StringRef Name) { - return false; - } - - /// Check if target has a given feature enabled - virtual bool hasFeatureEnabled(const llvm::StringMap<bool> &Features, - StringRef Name) const { - return Features.lookup(Name); - } - - /// Enable or disable a specific target feature; - /// the feature name must be valid. - virtual void setFeatureEnabled(llvm::StringMap<bool> &Features, - StringRef Name, - bool Enabled) const { - Features[Name] = Enabled; - } - - /// Determine whether this TargetInfo supports the given feature. - virtual bool isValidFeatureName(StringRef Feature) const { - return true; - } - - /// Returns true if feature has an impact on target code - /// generation. - virtual bool doesFeatureAffectCodeGen(StringRef Feature) const { - return true; - } - - class BranchProtectionInfo { - public: - LangOptions::SignReturnAddressScopeKind SignReturnAddr; - LangOptions::SignReturnAddressKeyKind SignKey; - bool BranchTargetEnforcement; - bool BranchProtectionPAuthLR; - bool GuardedControlStack; - - protected: - const char *getSignReturnAddrStr() const { - switch (SignReturnAddr) { - case LangOptions::SignReturnAddressScopeKind::None: - return "none"; - case LangOptions::SignReturnAddressScopeKind::NonLeaf: - return "non-leaf"; - case LangOptions::SignReturnAddressScopeKind::All: - return "all"; - } - llvm_unreachable("Unexpected SignReturnAddressScopeKind"); - } - const char *getSignKeyStr() const { - switch (SignKey) { - case LangOptions::SignReturnAddressKeyKind::AKey: - return "a_key"; - case LangOptions::SignReturnAddressKeyKind::BKey: - return "b_key"; - } - llvm_unreachable("Unexpected SignReturnAddressKeyKind"); - } - - public: - BranchProtectionInfo() = default; - BranchProtectionInfo(const LangOptions &LangOpts) { - SignReturnAddr = - LangOpts.hasSignReturnAddress() - ? (LangOpts.isSignReturnAddressScopeAll() - ? LangOptions::SignReturnAddressScopeKind::All - : LangOptions::SignReturnAddressScopeKind::NonLeaf) - : LangOptions::SignReturnAddressScopeKind::None; - SignKey = LangOpts.isSignReturnAddressWithAKey() - ? LangOptions::SignReturnAddressKeyKind::AKey - : LangOptions::SignReturnAddressKeyKind::BKey; - BranchTargetEnforcement = LangOpts.BranchTargetEnforcement; - BranchProtectionPAuthLR = LangOpts.BranchProtectionPAuthLR; - GuardedControlStack = LangOpts.GuardedControlStack; - } - - void setFnAttributes(llvm::Function &F) { - llvm::AttrBuilder FuncAttrs(F.getContext()); - setFnAttributes(FuncAttrs); - F.addFnAttrs(FuncAttrs); - } - - void setFnAttributes(llvm::AttrBuilder &FuncAttrs) { - if (SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { - FuncAttrs.addAttribute("sign-return-address", getSignReturnAddrStr()); - FuncAttrs.addAttribute("sign-return-address-key", getSignKeyStr()); - } - if (BranchTargetEnforcement) - FuncAttrs.addAttribute("branch-target-enforcement"); - if (BranchProtectionPAuthLR) - FuncAttrs.addAttribute("branch-protection-pauth-lr"); - if (GuardedControlStack) - FuncAttrs.addAttribute("guarded-control-stack"); - } - }; - - /// Determine if the Architecture in this TargetInfo supports branch - /// protection - virtual bool isBranchProtectionSupportedArch(StringRef Arch) const { - return false; - } - - /// Determine if this TargetInfo supports the given branch protection - /// specification - virtual bool validateBranchProtection(StringRef Spec, StringRef Arch, - BranchProtectionInfo &BPI, - StringRef &Err) const { - Err = ""; - return false; - } - - /// Perform initialization based on the user configured - /// set of features (e.g., +sse4). - /// - /// The list is guaranteed to have at most one entry per feature. - /// - /// The target may modify the features list, to change which options are - /// passed onwards to the backend. - /// FIXME: This part should be fixed so that we can change handleTargetFeatures - /// to merely a TargetInfo initialization routine. - /// - /// \return False on error. - virtual bool handleTargetFeatures(std::vector<std::string> &Features, - DiagnosticsEngine &Diags) { - return true; - } - - /// Determine whether the given target has the given feature. - virtual bool hasFeature(StringRef Feature) const { - return false; - } - - /// Determine whether the given target feature is read only. - bool isReadOnlyFeature(StringRef Feature) const { - return ReadOnlyFeatures.count(Feature); - } - - /// Identify whether this target supports multiversioning of functions, - /// which requires support for cpu_supports and cpu_is functionality. - bool supportsMultiVersioning() const { - return getTriple().isX86() || getTriple().isAArch64(); - } - - /// Identify whether this target supports IFuncs. - bool supportsIFunc() const { - if (getTriple().isOSBinFormatMachO()) - return true; - return getTriple().isOSBinFormatELF() && - ((getTriple().isOSLinux() && !getTriple().isMusl()) || - getTriple().isOSFreeBSD()); - } - - // Identify whether this target supports __builtin_cpu_supports and - // __builtin_cpu_is. - virtual bool supportsCpuSupports() const { return false; } - virtual bool supportsCpuIs() const { return false; } - virtual bool supportsCpuInit() const { return false; } - - // Validate the contents of the __builtin_cpu_supports(const char*) - // argument. - virtual bool validateCpuSupports(StringRef Name) const { return false; } - - // Return the target-specific priority for features/cpus/vendors so - // that they can be properly sorted for checking. - virtual unsigned multiVersionSortPriority(StringRef Name) const { - return 0; - } - - // Return the target-specific cost for feature - // that taken into account in priority sorting. - virtual unsigned multiVersionFeatureCost() const { return 0; } - - // Validate the contents of the __builtin_cpu_is(const char*) - // argument. - virtual bool validateCpuIs(StringRef Name) const { return false; } - - // Validate a cpu_dispatch/cpu_specific CPU option, which is a different list - // from cpu_is, since it checks via features rather than CPUs directly. - virtual bool validateCPUSpecificCPUDispatch(StringRef Name) const { - return false; - } - - // Get the character to be added for mangling purposes for cpu_specific. - virtual char CPUSpecificManglingCharacter(StringRef Name) const { - llvm_unreachable( - "cpu_specific Multiversioning not implemented on this target"); - } - - // Get the value for the 'tune-cpu' flag for a cpu_specific variant with the - // programmer-specified 'Name'. - virtual StringRef getCPUSpecificTuneName(StringRef Name) const { - llvm_unreachable( - "cpu_specific Multiversioning not implemented on this target"); - } - - // Get a list of the features that make up the CPU option for - // cpu_specific/cpu_dispatch so that it can be passed to llvm as optimization - // options. - virtual void getCPUSpecificCPUDispatchFeatures( - StringRef Name, llvm::SmallVectorImpl<StringRef> &Features) const { - llvm_unreachable( - "cpu_specific Multiversioning not implemented on this target"); - } - - // Get the cache line size of a given cpu. This method switches over - // the given cpu and returns "std::nullopt" if the CPU is not found. - virtual std::optional<unsigned> getCPUCacheLineSize() const { - return std::nullopt; - } - - // Returns maximal number of args passed in registers. - unsigned getRegParmMax() const { - assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); - return RegParmMax; - } - - /// Whether the target supports thread-local storage. - bool isTLSSupported() const { - return TLSSupported; - } - - /// Return the maximum alignment (in bits) of a TLS variable - /// - /// Gets the maximum alignment (in bits) of a TLS variable on this target. - /// Returns zero if there is no such constraint. - unsigned getMaxTLSAlign() const { return MaxTLSAlign; } - - /// Whether target supports variable-length arrays. - bool isVLASupported() const { return VLASupported; } - - /// Whether the target supports SEH __try. - bool isSEHTrySupported() const { - return getTriple().isOSWindows() && - (getTriple().isX86() || - getTriple().getArch() == llvm::Triple::aarch64); - } - - /// Return true if {|} are normal characters in the asm string. - /// - /// If this returns false (the default), then {abc|xyz} is syntax - /// that says that when compiling for asm variant #0, "abc" should be - /// generated, but when compiling for asm variant #1, "xyz" should be - /// generated. - bool hasNoAsmVariants() const { - return NoAsmVariants; - } - - /// Return the register number that __builtin_eh_return_regno would - /// return with the specified argument. - /// This corresponds with TargetLowering's getExceptionPointerRegister - /// and getExceptionSelectorRegister in the backend. - virtual int getEHDataRegisterNumber(unsigned RegNo) const { - return -1; - } - - /// Return the section to use for C++ static initialization functions. - virtual const char *getStaticInitSectionSpecifier() const { - return nullptr; - } - - const LangASMap &getAddressSpaceMap() const { return *AddrSpaceMap; } - unsigned getTargetAddressSpace(LangAS AS) const { - if (isTargetAddressSpace(AS)) - return toTargetAddressSpace(AS); - return getAddressSpaceMap()[(unsigned)AS]; - } - - /// Determine whether the given pointer-authentication key is valid. - /// - /// The value has been coerced to type 'int'. - virtual bool validatePointerAuthKey(const llvm::APSInt &value) const; - - /// Map from the address space field in builtin description strings to the - /// language address space. - virtual LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const { - return getLangASFromTargetAS(AS); - } - - /// Map from the address space field in builtin description strings to the - /// language address space. - virtual LangAS getCUDABuiltinAddressSpace(unsigned AS) const { - return getLangASFromTargetAS(AS); - } - - /// Return an AST address space which can be used opportunistically - /// for constant global memory. It must be possible to convert pointers into - /// this address space to LangAS::Default. If no such address space exists, - /// this may return std::nullopt, and such optimizations will be disabled. - virtual std::optional<LangAS> getConstantAddressSpace() const { - return LangAS::Default; - } - - // access target-specific GPU grid values that must be consistent between - // host RTL (plugin), deviceRTL and clang. - virtual const llvm::omp::GV &getGridValue() const { - llvm_unreachable("getGridValue not implemented on this target"); - } - - /// Retrieve the name of the platform as it is used in the - /// availability attribute. - StringRef getPlatformName() const { return PlatformName; } - - /// Retrieve the minimum desired version of the platform, to - /// which the program should be compiled. - VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; } - - bool isBigEndian() const { return BigEndian; } - bool isLittleEndian() const { return !BigEndian; } - - /// Whether the option -fextend-arguments={32,64} is supported on the target. - virtual bool supportsExtendIntArgs() const { return false; } - - /// Controls if __arithmetic_fence is supported in the targeted backend. - virtual bool checkArithmeticFenceSupported() const { return false; } - - /// Gets the default calling convention for the given target and - /// declaration context. - virtual CallingConv getDefaultCallingConv() const { - // Not all targets will specify an explicit calling convention that we can - // express. This will always do the right thing, even though it's not - // an explicit calling convention. - return CC_C; - } - - enum CallingConvCheckResult { - CCCR_OK, - CCCR_Warning, - CCCR_Ignore, - CCCR_Error, - }; - - /// Determines whether a given calling convention is valid for the - /// target. A calling convention can either be accepted, produce a warning - /// and be substituted with the default calling convention, or (someday) - /// produce an error (such as using thiscall on a non-instance function). - virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { - switch (CC) { - default: - return CCCR_Warning; - case CC_C: - return CCCR_OK; - } - } - - enum CallingConvKind { - CCK_Default, - CCK_ClangABI4OrPS4, - CCK_MicrosoftWin64 - }; - - virtual CallingConvKind getCallingConvKind(bool ClangABICompat4) const; - - /// Controls whether explicitly defaulted (`= default`) special member - /// functions disqualify something from being POD-for-the-purposes-of-layout. - /// Historically, Clang didn't consider these acceptable for POD, but GCC - /// does. So in newer Clang ABIs they are acceptable for POD to be compatible - /// with GCC/Itanium ABI, and remains disqualifying for targets that need - /// Clang backwards compatibility rather than GCC/Itanium ABI compatibility. - virtual bool areDefaultedSMFStillPOD(const LangOptions&) const; - - /// Controls if __builtin_longjmp / __builtin_setjmp can be lowered to - /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp. - virtual bool hasSjLjLowering() const { - return false; - } - - /// Check if the target supports CFProtection branch. - virtual bool - checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const; - - /// Check if the target supports CFProtection return. - virtual bool - checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const; - - /// Whether target allows to overalign ABI-specified preferred alignment - virtual bool allowsLargerPreferedTypeAlignment() const { return true; } - - /// Whether target defaults to the `power` alignment rules of AIX. - virtual bool defaultsToAIXPowerAlignment() const { return false; } - - /// Set supported OpenCL extensions and optional core features. - virtual void setSupportedOpenCLOpts() {} - - virtual void supportAllOpenCLOpts(bool V = true) { -#define OPENCLEXTNAME(Ext) \ - setFeatureEnabled(getTargetOpts().OpenCLFeaturesMap, #Ext, V); -#include "clang/Basic/OpenCLExtensions.def" - } - - /// Set supported OpenCL extensions as written on command line - virtual void setCommandLineOpenCLOpts() { - for (const auto &Ext : getTargetOpts().OpenCLExtensionsAsWritten) { - bool IsPrefixed = (Ext[0] == '+' || Ext[0] == '-'); - std::string Name = IsPrefixed ? Ext.substr(1) : Ext; - bool V = IsPrefixed ? Ext[0] == '+' : true; - - if (Name == "all") { - supportAllOpenCLOpts(V); - continue; - } - - getTargetOpts().OpenCLFeaturesMap[Name] = V; - } - } - - /// Get supported OpenCL extensions and optional core features. - llvm::StringMap<bool> &getSupportedOpenCLOpts() { - return getTargetOpts().OpenCLFeaturesMap; - } - - /// Get const supported OpenCL extensions and optional core features. - const llvm::StringMap<bool> &getSupportedOpenCLOpts() const { - return getTargetOpts().OpenCLFeaturesMap; - } - - /// Get address space for OpenCL type. - virtual LangAS getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const; - - /// \returns Target specific vtbl ptr address space. - virtual unsigned getVtblPtrAddressSpace() const { - return 0; - } - - /// \returns If a target requires an address within a target specific address - /// space \p AddressSpace to be converted in order to be used, then return the - /// corresponding target specific DWARF address space. - /// - /// \returns Otherwise return std::nullopt and no conversion will be emitted - /// in the DWARF. - virtual std::optional<unsigned> getDWARFAddressSpace(unsigned AddressSpace) - const { - return std::nullopt; - } - - /// \returns The version of the SDK which was used during the compilation if - /// one was specified, or an empty version otherwise. - const llvm::VersionTuple &getSDKVersion() const { - return getTargetOpts().SDKVersion; - } - - /// Check the target is valid after it is fully initialized. - virtual bool validateTarget(DiagnosticsEngine &Diags) const { - return true; - } - - /// Check that OpenCL target has valid options setting based on OpenCL - /// version. - virtual bool validateOpenCLTarget(const LangOptions &Opts, - DiagnosticsEngine &Diags) const; - - virtual void setAuxTarget(const TargetInfo *Aux) {} - - /// Whether target allows debuginfo types for decl only variables/functions. - virtual bool allowDebugInfoForExternalRef() const { return false; } - - /// Returns the darwin target variant triple, the variant of the deployment - /// target for which the code is being compiled. - const llvm::Triple *getDarwinTargetVariantTriple() const { - return DarwinTargetVariantTriple ? &*DarwinTargetVariantTriple : nullptr; - } - - /// Returns the version of the darwin target variant SDK which was used during - /// the compilation if one was specified, or an empty version otherwise. - const std::optional<VersionTuple> getDarwinTargetVariantSDKVersion() const { - return !getTargetOpts().DarwinTargetVariantSDKVersion.empty() - ? getTargetOpts().DarwinTargetVariantSDKVersion - : std::optional<VersionTuple>(); - } - - /// Whether to support HIP image/texture API's. - virtual bool hasHIPImageSupport() const { return true; } - - /// The first value in the pair is the minimum offset between two objects to - /// avoid false sharing (destructive interference). The second value in the - /// pair is maximum size of contiguous memory to promote true sharing - /// (constructive interference). Neither of these values are considered part - /// of the ABI and can be changed by targets at any time. - virtual std::pair<unsigned, unsigned> hardwareInterferenceSizes() const { - return std::make_pair(64, 64); - } - -protected: - /// Copy type and layout related info. - void copyAuxTarget(const TargetInfo *Aux); - virtual uint64_t getPointerWidthV(LangAS AddrSpace) const { - return PointerWidth; - } - virtual uint64_t getPointerAlignV(LangAS AddrSpace) const { - return PointerAlign; - } - virtual enum IntType getPtrDiffTypeV(LangAS AddrSpace) const { - return PtrDiffType; - } - virtual ArrayRef<const char *> getGCCRegNames() const = 0; - virtual ArrayRef<GCCRegAlias> getGCCRegAliases() const = 0; - virtual ArrayRef<AddlRegName> getGCCAddlRegNames() const { - return std::nullopt; - } - - private: - // Assert the values for the fractional and integral bits for each fixed point - // type follow the restrictions given in clause 6.2.6.3 of N1169. - void CheckFixedPointBits() const; -}; - -} // end namespace clang - -#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits