mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
252bda7ebd
the call's return type is void Instead of trying hard to prevent global optimization passes such as deadargelim from changing the return type to void, just ignore the bundle if the return type is void. clang currently emits calls to @llvm.objc.clang.arc.noop.use, which consumes the function call result, immediately after the function call to prevent changes to the return type, but optimization passes can delete the call to @llvm.objc.clang.arc.noop.use if the function call doesn't return, which enables deadargelim to change the return type. rdar://76671438 Differential Revision: https://reviews.llvm.org/D103062
85 lines
2.9 KiB
LLVM
85 lines
2.9 KiB
LLVM
; RUN: not opt -verify < %s 2>&1 | FileCheck %s
|
|
|
|
%0 = type opaque
|
|
declare void @g()
|
|
declare %0* @foo0()
|
|
declare i8 @foo1()
|
|
declare void @noreturn_func()
|
|
|
|
; Operand bundles uses are like regular uses, and need to be dominated
|
|
; by their defs.
|
|
|
|
define void @f0(i32* %ptr) {
|
|
; CHECK: Instruction does not dominate all uses!
|
|
; CHECK-NEXT: %x = add i32 42, 1
|
|
; CHECK-NEXT: call void @g() [ "foo"(i32 42, i64 100, i32 %x), "bar"(float 0.000000e+00, i64 100, i32 %l) ]
|
|
|
|
entry:
|
|
%l = load i32, i32* %ptr
|
|
call void @g() [ "foo"(i32 42, i64 100, i32 %x), "bar"(float 0.0, i64 100, i32 %l) ]
|
|
%x = add i32 42, 1
|
|
ret void
|
|
}
|
|
|
|
define void @f1(i32* %ptr) personality i8 3 {
|
|
; CHECK: Instruction does not dominate all uses!
|
|
; CHECK-NEXT: %x = add i32 42, 1
|
|
; CHECK-NEXT: invoke void @g() [ "foo"(i32 42, i64 100, i32 %x), "bar"(float 0.000000e+00, i64 100, i32 %l) ]
|
|
|
|
entry:
|
|
%l = load i32, i32* %ptr
|
|
invoke void @g() [ "foo"(i32 42, i64 100, i32 %x), "bar"(float 0.0, i64 100, i32 %l) ] to label %normal unwind label %exception
|
|
|
|
exception:
|
|
%cleanup = landingpad i8 cleanup
|
|
br label %normal
|
|
|
|
normal:
|
|
%x = add i32 42, 1
|
|
ret void
|
|
}
|
|
|
|
define void @f_deopt(i32* %ptr) {
|
|
; CHECK: Multiple deopt operand bundles
|
|
; CHECK-NEXT: call void @g() [ "deopt"(i32 42, i64 100, i32 %x), "deopt"(float 0.000000e+00, i64 100, i32 %l) ]
|
|
; CHECK-NOT: call void @g() [ "deopt"(i32 42, i64 120, i32 %x) ]
|
|
|
|
entry:
|
|
%l = load i32, i32* %ptr
|
|
call void @g() [ "deopt"(i32 42, i64 100, i32 %x), "deopt"(float 0.0, i64 100, i32 %l) ]
|
|
call void @g() [ "deopt"(i32 42, i64 120) ] ;; The verifier should not complain about this one
|
|
%x = add i32 42, 1
|
|
ret void
|
|
}
|
|
|
|
define void @f_gc_transition(i32* %ptr) {
|
|
; CHECK: Multiple gc-transition operand bundles
|
|
; CHECK-NEXT: call void @g() [ "gc-transition"(i32 42, i64 100, i32 %x), "gc-transition"(float 0.000000e+00, i64 100, i32 %l) ]
|
|
; CHECK-NOT: call void @g() [ "gc-transition"(i32 42, i64 120, i32 %x) ]
|
|
|
|
entry:
|
|
%l = load i32, i32* %ptr
|
|
call void @g() [ "gc-transition"(i32 42, i64 100, i32 %x), "gc-transition"(float 0.0, i64 100, i32 %l) ]
|
|
call void @g() [ "gc-transition"(i32 42, i64 120) ] ;; The verifier should not complain about this one
|
|
%x = add i32 42, 1
|
|
ret void
|
|
}
|
|
|
|
define void @f_clang_arc_attachedcall() {
|
|
; CHECK: Multiple "clang.arc.attachedcall" operand bundles
|
|
; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"(i64 0), "clang.arc.attachedcall"(i64 0) ]
|
|
; CHECK-NEXT: must call a function returning a pointer
|
|
; CHECK-NEXT: call i8 @foo1() [ "clang.arc.attachedcall"(i64 0) ]
|
|
; CHECK-NEXT: or a non-returning function
|
|
; CHECK-NEXT: call void @g() [ "clang.arc.attachedcall"(i64 0) ]
|
|
|
|
call %0* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
|
|
call %0* @foo0() [ "clang.arc.attachedcall"(i64 0), "clang.arc.attachedcall"(i64 0) ]
|
|
call i8 @foo1() [ "clang.arc.attachedcall"(i64 0) ]
|
|
call void @noreturn_func() #0 [ "clang.arc.attachedcall"(i64 0) ]
|
|
call void @g() [ "clang.arc.attachedcall"(i64 0) ]
|
|
ret void
|
|
}
|
|
|
|
attributes #0 = { noreturn }
|