ab created this revision.
ab added reviewers: rjmccall, ahatanak, bruno, pcc, apazos, kristof.beyls, 
t.p.northover, pbarrio, chill, danielkiss, psmith.
ab added a project: clang.
Herald added subscribers: dexonsmith, zzheng, dang, mgorny.
ab requested review of this revision.

Building on D90868 <https://reviews.llvm.org/D90868>, this defines the basic 
set of pointer authentication clang builtins (provided in a new header, 
`ptrauth.h`), with diagnostics and IRGen support.
The availability of the builtins is gated on a new flag `-fptrauth-intrinsics`, 
which is enabled by default by the driver for darwin arm64e.

Note that this only includes the basic intrinsics (matching D90868 
<https://reviews.llvm.org/D90868>), and notably excludes 
`ptrauth_sign_constant`, and 
`ptrauth_type_discriminator`/`ptrauth_string_discriminator`, which need extra 
logic to be fully supported.  If it helps, I can bring the header/sema support 
here so that we can review all builtins together, and do full IRGen later.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D112941

Files:
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/Features.def
  clang/include/clang/Basic/LangOptions.def
  clang/include/clang/Basic/TargetInfo.h
  clang/include/clang/Driver/Options.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Basic/Module.cpp
  clang/lib/Basic/TargetInfo.cpp
  clang/lib/Basic/Targets/AArch64.cpp
  clang/lib/Basic/Targets/AArch64.h
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Driver/ToolChains/Darwin.cpp
  clang/lib/Driver/ToolChains/Darwin.h
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Headers/CMakeLists.txt
  clang/lib/Headers/module.modulemap
  clang/lib/Headers/ptrauth.h
  clang/lib/Sema/SemaChecking.cpp
  clang/test/CodeGen/ptrauth-intrinsics.c
  clang/test/Driver/arch-arm64e.c
  clang/test/Modules/Inputs/ptrauth-include-from-darwin/module.modulemap
  clang/test/Modules/Inputs/ptrauth-include-from-darwin/ptrauth.h
  clang/test/Modules/Inputs/ptrauth-include-from-darwin/stddef.h
  clang/test/Modules/ptrauth-include-from-darwin.m
  clang/test/Preprocessor/ptrauth_feature.c
  clang/test/Sema/ptrauth-intrinsics-macro.c
  clang/test/Sema/ptrauth.c

Index: clang/test/Sema/ptrauth.c
===================================================================
--- /dev/null
+++ clang/test/Sema/ptrauth.c
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s
+
+#if __has_feature(ptrauth_intrinsics)
+#warning Pointer authentication enabled!
+// expected-warning@-1 {{Pointer authentication enabled!}}
+#endif
+
+#if __aarch64__
+#define VALID_CODE_KEY 0
+#define VALID_DATA_KEY 2
+#define INVALID_KEY 200
+#else
+#error Provide these constants if you port this test
+#endif
+
+#define NULL ((void*) 0)
+struct A { int x; } mismatched_type;
+
+extern int dv;
+extern int fv(int);
+
+void test_strip(int *dp, int (*fp)(int)) {
+  __builtin_ptrauth_strip(dp); // expected-error {{too few arguments}}
+  __builtin_ptrauth_strip(dp, VALID_DATA_KEY, dp); // expected-error {{too many arguments}}
+  (void) __builtin_ptrauth_strip(NULL, VALID_DATA_KEY); // no warning
+
+  __builtin_ptrauth_strip(mismatched_type, VALID_DATA_KEY); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+  __builtin_ptrauth_strip(dp, mismatched_type); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+
+  int *dr = __builtin_ptrauth_strip(dp, VALID_DATA_KEY);
+  dr = __builtin_ptrauth_strip(dp, INVALID_KEY); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  int (*fr)(int) = __builtin_ptrauth_strip(fp, VALID_CODE_KEY);
+  fr = __builtin_ptrauth_strip(fp, INVALID_KEY); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  float *mismatch = __builtin_ptrauth_strip(dp, VALID_DATA_KEY); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+}
+
+void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
+  __builtin_ptrauth_blend_discriminator(dp); // expected-error {{too few arguments}}
+  __builtin_ptrauth_blend_discriminator(dp, dp, dp); // expected-error {{too many arguments}}
+  (void) __builtin_ptrauth_blend_discriminator(dp, value); // no warning
+
+  __builtin_ptrauth_blend_discriminator(mismatched_type, value); // expected-error {{blended pointer must have pointer type; type here is 'struct A'}}
+  __builtin_ptrauth_blend_discriminator(dp, mismatched_type); // expected-error {{blended integer must have integer type; type here is 'struct A'}}
+
+  float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-warning {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
+}
+
+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}}
+
+  __builtin_ptrauth_sign_unauthenticated(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+  __builtin_ptrauth_sign_unauthenticated(dp, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+  __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+
+  (void) __builtin_ptrauth_sign_unauthenticated(NULL, VALID_DATA_KEY, 0); // expected-warning {{signing a null pointer will yield a non-null pointer}}
+
+  int *dr = __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0);
+  dr = __builtin_ptrauth_sign_unauthenticated(dp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  int (*fr)(int) = __builtin_ptrauth_sign_unauthenticated(fp, VALID_CODE_KEY, 0);
+  fr = __builtin_ptrauth_sign_unauthenticated(fp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  float *mismatch = __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+}
+
+void test_auth(int *dp, int (*fp)(int)) {
+  __builtin_ptrauth_auth(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
+  __builtin_ptrauth_auth(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}
+
+  __builtin_ptrauth_auth(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+  __builtin_ptrauth_auth(dp, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+  __builtin_ptrauth_auth(dp, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+
+  (void) __builtin_ptrauth_auth(NULL, VALID_DATA_KEY, 0); // expected-warning {{authenticating a null pointer will almost certainly trap}}
+
+  int *dr = __builtin_ptrauth_auth(dp, VALID_DATA_KEY, 0);
+  dr = __builtin_ptrauth_auth(dp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  int (*fr)(int) = __builtin_ptrauth_auth(fp, VALID_CODE_KEY, 0);
+  fr = __builtin_ptrauth_auth(fp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  float *mismatch = __builtin_ptrauth_auth(dp, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+}
+
+void test_auth_and_resign(int *dp, int (*fp)(int)) {
+  __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY); // expected-error {{too few arguments}}
+  __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp, 0); // expected-error {{too many arguments}}
+
+  __builtin_ptrauth_auth_and_resign(mismatched_type, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+  __builtin_ptrauth_auth_and_resign(dp, mismatched_type, 0, VALID_DATA_KEY, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+  __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, mismatched_type, VALID_DATA_KEY, dp); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+  __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, mismatched_type, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+  __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+
+  (void) __builtin_ptrauth_auth_and_resign(NULL, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{authenticating a null pointer will almost certainly trap}}
+
+  int *dr = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp);
+  dr = __builtin_ptrauth_auth_and_resign(dp, INVALID_KEY, 0, VALID_DATA_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+  dr = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  int (*fr)(int) = __builtin_ptrauth_auth_and_resign(fp, VALID_CODE_KEY, 0, VALID_CODE_KEY, dp);
+  fr = __builtin_ptrauth_auth_and_resign(fp, INVALID_KEY, 0, VALID_CODE_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+  fr = __builtin_ptrauth_auth_and_resign(fp, VALID_CODE_KEY, 0, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+  float *mismatch = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+}
+
+void test_sign_generic_data(int *dp) {
+  __builtin_ptrauth_sign_generic_data(dp); // expected-error {{too few arguments}}
+  __builtin_ptrauth_sign_generic_data(dp, 0, 0); // expected-error {{too many arguments}}
+
+  __builtin_ptrauth_sign_generic_data(mismatched_type, 0); // expected-error {{signed value must have pointer or integer type; type here is 'struct A'}}
+  __builtin_ptrauth_sign_generic_data(dp, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+
+  (void) __builtin_ptrauth_sign_generic_data(NULL, 0); // no warning
+
+  unsigned long dr = __builtin_ptrauth_sign_generic_data(dp, 0);
+  dr = __builtin_ptrauth_sign_generic_data(dp, &dv);
+  dr = __builtin_ptrauth_sign_generic_data(12314, 0);
+  dr = __builtin_ptrauth_sign_generic_data(12314, &dv);
+
+  int *mismatch = __builtin_ptrauth_sign_generic_data(dp, 0); // expected-warning {{incompatible integer to pointer conversion initializing 'int *' with an expression of type}}
+}
Index: clang/test/Sema/ptrauth-intrinsics-macro.c
===================================================================
--- /dev/null
+++ clang/test/Sema/ptrauth-intrinsics-macro.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -Wall -fsyntax-only -verify -fptrauth-intrinsics %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -Wall -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+#include <ptrauth.h>
+
+#define VALID_CODE_KEY 0
+#define VALID_DATA_KEY 2
+
+extern int dv;
+
+void test(int *dp, int value) {
+  dp = ptrauth_strip(dp, VALID_DATA_KEY);
+  ptrauth_extra_data_t t0 = ptrauth_blend_discriminator(dp, value);
+  (void)t0;
+  dp = ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0);
+  dp = ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp);
+  dp = ptrauth_auth_data(dp, VALID_DATA_KEY, 0);
+  int pu0 = 0, pu1 = 0, pu2 = 0, pu3 = 0, pu4 = 0, pu5 = 0, pu6 = 0, pu7 = 0;
+  ptrauth_blend_discriminator(&pu0, value);
+  ptrauth_auth_and_resign(&pu1, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp);
+  ptrauth_auth_and_resign(dp, VALID_DATA_KEY, &pu2, VALID_DATA_KEY, dp);
+  ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, &pu3);
+  ptrauth_sign_generic_data(pu4, dp);
+  ptrauth_sign_generic_data(dp, pu5);
+  ptrauth_auth_data(&pu6, VALID_DATA_KEY, value);
+  ptrauth_auth_data(dp, VALID_DATA_KEY, pu7);
+
+
+
+  int t2 = ptrauth_sign_generic_data(dp, 0);
+  (void)t2;
+}
Index: clang/test/Preprocessor/ptrauth_feature.c
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/ptrauth_feature.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -E -triple=arm64-- | FileCheck %s --check-prefixes=NOINTRIN
+// RUN: %clang_cc1 %s -E -triple=arm64-- -fptrauth-intrinsics | FileCheck %s --check-prefixes=INTRIN
+
+#if __has_feature(ptrauth_intrinsics)
+// INTRIN: has_ptrauth_intrinsics
+void has_ptrauth_intrinsics() {}
+#else
+// NOINTRIN: no_ptrauth_intrinsics
+void no_ptrauth_intrinsics() {}
+#endif
Index: clang/test/Modules/ptrauth-include-from-darwin.m
===================================================================
--- /dev/null
+++ clang/test/Modules/ptrauth-include-from-darwin.m
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/ptrauth-include-from-darwin %s -verify
+// expected-no-diagnostics
+
+@import libc;
+void bar() { foo(); }
Index: clang/test/Modules/Inputs/ptrauth-include-from-darwin/stddef.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/ptrauth-include-from-darwin/stddef.h
@@ -0,0 +1 @@
+@import ptrauth;
Index: clang/test/Modules/Inputs/ptrauth-include-from-darwin/ptrauth.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/ptrauth-include-from-darwin/ptrauth.h
@@ -0,0 +1 @@
+void foo();
Index: clang/test/Modules/Inputs/ptrauth-include-from-darwin/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/ptrauth-include-from-darwin/module.modulemap
@@ -0,0 +1,8 @@
+module libc [no_undeclared_includes] {
+  module stddef { header "stddef.h" export * }
+}
+
+module ptrauth {
+  header "ptrauth.h"
+  export *
+}
Index: clang/test/Driver/arch-arm64e.c
===================================================================
--- /dev/null
+++ clang/test/Driver/arch-arm64e.c
@@ -0,0 +1,22 @@
+// Check that we can manually enable specific ptrauth features.
+
+// RUN: %clang -target arm64-apple-ios -c %s -### 2>&1 | FileCheck %s --check-prefix NONE
+// NONE: "-cc1"
+// NONE-NOT: "-fptrauth-intrinsics"
+
+// RUN: %clang -target arm64-apple-ios -fptrauth-intrinsics -c %s -### 2>&1 | FileCheck %s --check-prefix INTRIN
+// INTRIN: "-cc1"{{.*}} {{.*}} "-fptrauth-intrinsics"
+
+
+// Check the arm64e defaults.
+
+// RUN: %clang -target arm64e-apple-ios -c %s -### 2>&1 | FileCheck %s --check-prefix DEFAULT
+// RUN: %clang -mkernel -target arm64e-apple-ios -c %s -### 2>&1 | FileCheck %s --check-prefix DEFAULT-KERN
+// RUN: %clang -fapple-kext -target arm64e-apple-ios -c %s -### 2>&1 | FileCheck %s --check-prefix DEFAULT-KERN
+// DEFAULT: "-fptrauth-intrinsics" "-target-cpu" "apple-a12"{{.*}}
+// DEFAULT-KERN: "-fptrauth-intrinsics" "-target-cpu" "apple-a12"{{.*}}
+
+// RUN: %clang -target arm64e-apple-ios -fno-ptrauth-intrinsics -c %s -### 2>&1 | FileCheck %s --check-prefix NOINTRIN
+
+// NOINTRIN-NOT: "-fptrauth-intrinsics"
+// NOINTRIN: "-target-cpu" "apple-a12"{{.*}}
Index: clang/test/CodeGen/ptrauth-intrinsics.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/ptrauth-intrinsics.c
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -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()
+void test_auth() {
+  // CHECK:      [[PTR:%.*]] = load void ()*, void ()** @fnptr,
+  // CHECK-NEXT: [[DISC0:%.*]] = load i8*, i8** @ptr_discriminator,
+  // CHECK-NEXT: [[T0:%.*]] = ptrtoint void ()* [[PTR]] to i64
+  // CHECK-NEXT: [[DISC:%.*]] = ptrtoint i8* [[DISC0]] to i64
+  // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 0, i64 [[DISC]])
+  // CHECK-NEXT: [[RESULT:%.*]] = inttoptr  i64 [[T1]] to void ()*
+  // CHECK-NEXT: store void ()* [[RESULT]], void ()** @fnptr,
+  fnptr = __builtin_ptrauth_auth(fnptr, 0, ptr_discriminator);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_strip()
+void test_strip() {
+  // CHECK:      [[PTR:%.*]] = load void ()*, void ()** @fnptr,
+  // CHECK-NEXT: [[T0:%.*]] = ptrtoint void ()* [[PTR]] to i64
+  // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[T0]], i32 0)
+  // CHECK-NEXT: [[RESULT:%.*]] = inttoptr  i64 [[T1]] to void ()*
+  // CHECK-NEXT: store void ()* [[RESULT]], void ()** @fnptr,
+  fnptr = __builtin_ptrauth_strip(fnptr, 0);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_sign_unauthenticated()
+void test_sign_unauthenticated() {
+  // CHECK:      [[PTR:%.*]] = load void ()*, void ()** @fnptr,
+  // CHECK-NEXT: [[DISC0:%.*]] = load i8*, i8** @ptr_discriminator,
+  // CHECK-NEXT: [[T0:%.*]] = ptrtoint void ()* [[PTR]] to i64
+  // CHECK-NEXT: [[DISC:%.*]] = ptrtoint i8* [[DISC0]] to i64
+  // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[T0]], i32 0, i64 [[DISC]])
+  // CHECK-NEXT: [[RESULT:%.*]] = inttoptr  i64 [[T1]] to void ()*
+  // CHECK-NEXT: store void ()* [[RESULT]], void ()** @fnptr,
+  fnptr = __builtin_ptrauth_sign_unauthenticated(fnptr, 0, ptr_discriminator);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_auth_and_resign()
+void test_auth_and_resign() {
+  // CHECK:      [[PTR:%.*]] = load void ()*, void ()** @fnptr,
+  // CHECK-NEXT: [[DISC0:%.*]] = load i8*, i8** @ptr_discriminator,
+  // CHECK-NEXT: [[T0:%.*]] = ptrtoint void ()* [[PTR]] to i64
+  // CHECK-NEXT: [[DISC:%.*]] = ptrtoint i8* [[DISC0]] to i64
+  // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 0, i64 [[DISC]], i32 3, i64 15)
+  // CHECK-NEXT: [[RESULT:%.*]] = inttoptr  i64 [[T1]] to void ()*
+  // CHECK-NEXT: store void ()* [[RESULT]], void ()** @fnptr,
+  fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_blend_discriminator()
+void test_blend_discriminator() {
+  // CHECK:      [[PTR:%.*]] = load void ()*, void ()** @fnptr,
+  // CHECK-NEXT: [[DISC:%.*]] = load i64, i64* @int_discriminator,
+  // CHECK-NEXT: [[T0:%.*]] = ptrtoint void ()* [[PTR]] to i64
+  // CHECK-NEXT: [[RESULT:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 [[DISC]])
+  // CHECK-NEXT: store i64 [[RESULT]], i64* @int_discriminator,
+  int_discriminator = __builtin_ptrauth_blend_discriminator(fnptr, int_discriminator);
+}
+
+// CHECK-LABEL: define{{.*}} void @test_sign_generic_data()
+void test_sign_generic_data() {
+  // CHECK:      [[PTR:%.*]] = load void ()*, void ()** @fnptr,
+  // CHECK-NEXT: [[DISC0:%.*]] = load i8*, i8** @ptr_discriminator,
+  // CHECK-NEXT: [[T0:%.*]] = ptrtoint void ()* [[PTR]] to i64
+  // CHECK-NEXT: [[DISC:%.*]] = ptrtoint i8* [[DISC0]] to i64
+  // CHECK-NEXT: [[RESULT:%.*]] = call i64 @llvm.ptrauth.sign.generic(i64 [[T0]], i64 [[DISC]])
+  // CHECK-NEXT: store i64 [[RESULT]], i64* @signature,
+  signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
+}
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -129,6 +129,20 @@
     << call->getArg(1)->getSourceRange();
 }
 
+static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) {
+  if (Value->isTypeDependent())
+    return false;
+
+  InitializedEntity Entity =
+    InitializedEntity::InitializeParameter(S.Context, Ty, false);
+  ExprResult Result =
+    S.PerformCopyInitialization(Entity, SourceLocation(), Value);
+  if (Result.isInvalid())
+    return true;
+  Value = Result.get();
+  return false;
+}
+
 /// Check that the first argument to __builtin_annotation is an integer
 /// and the second argument is a non-wide string literal.
 static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
@@ -1329,6 +1343,184 @@
   return false;
 }
 
+namespace {
+  enum PointerAuthOpKind {
+    PAO_Strip, PAO_Sign, PAO_Auth, PAO_SignGeneric, PAO_Discriminator,
+    PAO_BlendPointer, PAO_BlendInteger
+  };
+}
+
+static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
+  if (S.getLangOpts().PointerAuthIntrinsics)
+    return false;
+
+  S.diagnosePointerAuthDisabled(E->getExprLoc(), E->getSourceRange());
+  return true;
+}
+
+void Sema::diagnosePointerAuthDisabled(SourceLocation loc, SourceRange range) {
+  if (!Context.getTargetInfo().isPointerAuthSupported()) {
+    Diag(loc, diag::err_ptrauth_disabled_target) << range;
+  } else {
+    Diag(loc, diag::err_ptrauth_disabled) << range;
+  }
+}
+
+static bool checkPointerAuthKey(Sema &S, Expr *&Arg) {
+  // Convert it to type 'int'.
+  if (convertArgumentToType(S, Arg, S.Context.IntTy))
+    return true;
+
+  // Value-dependent expressions are okay; wait for template instantiation.
+  if (Arg->isValueDependent())
+    return false;
+
+  unsigned KeyValue;
+  return S.checkConstantPointerAuthKey(Arg, KeyValue);
+}
+
+bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
+  // Attempt to constant-evaluate the expression.
+  Optional<llvm::APSInt> KeyValue = Arg->getIntegerConstantExpr(Context);
+  if (!KeyValue) {
+    Diag(Arg->getExprLoc(), diag::err_expr_not_ice) << 0
+      << Arg->getSourceRange();
+    return true;
+  }
+
+  // Ask the target to validate the key parameter.
+  if (!Context.getTargetInfo().validatePointerAuthKey(*KeyValue)) {
+    llvm::SmallString<32> Value; {
+      llvm::raw_svector_ostream Str(Value);
+      Str << *KeyValue;
+    }
+
+    Diag(Arg->getExprLoc(), diag::err_ptrauth_invalid_key)
+      << Value << Arg->getSourceRange();
+    return true;
+  }
+
+  Result = KeyValue->getZExtValue();
+  return false;
+}
+
+static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
+                                  PointerAuthOpKind OpKind) {
+  if (Arg->hasPlaceholderType()) {
+    ExprResult R = S.CheckPlaceholderExpr(Arg);
+    if (R.isInvalid()) return true;
+    Arg = R.get();
+  }
+
+  auto allowsPointer = [](PointerAuthOpKind OpKind) {
+    return OpKind != PAO_BlendInteger;
+  };
+  auto allowsInteger = [](PointerAuthOpKind OpKind) {
+    return OpKind == PAO_Discriminator ||
+           OpKind == PAO_BlendInteger ||
+           OpKind == PAO_SignGeneric;
+  };
+
+  // Require the value to have the right range of type.
+  QualType ExpectedTy;
+  if (allowsPointer(OpKind) && Arg->getType()->isPointerType()) {
+    ExpectedTy = Arg->getType().getUnqualifiedType();
+  } else if (allowsPointer(OpKind) && Arg->getType()->isNullPtrType()) {
+    ExpectedTy = S.Context.VoidPtrTy;
+  } else if (allowsInteger(OpKind) &&
+             Arg->getType()->isIntegralOrUnscopedEnumerationType()) {
+    ExpectedTy = S.Context.getUIntPtrType();
+
+  // Diagnose the failures.
+  } else {
+    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_value_bad_type)
+      << unsigned(OpKind == PAO_Discriminator ? 1 :
+                  OpKind == PAO_BlendPointer ? 2 :
+                  OpKind == PAO_BlendInteger ? 3 : 0)
+      << unsigned(allowsInteger(OpKind) ?
+                    (allowsPointer(OpKind) ? 2 : 1) : 0)
+      << Arg->getType()
+      << Arg->getSourceRange();
+    return true;
+  }
+
+  // Convert to that type.  This should just be an lvalue-to-rvalue
+  // conversion.
+  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();
+  }
+
+  return false;
+}
+
+static ExprResult SemaPointerAuthStrip(Sema &S, CallExpr *Call) {
+  if (checkArgCount(S, Call, 2)) return ExprError();
+  if (checkPointerAuthEnabled(S, Call)) return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Strip) |
+      checkPointerAuthKey(S, Call->getArgs()[1]))
+    return ExprError();
+
+  Call->setType(Call->getArgs()[0]->getType());
+  return Call;
+}
+
+static ExprResult SemaPointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) {
+  if (checkArgCount(S, Call, 2)) return ExprError();
+  if (checkPointerAuthEnabled(S, Call)) return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_BlendPointer) |
+      checkPointerAuthValue(S, Call->getArgs()[1], PAO_BlendInteger))
+    return ExprError();
+
+  Call->setType(S.Context.getUIntPtrType());
+  return Call;
+}
+
+static ExprResult SemaPointerAuthSignGenericData(Sema &S, CallExpr *Call) {
+  if (checkArgCount(S, Call, 2)) return ExprError();
+  if (checkPointerAuthEnabled(S, Call)) return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_SignGeneric) |
+      checkPointerAuthValue(S, Call->getArgs()[1], PAO_Discriminator))
+    return ExprError();
+
+  Call->setType(S.Context.getUIntPtrType());
+  return Call;
+}
+
+static ExprResult SemaPointerAuthSignOrAuth(Sema &S, CallExpr *Call,
+                                            PointerAuthOpKind OpKind) {
+  if (checkArgCount(S, Call, 3)) return ExprError();
+  if (checkPointerAuthEnabled(S, Call)) return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind) |
+      checkPointerAuthKey(S, Call->getArgs()[1]) |
+      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator))
+    return ExprError();
+
+  Call->setType(Call->getArgs()[0]->getType());
+  return Call;
+}
+
+static ExprResult SemaPointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
+  if (checkArgCount(S, Call, 5)) return ExprError();
+  if (checkPointerAuthEnabled(S, Call)) return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) |
+      checkPointerAuthKey(S, Call->getArgs()[1]) |
+      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) |
+      checkPointerAuthKey(S, Call->getArgs()[3]) |
+      checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator))
+    return ExprError();
+
+  Call->setType(Call->getArgs()[0]->getType());
+  return Call;
+}
+
 static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
   if (checkArgCount(S, TheCall, 1))
     return ExprError();
@@ -1890,6 +2082,18 @@
 
     TheCall->setType(Context.VoidPtrTy);
     break;
+  case Builtin::BI__builtin_ptrauth_strip:
+    return SemaPointerAuthStrip(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_blend_discriminator:
+    return SemaPointerAuthBlendDiscriminator(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
+    return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Sign);
+  case Builtin::BI__builtin_ptrauth_auth:
+    return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Auth);
+  case Builtin::BI__builtin_ptrauth_sign_generic_data:
+    return SemaPointerAuthSignGenericData(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_auth_and_resign:
+    return SemaPointerAuthAuthAndResign(*this, TheCall);
   // OpenCL v2.0, s6.13.16 - Pipe functions
   case Builtin::BIread_pipe:
   case Builtin::BIwrite_pipe:
Index: clang/lib/Headers/ptrauth.h
===================================================================
--- /dev/null
+++ clang/lib/Headers/ptrauth.h
@@ -0,0 +1,167 @@
+/*===---- ptrauth.h - 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
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __PTRAUTH_H
+#define __PTRAUTH_H
+
+typedef enum {
+  ptrauth_key_asia = 0,
+  ptrauth_key_asib = 1,
+  ptrauth_key_asda = 2,
+  ptrauth_key_asdb = 3,
+
+  /* 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,
+
+} ptrauth_key;
+
+/* An integer type of the appropriate size for a discriminator argument. */
+typedef __UINTPTR_TYPE__ ptrauth_extra_data_t;
+
+/* An integer type of the appropriate size for a generic signature. */
+typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
+
+/* A signed pointer value embeds the original pointer together with
+   a signature that attests to the validity of that pointer.  Because
+   this signature must use only "spare" bits of the pointer, a
+   signature's validity is probabilistic in practice: it is unlikely
+   but still plausible that an invalidly-derived signature will
+   somehow equal the correct signature and therefore successfully
+   authenticate.  Nonetheless, this scheme provides a strong degree
+   of protection against certain kinds of attacks. */
+
+/* Authenticating a pointer that was not signed with the given key
+   and extra-data value will (likely) fail by trapping. */
+
+#if __has_feature(ptrauth_intrinsics)
+
+/* Strip the signature from a value without authenticating it.
+
+   If the value is a function pointer, the result will not be a
+   legal function pointer because of the missing signature, and
+   attempting to call it will result in an authentication failure.
+
+   The value must be an expression of pointer type.
+   The key must be a constant expression of type ptrauth_key.
+   The result will have the same type as the original value. */
+#define ptrauth_strip(__value, __key) \
+  __builtin_ptrauth_strip(__value, __key)
+
+/* Blend a constant discriminator into the given pointer-like value
+   to form a new discriminator.  Not all bits of the inputs are
+   guaranteed to contribute to the result.
+
+   On arm64e, the integer must fall within the range of a uint16_t;
+   other bits may be ignored.
+
+   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.
+
+   This operation does not authenticate the original value and is
+   therefore potentially insecure if an attacker could possibly
+   control that value.
+
+   The value must be an expression of 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. */
+#define ptrauth_sign_unauthenticated(__value, __key, __data) \
+  __builtin_ptrauth_sign_unauthenticated(__value, __key, __data)
+
+/* Authenticate a pointer using one scheme and resign it using another.
+
+   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 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.
+
+   Do not pass a null pointer to this function. A null pointer
+   will not successfully authenticate. */
+#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data) \
+  __builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data)
+
+/* Authenticate a data pointer.
+
+   The value must be an expression of non-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.
+
+   If the authentication fails, dereferencing the resulting pointer
+   will fail. */
+#define ptrauth_auth_data(__value, __old_key, __old_data) \
+  __builtin_ptrauth_auth(__value, __old_key, __old_data)
+
+/* Compute a signature for the given pair of pointer-sized values.
+   The order of the arguments is significant.
+
+   Like a pointer signature, the resulting signature depends on
+   private key data and therefore should not be reliably reproducible
+   by attackers.  That means that this can be used to validate the
+   integrity of arbitrary data by storing a signature for that data
+   alongside it, then checking that the signature is still valid later.
+   Data which exceeds two pointers in size can be signed by either
+   computing a tree of generic signatures or just signing an ordinary
+   cryptographic hash of the data.
+
+   The result has type ptrauth_generic_signature_t.  However, it may
+   not have as many bits of entropy as that type's width would suggest;
+   some implementations are known to compute a compressed signature as
+   if the arguments were a pointer and a discriminator.
+
+   The arguments must be either pointers or integers; if integers, they
+   will be coerce to uintptr_t. */
+#define ptrauth_sign_generic_data(__value, __data) \
+  __builtin_ptrauth_sign_generic_data(__value, __data)
+
+#else
+
+#define ptrauth_strip(__value, __key) ({(void)__key; __value;})
+#define ptrauth_blend_discriminator(__pointer, __integer) ({(void)__pointer; (void)__integer; ((ptrauth_extra_data_t)0);})
+#define ptrauth_sign_unauthenticated(__value, __key, __data) ({(void)__key; (void)__data; __value;})
+#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, __new_data) ({(void)__old_key; (void)__old_data; (void)__new_key; (void)__new_data; __value;})
+#define ptrauth_auth_data(__value, __old_key, __old_data) ({(void)__old_key;(void)__old_data;__value;})
+#define ptrauth_sign_generic_data(__value, __data) ({(void)__value;(void)__data;((ptrauth_generic_signature_t)0);})
+
+#endif /* __has_feature(ptrauth_intrinsics) */
+
+#endif /* __PTRAUTH_H */
Index: clang/lib/Headers/module.modulemap
===================================================================
--- clang/lib/Headers/module.modulemap
+++ clang/lib/Headers/module.modulemap
@@ -162,3 +162,8 @@
   header "opencl-c.h"
   header "opencl-c-base.h"
 }
+
+module ptrauth {
+  header "ptrauth.h"
+  export *
+}
Index: clang/lib/Headers/CMakeLists.txt
===================================================================
--- clang/lib/Headers/CMakeLists.txt
+++ clang/lib/Headers/CMakeLists.txt
@@ -103,6 +103,7 @@
   pconfigintrin.h
   popcntintrin.h
   prfchwintrin.h
+  ptrauth.h
   ptwriteintrin.h
   rdseedintrin.h
   rtmintrin.h
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -3103,6 +3103,18 @@
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 
+static void GeneratePointerAuthArgs(LangOptions &Opts,
+                                    SmallVectorImpl<const char *> &Args,
+                                    CompilerInvocation::StringAllocator SA) {
+  if (Opts.PointerAuthIntrinsics)
+    GenerateArg(Args, OPT_fptrauth_intrinsics, SA);
+}
+
+static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
+                                 DiagnosticsEngine &Diags) {
+  Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
+}
+
 void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
                                          const llvm::Triple &T,
                                          std::vector<std::string> &Includes,
@@ -4464,6 +4476,7 @@
   llvm::Triple T(Res.getTargetOpts().Triple);
   ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags,
                         Res.getFileSystemOpts().WorkingDir);
+  ParsePointerAuthArgs(LangOpts, Args, Diags);
 
   ParseLangArgs(LangOpts, Args, DashX, T, Res.getPreprocessorOpts().Includes,
                 Diags);
@@ -4645,6 +4658,7 @@
   GenerateFrontendArgs(FrontendOpts, Args, SA, LangOpts->IsHeaderFile);
   GenerateTargetArgs(*TargetOpts, Args, SA);
   GenerateHeaderSearchArgs(*HeaderSearchOpts, Args, SA);
+  GeneratePointerAuthArgs(*LangOpts, Args, SA);
   GenerateLangArgs(*LangOpts, Args, SA, T, FrontendOpts.DashX);
   GenerateCodeGenArgs(CodeGenOpts, Args, SA, T, FrontendOpts.OutputFile,
                       &*LangOpts);
Index: clang/lib/Driver/ToolChains/Darwin.h
===================================================================
--- clang/lib/Driver/ToolChains/Darwin.h
+++ clang/lib/Driver/ToolChains/Darwin.h
@@ -579,6 +579,10 @@
 
   void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
 
+  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+                             llvm::opt::ArgStringList &CC1Args,
+                             Action::OffloadKind DeviceOffloadKind) const override;
+
   void AddLinkARCArgs(const llvm::opt::ArgList &Args,
                       llvm::opt::ArgStringList &CmdArgs) const override;
 
Index: clang/lib/Driver/ToolChains/Darwin.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Darwin.cpp
+++ clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1061,6 +1061,20 @@
   }
 }
 
+void DarwinClang::addClangTargetOptions(
+  const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+  Action::OffloadKind DeviceOffloadKind) const{
+
+  Darwin::addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadKind);
+
+  // On arm64e, enable pointer authentication intrinsics.
+  if (getTriple().isArm64e()) {
+    if (!DriverArgs.hasArg(options::OPT_fptrauth_intrinsics,
+                           options::OPT_fno_ptrauth_intrinsics))
+      CC1Args.push_back("-fptrauth-intrinsics");
+  }
+}
+
 /// Take a path that speculatively points into Xcode and return the
 /// `XCODE/Contents/Developer` path if it is an Xcode path, or an empty path
 /// otherwise.
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -6470,6 +6470,11 @@
   if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false))
     CmdArgs.push_back("-fcommon");
 
+  if (Args.hasFlag(options::OPT_fptrauth_intrinsics,
+                   options::OPT_fno_ptrauth_intrinsics, false))
+    CmdArgs.push_back("-fptrauth-intrinsics");
+
+
   // -fsigned-bitfields is default, and clang doesn't yet support
   // -funsigned-bitfields.
   if (!Args.hasFlag(options::OPT_fsigned_bitfields,
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -4568,6 +4568,73 @@
   case Builtin::BI__iso_volatile_store64:
     return RValue::get(EmitISOVolatileStore(*this, E));
 
+  case Builtin::BI__builtin_ptrauth_auth:
+  case Builtin::BI__builtin_ptrauth_auth_and_resign:
+  case Builtin::BI__builtin_ptrauth_blend_discriminator:
+  case Builtin::BI__builtin_ptrauth_sign_generic_data:
+  case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
+  case Builtin::BI__builtin_ptrauth_strip: {
+    // Emit the arguments.
+    SmallVector<llvm::Value*, 5> args;
+    for (auto argExpr : E->arguments())
+      args.push_back(EmitScalarExpr(argExpr));
+
+    // Cast the value to intptr_t, saving its original type.
+    llvm::Type *origValueType = args[0]->getType();
+    if (origValueType->isPointerTy())
+      args[0] = Builder.CreatePtrToInt(args[0], IntPtrTy);
+
+    switch (BuiltinID) {
+      case Builtin::BI__builtin_ptrauth_auth_and_resign:
+        if (args[4]->getType()->isPointerTy())
+          args[4] = Builder.CreatePtrToInt(args[4], IntPtrTy);
+        LLVM_FALLTHROUGH;
+
+      case Builtin::BI__builtin_ptrauth_auth:
+      case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
+        if (args[2]->getType()->isPointerTy())
+          args[2] = Builder.CreatePtrToInt(args[2], IntPtrTy);
+        break;
+
+      case Builtin::BI__builtin_ptrauth_sign_generic_data:
+        if (args[1]->getType()->isPointerTy())
+          args[1] = Builder.CreatePtrToInt(args[1], IntPtrTy);
+        break;
+
+      case Builtin::BI__builtin_ptrauth_blend_discriminator:
+      case Builtin::BI__builtin_ptrauth_strip:
+        break;
+    }
+
+    // Call the intrinsic.
+    auto intrinsicID = [&]() -> unsigned {
+      switch (BuiltinID) {
+      case Builtin::BI__builtin_ptrauth_auth:
+        return llvm::Intrinsic::ptrauth_auth;
+      case Builtin::BI__builtin_ptrauth_auth_and_resign:
+        return llvm::Intrinsic::ptrauth_resign;
+      case Builtin::BI__builtin_ptrauth_blend_discriminator:
+        return llvm::Intrinsic::ptrauth_blend;
+      case Builtin::BI__builtin_ptrauth_sign_generic_data:
+        return llvm::Intrinsic::ptrauth_sign_generic;
+      case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
+        return llvm::Intrinsic::ptrauth_sign;
+      case Builtin::BI__builtin_ptrauth_strip:
+        return llvm::Intrinsic::ptrauth_strip;
+      }
+      llvm_unreachable("bad ptrauth intrinsic");
+    }();
+    auto intrinsic = CGM.getIntrinsic(intrinsicID);
+    llvm::Value *result = EmitRuntimeCall(intrinsic, args);
+
+    if (BuiltinID != Builtin::BI__builtin_ptrauth_sign_generic_data &&
+        BuiltinID != Builtin::BI__builtin_ptrauth_blend_discriminator &&
+        origValueType->isPointerTy()) {
+      result = Builder.CreateIntToPtr(result, origValueType);
+    }
+    return RValue::get(result);
+  }
+
   case Builtin::BI__exception_code:
   case Builtin::BI_exception_code:
     return RValue::get(EmitSEHExceptionCode());
Index: clang/lib/Basic/Targets/AArch64.h
===================================================================
--- clang/lib/Basic/Targets/AArch64.h
+++ clang/lib/Basic/Targets/AArch64.h
@@ -147,6 +147,8 @@
 
   int getEHDataRegisterNumber(unsigned RegNo) const override;
 
+  bool validatePointerAuthKey(const llvm::APSInt &value) const override;
+
   const char *getBFloat16Mangling() const override { return "u6__bf16"; };
   bool hasInt128Type() const override;
 
Index: clang/lib/Basic/Targets/AArch64.cpp
===================================================================
--- clang/lib/Basic/Targets/AArch64.cpp
+++ clang/lib/Basic/Targets/AArch64.cpp
@@ -14,6 +14,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -125,6 +126,9 @@
   else if (Triple.getOS() == llvm::Triple::UnknownOS)
     this->MCountName =
         Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount";
+
+  if (Triple.isArm64e())
+    PointerAuthSupported = true;
 }
 
 StringRef AArch64TargetInfo::getABI() const { return ABI; }
@@ -838,6 +842,11 @@
   return -1;
 }
 
+bool AArch64TargetInfo::validatePointerAuthKey(
+    const llvm::APSInt &value) const {
+  return 0 <= value && value <= 3;
+}
+
 bool AArch64TargetInfo::hasInt128Type() const { return true; }
 
 AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple,
Index: clang/lib/Basic/TargetInfo.cpp
===================================================================
--- clang/lib/Basic/TargetInfo.cpp
+++ clang/lib/Basic/TargetInfo.cpp
@@ -127,6 +127,7 @@
   HasRISCVVTypes = false;
   AllowAMDGPUUnsafeFPAtomics = false;
   ARMCDECoprocMask = 0;
+  PointerAuthSupported = false;
 
   // Default to no types using fpret.
   RealTypeUsesObjCFPRet = 0;
@@ -813,6 +814,10 @@
   return true;
 }
 
+bool TargetInfo::validatePointerAuthKey(const llvm::APSInt &value) const {
+  return false;
+}
+
 void TargetInfo::CheckFixedPointBits() const {
   // Check that the number of fractional and integral bits (and maybe sign) can
   // fit into the bits given for a fixed point type.
Index: clang/lib/Basic/Module.cpp
===================================================================
--- clang/lib/Basic/Module.cpp
+++ clang/lib/Basic/Module.cpp
@@ -282,6 +282,10 @@
   if (!Requested->Parent && Requested->Name == "_Builtin_stddef_max_align_t")
     return true;
 
+  // Anyone is allowed to use our builtin ptrauth.h and its accompanying module.
+  if (!Requested->Parent && Requested->Name == "ptrauth")
+    return true;
+
   return false;
 }
 
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2669,6 +2669,9 @@
                             SourceLocation AtomicQualLoc = SourceLocation(),
                             SourceLocation UnalignedQualLoc = SourceLocation());
 
+  void diagnosePointerAuthDisabled(SourceLocation loc, SourceRange range);
+  bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key);
+
   static bool adjustContextForLocalExternDecl(DeclContext *&DC);
   void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
   NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D,
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2862,6 +2862,14 @@
             " of a non-void function as unreachable">,
   PosFlag<SetTrue>>;
 
+let Group = f_Group in {
+  let Flags = [CC1Option] in {
+    def fptrauth_intrinsics : Flag<["-"], "fptrauth-intrinsics">,
+      HelpText<"Enable pointer-authentication intrinsics">;
+  }
+  def fno_ptrauth_intrinsics : Flag<["-"], "fno-ptrauth-intrinsics">;
+}
+
 def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
     Flags<[CC1Option]>,
     HelpText<"Enable matrix data type and related builtin functions">,
Index: clang/include/clang/Basic/TargetInfo.h
===================================================================
--- clang/include/clang/Basic/TargetInfo.h
+++ clang/include/clang/Basic/TargetInfo.h
@@ -23,6 +23,7 @@
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/Optional.h"
@@ -233,6 +234,8 @@
 
   unsigned ARMCDECoprocMask : 8;
 
+  unsigned PointerAuthSupported : 1;
+
   unsigned MaxOpenCLWorkGroupSize;
 
   // TargetInfo Constructor.  Default initializes all fields.
@@ -1362,6 +1365,14 @@
     return TLSSupported;
   }
 
+  /// \brief Whether the target supports pointer authentication at all.
+  ///
+  /// Whether pointer authentication is actually being used is determined
+  /// by the language option.
+  bool isPointerAuthSupported() const {
+    return PointerAuthSupported;
+  }
+
   /// Return the maximum alignment (in bits) of a TLS variable
   ///
   /// Gets the maximum alignment (in bits) of a TLS variable on this target.
@@ -1403,6 +1414,11 @@
 
   const LangASMap &getAddressSpaceMap() const { return *AddrSpaceMap; }
 
+  /// Determine whether the given pointer-authentication key is valid.
+  ///
+  /// The value has been coerced to type 'int'.
+  virtual bool validatePointerAuthKey(const llvm::APSInt &value) const;
+
   /// Map from the address space field in builtin description strings to the
   /// language address space.
   virtual LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const {
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -150,6 +150,7 @@
 LANGOPT(Coroutines        , 1, 0, "C++20 coroutines")
 LANGOPT(DllExportInlines  , 1, 1, "dllexported classes dllexport inline methods")
 LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template template arguments")
+LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
 
 LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
 
Index: clang/include/clang/Basic/Features.def
===================================================================
--- clang/include/clang/Basic/Features.def
+++ clang/include/clang/Basic/Features.def
@@ -93,6 +93,7 @@
 FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
 FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
 FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
+FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
 FEATURE(swiftasynccc,
   PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) ==
   clang::TargetInfo::CCCR_OK)
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -833,6 +833,23 @@
   " but format string expands to at least %2">,
   InGroup<FortifySource>;
 
+def err_ptrauth_disabled_target :
+  Error<"this target does not support pointer authentication">;
+def err_ptrauth_disabled :
+  Error<"pointer authentication is disabled for the current target">;
+def err_ptrauth_invalid_key :
+  Error<"%0 does not identify a valid pointer authentication key for "
+        "the current target">;
+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 warn_ptrauth_sign_null_pointer :
+  Warning<"signing a null pointer will yield a non-null pointer">,
+  InGroup<PtrAuthNullPointers>;
+def warn_ptrauth_auth_null_pointer :
+  Warning<"authenticating a null pointer will almost certainly trap">,
+  InGroup<PtrAuthNullPointers>;
 
 /// main()
 // static main() is not an error in C, just in C++.
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -797,6 +797,7 @@
 def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
 def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
 def MisleadingIndentation : DiagGroup<"misleading-indentation">;
+def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">;
 
 // This covers both the deprecated case (in C++98)
 // and the extension case (in C++11 onwards).
Index: clang/include/clang/Basic/Builtins.def
===================================================================
--- clang/include/clang/Basic/Builtins.def
+++ clang/include/clang/Basic/Builtins.def
@@ -1598,6 +1598,14 @@
 LANGBUILTIN(__builtin_coro_suspend, "cIb", "n", COR_LANG)
 LANGBUILTIN(__builtin_coro_param, "bv*v*", "n", COR_LANG)
 
+// Pointer authentication builtins.
+BUILTIN(__builtin_ptrauth_strip, "v*v*i", "tnc")
+BUILTIN(__builtin_ptrauth_blend_discriminator, "zv*i", "tnc")
+BUILTIN(__builtin_ptrauth_sign_unauthenticated, "v*v*iv*", "tnc")
+BUILTIN(__builtin_ptrauth_sign_generic_data, "zv*v*", "tnc")
+BUILTIN(__builtin_ptrauth_auth_and_resign, "v*v*iv*iv*", "tn")
+BUILTIN(__builtin_ptrauth_auth, "v*v*iv*", "tn")
+
 // OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
 // We need the generic prototype, since the packet type could be anything.
 LANGBUILTIN(read_pipe, "i.", "tn", OCLC20_LANG)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to