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