diff --git a/llvm/lib/Transforms/Utils/FunctionComparator.cpp b/llvm/lib/Transforms/Utils/FunctionComparator.cpp index 7cf19177db545..80b02d579f5da 100644 --- a/llvm/lib/Transforms/Utils/FunctionComparator.cpp +++ b/llvm/lib/Transforms/Utils/FunctionComparator.cpp @@ -518,6 +518,20 @@ int FunctionComparator::cmpConstants(const Constant *L, const auto *REquiv = cast(R); return cmpGlobalValues(LEquiv->getGlobalValue(), REquiv->getGlobalValue()); } + case Value::ConstantPtrAuthVal: { + // Handle authenticated pointer constants produced by ConstantPtrAuth::get. + const ConstantPtrAuth *LPA = cast(L); + const ConstantPtrAuth *RPA = cast(R); + if (int Res = cmpConstants(LPA->getPointer(), RPA->getPointer())) + return Res; + if (int Res = cmpConstants(LPA->getKey(), RPA->getKey())) + return Res; + if (int Res = + cmpConstants(LPA->getDiscriminator(), RPA->getDiscriminator())) + return Res; + return cmpConstants(LPA->getAddrDiscriminator(), + RPA->getAddrDiscriminator()); + } default: // Unknown constant, abort. LLVM_DEBUG(dbgs() << "Looking at valueID " << L->getValueID() << "\n"); llvm_unreachable("Constant ValueID not recognized."); diff --git a/llvm/test/Transforms/MergeFunc/ptrauth-const-compare.ll b/llvm/test/Transforms/MergeFunc/ptrauth-const-compare.ll new file mode 100644 index 0000000000000..f25283dd037f3 --- /dev/null +++ b/llvm/test/Transforms/MergeFunc/ptrauth-const-compare.ll @@ -0,0 +1,133 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -passes=mergefunc -S < %s | FileCheck %s +; Ensure MergeFunc handles ConstantPtrAuth correctly and does not +; merge when any ptrauth operand differs (ptr, key, int disc, addr disc). +; Each pair of functions differs only in a single ptrauth component but shares +; the same return value, so disabling any single comparison would cause a +; test failure due to unexpected merging. + +target triple = "arm64e-apple-ios14.0.0" + +declare void @baz() +@ADDR = external global i8 + +declare void @callee(ptr) + +; different base pointer (null vs @baz) + +define i32 @f_ptr_null() { +; CHECK-LABEL: define i32 @f_ptr_null() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr null, i32 0)) +; CHECK-NEXT: ret i32 1 +; +entry: + call void @callee(ptr ptrauth (ptr null, i32 0)) + ret i32 1 +} + +define i32 @g_ptr_baz() { +; CHECK-LABEL: define i32 @g_ptr_baz() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 0)) +; CHECK-NEXT: ret i32 1 +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0)) + ret i32 1 +} + +; different key (i32 0 vs i32 1) + +define i32 @f_key0() { +; CHECK-LABEL: define i32 @f_key0() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 0)) +; CHECK-NEXT: ret i32 2 +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0)) + ret i32 2 +} + +define i32 @g_key1() { +; CHECK-LABEL: define i32 @g_key1() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 1)) +; CHECK-NEXT: ret i32 2 +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 1)) + ret i32 2 +} + +; different integer disc (i64 0 vs i64 7) + +define i32 @f_disc0() { +; CHECK-LABEL: define i32 @f_disc0() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 0)) +; CHECK-NEXT: ret i32 3 +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0)) + ret i32 3 +} + +define i32 @g_disc7() { +; CHECK-LABEL: define i32 @g_disc7() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 0, i64 7)) +; CHECK-NEXT: ret i32 3 +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0, i64 7)) + ret i32 3 +} + +; different addr disc (ptr null vs @ADDR) + +define i32 @f_addr_null() { +; CHECK-LABEL: define i32 @f_addr_null() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 0)) +; CHECK-NEXT: ret i32 4 +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0)) + ret i32 4 +} + +define i32 @g_addr_ADDR() { +; CHECK-LABEL: define i32 @g_addr_ADDR() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)) +; CHECK-NEXT: ret i32 4 +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)) + ret i32 4 +} + +; positive test: identical ptrauth operands, should be merged + +define void @merge_ptrauth_a() { +; CHECK-LABEL: define void @merge_ptrauth_a() { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @callee(ptr ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)) +; CHECK-NEXT: ret void +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)) + ret void +} + +define void @merge_ptrauth_b() { +; CHECK-LABEL: define void @merge_ptrauth_b() { +; CHECK-NEXT: tail call void @merge_ptrauth_a() +; CHECK-NEXT: ret void +; +entry: + call void @callee(ptr ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)) + ret void +}