| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt -S -passes=mergefunc < %s | FileCheck %s | |
| ; A function's address is observable when it is used as a value, so it must not | |
| ; be replaced with the address of a forwarding thunk's target. | |
| define void @f(ptr %p) { | |
| ; CHECK-LABEL: define void @f( | |
| ; CHECK-SAME: ptr [[P:%.*]]) { | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P]], @f | |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| %cmp = icmp eq ptr %p, @f | |
| call void @llvm.assume(i1 %cmp) | |
| ret void | |
| } | |
| define void @g(ptr %p) { | |
| ; CHECK-LABEL: define void @g( | |
| ; CHECK-SAME: ptr [[P:%.*]]) { | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P]], @g | |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| %cmp = icmp eq ptr %p, @g | |
| call void @llvm.assume(i1 %cmp) | |
| ret void | |
| } | |
| ; A self-reference passed as an argument is also observable and must remain a | |
| ; normal value comparison rather than a call-target comparison. | |
| declare void @consume(ptr) | |
| define void @arg_f() { | |
| ; CHECK-LABEL: define void @arg_f() { | |
| ; CHECK-NEXT: call void @consume(ptr @arg_f) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| call void @consume(ptr @arg_f) | |
| ret void | |
| } | |
| define void @arg_g() { | |
| ; CHECK-LABEL: define void @arg_g() { | |
| ; CHECK-NEXT: call void @consume(ptr @arg_g) | |
| ; CHECK-NEXT: ret void | |
| ; | |
| call void @consume(ptr @arg_g) | |
| ret void | |
| } | |
| define i32 @main() { | |
| ; CHECK-LABEL: define i32 @main() { | |
| ; CHECK-NEXT: call void @f(ptr @f) | |
| ; CHECK-NEXT: call void @g(ptr @g) | |
| ; CHECK-NEXT: call void @arg_f() | |
| ; CHECK-NEXT: call void @arg_g() | |
| ; CHECK-NEXT: ret i32 0 | |
| ; | |
| call void @f(ptr @f) | |
| call void @g(ptr @g) | |
| call void @arg_f() | |
| call void @arg_g() | |
| ret i32 0 | |
| } |