[llvm-branch-commits] [clang] [llvm] [clang] Implement function pointer signing and authenticated function calls (PR #93906)

Akira Hatanaka via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jun 18 21:41:56 PDT 2024


https://github.com/ahatanak updated https://github.com/llvm/llvm-project/pull/93906

>From fc8f76b404b25951dc10ecaaa760b4b4c3d4f858 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Thu, 30 May 2024 17:07:04 -0700
Subject: [PATCH 01/14] [clang] Add arm64e ABI-defined key assignments to
 ptrauth.h.

These are currently gated by __APPLE__; we can figure out a way to
define these on ELF targets as well, and maybe have them be defined
by clang itself, depending on ABI modes.
---
 clang/lib/Headers/ptrauth.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 56c3c3636c9bc..036665d75a91b 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -15,6 +15,29 @@ typedef enum {
   ptrauth_key_asib = 1,
   ptrauth_key_asda = 2,
   ptrauth_key_asdb = 3,
+
+#ifdef __APPLE__
+  /* A process-independent key which can be used to sign code pointers.
+     Signing and authenticating with this key is a no-op in processes
+     which disable ABI pointer authentication. */
+  ptrauth_key_process_independent_code = ptrauth_key_asia,
+
+  /* A process-specific key which can be used to sign code pointers.
+     Signing and authenticating with this key is enforced even in processes
+     which disable ABI pointer authentication. */
+  ptrauth_key_process_dependent_code = ptrauth_key_asib,
+
+  /* A process-independent key which can be used to sign data pointers.
+     Signing and authenticating with this key is a no-op in processes
+     which disable ABI pointer authentication. */
+  ptrauth_key_process_independent_data = ptrauth_key_asda,
+
+  /* A process-specific key which can be used to sign data pointers.
+     Signing and authenticating with this key is a no-op in processes
+     which disable ABI pointer authentication. */
+  ptrauth_key_process_dependent_data = ptrauth_key_asdb,
+#endif /* __APPLE__ */
+
 } ptrauth_key;
 
 /* An integer type of the appropriate size for a discriminator argument. */

>From 42cb73fecf1033aefbe824149f3d8a5352bb2103 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Thu, 30 May 2024 17:05:31 -0700
Subject: [PATCH 02/14] [Support] Add SipHash-based 16/64-bit ptrauth stable
 hash.

Based on the SipHash reference implementation:
  https://github.com/veorq/SipHash
which has very graciously been licensed under our llvm license
(Apache-2.0 WITH LLVM-exception) by Jean-Philippe Aumasson.

This lightly modifies it to fit into libSupport, and wraps it for the
two main interfaces we're interested in (16/64-bit).

This intentionally doesn't expose a raw interface beyond that to
encourage others to carefully consider their use.

The exact algorithm is the little-endian interpretation of the
non-doubled (i.e. 64-bit) result of applying a SipHash-2-4 using
a specific key value which can be found in the source.

By "stable" we mean that the result of this hash algorithm will the same
across different compiler versions and target platforms.

The 16-bit variant is used extensively for the AArch64 ptrauth ABI,
because AArch64 can efficiently load a 16-bit immediate into the high
bits of a register without disturbing the remainder of the value, which
serves as a nice blend operation.

16 bits is also sufficiently compact to not inflate a loader relocation.
We disallow zero to guarantee a different discriminator from the places
in the ABI that use a constant zero.

Co-Authored-By: John McCall <rjmccall at apple.com>
---
 llvm/include/llvm/Support/SipHash.h    |  47 +++++++
 llvm/lib/Support/CMakeLists.txt        |   1 +
 llvm/lib/Support/SipHash.cpp           | 174 +++++++++++++++++++++++++
 llvm/unittests/Support/CMakeLists.txt  |   1 +
 llvm/unittests/Support/SipHashTest.cpp |  43 ++++++
 5 files changed, 266 insertions(+)
 create mode 100644 llvm/include/llvm/Support/SipHash.h
 create mode 100644 llvm/lib/Support/SipHash.cpp
 create mode 100644 llvm/unittests/Support/SipHashTest.cpp

diff --git a/llvm/include/llvm/Support/SipHash.h b/llvm/include/llvm/Support/SipHash.h
new file mode 100644
index 0000000000000..fcc29c00da185
--- /dev/null
+++ b/llvm/include/llvm/Support/SipHash.h
@@ -0,0 +1,47 @@
+//===--- SipHash.h - An ABI-stable string SipHash ---------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A family of ABI-stable string hash algorithms based on SipHash, currently
+// used to compute ptrauth discriminators.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SIPHASH_H
+#define LLVM_SUPPORT_SIPHASH_H
+
+#include <cstdint>
+
+namespace llvm {
+class StringRef;
+
+/// Compute a stable 64-bit hash of the given string.
+///
+/// The exact algorithm is the little-endian interpretation of the
+/// non-doubled (i.e. 64-bit) result of applying a SipHash-2-4 using
+/// a specific key value which can be found in the source.
+///
+/// By "stable" we mean that the result of this hash algorithm will
+/// the same across different compiler versions and target platforms.
+uint64_t getPointerAuthStableSipHash64(StringRef S);
+
+/// Compute a stable non-zero 16-bit hash of the given string.
+///
+/// This computes the full getPointerAuthStableSipHash64, but additionally
+/// truncates it down to a non-zero 16-bit value.
+///
+/// We use a 16-bit discriminator because ARM64 can efficiently load
+/// a 16-bit immediate into the high bits of a register without disturbing
+/// the remainder of the value, which serves as a nice blend operation.
+/// 16 bits is also sufficiently compact to not inflate a loader relocation.
+/// We disallow zero to guarantee a different discriminator from the places
+/// in the ABI that use a constant zero.
+uint64_t getPointerAuthStableSipHash16(StringRef S);
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index be4badc09efa5..aa37b812791ff 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -222,6 +222,7 @@ add_llvm_component_library(LLVMSupport
   SHA1.cpp
   SHA256.cpp
   Signposts.cpp
+  SipHash.cpp
   SmallPtrSet.cpp
   SmallVector.cpp
   SourceMgr.cpp
diff --git a/llvm/lib/Support/SipHash.cpp b/llvm/lib/Support/SipHash.cpp
new file mode 100644
index 0000000000000..dbd60fb73ebb5
--- /dev/null
+++ b/llvm/lib/Support/SipHash.cpp
@@ -0,0 +1,174 @@
+//===--- StableHash.cpp - An ABI-stable string hash -----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements an ABI-stable string hash based on SipHash, used to
+//  compute ptrauth discriminators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SipHash.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Debug.h"
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "llvm-siphash"
+
+//  Lightly adapted from the SipHash reference C implementation by
+//  Jean-Philippe Aumasson and Daniel J. Bernstein.
+
+#define SIPHASH_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+
+#define SIPHASH_U8TO64_LE(p)                                                   \
+  (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                          \
+   ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                   \
+   ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                   \
+   ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
+
+#define SIPHASH_SIPROUND                                                       \
+  do {                                                                         \
+    v0 += v1;                                                                  \
+    v1 = SIPHASH_ROTL(v1, 13);                                                 \
+    v1 ^= v0;                                                                  \
+    v0 = SIPHASH_ROTL(v0, 32);                                                 \
+    v2 += v3;                                                                  \
+    v3 = SIPHASH_ROTL(v3, 16);                                                 \
+    v3 ^= v2;                                                                  \
+    v0 += v3;                                                                  \
+    v3 = SIPHASH_ROTL(v3, 21);                                                 \
+    v3 ^= v0;                                                                  \
+    v2 += v1;                                                                  \
+    v1 = SIPHASH_ROTL(v1, 17);                                                 \
+    v1 ^= v2;                                                                  \
+    v2 = SIPHASH_ROTL(v2, 32);                                                 \
+  } while (0)
+
+template <int cROUNDS, int dROUNDS, class ResultTy>
+static inline ResultTy siphash(const uint8_t *in, uint64_t inlen,
+                               const uint8_t (&k)[16]) {
+  static_assert(sizeof(ResultTy) == 8 || sizeof(ResultTy) == 16,
+                "result type should be uint64_t or uint128_t");
+  uint64_t v0 = 0x736f6d6570736575ULL;
+  uint64_t v1 = 0x646f72616e646f6dULL;
+  uint64_t v2 = 0x6c7967656e657261ULL;
+  uint64_t v3 = 0x7465646279746573ULL;
+  uint64_t b;
+  uint64_t k0 = SIPHASH_U8TO64_LE(k);
+  uint64_t k1 = SIPHASH_U8TO64_LE(k + 8);
+  uint64_t m;
+  int i;
+  const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t));
+  const int left = inlen & 7;
+  b = ((uint64_t)inlen) << 56;
+  v3 ^= k1;
+  v2 ^= k0;
+  v1 ^= k1;
+  v0 ^= k0;
+
+  if (sizeof(ResultTy) == 16) {
+    v1 ^= 0xee;
+  }
+
+  for (; in != end; in += 8) {
+    m = SIPHASH_U8TO64_LE(in);
+    v3 ^= m;
+
+    for (i = 0; i < cROUNDS; ++i)
+      SIPHASH_SIPROUND;
+
+    v0 ^= m;
+  }
+
+  switch (left) {
+  case 7:
+    b |= ((uint64_t)in[6]) << 48;
+    LLVM_FALLTHROUGH;
+  case 6:
+    b |= ((uint64_t)in[5]) << 40;
+    LLVM_FALLTHROUGH;
+  case 5:
+    b |= ((uint64_t)in[4]) << 32;
+    LLVM_FALLTHROUGH;
+  case 4:
+    b |= ((uint64_t)in[3]) << 24;
+    LLVM_FALLTHROUGH;
+  case 3:
+    b |= ((uint64_t)in[2]) << 16;
+    LLVM_FALLTHROUGH;
+  case 2:
+    b |= ((uint64_t)in[1]) << 8;
+    LLVM_FALLTHROUGH;
+  case 1:
+    b |= ((uint64_t)in[0]);
+    break;
+  case 0:
+    break;
+  }
+
+  v3 ^= b;
+
+  for (i = 0; i < cROUNDS; ++i)
+    SIPHASH_SIPROUND;
+
+  v0 ^= b;
+
+  if (sizeof(ResultTy) == 8) {
+    v2 ^= 0xff;
+  } else {
+    v2 ^= 0xee;
+  }
+
+  for (i = 0; i < dROUNDS; ++i)
+    SIPHASH_SIPROUND;
+
+  b = v0 ^ v1 ^ v2 ^ v3;
+
+  // This mess with the result type would be easier with 'if constexpr'.
+
+  uint64_t firstHalf = b;
+  if (sizeof(ResultTy) == 8)
+    return firstHalf;
+
+  v1 ^= 0xdd;
+
+  for (i = 0; i < dROUNDS; ++i)
+    SIPHASH_SIPROUND;
+
+  b = v0 ^ v1 ^ v2 ^ v3;
+  uint64_t secondHalf = b;
+
+  return firstHalf | (ResultTy(secondHalf) << (sizeof(ResultTy) == 8 ? 0 : 64));
+}
+
+//===--- LLVM-specific wrappers around siphash.
+
+/// Compute an ABI-stable 64-bit hash of the given string.
+uint64_t llvm::getPointerAuthStableSipHash64(StringRef Str) {
+  static const uint8_t K[16] = {0xb5, 0xd4, 0xc9, 0xeb, 0x79, 0x10, 0x4a, 0x79,
+                                0x6f, 0xec, 0x8b, 0x1b, 0x42, 0x87, 0x81, 0xd4};
+
+  // The aliasing is fine here because of omnipotent char.
+  auto *Data = reinterpret_cast<const uint8_t *>(Str.data());
+  return siphash<2, 4, uint64_t>(Data, Str.size(), K);
+}
+
+/// Compute an ABI-stable 16-bit hash of the given string.
+uint64_t llvm::getPointerAuthStableSipHash16(StringRef Str) {
+  uint64_t RawHash = getPointerAuthStableSipHash64(Str);
+
+  // Produce a non-zero 16-bit discriminator.
+  uint64_t Discriminator = (RawHash % 0xFFFF) + 1;
+  LLVM_DEBUG(dbgs() << "ptrauth stable hash 16-bit discriminator: "
+                    << utostr(Discriminator) << " (0x"
+                    << utohexstr(Discriminator) << ")"
+                    << " of: " << Str << "\n");
+  return Discriminator;
+}
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 2718be8450f80..631f2e6bf00df 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -75,6 +75,7 @@ add_llvm_unittest(SupportTests
   ScopedPrinterTest.cpp
   SHA256.cpp
   SignalsTest.cpp
+  SipHashTest.cpp
   SourceMgrTest.cpp
   SpecialCaseListTest.cpp
   SuffixTreeTest.cpp
diff --git a/llvm/unittests/Support/SipHashTest.cpp b/llvm/unittests/Support/SipHashTest.cpp
new file mode 100644
index 0000000000000..1a8143d9c9375
--- /dev/null
+++ b/llvm/unittests/Support/SipHashTest.cpp
@@ -0,0 +1,43 @@
+//===- llvm/unittest/Support/SipHashTest.cpp ------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SipHash.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(SipHashTest, PointerAuthSipHash) {
+  // Test some basic cases, for 16 bit and 64 bit results.
+  EXPECT_EQ(0xE793U, getPointerAuthStableSipHash16(""));
+  EXPECT_EQ(0xF468U, getPointerAuthStableSipHash16("strlen"));
+  EXPECT_EQ(0x2D15U, getPointerAuthStableSipHash16("_ZN1 ind; f"));
+
+  EXPECT_EQ(0xB2BB69BB0A2AC0F1U, getPointerAuthStableSipHash64(""));
+  EXPECT_EQ(0x9304ABFF427B72E8U, getPointerAuthStableSipHash64("strlen"));
+  EXPECT_EQ(0x55F45179A08AE51BU, getPointerAuthStableSipHash64("_ZN1 ind; f"));
+
+  // Test some known strings that are already enshrined in the ABI.
+  EXPECT_EQ(0x6AE1U, getPointerAuthStableSipHash16("isa"));
+  EXPECT_EQ(0xB5ABU, getPointerAuthStableSipHash16("objc_class:superclass"));
+  EXPECT_EQ(0xC0BBU, getPointerAuthStableSipHash16("block_descriptor"));
+  EXPECT_EQ(0xC310U, getPointerAuthStableSipHash16("method_list_t"));
+
+  // Test the limits that apply to 16 bit results but don't to 64 bit results.
+  EXPECT_EQ(1U,                  getPointerAuthStableSipHash16("_Zptrkvttf"));
+  EXPECT_EQ(0x314FD87E0611F020U, getPointerAuthStableSipHash64("_Zptrkvttf"));
+
+  EXPECT_EQ(0xFFFFU,             getPointerAuthStableSipHash16("_Zaflhllod"));
+  EXPECT_EQ(0x1292F635FB3DFBF8U, getPointerAuthStableSipHash64("_Zaflhllod"));
+}
+
+} // end anonymous namespace

>From 61be7a922397d66773a8f4a6e476ea321f52f00c Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Thu, 30 May 2024 17:22:29 -0700
Subject: [PATCH 03/14] [clang] Define ptrauth_string_discriminator builtin.

This exposes the ABI-stable hash function that allows computing a 16-bit
discriminator from a constant string.

This allows manually matching the implicit string discriminators
computed in the ABI (e.g., from mangled names for vtable pointer/entry
signing), as well as enabling the use of interesting discriminators when
manually annotating specific pointers with the __ptrauth qualifier.

Co-Authored-By: John McCall <rjmccall at apple.com>
---
 clang/include/clang/Basic/Builtins.td         |  6 ++++++
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 ++
 clang/lib/AST/ExprConstant.cpp                |  7 +++++++
 clang/lib/Headers/ptrauth.h                   | 17 ++++++++++++++++
 clang/lib/Sema/SemaChecking.cpp               | 20 +++++++++++++++++++
 clang/test/CodeGen/ptrauth-intrinsics.c       | 13 ++++++++++++
 clang/test/Sema/ptrauth-intrinsics-macro.c    |  5 +++++
 7 files changed, 70 insertions(+)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..836697632a3bc 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4411,6 +4411,12 @@ def PtrauthAuth : Builtin {
   let Prototype = "void*(void*,int,void*)";
 }
 
+def PtrauthStringDiscriminator : Builtin {
+  let Spellings = ["__builtin_ptrauth_string_discriminator"];
+  let Attributes = [NoThrow, Const, Constexpr];
+  let Prototype = "size_t(char const*)";
+}
+
 // OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
 // We need the generic prototype, since the packet type could be anything.
 def ReadPipe : OCLPipeLangBuiltin {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f15cba63624ea..64add46248c69 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -928,6 +928,8 @@ def warn_ptrauth_sign_null_pointer :
 def warn_ptrauth_auth_null_pointer :
   Warning<"authenticating a null pointer will almost certainly trap">,
   InGroup<PtrAuthNullPointers>;
+def err_ptrauth_string_not_literal : Error<
+  "argument must be a string literal%select{| of char type}0">;
 
 /// main()
 // static main() is not an error in C, just in C++.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..eafecfb5fe5b1 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -58,6 +58,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/SipHash.h"
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstring>
@@ -12583,6 +12584,12 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
   case Builtin::BI__builtin_expect_with_probability:
     return Visit(E->getArg(0));
 
+  case Builtin::BI__builtin_ptrauth_string_discriminator: {
+    auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
+    auto result = getPointerAuthStableSipHash16(literal->getString());
+    return Success(result, E);
+  }
+
   case Builtin::BI__builtin_ffs:
   case Builtin::BI__builtin_ffsl:
   case Builtin::BI__builtin_ffsll: {
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 036665d75a91b..3e58af1802084 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -135,6 +135,17 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
 #define ptrauth_auth_data(__value, __old_key, __old_data)                      \
   __builtin_ptrauth_auth(__value, __old_key, __old_data)
 
+/* Compute a constant discriminator from the given string.
+
+   The result can be used as the second argument to
+   ptrauth_blend_discriminator or the third argument to the
+   __ptrauth qualifier.  It has type size_t.
+
+   The argument must be a string literal.
+   A call to this function is an integer constant expression. */
+#define ptrauth_string_discriminator(__string)                                 \
+  __builtin_ptrauth_string_discriminator(__string)
+
 /* Compute a signature for the given pair of pointer-sized values.
    The order of the arguments is significant.
 
@@ -196,6 +207,12 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
     __value;                                                                   \
   })
 
+#define ptrauth_string_discriminator(__string)                                 \
+  ({                                                                           \
+    (void)__string;                                                            \
+    ((ptrauth_extra_data_t)0);                                                 \
+  })
+
 #define ptrauth_sign_generic_data(__value, __data)                             \
   ({                                                                           \
     (void)__value;                                                             \
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c3251f3cc9d81..f6012ef4b3601 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2156,6 +2156,24 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
   return Call;
 }
 
+static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *call) {
+  if (checkPointerAuthEnabled(S, call)) return ExprError();
+
+  // We've already performed normal call type-checking.
+  Expr *arg = call->getArgs()[0]->IgnoreParenImpCasts();
+
+  // Operand must be an ordinary or UTF-8 string literal.
+  auto literal = dyn_cast<StringLiteral>(arg);
+  if (!literal || literal->getCharByteWidth() != 1) {
+    S.Diag(arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
+      << (literal ? 1 : 0)
+      << arg->getSourceRange();
+    return ExprError();
+  }
+
+  return call;
+}
+
 static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
   if (S.checkArgCount(TheCall, 1))
     return ExprError();
@@ -2922,6 +2940,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     return PointerAuthSignGenericData(*this, TheCall);
   case Builtin::BI__builtin_ptrauth_auth_and_resign:
     return PointerAuthAuthAndResign(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_string_discriminator:
+    return PointerAuthStringDiscriminator(*this, TheCall);
   // OpenCL v2.0, s6.13.16 - Pipe functions
   case Builtin::BIread_pipe:
   case Builtin::BIwrite_pipe:
diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c
index 17f28dddb3801..d602325da8b17 100644
--- a/clang/test/CodeGen/ptrauth-intrinsics.c
+++ b/clang/test/CodeGen/ptrauth-intrinsics.c
@@ -71,3 +71,16 @@ void test_sign_generic_data() {
   // CHECK-NEXT: store i64 [[RESULT]], ptr @signature,
   signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
 }
+
+// CHECK-LABEL: define void @test_string_discriminator()
+void test_string_discriminator() {
+  // CHECK:      [[X:%.*]] = alloca i32
+
+  // Check a couple of random discriminators used by Swift.
+
+  // CHECK:      store i32 58298, ptr [[X]],
+  int x = __builtin_ptrauth_string_discriminator("InitializeWithCopy");
+
+  // CHECK:      store i32 9112, ptr [[X]],
+  x = __builtin_ptrauth_string_discriminator("DestroyArray");
+}
diff --git a/clang/test/Sema/ptrauth-intrinsics-macro.c b/clang/test/Sema/ptrauth-intrinsics-macro.c
index 07d6374045145..540f2846b7ce1 100644
--- a/clang/test/Sema/ptrauth-intrinsics-macro.c
+++ b/clang/test/Sema/ptrauth-intrinsics-macro.c
@@ -32,3 +32,8 @@ void test(int *dp, int value) {
   int t2 = ptrauth_sign_generic_data(dp, 0);
   (void)t2;
 }
+
+void test_string_discriminator(int *dp) {
+  ptrauth_extra_data_t t0 = ptrauth_string_discriminator("string");
+  (void)t0;
+}

>From 1a23a99f23714ba6a83b354e3b9afd056b263a02 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Thu, 30 May 2024 17:33:04 -0700
Subject: [PATCH 04/14] [clang] Define ptrauth_sign_constant builtin.

This is constant-expression equivalent to __builtin_ptrauth_sign,
allowing its usage in global initializers, but requiring constant
pointers and discriminators.

Co-Authored-By: John McCall <rjmccall at apple.com>
---
 clang/include/clang/Basic/Builtins.td         |   6 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   7 +
 clang/include/clang/CodeGen/CodeGenABITypes.h |   6 +
 clang/lib/AST/ExprConstant.cpp                |   1 +
 clang/lib/CodeGen/CGBuiltin.cpp               |   3 +
 clang/lib/CodeGen/CGExprConstant.cpp          |  62 +++++++++
 clang/lib/CodeGen/CGPointerAuth.cpp           |  77 +++++++++++
 clang/lib/CodeGen/CMakeLists.txt              |   1 +
 clang/lib/CodeGen/CodeGenModule.h             |   5 +
 clang/lib/Headers/ptrauth.h                   |  25 ++++
 clang/lib/Sema/SemaChecking.cpp               | 128 ++++++++++++++++--
 .../CodeGen/ptrauth-intrinsic-sign-constant.c |  20 +++
 clang/test/Sema/ptrauth-intrinsics-macro.c    |   4 +
 clang/test/Sema/ptrauth.c                     |  29 ++++
 14 files changed, 360 insertions(+), 14 deletions(-)
 create mode 100644 clang/lib/CodeGen/CGPointerAuth.cpp
 create mode 100644 clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 836697632a3bc..557b70172fc08 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4393,6 +4393,12 @@ def PtrauthSignUnauthenticated : Builtin {
   let Prototype = "void*(void*,int,void*)";
 }
 
+def PtrauthSignConstant : Builtin {
+  let Spellings = ["__builtin_ptrauth_sign_constant"];
+  let Attributes = [CustomTypeChecking, NoThrow, Const, Constexpr];
+  let Prototype = "void*(void*,int,void*)";
+}
+
 def PtrauthSignGenericData : Builtin {
   let Spellings = ["__builtin_ptrauth_sign_generic_data"];
   let Attributes = [CustomTypeChecking, NoThrow, Const];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 64add46248c69..753e775ce0968 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -922,6 +922,13 @@ def err_ptrauth_value_bad_type :
   Error<"%select{signed value|extra discriminator|blended pointer|blended "
         "integer}0 must have %select{pointer|integer|pointer or integer}1 "
         "type; type here is %2">;
+def err_ptrauth_bad_constant_pointer :
+  Error<"argument to ptrauth_sign_constant must refer to a global variable "
+        "or function">;
+def err_ptrauth_bad_constant_discriminator :
+  Error<"discriminator argument to ptrauth_sign_constant must be a constant "
+        "integer, the address of the global variable where the result "
+        "will be stored, or a blend of the two">;
 def warn_ptrauth_sign_null_pointer :
   Warning<"signing a null pointer will yield a non-null pointer">,
   InGroup<PtrAuthNullPointers>;
diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h
index fda0855dc8683..8c62d8597ecbe 100644
--- a/clang/include/clang/CodeGen/CodeGenABITypes.h
+++ b/clang/include/clang/CodeGen/CodeGenABITypes.h
@@ -104,6 +104,12 @@ llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T);
 unsigned getLLVMFieldNumber(CodeGenModule &CGM,
                             const RecordDecl *RD, const FieldDecl *FD);
 
+/// Return a signed constant pointer.
+llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM,
+                                         llvm::Constant *pointer,
+                                         unsigned key,
+                                         llvm::Constant *storageAddress,
+                                         llvm::Constant *otherDiscriminator);
 /// Given the language and code-generation options that Clang was configured
 /// with, set the default LLVM IR attributes for a function definition.
 /// The attributes set here are mostly global target-configuration and
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index eafecfb5fe5b1..b1cb3c323074b 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2042,6 +2042,7 @@ static bool IsNoOpCall(const CallExpr *E) {
   unsigned Builtin = E->getBuiltinCallee();
   return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
           Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
+          Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
           Builtin == Builtin::BI__builtin_function_start);
 }
 
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a3c6510503324..b2e3b6fa64284 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -5273,6 +5273,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
   case Builtin::BI__iso_volatile_store64:
     return RValue::get(EmitISOVolatileStore(*this, E));
 
+  case Builtin::BI__builtin_ptrauth_sign_constant:
+    return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
+
   case Builtin::BI__builtin_ptrauth_auth:
   case Builtin::BI__builtin_ptrauth_auth_and_resign:
   case Builtin::BI__builtin_ptrauth_blend_discriminator:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 4eb65b34a89f5..de9380c0e63be 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1856,6 +1856,12 @@ class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
   ConstantLValue VisitMaterializeTemporaryExpr(
                                          const MaterializeTemporaryExpr *E);
 
+  ConstantLValue emitPointerAuthSignConstant(const CallExpr *E);
+  llvm::Constant *emitPointerAuthPointer(const Expr *E);
+  unsigned emitPointerAuthKey(const Expr *E);
+  std::pair<llvm::Constant*, llvm::Constant*>
+  emitPointerAuthDiscriminator(const Expr *E);
+
   bool hasNonZeroOffset() const {
     return !Value.getLValueOffset().isZero();
   }
@@ -2048,6 +2054,10 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
   if (builtin == Builtin::BI__builtin_function_start)
     return CGM.GetFunctionStart(
         E->getArg(0)->getAsBuiltinConstantDeclRef(CGM.getContext()));
+
+  if (builtin == Builtin::BI__builtin_ptrauth_sign_constant)
+    return emitPointerAuthSignConstant(E);
+
   if (builtin != Builtin::BI__builtin___CFStringMakeConstantString &&
       builtin != Builtin::BI__builtin___NSStringMakeConstantString)
     return nullptr;
@@ -2061,6 +2071,58 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
   }
 }
 
+ConstantLValue
+ConstantLValueEmitter::emitPointerAuthSignConstant(const CallExpr *E) {
+  auto unsignedPointer = emitPointerAuthPointer(E->getArg(0));
+  auto key = emitPointerAuthKey(E->getArg(1));
+  llvm::Constant *storageAddress;
+  llvm::Constant *otherDiscriminator;
+  std::tie(storageAddress, otherDiscriminator) =
+    emitPointerAuthDiscriminator(E->getArg(2));
+
+  auto signedPointer =
+    CGM.getConstantSignedPointer(unsignedPointer, key, storageAddress,
+                                 otherDiscriminator);
+  return signedPointer;
+}
+
+llvm::Constant *ConstantLValueEmitter::emitPointerAuthPointer(const Expr *E) {
+  Expr::EvalResult result;
+  bool succeeded = E->EvaluateAsRValue(result, CGM.getContext());
+  assert(succeeded); (void) succeeded;
+
+  // The assertions here are all checked by Sema.
+  assert(result.Val.isLValue());
+  return ConstantEmitter(CGM, Emitter.CGF)
+           .emitAbstract(E->getExprLoc(), result.Val, E->getType());
+}
+
+unsigned ConstantLValueEmitter::emitPointerAuthKey(const Expr *E) {
+  return E->EvaluateKnownConstInt(CGM.getContext()).getZExtValue();
+}
+
+std::pair<llvm::Constant*, llvm::Constant*>
+ConstantLValueEmitter::emitPointerAuthDiscriminator(const Expr *E) {
+  E = E->IgnoreParens();
+
+  if (auto call = dyn_cast<CallExpr>(E)) {
+    if (call->getBuiltinCallee() ==
+          Builtin::BI__builtin_ptrauth_blend_discriminator) {
+      auto pointer = ConstantEmitter(CGM).emitAbstract(call->getArg(0),
+                                            call->getArg(0)->getType());
+      auto extra = ConstantEmitter(CGM).emitAbstract(call->getArg(1),
+                                            call->getArg(1)->getType());
+      return { pointer, extra };
+    }
+  }
+
+  auto result = ConstantEmitter(CGM).emitAbstract(E, E->getType());
+  if (result->getType()->isPointerTy())
+    return { result, nullptr };
+  else
+    return { nullptr, result };
+}
+
 ConstantLValue
 ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *E) {
   StringRef functionName;
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
new file mode 100644
index 0000000000000..756c00aa42c8c
--- /dev/null
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -0,0 +1,77 @@
+//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains common routines relating to the emission of
+// pointer authentication operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGCXXABI.h"
+#include "CGCall.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/PointerAuthOptions.h"
+#include "clang/CodeGen/CodeGenABITypes.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/ValueMap.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include <vector>
+
+using namespace clang;
+using namespace CodeGen;
+
+/// Build a signed-pointer "ptrauth" constant.
+static llvm::ConstantPtrAuth *
+buildConstantAddress(CodeGenModule &CGM, llvm::Constant *pointer, unsigned key,
+                     llvm::Constant *storageAddress,
+                     llvm::Constant *otherDiscriminator) {
+  llvm::Constant *addressDiscriminator = nullptr;
+  if (storageAddress) {
+    addressDiscriminator = storageAddress;
+    assert(storageAddress->getType() == CGM.UnqualPtrTy);
+  } else {
+    addressDiscriminator = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
+  }
+
+  llvm::ConstantInt *integerDiscriminator = nullptr;
+  if (otherDiscriminator) {
+    assert(otherDiscriminator->getType() == CGM.Int64Ty);
+    integerDiscriminator = cast<llvm::ConstantInt>(otherDiscriminator);
+  } else {
+    integerDiscriminator = llvm::ConstantInt::get(CGM.Int64Ty, 0);
+  }
+
+  return llvm::ConstantPtrAuth::get(
+    pointer, llvm::ConstantInt::get(CGM.Int32Ty, key), integerDiscriminator,
+    addressDiscriminator);
+}
+
+llvm::Constant *
+CodeGenModule::getConstantSignedPointer(llvm::Constant *pointer,
+                                        unsigned key,
+                                        llvm::Constant *storageAddress,
+                                        llvm::Constant *otherDiscriminator) {
+  // Unique based on the underlying value, not a signing of it.
+  auto stripped = pointer->stripPointerCasts();
+
+  // Build the constant.
+  return buildConstantAddress(*this, stripped, key, storageAddress,
+                              otherDiscriminator);
+}
+
+llvm::Constant *
+CodeGen::getConstantSignedPointer(CodeGenModule &CGM,
+                                  llvm::Constant *pointer, unsigned key,
+                                  llvm::Constant *storageAddress,
+                                  llvm::Constant *otherDiscriminator) {
+  return CGM.getConstantSignedPointer(pointer, key, storageAddress,
+                                      otherDiscriminator);
+}
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 7a933d0ed0d0d..8dd9d8b54c25f 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -89,6 +89,7 @@ add_clang_library(clangCodeGen
   CGOpenCLRuntime.cpp
   CGOpenMPRuntime.cpp
   CGOpenMPRuntimeGPU.cpp
+  CGPointerAuth.cpp
   CGRecordLayoutBuilder.cpp
   CGStmt.cpp
   CGStmtOpenMP.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 0f68418130ead..194ac180171e0 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -938,6 +938,11 @@ class CodeGenModule : public CodeGenTypeCache {
   // Return the function body address of the given function.
   llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
 
+  llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
+                                           unsigned key,
+                                           llvm::Constant *storageAddress,
+                                           llvm::Constant *extraDiscrim);
+
   // Return whether RTTI information should be emitted for this target.
   bool shouldEmitRTTI(bool ForEH = false) {
     return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 3e58af1802084..069bd6ad03b03 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -78,12 +78,30 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
    On arm64e, the integer must fall within the range of a uint16_t;
    other bits may be ignored.
 
+   For the purposes of ptrauth_sign_constant, the result of calling
+   this function is considered a constant expression if the arguments
+   are constant.  Some restrictions may be imposed on the pointer.
+
    The first argument must be an expression of pointer type.
    The second argument must be an expression of integer type.
    The result will have type uintptr_t. */
 #define ptrauth_blend_discriminator(__pointer, __integer)                      \
   __builtin_ptrauth_blend_discriminator(__pointer, __integer)
 
+/* Add a signature to the given pointer value using a specific key,
+   using the given extra data as a salt to the signing process.
+
+   The value must be a constant expression of pointer type.
+   The key must be a constant expression of type ptrauth_key.
+   The extra data must be a constant expression of pointer or integer type;
+   if an integer, it will be coerced to ptrauth_extra_data_t.
+   The result will have the same type as the original value.
+
+   This is a constant expression if the extra data is an integer or
+   null pointer constant. */
+#define ptrauth_sign_constant(__value, __key, __data)                          \
+  __builtin_ptrauth_sign_constant(__value, __key, __data)
+
 /* Add a signature to the given pointer value using a specific key,
    using the given extra data as a salt to the signing process.
 
@@ -183,6 +201,13 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
     ((ptrauth_extra_data_t)0);                                                 \
   })
 
+#define ptrauth_sign_constant(__value, __key, __data)                          \
+  ({                                                                           \
+    (void)__key;                                                               \
+    (void)__data;                                                              \
+    __value;                                                                   \
+  })
+
 #define ptrauth_sign_unauthenticated(__value, __key, __data)                   \
   ({                                                                           \
     (void)__key;                                                               \
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f6012ef4b3601..52eba53cd2053 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2030,8 +2030,26 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
   return false;
 }
 
+static std::pair<const ValueDecl *, CharUnits>
+findConstantBaseAndOffset(Sema &S, Expr *E) {
+  // Must evaluate as a pointer.
+  Expr::EvalResult result;
+  if (!E->EvaluateAsRValue(result, S.Context) ||
+      !result.Val.isLValue())
+    return std::make_pair(nullptr, CharUnits());
+
+  // Base must be a declaration and can't be weakly imported.
+  auto baseDecl =
+    result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
+  if (!baseDecl || baseDecl->hasAttr<WeakRefAttr>())
+    return std::make_pair(nullptr, CharUnits());
+
+  return std::make_pair(baseDecl, result.Val.getLValueOffset());
+}
+
 static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
-                                  PointerAuthOpKind OpKind) {
+                                  PointerAuthOpKind OpKind,
+                                  bool RequireConstant = false) {
   if (Arg->hasPlaceholderType()) {
     ExprResult R = S.CheckPlaceholderExpr(Arg);
     if (R.isInvalid())
@@ -2074,16 +2092,91 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
   if (convertArgumentToType(S, Arg, ExpectedTy))
     return true;
 
-  // Warn about null pointers for non-generic sign and auth operations.
-  if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
-      Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
-    S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
-                                  ? diag::warn_ptrauth_sign_null_pointer
-                                  : diag::warn_ptrauth_auth_null_pointer)
-        << Arg->getSourceRange();
+  if (!RequireConstant) {
+    // Warn about null pointers for non-generic sign and auth operations.
+    if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
+        Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
+      S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
+                                    ? diag::warn_ptrauth_sign_null_pointer
+                                    : diag::warn_ptrauth_auth_null_pointer)
+          << Arg->getSourceRange();
+    }
+
+    return false;
   }
 
-  return false;
+  // Perform special checking on the arguments to ptrauth_sign_constant.
+
+  // The main argument.
+  if (OpKind == PAO_Sign) {
+    // Require the value we're signing to have a special form.
+    auto result = findConstantBaseAndOffset(S, Arg);
+    bool invalid;
+
+    // Must be rooted in a declaration reference.
+    if (!result.first) {
+      invalid = true;
+
+    // If it's a function declaration, we can't have an offset.
+    } else if (isa<FunctionDecl>(result.first)) {
+      invalid = !result.second.isZero();
+
+    // Otherwise we're fine.
+    } else {
+      invalid = false;
+    }
+
+    if (invalid) {
+      S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer);
+    }
+    return invalid;
+  }
+
+  // The discriminator argument.
+  assert(OpKind == PAO_Discriminator);
+
+  // Must be a pointer or integer or blend thereof.
+  Expr *pointer = nullptr;
+  Expr *integer = nullptr;
+  if (auto call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
+    if (call->getBuiltinCallee() ==
+          Builtin::BI__builtin_ptrauth_blend_discriminator) {
+      pointer = call->getArg(0);
+      integer = call->getArg(1);
+    }
+  }
+  if (!pointer && !integer) {
+    if (Arg->getType()->isPointerType())
+      pointer = Arg;
+    else
+      integer = Arg;
+  }
+
+  // Check the pointer.
+  bool invalid = false;
+  if (pointer) {
+    assert(pointer->getType()->isPointerType());
+
+    // TODO: if we're initializing a global, check that the address is
+    // somehow related to what we're initializing.  This probably will
+    // never really be feasible and we'll have to catch it at link-time.
+    auto result = findConstantBaseAndOffset(S, pointer);
+    if (!result.first || !isa<VarDecl>(result.first)) {
+      invalid = true;
+    }
+  }
+
+  // Check the integer.
+  if (integer) {
+    assert(integer->getType()->isIntegerType());
+    if (!integer->isEvaluatable(S.Context))
+      invalid = true;
+  }
+
+  if (invalid) {
+    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator);
+  }
+  return invalid;
 }
 
 static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) {
@@ -2126,14 +2219,16 @@ static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) {
 }
 
 static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call,
-                                        PointerAuthOpKind OpKind) {
+                                        PointerAuthOpKind OpKind,
+                                        bool RequireConstant) {
   if (S.checkArgCount(Call, 3))
     return ExprError();
   if (checkPointerAuthEnabled(S, Call))
     return ExprError();
-  if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind) ||
+  if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind, RequireConstant) ||
       checkPointerAuthKey(S, Call->getArgs()[1]) ||
-      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator))
+      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator,
+                            RequireConstant))
     return ExprError();
 
   Call->setType(Call->getArgs()[0]->getType());
@@ -2932,10 +3027,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     return PointerAuthStrip(*this, TheCall);
   case Builtin::BI__builtin_ptrauth_blend_discriminator:
     return PointerAuthBlendDiscriminator(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_sign_constant:
+    return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
+                                 /*constant*/ true);
   case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
-    return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign);
+    return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
+                                 /*constant*/ false);
   case Builtin::BI__builtin_ptrauth_auth:
-    return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth);
+    return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth,
+                                 /*constant*/ false);
   case Builtin::BI__builtin_ptrauth_sign_generic_data:
     return PointerAuthSignGenericData(*this, TheCall);
   case Builtin::BI__builtin_ptrauth_auth_and_resign:
diff --git a/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c b/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
new file mode 100644
index 0000000000000..3915834812990
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
+
+extern int external;
+
+// CHECK: @ptr1 = global ptr ptrauth (ptr @external, i32 0, i64 26)
+void *ptr1 = __builtin_ptrauth_sign_constant(&external, 0, 26);
+
+// CHECK: @ptr2 = global ptr ptrauth (ptr @external, i32 2, i64 26, ptr @ptr2)
+void *ptr2 = __builtin_ptrauth_sign_constant(&external, 2, __builtin_ptrauth_blend_discriminator(&ptr2, 26));
+
+// CHECK: @ptr3 = global ptr null
+void *ptr3;
+
+void test_sign_constant_code() {
+// CHECK-LABEL: define void @test_sign_constant_code()
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    store ptr ptrauth (ptr @external, i32 2, i64 1234), ptr @ptr3, align 8
+// CHECK-NEXT:    ret void
+  ptr3 = __builtin_ptrauth_sign_constant(&external, 2, 1234);
+}
diff --git a/clang/test/Sema/ptrauth-intrinsics-macro.c b/clang/test/Sema/ptrauth-intrinsics-macro.c
index 540f2846b7ce1..f76f677315dd3 100644
--- a/clang/test/Sema/ptrauth-intrinsics-macro.c
+++ b/clang/test/Sema/ptrauth-intrinsics-macro.c
@@ -37,3 +37,7 @@ void test_string_discriminator(int *dp) {
   ptrauth_extra_data_t t0 = ptrauth_string_discriminator("string");
   (void)t0;
 }
+
+void test_sign_constant(int *dp) {
+  dp = ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
+}
diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c
index 3ad3d70c24e41..06ce1a4193691 100644
--- a/clang/test/Sema/ptrauth.c
+++ b/clang/test/Sema/ptrauth.c
@@ -47,6 +47,35 @@ void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
   float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-error {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
 }
 
+void test_sign_constant(int *dp, int (*fp)(int)) {
+  __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY); // expected-error {{too few arguments}}
+  __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &dv, &dv); // expected-error {{too many arguments}}
+
+  __builtin_ptrauth_sign_constant(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+  __builtin_ptrauth_sign_constant(&dv, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+  __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+
+  (void) __builtin_ptrauth_sign_constant(NULL, VALID_DATA_KEY, &dv); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
+
+  int *dr = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
+  dr = __builtin_ptrauth_sign_constant(&dv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  dr = __builtin_ptrauth_sign_constant(dp, VALID_DATA_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
+  dr = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, dp); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
+
+  int (*fr)(int) = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, 0);
+  fr = __builtin_ptrauth_sign_constant(&fv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  fr = __builtin_ptrauth_sign_constant(fp, VALID_DATA_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
+  fr = __builtin_ptrauth_sign_constant(&fv, VALID_DATA_KEY, dp); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
+
+  fr = __builtin_ptrauth_sign_constant(&fv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&fr, 0)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
+  fr = __builtin_ptrauth_sign_constant(&fv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv, *dp)); // expected-error {{discriminator argument to ptrauth_sign_constant must be a constant integer, the address of the global variable where the result will be stored, or a blend of the two}}
+  fr = __builtin_ptrauth_sign_constant(&fv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
+
+  float *mismatch = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+}
+
 void test_sign_unauthenticated(int *dp, int (*fp)(int)) {
   __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
   __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}

>From 0e85001f6d53e63beca77a76eaba1875ec84000d Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Fri, 24 May 2024 20:23:36 -0700
Subject: [PATCH 05/14] [clang] Implement function pointer signing.

Co-Authored-By: John McCall <rjmccall at apple.com>
---
 clang/include/clang/Basic/CodeGenOptions.h    |   4 +
 .../clang/Basic/DiagnosticDriverKinds.td      |   3 +
 clang/include/clang/Basic/LangOptions.h       |   2 +
 .../include/clang/Basic/PointerAuthOptions.h  | 136 ++++++++++++++++++
 .../clang/Frontend/CompilerInvocation.h       |  10 ++
 clang/lib/CodeGen/CGBuiltin.cpp               |   3 +-
 clang/lib/CodeGen/CGCall.cpp                  |   3 +
 clang/lib/CodeGen/CGCall.h                    |  28 +++-
 clang/lib/CodeGen/CGExpr.cpp                  |  17 +--
 clang/lib/CodeGen/CGExprConstant.cpp          |  19 ++-
 clang/lib/CodeGen/CGPointerAuth.cpp           |  51 +++++++
 clang/lib/CodeGen/CGPointerAuthInfo.h         |  96 +++++++++++++
 clang/lib/CodeGen/CodeGenFunction.cpp         |  58 ++++++++
 clang/lib/CodeGen/CodeGenFunction.h           |  10 ++
 clang/lib/CodeGen/CodeGenModule.h             |  34 +++++
 clang/lib/Frontend/CompilerInvocation.cpp     |  36 +++++
 clang/lib/Headers/ptrauth.h                   |  34 +++++
 .../CodeGen/ptrauth-function-attributes.c     |  13 ++
 .../test/CodeGen/ptrauth-function-init-fail.c |   5 +
 clang/test/CodeGen/ptrauth-function-init.c    |  31 ++++
 .../CodeGen/ptrauth-function-lvalue-cast.c    |  23 +++
 clang/test/CodeGen/ptrauth-weak_import.c      |  10 ++
 clang/test/CodeGenCXX/ptrauth.cpp             |  24 ++++
 23 files changed, 633 insertions(+), 17 deletions(-)
 create mode 100644 clang/lib/CodeGen/CGPointerAuthInfo.h
 create mode 100644 clang/test/CodeGen/ptrauth-function-attributes.c
 create mode 100644 clang/test/CodeGen/ptrauth-function-init-fail.c
 create mode 100644 clang/test/CodeGen/ptrauth-function-init.c
 create mode 100644 clang/test/CodeGen/ptrauth-function-lvalue-cast.c
 create mode 100644 clang/test/CodeGen/ptrauth-weak_import.c
 create mode 100644 clang/test/CodeGenCXX/ptrauth.cpp

diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 9469a424045bb..502722a6ec4eb 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_BASIC_CODEGENOPTIONS_H
 #define LLVM_CLANG_BASIC_CODEGENOPTIONS_H
 
+#include "clang/Basic/PointerAuthOptions.h"
 #include "clang/Basic/Sanitizers.h"
 #include "clang/Basic/XRayInstr.h"
 #include "llvm/ADT/FloatingPointMode.h"
@@ -388,6 +389,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
 
   std::vector<std::string> Reciprocals;
 
+  /// Configuration for pointer-signing.
+  PointerAuthOptions PointerAuth;
+
   /// The preferred width for auto-vectorization transforms. This is intended to
   /// override default transforms based on the width of the architected vector
   /// registers.
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 773b234cd68fe..6cbb0c8401c15 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -351,6 +351,9 @@ def err_drv_omp_host_ir_file_not_found : Error<
   "target regions but cannot be found">;
 def err_drv_omp_host_target_not_supported : Error<
   "target '%0' is not a supported OpenMP host target">;
+def err_drv_ptrauth_not_supported : Error<
+  "target '%0' does not support native pointer authentication">;
+
 def err_drv_expecting_fopenmp_with_fopenmp_targets : Error<
   "'-fopenmp-targets' must be used in conjunction with a '-fopenmp' option "
   "compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">;
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 75e88afbd9705..5216822e45b1b 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -346,6 +346,8 @@ class LangOptionsBase {
     BKey
   };
 
+  using PointerAuthenticationMode = ::clang::PointerAuthenticationMode;
+
   enum class ThreadModelKind {
     /// POSIX Threads.
     POSIX,
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
index e5cdcc31ebfb7..32b179e3f9460 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -14,10 +14,146 @@
 #ifndef LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
 #define LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
 
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Target/TargetOptions.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
 namespace clang {
 
 constexpr unsigned PointerAuthKeyNone = -1;
 
+class PointerAuthSchema {
+public:
+  enum class Kind : unsigned {
+    None,
+    ARM8_3,
+  };
+
+  /// Hardware pointer-signing keys in ARM8.3.
+  ///
+  /// These values are the same used in ptrauth.h.
+  enum class ARM8_3Key : unsigned {
+    ASIA = 0,
+    ASIB = 1,
+    ASDA = 2,
+    ASDB = 3
+  };
+
+  /// Forms of extra discrimination.
+  enum class Discrimination : unsigned {
+    /// No additional discrimination.
+    None,
+
+    /// Discriminate using a constant value.
+    Constant,
+  };
+
+private:
+  Kind TheKind : 2;
+  unsigned IsAddressDiscriminated : 1;
+  unsigned IsIsaPointer : 1;
+  unsigned AuthenticatesNullValues : 1;
+  PointerAuthenticationMode SelectedAuthenticationMode : 2;
+  Discrimination DiscriminationKind : 2;
+  unsigned Key : 4;
+  unsigned ConstantDiscriminator : 16;
+
+public:
+  PointerAuthSchema() : TheKind(Kind::None) {}
+
+  PointerAuthSchema(
+      ARM8_3Key Key, bool IsAddressDiscriminated,
+      PointerAuthenticationMode AuthenticationMode,
+      Discrimination OtherDiscrimination,
+      std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt,
+      bool IsIsaPointer = false, bool AuthenticatesNullValues = false)
+      : TheKind(Kind::ARM8_3), IsAddressDiscriminated(IsAddressDiscriminated),
+        IsIsaPointer(IsIsaPointer),
+        AuthenticatesNullValues(AuthenticatesNullValues),
+        SelectedAuthenticationMode(AuthenticationMode),
+        DiscriminationKind(OtherDiscrimination), Key(unsigned(Key)) {
+    assert((getOtherDiscrimination() != Discrimination::Constant ||
+            ConstantDiscriminatorOrNone) &&
+           "constant discrimination requires a constant!");
+    if (ConstantDiscriminatorOrNone)
+      ConstantDiscriminator = *ConstantDiscriminatorOrNone;
+  }
+
+  PointerAuthSchema(
+      ARM8_3Key Key, bool IsAddressDiscriminated,
+      Discrimination OtherDiscrimination,
+      std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt,
+      bool IsIsaPointer = false, bool AuthenticatesNullValues = false)
+      : PointerAuthSchema(Key, IsAddressDiscriminated,
+                          PointerAuthenticationMode::SignAndAuth,
+                          OtherDiscrimination, ConstantDiscriminatorOrNone,
+                          IsIsaPointer, AuthenticatesNullValues) {}
+
+  Kind getKind() const { return TheKind; }
+
+  explicit operator bool() const { return isEnabled(); }
+
+  bool isEnabled() const { return getKind() != Kind::None; }
+
+  bool isAddressDiscriminated() const {
+    assert(getKind() != Kind::None);
+    return IsAddressDiscriminated;
+  }
+
+  bool isIsaPointer() const {
+    assert(getKind() != Kind::None);
+    return IsIsaPointer;
+  }
+
+  bool authenticatesNullValues() const {
+    assert(getKind() != Kind::None);
+    return AuthenticatesNullValues;
+  }
+
+  bool hasOtherDiscrimination() const {
+    return getOtherDiscrimination() != Discrimination::None;
+  }
+
+  Discrimination getOtherDiscrimination() const {
+    assert(getKind() != Kind::None);
+    return DiscriminationKind;
+  }
+
+  uint16_t getConstantDiscrimination() const {
+    assert(getOtherDiscrimination() == Discrimination::Constant);
+    return (uint16_t)ConstantDiscriminator;
+  }
+
+  unsigned getKey() const {
+    switch (getKind()) {
+    case Kind::None:
+      llvm_unreachable("calling getKey() on disabled schema");
+    case Kind::ARM8_3:
+      return unsigned(getARM8_3Key());
+    }
+    llvm_unreachable("bad key kind");
+  }
+
+  PointerAuthenticationMode getAuthenticationMode() const {
+    return SelectedAuthenticationMode;
+  }
+
+  ARM8_3Key getARM8_3Key() const {
+    assert(getKind() == Kind::ARM8_3);
+    return ARM8_3Key(Key);
+  }
+};
+
+struct PointerAuthOptions {
+  /// The ABI for C function pointers.
+  PointerAuthSchema FunctionPointers;
+};
+
 } // end namespace clang
 
 #endif
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 1a2a39411e58d..e60e5aad6c70d 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -305,6 +305,16 @@ class CompilerInvocation : public CompilerInvocationBase {
   /// executable), for finding the builtin compiler path.
   static std::string GetResourcesPath(const char *Argv0, void *MainAddr);
 
+  /// Populate \p Opts with the default set of pointer authentication-related
+  /// options given \p LangOpts and \p Triple. Return true if defaults are
+  /// available.
+  ///
+  /// Note: This is intended to be used by tools which must be aware of
+  /// pointer authentication-related code generation, e.g. lldb.
+  static bool setDefaultPointerAuthOptions(PointerAuthOptions &Opts,
+                                           const LangOptions &LangOpts,
+                                           const llvm::Triple &Triple);
+
   /// Retrieve a module hash string that is suitable for uniquely
   /// identifying the conditions under which the module was built.
   std::string getModuleHash() const;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index b2e3b6fa64284..1f528f9490cd2 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -5999,8 +5999,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
   // If this is a predefined lib function (e.g. malloc), emit the call
   // using exactly the normal call path.
   if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
-    return emitLibraryCall(
-        *this, FD, E, cast<llvm::Constant>(EmitScalarExpr(E->getCallee())));
+    return emitLibraryCall(*this, FD, E, CGM.getRawFunctionPointer(FD));
 
   // Check that a call to a target specific builtin has the correct target
   // features.
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 97449a5e51e73..c33f37bf5b8c4 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5677,6 +5677,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
       !isa_and_nonnull<FunctionDecl>(TargetDecl))
     EmitKCFIOperandBundle(ConcreteCallee, BundleList);
 
+  // Add the pointer-authentication bundle.
+  EmitPointerAuthOperandBundle(ConcreteCallee.getPointerAuthInfo(), BundleList);
+
   if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
     if (FD->hasAttr<StrictFPAttr>())
       // All calls within a strictfp function are marked strictfp
diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h
index 6b676ac196db2..4b0e1561b4ef5 100644
--- a/clang/lib/CodeGen/CGCall.h
+++ b/clang/lib/CodeGen/CGCall.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H
 #define LLVM_CLANG_LIB_CODEGEN_CGCALL_H
 
+#include "CGPointerAuthInfo.h"
 #include "CGValue.h"
 #include "EHScopeStack.h"
 #include "clang/AST/ASTFwd.h"
@@ -69,6 +70,10 @@ class CGCallee {
     Last = Virtual
   };
 
+  struct OrdinaryInfoStorage {
+    CGCalleeInfo AbstractInfo;
+    CGPointerAuthInfo PointerAuthInfo;
+  };
   struct BuiltinInfoStorage {
     const FunctionDecl *Decl;
     unsigned ID;
@@ -85,7 +90,7 @@ class CGCallee {
 
   SpecialKind KindOrFunctionPointer;
   union {
-    CGCalleeInfo AbstractInfo;
+    OrdinaryInfoStorage OrdinaryInfo;
     BuiltinInfoStorage BuiltinInfo;
     PseudoDestructorInfoStorage PseudoDestructorInfo;
     VirtualInfoStorage VirtualInfo;
@@ -104,10 +109,13 @@ class CGCallee {
 
   /// Construct a callee.  Call this constructor directly when this
   /// isn't a direct call.
-  CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr)
+  CGCallee(
+      const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr,
+      const CGPointerAuthInfo &pointerAuthInfo = /*FIXME*/ CGPointerAuthInfo())
       : KindOrFunctionPointer(
             SpecialKind(reinterpret_cast<uintptr_t>(functionPtr))) {
-    AbstractInfo = abstractInfo;
+    OrdinaryInfo.AbstractInfo = abstractInfo;
+    OrdinaryInfo.PointerAuthInfo = pointerAuthInfo;
     assert(functionPtr && "configuring callee without function pointer");
     assert(functionPtr->getType()->isPointerTy());
   }
@@ -128,12 +136,12 @@ class CGCallee {
 
   static CGCallee forDirect(llvm::Constant *functionPtr,
                             const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
-    return CGCallee(abstractInfo, functionPtr);
+    return CGCallee(abstractInfo, functionPtr, CGPointerAuthInfo());
   }
 
   static CGCallee forDirect(llvm::FunctionCallee functionPtr,
                             const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
-    return CGCallee(abstractInfo, functionPtr.getCallee());
+    return CGCallee(abstractInfo, functionPtr.getCallee(), CGPointerAuthInfo());
   }
 
   static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr,
@@ -173,7 +181,11 @@ class CGCallee {
     if (isVirtual())
       return VirtualInfo.MD;
     assert(isOrdinary());
-    return AbstractInfo;
+    return OrdinaryInfo.AbstractInfo;
+  }
+  const CGPointerAuthInfo &getPointerAuthInfo() const {
+    assert(isOrdinary());
+    return OrdinaryInfo.PointerAuthInfo;
   }
   llvm::Value *getFunctionPointer() const {
     assert(isOrdinary());
@@ -184,6 +196,10 @@ class CGCallee {
     KindOrFunctionPointer =
         SpecialKind(reinterpret_cast<uintptr_t>(functionPtr));
   }
+  void setPointerAuthInfo(CGPointerAuthInfo pointerAuth) {
+    assert(isOrdinary());
+    OrdinaryInfo.PointerAuthInfo = pointerAuth;
+  }
 
   bool isVirtual() const {
     return KindOrFunctionPointer == SpecialKind::Virtual;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index d6478cc6835d8..152f51f5865e0 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2850,22 +2850,22 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
   return LV;
 }
 
-static llvm::Constant *EmitFunctionDeclPointer(CodeGenModule &CGM,
-                                               GlobalDecl GD) {
+llvm::Constant *CodeGenModule::getRawFunctionPointer(GlobalDecl GD,
+                                                     llvm::Type *Ty) {
   const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
   if (FD->hasAttr<WeakRefAttr>()) {
-    ConstantAddress aliasee = CGM.GetWeakRefReference(FD);
+    ConstantAddress aliasee = GetWeakRefReference(FD);
     return aliasee.getPointer();
   }
 
-  llvm::Constant *V = CGM.GetAddrOfFunction(GD);
+  llvm::Constant *V = GetAddrOfFunction(GD, Ty);
   return V;
 }
 
 static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, const Expr *E,
                                      GlobalDecl GD) {
   const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-  llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, GD);
+  llvm::Constant *V = CGF.CGM.getFunctionPointer(GD);
   CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
   return CGF.MakeAddrLValue(V, E->getType(), Alignment,
                             AlignmentSource::Decl);
@@ -5501,7 +5501,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
     // name to make it clear it's not the actual builtin.
     if (CGF.CurFn->getName() != FDInlineName &&
         OnlyHasInlineBuiltinDeclaration(FD)) {
-      llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
+      llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
       llvm::Function *Fn = llvm::cast<llvm::Function>(CalleePtr);
       llvm::Module *M = Fn->getParent();
       llvm::Function *Clone = M->getFunction(FDInlineName);
@@ -5524,7 +5524,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
       return CGCallee::forBuiltin(builtinID, FD);
   }
 
-  llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
+  llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
   if (CGF.CGM.getLangOpts().CUDA && !CGF.CGM.getLangOpts().CUDAIsDevice &&
       FD->hasAttr<CUDAGlobalAttr>())
     CalleePtr = CGF.CGM.getCUDARuntime().getKernelStub(
@@ -5581,7 +5581,8 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) {
     GD = GlobalDecl(VD);
 
   CGCalleeInfo calleeInfo(functionType->getAs<FunctionProtoType>(), GD);
-  CGCallee callee(calleeInfo, calleePtr);
+  CGPointerAuthInfo pointerAuth = CGM.getFunctionPointerAuthInfo(functionType);
+  CGCallee callee(calleeInfo, calleePtr, pointerAuth);
   return callee;
 }
 
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index de9380c0e63be..bfb545a2fe1f6 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1956,8 +1956,25 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
     if (D->hasAttr<WeakRefAttr>())
       return CGM.GetWeakRefReference(D).getPointer();
 
+    auto PtrAuthSign = [&](llvm::Constant *C) {
+      CGPointerAuthInfo AuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
+
+      if (AuthInfo) {
+        if (hasNonZeroOffset())
+          return ConstantLValue(nullptr);
+
+        C = applyOffset(C);
+        C = CGM.getConstantSignedPointer(
+            C, AuthInfo.getKey(), nullptr,
+            cast_or_null<llvm::Constant>(AuthInfo.getDiscriminator()));
+        return ConstantLValue(C, /*applied offset*/ true);
+      }
+
+      return ConstantLValue(C);
+    };
+
     if (auto FD = dyn_cast<FunctionDecl>(D))
-      return CGM.GetAddrOfFunction(FD);
+      return PtrAuthSign(CGM.getRawFunctionPointer(FD));
 
     if (auto VD = dyn_cast<VarDecl>(D)) {
       // We can never refer to a variable with local storage.
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index 756c00aa42c8c..adfa721ac89d3 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -28,6 +28,24 @@
 using namespace clang;
 using namespace CodeGen;
 
+/// Return the abstract pointer authentication schema for a pointer to the given
+/// function type.
+CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {
+  auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;
+  if (!Schema)
+    return CGPointerAuthInfo();
+
+  assert(!Schema.isAddressDiscriminated() &&
+         "function pointers cannot use address-specific discrimination");
+
+  assert(!Schema.hasOtherDiscrimination() &&
+         "function pointers don't support any discrimination yet");
+
+  return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
+                           /*IsaPointer=*/false, /*AuthenticatesNull=*/false,
+                           /*Discriminator=*/nullptr);
+}
+
 /// Build a signed-pointer "ptrauth" constant.
 static llvm::ConstantPtrAuth *
 buildConstantAddress(CodeGenModule &CGM, llvm::Constant *pointer, unsigned key,
@@ -75,3 +93,36 @@ CodeGen::getConstantSignedPointer(CodeGenModule &CGM,
   return CGM.getConstantSignedPointer(pointer, key, storageAddress,
                                       otherDiscriminator);
 }
+
+/// If applicable, sign a given constant function pointer with the ABI rules for
+/// functionType.
+llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *pointer,
+                                                  QualType functionType,
+                                                  GlobalDecl GD) {
+  assert(functionType->isFunctionType() ||
+         functionType->isFunctionReferenceType() ||
+         functionType->isFunctionPointerType());
+
+  if (auto pointerAuth = getFunctionPointerAuthInfo(functionType)) {
+    return getConstantSignedPointer(
+      pointer, pointerAuth.getKey(), nullptr,
+      cast_or_null<llvm::Constant>(pointerAuth.getDiscriminator()));
+  }
+
+  return pointer;
+}
+
+llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
+                                                  llvm::Type *Ty) {
+  const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
+  // Annoyingly, K&R functions have prototypes in the clang AST, but
+  // expressions referring to them are unprototyped.
+  QualType FuncType = FD->getType();
+  if (!FD->hasPrototype())
+    if (const auto *Proto = FuncType->getAs<FunctionProtoType>())
+      FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(),
+                                                Proto->getExtInfo());
+
+  return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType, GD);
+}
diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h
new file mode 100644
index 0000000000000..e870c3145acba
--- /dev/null
+++ b/clang/lib/CodeGen/CGPointerAuthInfo.h
@@ -0,0 +1,96 @@
+//===----- CGPointerAuthInfo.h -  -------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Pointer auth info class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGPOINTERAUTHINFO_H
+#define LLVM_CLANG_LIB_CODEGEN_CGPOINTERAUTHINFO_H
+
+#include "clang/AST/Type.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+
+namespace clang {
+namespace CodeGen {
+
+class CGPointerAuthInfo {
+private:
+  PointerAuthenticationMode AuthenticationMode : 2;
+  bool IsIsaPointer : 1;
+  bool AuthenticatesNullValues : 1;
+  unsigned Key : 28;
+  llvm::Value *Discriminator;
+
+public:
+  CGPointerAuthInfo()
+      : AuthenticationMode(PointerAuthenticationMode::None),
+        IsIsaPointer(false), AuthenticatesNullValues(false), Key(0),
+        Discriminator(nullptr) {}
+  CGPointerAuthInfo(unsigned Key, PointerAuthenticationMode AuthenticationMode,
+                    bool IsIsaPointer, bool AuthenticatesNullValues,
+                    llvm::Value *Discriminator)
+      : AuthenticationMode(AuthenticationMode), IsIsaPointer(IsIsaPointer),
+        AuthenticatesNullValues(AuthenticatesNullValues), Key(Key),
+        Discriminator(Discriminator) {
+    assert(!Discriminator || Discriminator->getType()->isIntegerTy() ||
+           Discriminator->getType()->isPointerTy());
+  }
+
+  explicit operator bool() const { return isSigned(); }
+
+  bool isSigned() const {
+    return AuthenticationMode != PointerAuthenticationMode::None;
+  }
+
+  unsigned getKey() const {
+    assert(isSigned());
+    return Key;
+  }
+  llvm::Value *getDiscriminator() const {
+    assert(isSigned());
+    return Discriminator;
+  }
+
+  PointerAuthenticationMode getAuthenticationMode() const {
+    return AuthenticationMode;
+  }
+
+  bool isIsaPointer() const { return IsIsaPointer; }
+
+  bool authenticatesNullValues() const { return AuthenticatesNullValues; }
+
+  bool shouldStrip() const {
+    return AuthenticationMode == PointerAuthenticationMode::Strip ||
+           AuthenticationMode == PointerAuthenticationMode::SignAndStrip;
+  }
+
+  bool shouldSign() const {
+    return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
+           AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
+  }
+
+  bool shouldAuth() const {
+    return AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
+  }
+
+  bool operator!=(const CGPointerAuthInfo &Other) const {
+    return Key != Other.Key || Discriminator != Other.Discriminator ||
+           AuthenticationMode != Other.AuthenticationMode;
+  }
+
+  bool operator==(const CGPointerAuthInfo &Other) const {
+    return !(*this != Other);
+  }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index f0345f3b191b8..cb5acf1a1abb7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -859,6 +859,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
         FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass)
       SanOpts.Mask &= ~SanitizerKind::Null;
 
+  // Add pointer authentication attributes.
+  const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
+  if (CodeGenOpts.PointerAuth.FunctionPointers)
+    Fn->addFnAttr("ptrauth-calls");
+
   // Apply xray attributes to the function (as a string, for now)
   bool AlwaysXRayAttr = false;
   if (const auto *XRayAttr = D ? D->getAttr<XRayInstrumentAttr>() : nullptr) {
@@ -3041,3 +3046,56 @@ llvm::Value *CodeGenFunction::emitBoolVecConversion(llvm::Value *SrcVec,
 
   return Builder.CreateShuffleVector(SrcVec, ShuffleMask, Name);
 }
+
+void CodeGenFunction::EmitPointerAuthOperandBundle(
+    const CGPointerAuthInfo &pointerAuth,
+    SmallVectorImpl<llvm::OperandBundleDef> &bundles) {
+  if (!pointerAuth.isSigned())
+    return;
+
+  auto key = Builder.getInt32(pointerAuth.getKey());
+
+  llvm::Value *discriminator = pointerAuth.getDiscriminator();
+  if (!discriminator) {
+    discriminator = Builder.getSize(0);
+  }
+
+  llvm::Value *args[] = {key, discriminator};
+  bundles.emplace_back("ptrauth", args);
+}
+
+static llvm::Value *EmitPointerAuthCommon(CodeGenFunction &CGF,
+                                          const CGPointerAuthInfo &pointerAuth,
+                                          llvm::Value *pointer,
+                                          unsigned intrinsicID) {
+  if (!pointerAuth)
+    return pointer;
+
+  auto key = CGF.Builder.getInt32(pointerAuth.getKey());
+
+  llvm::Value *discriminator = pointerAuth.getDiscriminator();
+  if (!discriminator) {
+    discriminator = CGF.Builder.getSize(0);
+  }
+
+  // Convert the pointer to intptr_t before signing it.
+  auto origType = pointer->getType();
+  pointer = CGF.Builder.CreatePtrToInt(pointer, CGF.IntPtrTy);
+
+  // call i64 @llvm.ptrauth.sign.i64(i64 %pointer, i32 %key, i64 %discriminator)
+  auto intrinsic = CGF.CGM.getIntrinsic(intrinsicID);
+  pointer = CGF.EmitRuntimeCall(intrinsic, {pointer, key, discriminator});
+
+  // Convert back to the original type.
+  pointer = CGF.Builder.CreateIntToPtr(pointer, origType);
+  return pointer;
+}
+
+llvm::Value *
+CodeGenFunction::EmitPointerAuthSign(const CGPointerAuthInfo &pointerAuth,
+                                     llvm::Value *pointer) {
+  if (!pointerAuth.shouldSign())
+    return pointer;
+  return EmitPointerAuthCommon(*this, pointerAuth, pointer,
+                               llvm::Intrinsic::ptrauth_sign);
+}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 45585361a4fc9..a0518b7525df1 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4406,6 +4406,16 @@ class CodeGenFunction : public CodeGenTypeCache {
   }
 
   bool isPointerKnownNonNull(const Expr *E);
+  CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &schema,
+                                        llvm::Value *storageAddress,
+                                        GlobalDecl calleeDecl,
+                                        QualType calleeType);
+  llvm::Value *EmitPointerAuthSign(QualType pointeeType, llvm::Value *pointer);
+  llvm::Value *EmitPointerAuthSign(const CGPointerAuthInfo &info,
+                                   llvm::Value *pointer);
+  void EmitPointerAuthOperandBundle(
+      const CGPointerAuthInfo &info,
+      SmallVectorImpl<llvm::OperandBundleDef> &bundles);
 
   // Return the copy constructor name with the prefix "__copy_constructor_"
   // removed.
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 194ac180171e0..5e30c5740b2f1 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -26,6 +26,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/Module.h"
 #include "clang/Basic/NoSanitizeList.h"
+#include "clang/Basic/PointerAuthOptions.h"
 #include "clang/Basic/ProfileList.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/XRayLists.h"
@@ -70,6 +71,7 @@ class Expr;
 class Stmt;
 class StringLiteral;
 class NamedDecl;
+class PointerAuthSchema;
 class ValueDecl;
 class VarDecl;
 class LangOptions;
@@ -938,11 +940,43 @@ class CodeGenModule : public CodeGenTypeCache {
   // Return the function body address of the given function.
   llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
 
+  /// Return a function pointer for a reference to the given function.
+  /// This correctly handles weak references, but does not apply a
+  /// pointer signature.
+  llvm::Constant *getRawFunctionPointer(GlobalDecl GD,
+                                        llvm::Type *Ty = nullptr);
+
+  /// Return the ABI-correct function pointer value for a reference
+  /// to the given function.  This will apply a pointer signature if
+  /// necessary, caching the result for the given function.
+  llvm::Constant *getFunctionPointer(GlobalDecl GD, llvm::Type *Ty = nullptr);
+
+  /// Return the ABI-correct function pointer value for a reference
+  /// to the given function.  This will apply a pointer signature if
+  /// necessary, but will only cache the result if \p FD is passed.
+  llvm::Constant *getFunctionPointer(llvm::Constant *pointer,
+                                     QualType functionType,
+                                     GlobalDecl GD = GlobalDecl());
+
+  CGPointerAuthInfo getFunctionPointerAuthInfo(QualType functionType);
+
+  CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type);
+
+  CGPointerAuthInfo getPointerAuthInfoForType(QualType type);
+
+  llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
+                                           const PointerAuthSchema &schema,
+                                           llvm::Constant *storageAddress,
+                                           GlobalDecl schemaDecl,
+                                           QualType schemaType);
+
   llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
                                            unsigned key,
                                            llvm::Constant *storageAddress,
                                            llvm::Constant *extraDiscrim);
 
+  CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD);
+
   // Return whether RTTI information should be emitted for this target.
   bool shouldEmitRTTI(bool ForEH = false) {
     return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 14ee02c4cd582..b4ca3e413b2c0 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1458,6 +1458,39 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts,
     Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
 }
 
+bool CompilerInvocation::setDefaultPointerAuthOptions(
+    PointerAuthOptions &Opts, const LangOptions &LangOpts,
+    const llvm::Triple &Triple) {
+  if (Triple.getArch() == llvm::Triple::aarch64) {
+    if (LangOpts.PointerAuthCalls) {
+      using Key = PointerAuthSchema::ARM8_3Key;
+      using Discrimination = PointerAuthSchema::Discrimination;
+      // If you change anything here, be sure to update <ptrauth.h>.
+      Opts.FunctionPointers =
+          PointerAuthSchema(Key::ASIA, false, Discrimination::None);
+    }
+    return true;
+  }
+
+  return false;
+}
+
+static bool parsePointerAuthOptions(PointerAuthOptions &Opts,
+                                    ArgList &Args,
+                                    const LangOptions &LangOpts,
+                                    const llvm::Triple &Triple,
+                                    DiagnosticsEngine &Diags) {
+  if (!LangOpts.PointerAuthCalls)
+    return true;
+
+  if (CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple))
+    return true;
+
+  Diags.Report(diag::err_drv_ptrauth_not_supported)
+    << Triple.str();
+  return false;
+}
+
 void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
                                                  ArgumentConsumer Consumer,
                                                  const llvm::Triple &T,
@@ -2153,6 +2186,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
 
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
+  if (!LangOpts->CUDAIsDevice)
+    parsePointerAuthOptions(Opts.PointerAuth, Args, *LangOpts, T, Diags);
+
   if (Args.hasArg(options::OPT_ffinite_loops))
     Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always;
   else if (Args.hasArg(options::OPT_fno_finite_loops))
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 069bd6ad03b03..aec387153d87c 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -38,6 +38,12 @@ typedef enum {
   ptrauth_key_process_dependent_data = ptrauth_key_asdb,
 #endif /* __APPLE__ */
 
+  /* The key used to sign C function pointers.
+     The extra data is always 0. */
+  ptrauth_key_function_pointer = ptrauth_key_process_independent_code,
+
+  /* Other pointers signed under the ABI use private ABI rules. */
+
 } ptrauth_key;
 
 /* An integer type of the appropriate size for a discriminator argument. */
@@ -141,6 +147,27 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
   __builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
                                     __new_data)
 
+/* Authenticate a pointer using one scheme and resign it as a C
+   function pointer.
+
+   If the result is subsequently authenticated using the new scheme, that
+   authentication is guaranteed to fail if and only if the initial
+   authentication failed.
+
+   The value must be an expression of function pointer type.
+   The key must be a constant expression of type ptrauth_key.
+   The extra data must be an expression of pointer or integer type;
+   if an integer, it will be coerced to ptrauth_extra_data_t.
+   The result will have the same type as the original value.
+
+   This operation is guaranteed to not leave the intermediate value
+   available for attack before it is re-signed. Additionally, if this
+   expression is used syntactically as the function expression in a
+   call, only a single authentication will be performed. */
+#define ptrauth_auth_function(__value, __old_key, __old_data)                  \
+  ptrauth_auth_and_resign(__value, __old_key, __old_data,                      \
+                          ptrauth_key_function_pointer, 0)
+
 /* Authenticate a data pointer.
 
    The value must be an expression of non-function pointer type.
@@ -225,6 +252,13 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
     __value;                                                                   \
   })
 
+#define ptrauth_auth_function(__value, __old_key, __old_data)                  \
+  ({                                                                           \
+    (void)__old_key;                                                           \
+    (void)__old_data;                                                          \
+    __value;                                                                   \
+  })
+
 #define ptrauth_auth_data(__value, __old_key, __old_data)                      \
   ({                                                                           \
     (void)__old_key;                                                           \
diff --git a/clang/test/CodeGen/ptrauth-function-attributes.c b/clang/test/CodeGen/ptrauth-function-attributes.c
new file mode 100644
index 0000000000000..eda9c8813ed1e
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-function-attributes.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios                    -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,OFF
+// RUN: %clang_cc1 -triple arm64e-apple-ios                   -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,OFF
+
+// RUN: %clang_cc1 -triple arm64-apple-ios  -fptrauth-calls   -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,CALLS
+// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls   -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,CALLS
+
+// ALL-LABEL: define void @test() #0
+void test() {
+}
+
+// CALLS: attributes #0 = {{{.*}} "ptrauth-calls" {{.*}}}
+
+// OFF-NOT: attributes {{.*}} "ptrauth-
diff --git a/clang/test/CodeGen/ptrauth-function-init-fail.c b/clang/test/CodeGen/ptrauth-function-init-fail.c
new file mode 100644
index 0000000000000..012d4f7368eaf
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-function-init-fail.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls %s -verify -emit-llvm -o -
+
+void f(void);
+
+int *pf = (int *)&f + 1; // expected-error{{cannot compile this static initializer yet}}
diff --git a/clang/test/CodeGen/ptrauth-function-init.c b/clang/test/CodeGen/ptrauth-function-init.c
new file mode 100644
index 0000000000000..7d75f5ff2a0c3
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-function-init.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s       -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s
+// RUN: %clang_cc1 -xc++ %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CXX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void f(void);
+
+#ifdef __cplusplus
+
+// CXX-LABEL: define internal void @__cxx_global_var_init()
+// CXX: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr @_ZL2fp, align 8
+
+__attribute__((used))
+void (*const fp)(void) = (void (*)(void))((int *)&f + 2); // Error in C mode.
+
+#endif
+
+// CHECK-LABEL: define void @t1()
+void t1() {
+  // CHECK: [[PF:%.*]] = alloca ptr
+  // CHECK: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr [[PF]]
+
+  void (*pf)(void) = (void (*)(void))((int *)&f + 2);
+  (void)pf;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/clang/test/CodeGen/ptrauth-function-lvalue-cast.c b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c
new file mode 100644
index 0000000000000..8ca5490195bac
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck %s
+
+typedef void (*fptr_t)(void);
+
+char *cptr;
+void (*fptr)(void);
+
+// CHECK-LABEL: define void @test1
+void test1() {
+  // CHECK: [[LOAD:%.*]] = load ptr, ptr @cptr
+  // CHECK: call void [[LOAD]]() [ "ptrauth"(i32 0, i64 0) ]
+  // CHECK: ret void
+
+  (*(fptr_t)cptr)();
+}
+
+// CHECK-LABEL: define i8 @test2
+char test2() {
+  return *(char *)fptr;
+  // CHECK: [[LOAD:%.*]] = load ptr, ptr @fptr
+  // CHECK: [[LOAD1:%.*]] = load i8, ptr [[LOAD]]
+  // CHECK: ret i8 [[LOAD1]]
+}
diff --git a/clang/test/CodeGen/ptrauth-weak_import.c b/clang/test/CodeGen/ptrauth-weak_import.c
new file mode 100644
index 0000000000000..2fc8530d0677f
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-weak_import.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
+
+extern void foo() __attribute__((weak_import));
+
+// CHECK-LABEL: define void @bar()
+// CHECK: br i1 icmp ne (ptr ptrauth (ptr @foo, i32 0), ptr null), label
+void bar() {
+  if (foo)
+    foo();
+}
diff --git a/clang/test/CodeGenCXX/ptrauth.cpp b/clang/test/CodeGenCXX/ptrauth.cpp
new file mode 100644
index 0000000000000..d2d3317eb4a35
--- /dev/null
+++ b/clang/test/CodeGenCXX/ptrauth.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s
+
+void f(void);
+auto &f_ref = f;
+
+// CHECK-LABEL: define void @_Z1gv(
+// CHECK: call void ptrauth (ptr @_Z1fv, i32 0)() [ "ptrauth"(i32 0, i64 0) ]
+
+void g() { f_ref(); }
+
+void foo1();
+
+void test_terminate() noexcept {
+  foo1();
+}
+
+// CHECK: define void @_ZSt9terminatev() #[[ATTR4:.*]] {
+
+namespace std {
+  void terminate() noexcept {
+  }
+}
+
+// CHECK: attributes #[[ATTR4]] = {{{.*}}"ptrauth-calls"{{.*}}}

>From d1f35a544a7f4f5a2fa83f696a38e31a7d68a641 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Mon, 3 Jun 2024 09:11:41 -0700
Subject: [PATCH 06/14] Remove unused functions and add test case

---
 clang/lib/CodeGen/CodeGenFunction.cpp | 36 ---------------------------
 clang/lib/CodeGen/CodeGenFunction.h   |  3 ---
 clang/test/CodeGen/ptrauth-function.c | 28 +++++++++++++++++++++
 3 files changed, 28 insertions(+), 39 deletions(-)
 create mode 100644 clang/test/CodeGen/ptrauth-function.c

diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index cb5acf1a1abb7..fc48b2360c36e 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -3063,39 +3063,3 @@ void CodeGenFunction::EmitPointerAuthOperandBundle(
   llvm::Value *args[] = {key, discriminator};
   bundles.emplace_back("ptrauth", args);
 }
-
-static llvm::Value *EmitPointerAuthCommon(CodeGenFunction &CGF,
-                                          const CGPointerAuthInfo &pointerAuth,
-                                          llvm::Value *pointer,
-                                          unsigned intrinsicID) {
-  if (!pointerAuth)
-    return pointer;
-
-  auto key = CGF.Builder.getInt32(pointerAuth.getKey());
-
-  llvm::Value *discriminator = pointerAuth.getDiscriminator();
-  if (!discriminator) {
-    discriminator = CGF.Builder.getSize(0);
-  }
-
-  // Convert the pointer to intptr_t before signing it.
-  auto origType = pointer->getType();
-  pointer = CGF.Builder.CreatePtrToInt(pointer, CGF.IntPtrTy);
-
-  // call i64 @llvm.ptrauth.sign.i64(i64 %pointer, i32 %key, i64 %discriminator)
-  auto intrinsic = CGF.CGM.getIntrinsic(intrinsicID);
-  pointer = CGF.EmitRuntimeCall(intrinsic, {pointer, key, discriminator});
-
-  // Convert back to the original type.
-  pointer = CGF.Builder.CreateIntToPtr(pointer, origType);
-  return pointer;
-}
-
-llvm::Value *
-CodeGenFunction::EmitPointerAuthSign(const CGPointerAuthInfo &pointerAuth,
-                                     llvm::Value *pointer) {
-  if (!pointerAuth.shouldSign())
-    return pointer;
-  return EmitPointerAuthCommon(*this, pointerAuth, pointer,
-                               llvm::Intrinsic::ptrauth_sign);
-}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a0518b7525df1..8aaaa526bf016 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4410,9 +4410,6 @@ class CodeGenFunction : public CodeGenTypeCache {
                                         llvm::Value *storageAddress,
                                         GlobalDecl calleeDecl,
                                         QualType calleeType);
-  llvm::Value *EmitPointerAuthSign(QualType pointeeType, llvm::Value *pointer);
-  llvm::Value *EmitPointerAuthSign(const CGPointerAuthInfo &info,
-                                   llvm::Value *pointer);
   void EmitPointerAuthOperandBundle(
       const CGPointerAuthInfo &info,
       SmallVectorImpl<llvm::OperandBundleDef> &bundles);
diff --git a/clang/test/CodeGen/ptrauth-function.c b/clang/test/CodeGen/ptrauth-function.c
new file mode 100644
index 0000000000000..dc4f270e470f9
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-function.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck -check-prefix=CHECK %s
+
+void test_call();
+
+// CHECK-LABEL: define void @test_direct_call()
+void test_direct_call() {
+  // CHECK: call void @test_call(){{$}}
+  test_call();
+}
+
+void abort();
+// CHECK-LABEL: define void @test_direct_builtin_call()
+void test_direct_builtin_call() {
+  // CHECK: call void @abort() {{#[0-9]+$}}
+  abort();
+}
+
+// CHECK-LABEL: define void @test_memcpy_inline(
+// CHECK-NOT: call{{.*}}memcpy
+
+extern inline __attribute__((__always_inline__))
+void *memcpy(void *d, const void *s, unsigned long) {
+  return 0;
+}
+
+void test_memcpy_inline(char *d, char *s) {
+  memcpy(d, s, 4);
+}

>From 5e0ea2eac4673b842b1aa84e5d32cc18ed051fb5 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 11:00:39 -0700
Subject: [PATCH 07/14] Document ptrauth_string_discriminator in
 clang/docs/PointerAuthentication.

---
 clang/docs/PointerAuthentication.rst | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst
index 19b3384293aed..bd8bf92984225 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -328,6 +328,21 @@ be done in a single instruction with an immediate integer.
 ``pointer`` must have pointer type, and ``integer`` must have integer type. The
 result has type ``ptrauth_extra_data_t``.
 
+``ptrauth_string_discriminator``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: c
+
+  ptrauth_string_discriminator(string)
+
+Produce a discriminator value for the given string.  ``string`` must be
+a string literal of ``char`` character type.  The result has type
+``ptrauth_extra_data_t``.
+
+The result is always a constant expression.  The result value is never zero and
+always within range for both the ``__ptrauth`` qualifier and
+``ptrauth_blend_discriminator``.
+
 ``ptrauth_strip``
 ^^^^^^^^^^^^^^^^^
 

>From 7f3cd8777efcd3f54079a023cee0d4d937d7a1cb Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 11:00:47 -0700
Subject: [PATCH 08/14] Document ptrauth_sign_constant in
 clang/docs/PointerAuthentication.

---
 clang/docs/PointerAuthentication.rst | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst
index 19b3384293aed..f9f27d19680c5 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -339,6 +339,23 @@ Given that ``signedPointer`` matches the layout for signed pointers signed with
 the given key, extract the raw pointer from it.  This operation does not trap
 and cannot fail, even if the pointer is not validly signed.
 
+``ptrauth_sign_constant``
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: c
+
+  ptrauth_sign_constant(pointer, key, discriminator)
+
+Return a signed pointer for a constant address in a manner which guarantees
+a non-attackable sequence.
+
+``pointer`` must be a constant expression of pointer type which evaluates to
+a non-null pointer.  The result will have the same type as ``discriminator``.
+
+Calls to this are constant expressions if the discriminator is a null-pointer
+constant expression or an integer constant expression. Implementations may
+allow other pointer expressions as well.
+
 ``ptrauth_sign_unauthenticated``
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

>From 717e4eb0fdbad297a7496568486f7179adf39996 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 13:32:21 -0700
Subject: [PATCH 09/14] Address review feedback.

- add missing sema test
- also test ELF codegen for intrinsics
- various capitalization and type nits
---
 clang/lib/AST/ExprConstant.cpp          |  7 ++++---
 clang/lib/Sema/SemaChecking.cpp         | 18 +++++++++---------
 clang/test/CodeGen/ptrauth-intrinsics.c | 15 ++++++++-------
 clang/test/Sema/ptrauth.c               | 11 +++++++++++
 4 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index eafecfb5fe5b1..4ffe84ccd4516 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -12585,9 +12585,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
     return Visit(E->getArg(0));
 
   case Builtin::BI__builtin_ptrauth_string_discriminator: {
-    auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
-    auto result = getPointerAuthStableSipHash16(literal->getString());
-    return Success(result, E);
+    const auto *Literal =
+        cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
+    uint64_t Result = getPointerAuthStableSipHash16(Literal->getString());
+    return Success(Result, E);
   }
 
   case Builtin::BI__builtin_ffs:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f6012ef4b3601..b69542b9dc74d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2156,22 +2156,22 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
   return Call;
 }
 
-static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *call) {
-  if (checkPointerAuthEnabled(S, call)) return ExprError();
+static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
+  if (checkPointerAuthEnabled(S, Call)) return ExprError();
 
   // We've already performed normal call type-checking.
-  Expr *arg = call->getArgs()[0]->IgnoreParenImpCasts();
+  const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
 
   // Operand must be an ordinary or UTF-8 string literal.
-  auto literal = dyn_cast<StringLiteral>(arg);
-  if (!literal || literal->getCharByteWidth() != 1) {
-    S.Diag(arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
-      << (literal ? 1 : 0)
-      << arg->getSourceRange();
+  const auto *Literal = dyn_cast<StringLiteral>(Arg);
+  if (!Literal || Literal->getCharByteWidth() != 1) {
+    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
+      << (Literal ? 1 : 0)
+      << Arg->getSourceRange();
     return ExprError();
   }
 
-  return call;
+  return Call;
 }
 
 static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c
index d602325da8b17..db37d78553769 100644
--- a/clang/test/CodeGen/ptrauth-intrinsics.c
+++ b/clang/test/CodeGen/ptrauth-intrinsics.c
@@ -1,11 +1,12 @@
 // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-elf     -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
 
 void (*fnptr)(void);
 long int_discriminator;
 void *ptr_discriminator;
 long signature;
 
-// CHECK-LABEL: define void @test_auth()
+// CHECK-LABEL: define {{.*}}void @test_auth()
 void test_auth() {
   // CHECK:      [[PTR:%.*]] = load ptr, ptr @fnptr,
   // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -17,7 +18,7 @@ void test_auth() {
   fnptr = __builtin_ptrauth_auth(fnptr, 0, ptr_discriminator);
 }
 
-// CHECK-LABEL: define void @test_strip()
+// CHECK-LABEL: define {{.*}}void @test_strip()
 void test_strip() {
   // CHECK:      [[PTR:%.*]] = load ptr, ptr @fnptr,
   // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
@@ -27,7 +28,7 @@ void test_strip() {
   fnptr = __builtin_ptrauth_strip(fnptr, 0);
 }
 
-// CHECK-LABEL: define void @test_sign_unauthenticated()
+// CHECK-LABEL: define {{.*}}void @test_sign_unauthenticated()
 void test_sign_unauthenticated() {
   // CHECK:      [[PTR:%.*]] = load ptr, ptr @fnptr,
   // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -39,7 +40,7 @@ void test_sign_unauthenticated() {
   fnptr = __builtin_ptrauth_sign_unauthenticated(fnptr, 0, ptr_discriminator);
 }
 
-// CHECK-LABEL: define void @test_auth_and_resign()
+// CHECK-LABEL: define {{.*}}void @test_auth_and_resign()
 void test_auth_and_resign() {
   // CHECK:      [[PTR:%.*]] = load ptr, ptr @fnptr,
   // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -51,7 +52,7 @@ void test_auth_and_resign() {
   fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
 }
 
-// CHECK-LABEL: define void @test_blend_discriminator()
+// CHECK-LABEL: define {{.*}}void @test_blend_discriminator()
 void test_blend_discriminator() {
   // CHECK:      [[PTR:%.*]] = load ptr, ptr @fnptr,
   // CHECK-NEXT: [[DISC:%.*]] = load i64, ptr @int_discriminator,
@@ -61,7 +62,7 @@ void test_blend_discriminator() {
   int_discriminator = __builtin_ptrauth_blend_discriminator(fnptr, int_discriminator);
 }
 
-// CHECK-LABEL: define void @test_sign_generic_data()
+// CHECK-LABEL: define {{.*}}void @test_sign_generic_data()
 void test_sign_generic_data() {
   // CHECK:      [[PTR:%.*]] = load ptr, ptr @fnptr,
   // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -72,7 +73,7 @@ void test_sign_generic_data() {
   signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
 }
 
-// CHECK-LABEL: define void @test_string_discriminator()
+// CHECK-LABEL: define {{.*}}void @test_string_discriminator()
 void test_string_discriminator() {
   // CHECK:      [[X:%.*]] = alloca i32
 
diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c
index 3ad3d70c24e41..467ce5e02038c 100644
--- a/clang/test/Sema/ptrauth.c
+++ b/clang/test/Sema/ptrauth.c
@@ -47,6 +47,17 @@ void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
   float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-error {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
 }
 
+void test_string_discriminator(const char *str) {
+  __builtin_ptrauth_string_discriminator(); // expected-error {{too few arguments}}
+  __builtin_ptrauth_string_discriminator(str, str); // expected-error {{too many arguments}}
+  (void) __builtin_ptrauth_string_discriminator("test string"); // no warning
+
+  __builtin_ptrauth_string_discriminator(str); // expected-error {{argument must be a string literal}}
+
+  void *mismatch = __builtin_ptrauth_string_discriminator("test string"); // expected-error {{incompatible integer to pointer conversion initializing 'void *' with an expression of type 'unsigned long'}}
+}
+
+
 void test_sign_unauthenticated(int *dp, int (*fp)(int)) {
   __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
   __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}

>From 8e7d4bc0f98ecb8b0f6eb6371d7a1ba27a976c09 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 13:38:23 -0700
Subject: [PATCH 10/14] Format.

---
 clang/lib/Sema/SemaChecking.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b69542b9dc74d..236be292174d8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2157,7 +2157,8 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
 }
 
 static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
-  if (checkPointerAuthEnabled(S, Call)) return ExprError();
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
 
   // We've already performed normal call type-checking.
   const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
@@ -2166,8 +2167,7 @@ static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
   const auto *Literal = dyn_cast<StringLiteral>(Arg);
   if (!Literal || Literal->getCharByteWidth() != 1) {
     S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
-      << (Literal ? 1 : 0)
-      << Arg->getSourceRange();
+        << (Literal ? 1 : 0) << Arg->getSourceRange();
     return ExprError();
   }
 

>From 33cdfdd5f67aeed1ff74801fc0f048abbd54cd78 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 14:57:03 -0700
Subject: [PATCH 11/14] Address feedback.

- test elf as well
- rename every variable.
---
 clang/include/clang/CodeGen/CodeGenABITypes.h |  8 +-
 clang/lib/CodeGen/CGExprConstant.cpp          | 56 ++++++------
 clang/lib/CodeGen/CGPointerAuth.cpp           | 68 ++++++---------
 clang/lib/CodeGen/CodeGenModule.h             |  8 +-
 clang/lib/Sema/SemaChecking.cpp               | 85 +++++++++----------
 .../CodeGen/ptrauth-intrinsic-sign-constant.c |  3 +-
 6 files changed, 107 insertions(+), 121 deletions(-)

diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h
index 8c62d8597ecbe..45387b64eb517 100644
--- a/clang/include/clang/CodeGen/CodeGenABITypes.h
+++ b/clang/include/clang/CodeGen/CodeGenABITypes.h
@@ -106,10 +106,10 @@ unsigned getLLVMFieldNumber(CodeGenModule &CGM,
 
 /// Return a signed constant pointer.
 llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM,
-                                         llvm::Constant *pointer,
-                                         unsigned key,
-                                         llvm::Constant *storageAddress,
-                                         llvm::Constant *otherDiscriminator);
+                                         llvm::Constant *Pointer, unsigned Key,
+                                         llvm::Constant *StorageAddress,
+                                         llvm::Constant *OtherDiscriminator);
+
 /// Given the language and code-generation options that Clang was configured
 /// with, set the default LLVM IR attributes for a function definition.
 /// The attributes set here are mostly global target-configuration and
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index de9380c0e63be..974ec161cdf4c 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2073,54 +2073,54 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
 
 ConstantLValue
 ConstantLValueEmitter::emitPointerAuthSignConstant(const CallExpr *E) {
-  auto unsignedPointer = emitPointerAuthPointer(E->getArg(0));
-  auto key = emitPointerAuthKey(E->getArg(1));
-  llvm::Constant *storageAddress;
-  llvm::Constant *otherDiscriminator;
-  std::tie(storageAddress, otherDiscriminator) =
-    emitPointerAuthDiscriminator(E->getArg(2));
+  llvm::Constant *UnsignedPointer = emitPointerAuthPointer(E->getArg(0));
+  unsigned Key = emitPointerAuthKey(E->getArg(1));
+  llvm::Constant *StorageAddress;
+  llvm::Constant *OtherDiscriminator;
+  std::tie(StorageAddress, OtherDiscriminator) =
+      emitPointerAuthDiscriminator(E->getArg(2));
 
-  auto signedPointer =
-    CGM.getConstantSignedPointer(unsignedPointer, key, storageAddress,
-                                 otherDiscriminator);
-  return signedPointer;
+  llvm::Constant *SignedPointer = CGM.getConstantSignedPointer(
+      UnsignedPointer, Key, StorageAddress, OtherDiscriminator);
+  return SignedPointer;
 }
 
 llvm::Constant *ConstantLValueEmitter::emitPointerAuthPointer(const Expr *E) {
-  Expr::EvalResult result;
-  bool succeeded = E->EvaluateAsRValue(result, CGM.getContext());
-  assert(succeeded); (void) succeeded;
+  Expr::EvalResult Result;
+  bool Succeeded = E->EvaluateAsRValue(Result, CGM.getContext());
+  assert(Succeeded);
+  (void)Succeeded;
 
   // The assertions here are all checked by Sema.
-  assert(result.Val.isLValue());
+  assert(Result.Val.isLValue());
   return ConstantEmitter(CGM, Emitter.CGF)
-           .emitAbstract(E->getExprLoc(), result.Val, E->getType());
+      .emitAbstract(E->getExprLoc(), Result.Val, E->getType());
 }
 
 unsigned ConstantLValueEmitter::emitPointerAuthKey(const Expr *E) {
   return E->EvaluateKnownConstInt(CGM.getContext()).getZExtValue();
 }
 
-std::pair<llvm::Constant*, llvm::Constant*>
+std::pair<llvm::Constant *, llvm::Constant *>
 ConstantLValueEmitter::emitPointerAuthDiscriminator(const Expr *E) {
   E = E->IgnoreParens();
 
-  if (auto call = dyn_cast<CallExpr>(E)) {
-    if (call->getBuiltinCallee() ==
-          Builtin::BI__builtin_ptrauth_blend_discriminator) {
-      auto pointer = ConstantEmitter(CGM).emitAbstract(call->getArg(0),
-                                            call->getArg(0)->getType());
-      auto extra = ConstantEmitter(CGM).emitAbstract(call->getArg(1),
-                                            call->getArg(1)->getType());
-      return { pointer, extra };
+  if (auto *Call = dyn_cast<CallExpr>(E)) {
+    if (Call->getBuiltinCallee() ==
+        Builtin::BI__builtin_ptrauth_blend_discriminator) {
+      llvm::Constant *Pointer = ConstantEmitter(CGM).emitAbstract(
+          Call->getArg(0), Call->getArg(0)->getType());
+      llvm::Constant *Extra = ConstantEmitter(CGM).emitAbstract(
+          Call->getArg(1), Call->getArg(1)->getType());
+      return {Pointer, Extra};
     }
   }
 
-  auto result = ConstantEmitter(CGM).emitAbstract(E, E->getType());
-  if (result->getType()->isPointerTy())
-    return { result, nullptr };
+  llvm::Constant *Result = ConstantEmitter(CGM).emitAbstract(E, E->getType());
+  if (Result->getType()->isPointerTy())
+    return {Result, nullptr};
   else
-    return { nullptr, result };
+    return {nullptr, Result};
 }
 
 ConstantLValue
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index 756c00aa42c8c..8a1a786577d6b 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -11,67 +11,53 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CGCXXABI.h"
-#include "CGCall.h"
-#include "CodeGenFunction.h"
 #include "CodeGenModule.h"
-#include "clang/AST/Attr.h"
-#include "clang/Basic/PointerAuthOptions.h"
 #include "clang/CodeGen/CodeGenABITypes.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/IR/ValueMap.h"
-#include "llvm/Analysis/ValueTracking.h"
-#include <vector>
 
 using namespace clang;
 using namespace CodeGen;
 
 /// Build a signed-pointer "ptrauth" constant.
 static llvm::ConstantPtrAuth *
-buildConstantAddress(CodeGenModule &CGM, llvm::Constant *pointer, unsigned key,
-                     llvm::Constant *storageAddress,
-                     llvm::Constant *otherDiscriminator) {
-  llvm::Constant *addressDiscriminator = nullptr;
-  if (storageAddress) {
-    addressDiscriminator = storageAddress;
-    assert(storageAddress->getType() == CGM.UnqualPtrTy);
+buildConstantAddress(CodeGenModule &CGM, llvm::Constant *Pointer, unsigned Key,
+                     llvm::Constant *StorageAddress,
+                     llvm::Constant *OtherDiscriminator) {
+  llvm::Constant *AddressDiscriminator = nullptr;
+  if (StorageAddress) {
+    AddressDiscriminator = StorageAddress;
+    assert(StorageAddress->getType() == CGM.UnqualPtrTy);
   } else {
-    addressDiscriminator = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
+    AddressDiscriminator = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
   }
 
-  llvm::ConstantInt *integerDiscriminator = nullptr;
-  if (otherDiscriminator) {
-    assert(otherDiscriminator->getType() == CGM.Int64Ty);
-    integerDiscriminator = cast<llvm::ConstantInt>(otherDiscriminator);
+  llvm::ConstantInt *IntegerDiscriminator = nullptr;
+  if (OtherDiscriminator) {
+    assert(OtherDiscriminator->getType() == CGM.Int64Ty);
+    IntegerDiscriminator = cast<llvm::ConstantInt>(OtherDiscriminator);
   } else {
-    integerDiscriminator = llvm::ConstantInt::get(CGM.Int64Ty, 0);
+    IntegerDiscriminator = llvm::ConstantInt::get(CGM.Int64Ty, 0);
   }
 
-  return llvm::ConstantPtrAuth::get(
-    pointer, llvm::ConstantInt::get(CGM.Int32Ty, key), integerDiscriminator,
-    addressDiscriminator);
+  return llvm::ConstantPtrAuth::get(Pointer,
+                                    llvm::ConstantInt::get(CGM.Int32Ty, Key),
+                                    IntegerDiscriminator, AddressDiscriminator);
 }
 
 llvm::Constant *
-CodeGenModule::getConstantSignedPointer(llvm::Constant *pointer,
-                                        unsigned key,
-                                        llvm::Constant *storageAddress,
-                                        llvm::Constant *otherDiscriminator) {
-  // Unique based on the underlying value, not a signing of it.
-  auto stripped = pointer->stripPointerCasts();
+CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
+                                        llvm::Constant *StorageAddress,
+                                        llvm::Constant *OtherDiscriminator) {
+  llvm::Constant *Stripped = Pointer->stripPointerCasts();
 
   // Build the constant.
-  return buildConstantAddress(*this, stripped, key, storageAddress,
-                              otherDiscriminator);
+  return buildConstantAddress(*this, Stripped, Key, StorageAddress,
+                              OtherDiscriminator);
 }
 
 llvm::Constant *
-CodeGen::getConstantSignedPointer(CodeGenModule &CGM,
-                                  llvm::Constant *pointer, unsigned key,
-                                  llvm::Constant *storageAddress,
-                                  llvm::Constant *otherDiscriminator) {
-  return CGM.getConstantSignedPointer(pointer, key, storageAddress,
-                                      otherDiscriminator);
+CodeGen::getConstantSignedPointer(CodeGenModule &CGM, llvm::Constant *Pointer,
+                                  unsigned Key, llvm::Constant *StorageAddress,
+                                  llvm::Constant *OtherDiscriminator) {
+  return CGM.getConstantSignedPointer(Pointer, Key, StorageAddress,
+                                      OtherDiscriminator);
 }
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 194ac180171e0..7e01da470bc20 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -938,10 +938,10 @@ class CodeGenModule : public CodeGenTypeCache {
   // Return the function body address of the given function.
   llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
 
-  llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
-                                           unsigned key,
-                                           llvm::Constant *storageAddress,
-                                           llvm::Constant *extraDiscrim);
+  llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer,
+                                           unsigned Key,
+                                           llvm::Constant *StorageAddress,
+                                           llvm::Constant *ExtraDiscrim);
 
   // Return whether RTTI information should be emitted for this target.
   bool shouldEmitRTTI(bool ForEH = false) {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7f1505dc808a4..05cd431ae1fee 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2033,18 +2033,17 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
 static std::pair<const ValueDecl *, CharUnits>
 findConstantBaseAndOffset(Sema &S, Expr *E) {
   // Must evaluate as a pointer.
-  Expr::EvalResult result;
-  if (!E->EvaluateAsRValue(result, S.Context) ||
-      !result.Val.isLValue())
+  Expr::EvalResult Result;
+  if (!E->EvaluateAsRValue(Result, S.Context) || !Result.Val.isLValue())
     return std::make_pair(nullptr, CharUnits());
 
   // Base must be a declaration and can't be weakly imported.
-  auto baseDecl =
-    result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
-  if (!baseDecl || baseDecl->hasAttr<WeakRefAttr>())
+  const auto *BaseDecl =
+      Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
+  if (!BaseDecl || BaseDecl->hasAttr<WeakRefAttr>())
     return std::make_pair(nullptr, CharUnits());
 
-  return std::make_pair(baseDecl, result.Val.getLValueOffset());
+  return std::make_pair(BaseDecl, Result.Val.getLValueOffset());
 }
 
 static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
@@ -2110,73 +2109,73 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
   // The main argument.
   if (OpKind == PAO_Sign) {
     // Require the value we're signing to have a special form.
-    auto result = findConstantBaseAndOffset(S, Arg);
-    bool invalid;
+    auto BaseOffsetPair = findConstantBaseAndOffset(S, Arg);
+    bool Invalid;
 
     // Must be rooted in a declaration reference.
-    if (!result.first) {
-      invalid = true;
+    if (!BaseOffsetPair.first) {
+      Invalid = true;
 
-    // If it's a function declaration, we can't have an offset.
-    } else if (isa<FunctionDecl>(result.first)) {
-      invalid = !result.second.isZero();
+      // If it's a function declaration, we can't have an offset.
+    } else if (isa<FunctionDecl>(BaseOffsetPair.first)) {
+      Invalid = !BaseOffsetPair.second.isZero();
 
-    // Otherwise we're fine.
+      // Otherwise we're fine.
     } else {
-      invalid = false;
+      Invalid = false;
     }
 
-    if (invalid) {
+    if (Invalid) {
       S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer);
     }
-    return invalid;
+    return Invalid;
   }
 
   // The discriminator argument.
   assert(OpKind == PAO_Discriminator);
 
   // Must be a pointer or integer or blend thereof.
-  Expr *pointer = nullptr;
-  Expr *integer = nullptr;
-  if (auto call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
-    if (call->getBuiltinCallee() ==
-          Builtin::BI__builtin_ptrauth_blend_discriminator) {
-      pointer = call->getArg(0);
-      integer = call->getArg(1);
+  Expr *Pointer = nullptr;
+  Expr *Integer = nullptr;
+  if (auto *Call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
+    if (Call->getBuiltinCallee() ==
+        Builtin::BI__builtin_ptrauth_blend_discriminator) {
+      Pointer = Call->getArg(0);
+      Integer = Call->getArg(1);
     }
   }
-  if (!pointer && !integer) {
+  if (!Pointer && !Integer) {
     if (Arg->getType()->isPointerType())
-      pointer = Arg;
+      Pointer = Arg;
     else
-      integer = Arg;
+      Integer = Arg;
   }
 
   // Check the pointer.
-  bool invalid = false;
-  if (pointer) {
-    assert(pointer->getType()->isPointerType());
+  bool Invalid = false;
+  if (Pointer) {
+    assert(Pointer->getType()->isPointerType());
 
     // TODO: if we're initializing a global, check that the address is
     // somehow related to what we're initializing.  This probably will
     // never really be feasible and we'll have to catch it at link-time.
-    auto result = findConstantBaseAndOffset(S, pointer);
-    if (!result.first || !isa<VarDecl>(result.first)) {
-      invalid = true;
+    auto BaseOffsetPair = findConstantBaseAndOffset(S, Pointer);
+    if (!BaseOffsetPair.first || !isa<VarDecl>(BaseOffsetPair.first)) {
+      Invalid = true;
     }
   }
 
   // Check the integer.
-  if (integer) {
-    assert(integer->getType()->isIntegerType());
-    if (!integer->isEvaluatable(S.Context))
-      invalid = true;
+  if (Integer) {
+    assert(Integer->getType()->isIntegerType());
+    if (!Integer->isEvaluatable(S.Context))
+      Invalid = true;
   }
 
-  if (invalid) {
+  if (Invalid) {
     S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator);
   }
-  return invalid;
+  return Invalid;
 }
 
 static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) {
@@ -3029,13 +3028,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     return PointerAuthBlendDiscriminator(*this, TheCall);
   case Builtin::BI__builtin_ptrauth_sign_constant:
     return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
-                                 /*constant*/ true);
+                                 /*RequireConstant=*/true);
   case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
     return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
-                                 /*constant*/ false);
+                                 /*RequireConstant=*/false);
   case Builtin::BI__builtin_ptrauth_auth:
     return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth,
-                                 /*constant*/ false);
+                                 /*RequireConstant=*/false);
   case Builtin::BI__builtin_ptrauth_sign_generic_data:
     return PointerAuthSignGenericData(*this, TheCall);
   case Builtin::BI__builtin_ptrauth_auth_and_resign:
diff --git a/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c b/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
index 3915834812990..626eb4a2e01a8 100644
--- a/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
+++ b/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-elf     -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
 
 extern int external;
 
@@ -12,7 +13,7 @@ void *ptr2 = __builtin_ptrauth_sign_constant(&external, 2, __builtin_ptrauth_ble
 void *ptr3;
 
 void test_sign_constant_code() {
-// CHECK-LABEL: define void @test_sign_constant_code()
+// CHECK-LABEL: define {{.*}}void @test_sign_constant_code()
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    store ptr ptrauth (ptr @external, i32 2, i64 1234), ptr @ptr3, align 8
 // CHECK-NEXT:    ret void

>From 4fde673cc6b52cb7dd1167f1ead674ae2627d597 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Wed, 12 Jun 2024 10:12:50 -0700
Subject: [PATCH 12/14] Address review comments

- Remove unneeded declarations.
- Fix includes.
- Use `llvm::to_underlying`.
- Fix variable names.
- Fix size and type of bit-fields.
- Add test case for `err_drv_ptrauth_not_supported`.
---
 clang/include/clang/Basic/LangOptions.h       |  2 --
 .../include/clang/Basic/PointerAuthOptions.h  | 12 ++++----
 clang/lib/CodeGen/CGCall.h                    |  4 +--
 clang/lib/CodeGen/CGPointerAuth.cpp           | 30 +++++++------------
 clang/lib/CodeGen/CGPointerAuthInfo.h         |  7 +++--
 clang/lib/CodeGen/CodeGenFunction.cpp         | 18 +++++------
 clang/lib/CodeGen/CodeGenFunction.h           |  9 ++----
 clang/lib/CodeGen/CodeGenModule.h             | 23 +++++---------
 clang/lib/Frontend/CompilerInvocation.cpp     |  3 +-
 clang/test/Driver/ptrauth.c                   |  9 ++++++
 10 files changed, 52 insertions(+), 65 deletions(-)
 create mode 100644 clang/test/Driver/ptrauth.c

diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 5216822e45b1b..75e88afbd9705 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -346,8 +346,6 @@ class LangOptionsBase {
     BKey
   };
 
-  using PointerAuthenticationMode = ::clang::PointerAuthenticationMode;
-
   enum class ThreadModelKind {
     /// POSIX Threads.
     POSIX,
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
index 32b179e3f9460..9b34f4ebf70dc 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -16,12 +16,10 @@
 
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Target/TargetOptions.h"
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
+#include <optional>
 
 namespace clang {
 
@@ -76,7 +74,7 @@ class PointerAuthSchema {
         IsIsaPointer(IsIsaPointer),
         AuthenticatesNullValues(AuthenticatesNullValues),
         SelectedAuthenticationMode(AuthenticationMode),
-        DiscriminationKind(OtherDiscrimination), Key(unsigned(Key)) {
+        DiscriminationKind(OtherDiscrimination), Key(llvm::to_underlying(Key)) {
     assert((getOtherDiscrimination() != Discrimination::Constant ||
             ConstantDiscriminatorOrNone) &&
            "constant discrimination requires a constant!");
@@ -126,7 +124,7 @@ class PointerAuthSchema {
 
   uint16_t getConstantDiscrimination() const {
     assert(getOtherDiscrimination() == Discrimination::Constant);
-    return (uint16_t)ConstantDiscriminator;
+    return ConstantDiscriminator;
   }
 
   unsigned getKey() const {
@@ -134,7 +132,7 @@ class PointerAuthSchema {
     case Kind::None:
       llvm_unreachable("calling getKey() on disabled schema");
     case Kind::ARM8_3:
-      return unsigned(getARM8_3Key());
+      return llvm::to_underlying(getARM8_3Key());
     }
     llvm_unreachable("bad key kind");
   }
diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h
index 4b0e1561b4ef5..a601f5f47c7d8 100644
--- a/clang/lib/CodeGen/CGCall.h
+++ b/clang/lib/CodeGen/CGCall.h
@@ -196,9 +196,9 @@ class CGCallee {
     KindOrFunctionPointer =
         SpecialKind(reinterpret_cast<uintptr_t>(functionPtr));
   }
-  void setPointerAuthInfo(CGPointerAuthInfo pointerAuth) {
+  void setPointerAuthInfo(CGPointerAuthInfo PointerAuth) {
     assert(isOrdinary());
-    OrdinaryInfo.PointerAuthInfo = pointerAuth;
+    OrdinaryInfo.PointerAuthInfo = PointerAuth;
   }
 
   bool isVirtual() const {
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index adfa721ac89d3..d3e269be0b6e3 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -31,7 +31,7 @@ using namespace CodeGen;
 /// Return the abstract pointer authentication schema for a pointer to the given
 /// function type.
 CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {
-  auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;
+  const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;
   if (!Schema)
     return CGPointerAuthInfo();
 
@@ -96,33 +96,25 @@ CodeGen::getConstantSignedPointer(CodeGenModule &CGM,
 
 /// If applicable, sign a given constant function pointer with the ABI rules for
 /// functionType.
-llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *pointer,
-                                                  QualType functionType,
+llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
+                                                  QualType FunctionType,
                                                   GlobalDecl GD) {
-  assert(functionType->isFunctionType() ||
-         functionType->isFunctionReferenceType() ||
-         functionType->isFunctionPointerType());
+  assert(FunctionType->isFunctionType() ||
+         FunctionType->isFunctionReferenceType() ||
+         FunctionType->isFunctionPointerType());
 
-  if (auto pointerAuth = getFunctionPointerAuthInfo(functionType)) {
+  if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) {
     return getConstantSignedPointer(
-      pointer, pointerAuth.getKey(), nullptr,
-      cast_or_null<llvm::Constant>(pointerAuth.getDiscriminator()));
+      Pointer, PointerAuth.getKey(), nullptr,
+      cast_or_null<llvm::Constant>(PointerAuth.getDiscriminator()));
   }
 
-  return pointer;
+  return Pointer;
 }
 
 llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
                                                   llvm::Type *Ty) {
-  const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-
-  // Annoyingly, K&R functions have prototypes in the clang AST, but
-  // expressions referring to them are unprototyped.
+  const auto *FD = cast<FunctionDecl>(GD.getDecl());
   QualType FuncType = FD->getType();
-  if (!FD->hasPrototype())
-    if (const auto *Proto = FuncType->getAs<FunctionProtoType>())
-      FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(),
-                                                Proto->getExtInfo());
-
   return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType, GD);
 }
diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h
index e870c3145acba..7e93773257cc0 100644
--- a/clang/lib/CodeGen/CGPointerAuthInfo.h
+++ b/clang/lib/CodeGen/CGPointerAuthInfo.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_LIB_CODEGEN_CGPOINTERAUTHINFO_H
 
 #include "clang/AST/Type.h"
+#include "clang/Basic/LangOptions.h"
 #include "llvm/IR/Type.h"
 #include "llvm/IR/Value.h"
 
@@ -23,9 +24,9 @@ namespace CodeGen {
 class CGPointerAuthInfo {
 private:
   PointerAuthenticationMode AuthenticationMode : 2;
-  bool IsIsaPointer : 1;
-  bool AuthenticatesNullValues : 1;
-  unsigned Key : 28;
+  unsigned IsIsaPointer : 1;
+  unsigned AuthenticatesNullValues : 1;
+  unsigned Key : 4;
   llvm::Value *Discriminator;
 
 public:
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index fc48b2360c36e..255b9f668620a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -3048,18 +3048,18 @@ llvm::Value *CodeGenFunction::emitBoolVecConversion(llvm::Value *SrcVec,
 }
 
 void CodeGenFunction::EmitPointerAuthOperandBundle(
-    const CGPointerAuthInfo &pointerAuth,
-    SmallVectorImpl<llvm::OperandBundleDef> &bundles) {
-  if (!pointerAuth.isSigned())
+    const CGPointerAuthInfo &PointerAuth,
+    SmallVectorImpl<llvm::OperandBundleDef> &Bundles) {
+  if (!PointerAuth.isSigned())
     return;
 
-  auto key = Builder.getInt32(pointerAuth.getKey());
+  auto Key = Builder.getInt32(PointerAuth.getKey());
 
-  llvm::Value *discriminator = pointerAuth.getDiscriminator();
-  if (!discriminator) {
-    discriminator = Builder.getSize(0);
+  llvm::Value *Discriminator = PointerAuth.getDiscriminator();
+  if (!Discriminator) {
+    Discriminator = Builder.getSize(0);
   }
 
-  llvm::Value *args[] = {key, discriminator};
-  bundles.emplace_back("ptrauth", args);
+  llvm::Value *Args[] = {Key, Discriminator};
+  Bundles.emplace_back("ptrauth", Args);
 }
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 8aaaa526bf016..037ef7cc456a7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4406,13 +4406,10 @@ class CodeGenFunction : public CodeGenTypeCache {
   }
 
   bool isPointerKnownNonNull(const Expr *E);
-  CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &schema,
-                                        llvm::Value *storageAddress,
-                                        GlobalDecl calleeDecl,
-                                        QualType calleeType);
+
   void EmitPointerAuthOperandBundle(
-      const CGPointerAuthInfo &info,
-      SmallVectorImpl<llvm::OperandBundleDef> &bundles);
+      const CGPointerAuthInfo &Info,
+      SmallVectorImpl<llvm::OperandBundleDef> &Bundles);
 
   // Return the copy constructor name with the prefix "__copy_constructor_"
   // removed.
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 5e30c5740b2f1..98cc8f7c3efaf 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -26,7 +26,6 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/Module.h"
 #include "clang/Basic/NoSanitizeList.h"
-#include "clang/Basic/PointerAuthOptions.h"
 #include "clang/Basic/ProfileList.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/XRayLists.h"
@@ -954,29 +953,23 @@ class CodeGenModule : public CodeGenTypeCache {
   /// Return the ABI-correct function pointer value for a reference
   /// to the given function.  This will apply a pointer signature if
   /// necessary, but will only cache the result if \p FD is passed.
-  llvm::Constant *getFunctionPointer(llvm::Constant *pointer,
-                                     QualType functionType,
+  llvm::Constant *getFunctionPointer(llvm::Constant *Pointer,
+                                     QualType FunctionType,
                                      GlobalDecl GD = GlobalDecl());
 
-  CGPointerAuthInfo getFunctionPointerAuthInfo(QualType functionType);
+  CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T);
 
-  CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type);
-
-  CGPointerAuthInfo getPointerAuthInfoForType(QualType type);
-
-  llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
-                                           const PointerAuthSchema &schema,
-                                           llvm::Constant *storageAddress,
-                                           GlobalDecl schemaDecl,
-                                           QualType schemaType);
+  llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer,
+                                           const PointerAuthSchema &Schema,
+                                           llvm::Constant *StorageAddress,
+                                           GlobalDecl SchemaDecl,
+                                           QualType SchemaType);
 
   llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
                                            unsigned key,
                                            llvm::Constant *storageAddress,
                                            llvm::Constant *extraDiscrim);
 
-  CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD);
-
   // Return whether RTTI information should be emitted for this target.
   bool shouldEmitRTTI(bool ForEH = false) {
     return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b4ca3e413b2c0..78935ab60e96f 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1476,7 +1476,6 @@ bool CompilerInvocation::setDefaultPointerAuthOptions(
 }
 
 static bool parsePointerAuthOptions(PointerAuthOptions &Opts,
-                                    ArgList &Args,
                                     const LangOptions &LangOpts,
                                     const llvm::Triple &Triple,
                                     DiagnosticsEngine &Diags) {
@@ -2187,7 +2186,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
   Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
 
   if (!LangOpts->CUDAIsDevice)
-    parsePointerAuthOptions(Opts.PointerAuth, Args, *LangOpts, T, Diags);
+    parsePointerAuthOptions(Opts.PointerAuth, *LangOpts, T, Diags);
 
   if (Args.hasArg(options::OPT_ffinite_loops))
     Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always;
diff --git a/clang/test/Driver/ptrauth.c b/clang/test/Driver/ptrauth.c
new file mode 100644
index 0000000000000..a12b451a7ee0d
--- /dev/null
+++ b/clang/test/Driver/ptrauth.c
@@ -0,0 +1,9 @@
+// RUN: %clang -target arm64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS
+// RUN: %clang -target aarch64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS
+// RUN: %clang -target aarch64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS
+// RUN: not %clang -target x86_64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID
+// RUN: not %clang -target x86_64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID
+// RUN: not %clang -target x86_64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID
+
+// PTRAUTH_CALLS: "-fptrauth-calls"
+// INVALID: unsupported option '-fptrauth-calls'

>From c260f8d8c63cbf7ee376e5c34e3c021355e6ed39 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Wed, 12 Jun 2024 10:39:46 -0700
Subject: [PATCH 13/14] Declare operator== as a friend function instead of a
 member function

---
 clang/lib/CodeGen/CGPointerAuthInfo.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h
index 7e93773257cc0..1cf4943e1e266 100644
--- a/clang/lib/CodeGen/CGPointerAuthInfo.h
+++ b/clang/lib/CodeGen/CGPointerAuthInfo.h
@@ -81,13 +81,15 @@ class CGPointerAuthInfo {
     return AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
   }
 
-  bool operator!=(const CGPointerAuthInfo &Other) const {
-    return Key != Other.Key || Discriminator != Other.Discriminator ||
-           AuthenticationMode != Other.AuthenticationMode;
+  friend bool operator!=(const CGPointerAuthInfo &LHS,
+                         const CGPointerAuthInfo &RHS) {
+    return LHS.Key != RHS.Key || LHS.Discriminator != RHS.Discriminator ||
+           LHS.AuthenticationMode != RHS.AuthenticationMode;
   }
 
-  bool operator==(const CGPointerAuthInfo &Other) const {
-    return !(*this != Other);
+  friend bool operator==(const CGPointerAuthInfo &LHS,
+                         const CGPointerAuthInfo &RHS) {
+    return !(LHS != RHS);
   }
 };
 

>From 06529d3dc311d8fc2c1847de7007f0a82f4b2a27 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Tue, 18 Jun 2024 11:49:54 -0700
Subject: [PATCH 14/14] Address review comments

- Remove unused diagnostic.
- Change the size of Key fields to 2 bits.
- Stop passing the default argument to CGCallee's constructor.
- Remove unused functions and variables.
- Add a test for indirect calls.
- Run tests on linux too.
---
 .../clang/Basic/DiagnosticDriverKinds.td      |  3 --
 .../include/clang/Basic/PointerAuthOptions.h  |  2 +-
 .../clang/Frontend/CompilerInvocation.h       |  5 ++-
 clang/lib/CodeGen/CGCall.h                    | 10 +++---
 clang/lib/CodeGen/CGPointerAuth.cpp           | 14 +++------
 clang/lib/CodeGen/CGPointerAuthInfo.h         |  2 +-
 clang/lib/CodeGen/CodeGenFunction.cpp         |  5 ++-
 clang/lib/CodeGen/CodeGenModule.h             | 11 ++-----
 clang/lib/Frontend/CompilerInvocation.cpp     | 31 +++++++------------
 .../CodeGen/ptrauth-function-attributes.c     |  6 ++--
 .../test/CodeGen/ptrauth-function-init-fail.c |  2 ++
 clang/test/CodeGen/ptrauth-function-init.c    | 11 +++++--
 .../CodeGen/ptrauth-function-lvalue-cast.c    |  5 +--
 clang/test/CodeGen/ptrauth-function.c         | 16 ++++++++--
 clang/test/CodeGen/ptrauth-weak_import.c      |  3 +-
 clang/test/CodeGenCXX/ptrauth.cpp             |  5 +--
 clang/test/Driver/ptrauth.c                   |  9 ------
 17 files changed, 63 insertions(+), 77 deletions(-)
 delete mode 100644 clang/test/Driver/ptrauth.c

diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 6cbb0c8401c15..773b234cd68fe 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -351,9 +351,6 @@ def err_drv_omp_host_ir_file_not_found : Error<
   "target regions but cannot be found">;
 def err_drv_omp_host_target_not_supported : Error<
   "target '%0' is not a supported OpenMP host target">;
-def err_drv_ptrauth_not_supported : Error<
-  "target '%0' does not support native pointer authentication">;
-
 def err_drv_expecting_fopenmp_with_fopenmp_targets : Error<
   "'-fopenmp-targets' must be used in conjunction with a '-fopenmp' option "
   "compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">;
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
index 9b34f4ebf70dc..aaad4a2b2b5ae 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -58,7 +58,7 @@ class PointerAuthSchema {
   unsigned AuthenticatesNullValues : 1;
   PointerAuthenticationMode SelectedAuthenticationMode : 2;
   Discrimination DiscriminationKind : 2;
-  unsigned Key : 4;
+  unsigned Key : 2;
   unsigned ConstantDiscriminator : 16;
 
 public:
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index e60e5aad6c70d..9daa0a1ecf948 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -306,12 +306,11 @@ class CompilerInvocation : public CompilerInvocationBase {
   static std::string GetResourcesPath(const char *Argv0, void *MainAddr);
 
   /// Populate \p Opts with the default set of pointer authentication-related
-  /// options given \p LangOpts and \p Triple. Return true if defaults are
-  /// available.
+  /// options given \p LangOpts and \p Triple.
   ///
   /// Note: This is intended to be used by tools which must be aware of
   /// pointer authentication-related code generation, e.g. lldb.
-  static bool setDefaultPointerAuthOptions(PointerAuthOptions &Opts,
+  static void setDefaultPointerAuthOptions(PointerAuthOptions &Opts,
                                            const LangOptions &LangOpts,
                                            const llvm::Triple &Triple);
 
diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h
index a601f5f47c7d8..412b44a8c753a 100644
--- a/clang/lib/CodeGen/CGCall.h
+++ b/clang/lib/CodeGen/CGCall.h
@@ -109,9 +109,9 @@ class CGCallee {
 
   /// Construct a callee.  Call this constructor directly when this
   /// isn't a direct call.
-  CGCallee(
-      const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr,
-      const CGPointerAuthInfo &pointerAuthInfo = /*FIXME*/ CGPointerAuthInfo())
+  CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr,
+           /* FIXME: make parameter pointerAuthInfo mandatory */
+           const CGPointerAuthInfo &pointerAuthInfo = CGPointerAuthInfo())
       : KindOrFunctionPointer(
             SpecialKind(reinterpret_cast<uintptr_t>(functionPtr))) {
     OrdinaryInfo.AbstractInfo = abstractInfo;
@@ -136,12 +136,12 @@ class CGCallee {
 
   static CGCallee forDirect(llvm::Constant *functionPtr,
                             const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
-    return CGCallee(abstractInfo, functionPtr, CGPointerAuthInfo());
+    return CGCallee(abstractInfo, functionPtr);
   }
 
   static CGCallee forDirect(llvm::FunctionCallee functionPtr,
                             const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
-    return CGCallee(abstractInfo, functionPtr.getCallee(), CGPointerAuthInfo());
+    return CGCallee(abstractInfo, functionPtr.getCallee());
   }
 
   static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr,
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index d77f09bdbb1ca..df7e90c06cb4f 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -80,20 +80,16 @@ CodeGen::getConstantSignedPointer(CodeGenModule &CGM, llvm::Constant *Pointer,
                                       OtherDiscriminator);
 }
 
-/// If applicable, sign a given constant function pointer with the ABI rules for
-/// functionType.
 llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
-                                                  QualType FunctionType,
-                                                  GlobalDecl GD) {
+                                                  QualType FunctionType) {
   assert(FunctionType->isFunctionType() ||
          FunctionType->isFunctionReferenceType() ||
          FunctionType->isFunctionPointerType());
 
-  if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) {
+  if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType))
     return getConstantSignedPointer(
-      Pointer, PointerAuth.getKey(), nullptr,
-      cast_or_null<llvm::Constant>(PointerAuth.getDiscriminator()));
-  }
+        Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr,
+        cast_or_null<llvm::Constant>(PointerAuth.getDiscriminator()));
 
   return Pointer;
 }
@@ -102,5 +98,5 @@ llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
                                                   llvm::Type *Ty) {
   const auto *FD = cast<FunctionDecl>(GD.getDecl());
   QualType FuncType = FD->getType();
-  return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType, GD);
+  return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);
 }
diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h
index 1cf4943e1e266..0a0c11fb423f2 100644
--- a/clang/lib/CodeGen/CGPointerAuthInfo.h
+++ b/clang/lib/CodeGen/CGPointerAuthInfo.h
@@ -26,7 +26,7 @@ class CGPointerAuthInfo {
   PointerAuthenticationMode AuthenticationMode : 2;
   unsigned IsIsaPointer : 1;
   unsigned AuthenticatesNullValues : 1;
-  unsigned Key : 4;
+  unsigned Key : 2;
   llvm::Value *Discriminator;
 
 public:
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 255b9f668620a..baa7fe113b461 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -3053,12 +3053,11 @@ void CodeGenFunction::EmitPointerAuthOperandBundle(
   if (!PointerAuth.isSigned())
     return;
 
-  auto Key = Builder.getInt32(PointerAuth.getKey());
+  auto *Key = Builder.getInt32(PointerAuth.getKey());
 
   llvm::Value *Discriminator = PointerAuth.getDiscriminator();
-  if (!Discriminator) {
+  if (!Discriminator)
     Discriminator = Builder.getSize(0);
-  }
 
   llvm::Value *Args[] = {Key, Discriminator};
   Bundles.emplace_back("ptrauth", Args);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index d06fbdcc313ac..e4287c338d641 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -952,19 +952,12 @@ class CodeGenModule : public CodeGenTypeCache {
 
   /// Return the ABI-correct function pointer value for a reference
   /// to the given function.  This will apply a pointer signature if
-  /// necessary, but will only cache the result if \p FD is passed.
+  /// necessary.
   llvm::Constant *getFunctionPointer(llvm::Constant *Pointer,
-                                     QualType FunctionType,
-                                     GlobalDecl GD = GlobalDecl());
+                                     QualType FunctionType);
 
   CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T);
 
-  llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer,
-                                           const PointerAuthSchema &Schema,
-                                           llvm::Constant *StorageAddress,
-                                           GlobalDecl SchemaDecl,
-                                           QualType SchemaType);
-
   llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer,
                                            unsigned Key,
                                            llvm::Constant *StorageAddress,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 78935ab60e96f..9c851a0111b2c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1458,36 +1458,27 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts,
     Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
 }
 
-bool CompilerInvocation::setDefaultPointerAuthOptions(
+void CompilerInvocation::setDefaultPointerAuthOptions(
     PointerAuthOptions &Opts, const LangOptions &LangOpts,
     const llvm::Triple &Triple) {
-  if (Triple.getArch() == llvm::Triple::aarch64) {
-    if (LangOpts.PointerAuthCalls) {
-      using Key = PointerAuthSchema::ARM8_3Key;
-      using Discrimination = PointerAuthSchema::Discrimination;
-      // If you change anything here, be sure to update <ptrauth.h>.
-      Opts.FunctionPointers =
-          PointerAuthSchema(Key::ASIA, false, Discrimination::None);
-    }
-    return true;
+  assert(Triple.getArch() == llvm::Triple::aarch64);
+  if (LangOpts.PointerAuthCalls) {
+    using Key = PointerAuthSchema::ARM8_3Key;
+    using Discrimination = PointerAuthSchema::Discrimination;
+    // If you change anything here, be sure to update <ptrauth.h>.
+    Opts.FunctionPointers =
+        PointerAuthSchema(Key::ASIA, false, Discrimination::None);
   }
-
-  return false;
 }
 
-static bool parsePointerAuthOptions(PointerAuthOptions &Opts,
+static void parsePointerAuthOptions(PointerAuthOptions &Opts,
                                     const LangOptions &LangOpts,
                                     const llvm::Triple &Triple,
                                     DiagnosticsEngine &Diags) {
   if (!LangOpts.PointerAuthCalls)
-    return true;
-
-  if (CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple))
-    return true;
+    return;
 
-  Diags.Report(diag::err_drv_ptrauth_not_supported)
-    << Triple.str();
-  return false;
+  CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple);
 }
 
 void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
diff --git a/clang/test/CodeGen/ptrauth-function-attributes.c b/clang/test/CodeGen/ptrauth-function-attributes.c
index eda9c8813ed1e..7ec30498b9d35 100644
--- a/clang/test/CodeGen/ptrauth-function-attributes.c
+++ b/clang/test/CodeGen/ptrauth-function-attributes.c
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios                    -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,OFF
 // RUN: %clang_cc1 -triple arm64e-apple-ios                   -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,OFF
+// RUN: %clang_cc1 -triple aarch64-linux-gnu                  -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,OFF
 
 // RUN: %clang_cc1 -triple arm64-apple-ios  -fptrauth-calls   -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,CALLS
-// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls   -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,CALLS
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls  -emit-llvm %s  -o - | FileCheck %s --check-prefixes=ALL,CALLS
 
-// ALL-LABEL: define void @test() #0
+// ALL: define {{(dso_local )?}}void @test() #0
 void test() {
 }
 
diff --git a/clang/test/CodeGen/ptrauth-function-init-fail.c b/clang/test/CodeGen/ptrauth-function-init-fail.c
index 012d4f7368eaf..4522f6a14c4a8 100644
--- a/clang/test/CodeGen/ptrauth-function-init-fail.c
+++ b/clang/test/CodeGen/ptrauth-function-init-fail.c
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls %s -verify -emit-llvm -o -
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls %s -verify -emit-llvm -o -
 
 void f(void);
 
+// FIXME: We need a better diagnostic here.
 int *pf = (int *)&f + 1; // expected-error{{cannot compile this static initializer yet}}
diff --git a/clang/test/CodeGen/ptrauth-function-init.c b/clang/test/CodeGen/ptrauth-function-init.c
index 7d75f5ff2a0c3..bf8ee53364ecc 100644
--- a/clang/test/CodeGen/ptrauth-function-init.c
+++ b/clang/test/CodeGen/ptrauth-function-init.c
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 %s       -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s
+// RUN: %clang_cc1 %s       -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s
 // RUN: %clang_cc1 -xc++ %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CXX
+// RUN: %clang_cc1 -xc++ %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CXX
 
 #ifdef __cplusplus
 extern "C" {
@@ -9,15 +11,18 @@ void f(void);
 
 #ifdef __cplusplus
 
-// CXX-LABEL: define internal void @__cxx_global_var_init()
+// CXX: define {{(dso_local )?}}internal void @__cxx_global_var_init()
 // CXX: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr @_ZL2fp, align 8
 
+// This is rejected in C mode as adding a non-zero constant to a signed pointer
+// is unrepresentable in relocations. In C++ mode, this can be done dynamically
+// by the global constructor.
 __attribute__((used))
-void (*const fp)(void) = (void (*)(void))((int *)&f + 2); // Error in C mode.
+void (*const fp)(void) = (void (*)(void))((int *)&f + 2);
 
 #endif
 
-// CHECK-LABEL: define void @t1()
+// CHECK: define {{(dso_local )?}}void @t1()
 void t1() {
   // CHECK: [[PF:%.*]] = alloca ptr
   // CHECK: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr [[PF]]
diff --git a/clang/test/CodeGen/ptrauth-function-lvalue-cast.c b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c
index 8ca5490195bac..8d8af18fcafbe 100644
--- a/clang/test/CodeGen/ptrauth-function-lvalue-cast.c
+++ b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c
@@ -1,11 +1,12 @@
 // RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck %s
+// RUN: %clang_cc1 %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck %s
 
 typedef void (*fptr_t)(void);
 
 char *cptr;
 void (*fptr)(void);
 
-// CHECK-LABEL: define void @test1
+// CHECK: define {{(dso_local )?}}void @test1
 void test1() {
   // CHECK: [[LOAD:%.*]] = load ptr, ptr @cptr
   // CHECK: call void [[LOAD]]() [ "ptrauth"(i32 0, i64 0) ]
@@ -14,7 +15,7 @@ void test1() {
   (*(fptr_t)cptr)();
 }
 
-// CHECK-LABEL: define i8 @test2
+// CHECK: define {{(dso_local )?}}i8 @test2
 char test2() {
   return *(char *)fptr;
   // CHECK: [[LOAD:%.*]] = load ptr, ptr @fptr
diff --git a/clang/test/CodeGen/ptrauth-function.c b/clang/test/CodeGen/ptrauth-function.c
index dc4f270e470f9..eea3f7ed73747 100644
--- a/clang/test/CodeGen/ptrauth-function.c
+++ b/clang/test/CodeGen/ptrauth-function.c
@@ -1,21 +1,31 @@
 // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck -check-prefix=CHECK %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck -check-prefix=CHECK %s
 
 void test_call();
 
-// CHECK-LABEL: define void @test_direct_call()
+// CHECK: define {{(dso_local )?}}void @test_direct_call()
 void test_direct_call() {
   // CHECK: call void @test_call(){{$}}
   test_call();
 }
 
+// CHECK: define {{(dso_local )?}}void @test_indirect_call(ptr noundef %[[FP:.*]])
+void test_indirect_call(void (*fp(void))) {
+  // CHECK: %[[FP_ADDR:.*]] = alloca ptr, align 8
+  // CHECK: store ptr %[[FP]], ptr %[[FP_ADDR]], align 8
+  // CHECK: %[[V0:.*]] = load ptr, ptr %[[FP_ADDR]], align 8
+  // CHECK: %[[CALL:.*]] = call ptr %[[V0]]() [ "ptrauth"(i32 0, i64 0) ]
+  fp();
+}
+
 void abort();
-// CHECK-LABEL: define void @test_direct_builtin_call()
+// CHECK: define {{(dso_local )?}}void @test_direct_builtin_call()
 void test_direct_builtin_call() {
   // CHECK: call void @abort() {{#[0-9]+$}}
   abort();
 }
 
-// CHECK-LABEL: define void @test_memcpy_inline(
+// CHECK-LABEL: define {{(dso_local )?}}void @test_memcpy_inline(
 // CHECK-NOT: call{{.*}}memcpy
 
 extern inline __attribute__((__always_inline__))
diff --git a/clang/test/CodeGen/ptrauth-weak_import.c b/clang/test/CodeGen/ptrauth-weak_import.c
index 2fc8530d0677f..618042d575a1c 100644
--- a/clang/test/CodeGen/ptrauth-weak_import.c
+++ b/clang/test/CodeGen/ptrauth-weak_import.c
@@ -1,8 +1,9 @@
 // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s  -o - | FileCheck %s
 
 extern void foo() __attribute__((weak_import));
 
-// CHECK-LABEL: define void @bar()
+// CHECK: define {{(dso_local )?}}void @bar()
 // CHECK: br i1 icmp ne (ptr ptrauth (ptr @foo, i32 0), ptr null), label
 void bar() {
   if (foo)
diff --git a/clang/test/CodeGenCXX/ptrauth.cpp b/clang/test/CodeGenCXX/ptrauth.cpp
index d2d3317eb4a35..b0c069f43969b 100644
--- a/clang/test/CodeGenCXX/ptrauth.cpp
+++ b/clang/test/CodeGenCXX/ptrauth.cpp
@@ -1,9 +1,10 @@
 // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm -std=c++11 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s
 
 void f(void);
 auto &f_ref = f;
 
-// CHECK-LABEL: define void @_Z1gv(
+// CHECK: define {{(dso_local )?}}void @_Z1gv(
 // CHECK: call void ptrauth (ptr @_Z1fv, i32 0)() [ "ptrauth"(i32 0, i64 0) ]
 
 void g() { f_ref(); }
@@ -14,7 +15,7 @@ void test_terminate() noexcept {
   foo1();
 }
 
-// CHECK: define void @_ZSt9terminatev() #[[ATTR4:.*]] {
+// CHECK: define {{(dso_local )?}}void @_ZSt9terminatev() #[[ATTR4:.*]] {
 
 namespace std {
   void terminate() noexcept {
diff --git a/clang/test/Driver/ptrauth.c b/clang/test/Driver/ptrauth.c
deleted file mode 100644
index a12b451a7ee0d..0000000000000
--- a/clang/test/Driver/ptrauth.c
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang -target arm64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS
-// RUN: %clang -target aarch64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS
-// RUN: %clang -target aarch64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS
-// RUN: not %clang -target x86_64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID
-// RUN: not %clang -target x86_64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID
-// RUN: not %clang -target x86_64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID
-
-// PTRAUTH_CALLS: "-fptrauth-calls"
-// INVALID: unsupported option '-fptrauth-calls'



More information about the llvm-branch-commits mailing list