[llvm-branch-commits] [clang] [clang] Define ptrauth_sign_constant builtin. (PR #93904)

Ahmed Bougacha via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jun 18 18:24:41 PDT 2024


https://github.com/ahmedbougacha updated https://github.com/llvm/llvm-project/pull/93904

>From 20bbad26fa9f068910baf50b5abb60a0f4557564 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 1/5] [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                     |  28 ++++
 14 files changed, 359 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 e07ddf3b9b70b..9342b6bc75fc8 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 0900dad3c18cd..a5675879f45bc 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -924,6 +924,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 97b4c2080e14f..799872fe13c08 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 08a89bd123d03..fd4fe1633ea29 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -5285,6 +5285,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 0712f40fd8215..8a514afe81470 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 9b63f47ef42cb..0ec312c8cd3ec 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -937,6 +937,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 fd9df16bcc614..7570d1e312dda 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -68,12 +68,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.
 
@@ -175,6 +193,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 60a7a383858a2..459d89afcf4ca 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2040,8 +2040,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())
@@ -2084,16 +2102,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) {
@@ -2136,14 +2229,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());
@@ -2943,10 +3038,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 20786093ecd4c..d5dc574f48087 100644
--- a/clang/test/Sema/ptrauth.c
+++ b/clang/test/Sema/ptrauth.c
@@ -58,6 +58,34 @@ void test_string_discriminator(const char *str) {
   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_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}}

>From f5a87e536ddc6f5d1f4ac59f4dfdbbf156c23ed1 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 2/5] 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 130e6571a7bdb..096ba23a42291 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -356,6 +356,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 88b097dd4a59bec12d44aa29f820d47c28a4b33f 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 3/5] 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 8a514afe81470..ccaf2e7a5d61e 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 0ec312c8cd3ec..c64149f9ef428 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -937,10 +937,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 459d89afcf4ca..b4cf2223a6ac4 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2043,18 +2043,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,
@@ -2120,73 +2119,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) {
@@ -3040,13 +3039,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 6e7ba735684787ce2ec85d9fdf46bd34c45c61a1 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Tue, 18 Jun 2024 14:02:03 -0700
Subject: [PATCH 4/5] Simplify some functionality and address review feedback.

- don't reject weakref base pointers (allowed in quals now anyway)
- fold buildConstantAddress into getConstantSignedPointer (originally
  to provide a caching layer for global wrappers but not needed anymore)
- remove stripPointerCasts from it (originally for typed pointers)
- use ConstantInt for the integer/other component of discriminators
- remove CodeGen:: helper (originally for swift but not required)
- rejigger tests; try for parity in fn body and global init
- add a couple missing tests
- tweak doc/header comment
- adopt 'can be used in cst exprs' phrasing from LangExts doc
- various nits, naming, and format
---
 clang/docs/PointerAuthentication.rst          |  10 +-
 clang/include/clang/CodeGen/CodeGenABITypes.h |   6 -
 clang/lib/CodeGen/CGExprConstant.cpp          |  17 ++-
 clang/lib/CodeGen/CGPointerAuth.cpp           |  44 ++-----
 clang/lib/CodeGen/CodeGenModule.h             |   8 +-
 clang/lib/Headers/ptrauth.h                   |  10 +-
 clang/lib/Sema/SemaChecking.cpp               |  38 +++---
 clang/test/Sema/ptrauth.c                     | 109 +++++++++++++-----
 8 files changed, 132 insertions(+), 110 deletions(-)

diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst
index 096ba23a42291..302a3e03eb128 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -368,10 +368,14 @@ 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``.
+``pointer`` must be a constant expression of pointer type which evaluates to
+a non-null pointer.
+``key``  must be a constant expression of type ``ptrauth_key``.
+``discriminator`` 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 ``pointer``.
 
-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.
+This can be used in constant expressions.
 
 ``ptrauth_sign_unauthenticated``
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h
index 45387b64eb517..fda0855dc8683 100644
--- a/clang/include/clang/CodeGen/CodeGenABITypes.h
+++ b/clang/include/clang/CodeGen/CodeGenABITypes.h
@@ -104,12 +104,6 @@ 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/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index ccaf2e7a5d61e..d273c8059062d 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1859,7 +1859,7 @@ class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
   ConstantLValue emitPointerAuthSignConstant(const CallExpr *E);
   llvm::Constant *emitPointerAuthPointer(const Expr *E);
   unsigned emitPointerAuthKey(const Expr *E);
-  std::pair<llvm::Constant*, llvm::Constant*>
+  std::pair<llvm::Constant *, llvm::ConstantInt *>
   emitPointerAuthDiscriminator(const Expr *E);
 
   bool hasNonZeroOffset() const {
@@ -2075,9 +2075,7 @@ ConstantLValue
 ConstantLValueEmitter::emitPointerAuthSignConstant(const CallExpr *E) {
   llvm::Constant *UnsignedPointer = emitPointerAuthPointer(E->getArg(0));
   unsigned Key = emitPointerAuthKey(E->getArg(1));
-  llvm::Constant *StorageAddress;
-  llvm::Constant *OtherDiscriminator;
-  std::tie(StorageAddress, OtherDiscriminator) =
+  auto [StorageAddress, OtherDiscriminator] =
       emitPointerAuthDiscriminator(E->getArg(2));
 
   llvm::Constant *SignedPointer = CGM.getConstantSignedPointer(
@@ -2101,17 +2099,17 @@ unsigned ConstantLValueEmitter::emitPointerAuthKey(const Expr *E) {
   return E->EvaluateKnownConstInt(CGM.getContext()).getZExtValue();
 }
 
-std::pair<llvm::Constant *, llvm::Constant *>
+std::pair<llvm::Constant *, llvm::ConstantInt *>
 ConstantLValueEmitter::emitPointerAuthDiscriminator(const Expr *E) {
   E = E->IgnoreParens();
 
-  if (auto *Call = dyn_cast<CallExpr>(E)) {
+  if (const 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());
+      auto *Extra = cast<llvm::ConstantInt>(ConstantEmitter(CGM).emitAbstract(
+          Call->getArg(1), Call->getArg(1)->getType()));
       return {Pointer, Extra};
     }
   }
@@ -2119,8 +2117,7 @@ ConstantLValueEmitter::emitPointerAuthDiscriminator(const Expr *E) {
   llvm::Constant *Result = ConstantEmitter(CGM).emitAbstract(E, E->getType());
   if (Result->getType()->isPointerTy())
     return {Result, nullptr};
-  else
-    return {nullptr, Result};
+  return {nullptr, cast<llvm::ConstantInt>(Result)};
 }
 
 ConstantLValue
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index 8a1a786577d6b..e1fb0bdb85cfb 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -17,47 +17,27 @@
 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;
+llvm::Constant *
+CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
+                                        llvm::Constant *StorageAddress,
+                                        llvm::ConstantInt *OtherDiscriminator) {
+  llvm::Constant *AddressDiscriminator;
   if (StorageAddress) {
+    assert(StorageAddress->getType() == UnqualPtrTy);
     AddressDiscriminator = StorageAddress;
-    assert(StorageAddress->getType() == CGM.UnqualPtrTy);
   } else {
-    AddressDiscriminator = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
+    AddressDiscriminator = llvm::Constant::getNullValue(UnqualPtrTy);
   }
 
-  llvm::ConstantInt *IntegerDiscriminator = nullptr;
+  llvm::ConstantInt *IntegerDiscriminator;
   if (OtherDiscriminator) {
-    assert(OtherDiscriminator->getType() == CGM.Int64Ty);
-    IntegerDiscriminator = cast<llvm::ConstantInt>(OtherDiscriminator);
+    assert(OtherDiscriminator->getType() == Int64Ty);
+    IntegerDiscriminator = OtherDiscriminator;
   } else {
-    IntegerDiscriminator = llvm::ConstantInt::get(CGM.Int64Ty, 0);
+    IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0);
   }
 
   return llvm::ConstantPtrAuth::get(Pointer,
-                                    llvm::ConstantInt::get(CGM.Int32Ty, Key),
+                                    llvm::ConstantInt::get(Int32Ty, Key),
                                     IntegerDiscriminator, AddressDiscriminator);
 }
-
-llvm::Constant *
-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);
-}
-
-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/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index c64149f9ef428..04e1a392ef5d1 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -937,10 +937,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::ConstantInt *OtherDiscriminator);
 
   // Return whether RTTI information should be emitted for this target.
   bool shouldEmitRTTI(bool ForEH = false) {
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 7570d1e312dda..6aad9efb7a652 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -78,17 +78,17 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_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.
+/* Return a signed pointer for a constant address in a manner which guarantees
+   a non-attackable sequence.
 
-   The value must be a constant expression of pointer type.
+   The value must be a constant expression of pointer type which evaluates to
+   a non-null pointer.
    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. */
+   This can be used in constant expressions.  */
 #define ptrauth_sign_constant(__value, __key, __data)                          \
   __builtin_ptrauth_sign_constant(__value, __key, __data)
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b4cf2223a6ac4..7a2076d139c69 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2045,19 +2045,17 @@ 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());
+    return {nullptr, CharUnits()};
 
-  // Base must be a declaration and can't be weakly imported.
   const auto *BaseDecl =
       Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
-  if (!BaseDecl || BaseDecl->hasAttr<WeakRefAttr>())
-    return std::make_pair(nullptr, CharUnits());
+  if (!BaseDecl)
+    return {nullptr, CharUnits()};
 
-  return std::make_pair(BaseDecl, Result.Val.getLValueOffset());
+  return {BaseDecl, Result.Val.getLValueOffset()};
 }
 
-static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
-                                  PointerAuthOpKind OpKind,
+static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind,
                                   bool RequireConstant = false) {
   if (Arg->hasPlaceholderType()) {
     ExprResult R = S.CheckPlaceholderExpr(Arg);
@@ -2119,25 +2117,23 @@ 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 BaseOffsetPair = findConstantBaseAndOffset(S, Arg);
+    auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Arg);
     bool Invalid;
 
     // Must be rooted in a declaration reference.
-    if (!BaseOffsetPair.first) {
+    if (!BaseDecl)
       Invalid = true;
 
-      // If it's a function declaration, we can't have an offset.
-    } else if (isa<FunctionDecl>(BaseOffsetPair.first)) {
-      Invalid = !BaseOffsetPair.second.isZero();
+    // If it's a function declaration, we can't have an offset.
+    else if (isa<FunctionDecl>(BaseDecl))
+      Invalid = !Offset.isZero();
 
-      // Otherwise we're fine.
-    } else {
+    // Otherwise we're fine.
+    else
       Invalid = false;
-    }
 
-    if (Invalid) {
+    if (Invalid)
       S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer);
-    }
     return Invalid;
   }
 
@@ -2169,10 +2165,9 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
     // 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 BaseOffsetPair = findConstantBaseAndOffset(S, Pointer);
-    if (!BaseOffsetPair.first || !isa<VarDecl>(BaseOffsetPair.first)) {
+    auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Pointer);
+    if (!BaseDecl || !isa<VarDecl>(BaseDecl))
       Invalid = true;
-    }
   }
 
   // Check the integer.
@@ -2182,9 +2177,8 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
       Invalid = true;
   }
 
-  if (Invalid) {
+  if (Invalid)
     S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator);
-  }
   return Invalid;
 }
 
diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c
index d5dc574f48087..cd069881793c5 100644
--- a/clang/test/Sema/ptrauth.c
+++ b/clang/test/Sema/ptrauth.c
@@ -58,34 +58,6 @@ void test_string_discriminator(const char *str) {
   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_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}}
@@ -164,3 +136,84 @@ void test_sign_generic_data(int *dp) {
 
   int *mismatch = __builtin_ptrauth_sign_generic_data(dp, 0); // expected-error {{incompatible integer to pointer conversion initializing 'int *' with an expression of type}}
 }
+
+
+typedef int (*fp_t)(int);
+
+static int dv_weakref __attribute__((weakref("dv")));
+extern int dv_weak __attribute__((weak));
+
+int *t_cst_sig1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY); // expected-error {{too few arguments}}
+int *t_cst_sig2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &dv, &dv); // expected-error {{too many arguments}}
+
+int *t_cst_sig3 = __builtin_ptrauth_sign_constant(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+int *t_cst_sig4 = __builtin_ptrauth_sign_constant(&dv, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+int *t_cst_sig5 = __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'}}
+
+float *t_cst_result = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+
+int *t_cst_valid1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
+int *t_cst_valid2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
+int *t_cst_valid3 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
+int *t_cst_valid4 = __builtin_ptrauth_sign_constant(&dv_weak, VALID_DATA_KEY, 0);
+int *t_cst_valid5 = __builtin_ptrauth_sign_constant(&dv_weakref, VALID_DATA_KEY, 0);
+
+int *t_cst_ptr = __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 *t_cst_key = __builtin_ptrauth_sign_constant(&dv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+int *t_cst_disc1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &fv); // 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 *t_cst_disc2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&fv, 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}}
+
+fp_t t_cst_f_valid1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, 0);
+fp_t t_cst_f_valid2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
+fp_t t_cst_f_valid3 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
+
+fp_t t_cst_f_key = __builtin_ptrauth_sign_constant(&fv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+fp_t t_cst_f_disc1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, &fv); // 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}}
+fp_t t_cst_f_disc2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&fv, 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}}
+
+int *t_cst_offset = __builtin_ptrauth_sign_constant((int *)((char*)&dv + 16), VALID_DATA_KEY, 0);
+fp_t t_cst_f_offset = __builtin_ptrauth_sign_constant((int (*)(int))((char*)&fv + 16), VALID_CODE_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
+
+void test_sign_constant(int *dp, fp_t fp) {
+  int *sig1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY); // expected-error {{too few arguments}}
+  int *sig2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &dv, &dv); // expected-error {{too many arguments}}
+
+  int *sig3 = __builtin_ptrauth_sign_constant(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+  int *sig4 = __builtin_ptrauth_sign_constant(&dv, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+  int *sig5 = __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'}}
+
+  float *result = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+
+  int *valid1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
+  int *valid2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
+  int *valid3 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
+  int *valid4 = __builtin_ptrauth_sign_constant(&dv_weak, VALID_DATA_KEY, 0);
+  int *valid5 = __builtin_ptrauth_sign_constant(&dv_weakref, VALID_DATA_KEY, 0);
+
+  int *ptr = __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 *key = __builtin_ptrauth_sign_constant(&dv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+  int *disc1 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, &fv); // 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 *disc2 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(&fv, 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}}
+
+  int *ptr2 = __builtin_ptrauth_sign_constant(dp, VALID_DATA_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
+  int *disc3 = __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 *disc4 = __builtin_ptrauth_sign_constant(&dv, VALID_DATA_KEY, __builtin_ptrauth_blend_discriminator(dp, 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}}
+  int *disc5 = __builtin_ptrauth_sign_constant(&dv, 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}}
+
+  fp_t f_valid1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, 0);
+  fp_t f_valid2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv, 0));
+  fp_t f_valid3 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&dv + 8, 0));
+
+  fp_t f_key = __builtin_ptrauth_sign_constant(&fv, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+  fp_t f_disc1 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, &fv); // 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}}
+  fp_t f_disc2 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(&fv, 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}}
+
+  fp_t f_ptr = __builtin_ptrauth_sign_constant(fp, VALID_CODE_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
+  fp_t f_disc3 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_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}}
+
+  fp_t f_disc4 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_KEY, __builtin_ptrauth_blend_discriminator(dp, 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}}
+  fp_t f_disc5 = __builtin_ptrauth_sign_constant(&fv, VALID_CODE_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}}
+
+  int *offset = __builtin_ptrauth_sign_constant((int *)((char*)&dv + 16), VALID_DATA_KEY, 0);
+  fp_t f_offset = __builtin_ptrauth_sign_constant((fp_t)((char*)&fv + 16), VALID_CODE_KEY, 0); // expected-error {{argument to ptrauth_sign_constant must refer to a global variable or function}}
+}

>From 46c47e9392d94bcb77744b9bc91a8246fc02bac1 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Tue, 18 Jun 2024 18:23:52 -0700
Subject: [PATCH 5/5] Add more codegen tests.

---
 .../CodeGen/ptrauth-intrinsic-sign-constant.c | 28 +++++++++++++------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c b/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
index 626eb4a2e01a8..bab39897b9427 100644
--- a/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
+++ b/clang/test/CodeGen/ptrauth-intrinsic-sign-constant.c
@@ -3,19 +3,31 @@
 
 extern int external;
 
-// CHECK: @ptr1 = global ptr ptrauth (ptr @external, i32 0, i64 26)
-void *ptr1 = __builtin_ptrauth_sign_constant(&external, 0, 26);
+// CHECK: @ptr1 = global ptr ptrauth (ptr @external, i32 0)
+void *ptr1 = __builtin_ptrauth_sign_constant(&external, 0, 0);
 
-// 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: @ptr2 = global ptr ptrauth (ptr @external, i32 0, i64 1234)
+void *ptr2 = __builtin_ptrauth_sign_constant(&external, 0, 1234);
 
-// CHECK: @ptr3 = global ptr null
-void *ptr3;
+// CHECK: @ptr3 = global ptr ptrauth (ptr @external, i32 2, i64 0, ptr @ptr3)
+void *ptr3 = __builtin_ptrauth_sign_constant(&external, 2, &ptr3);
+
+// CHECK: @ptr4 = global ptr ptrauth (ptr @external, i32 2, i64 26, ptr @ptr4)
+void *ptr4 = __builtin_ptrauth_sign_constant(&external, 2, __builtin_ptrauth_blend_discriminator(&ptr4, 26));
+
+// CHECK: @ptr5 = global ptr null
+void *ptr5;
 
 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:    store ptr ptrauth (ptr @external, i32 0), ptr @ptr1, align 8
+// CHECK-NEXT:    store ptr ptrauth (ptr @external, i32 2, i64 1234), ptr @ptr2, align 8
+// CHECK-NEXT:    store ptr ptrauth (ptr @external, i32 2, i64 0, ptr @ptr3), ptr @ptr3, align 8
+// CHECK-NEXT:    store ptr ptrauth (ptr @external, i32 2, i64 1234, ptr @ptr4), ptr @ptr4, align 8
 // CHECK-NEXT:    ret void
-  ptr3 = __builtin_ptrauth_sign_constant(&external, 2, 1234);
+  ptr1 = __builtin_ptrauth_sign_constant(&external, 0, 0);
+  ptr2 = __builtin_ptrauth_sign_constant(&external, 2, 1234);
+  ptr3 = __builtin_ptrauth_sign_constant(&external, 2, &ptr3);
+  ptr4 = __builtin_ptrauth_sign_constant(&external, 2, __builtin_ptrauth_blend_discriminator(&ptr4, 1234));
 }



More information about the llvm-branch-commits mailing list