[clang] [Clang][ARM][AArch64] Add branch protection attributes to the defaults. (PR #83277)

Daniel Kiss via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 10 07:37:04 PDT 2024


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.kiss at 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.kiss at 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.kiss at 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.kiss at 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.kiss at 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.kiss at 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



More information about the cfe-commits mailing list