| ; 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 |
| } |