Stefan Gränitz bb4a04e794 [Verifier][WinEH] Check funclet tokens on intrinsic calls that may lower to function calls
WinEHPrepare requires funclet operand bundles ("tokens") on function calls from EH funclets to prevent them from getting removed as "implausible" calls. This includes calls to intrinsic functions that lower to function calls in the course of IR transformations (e.g. ObjC ARC runtime calls).

We can not detect such cases in WinEHPrepare itself, because at this point they mixed up with valid implausible calls. These must be removed to guarantee that the EH backend can assign unique colors and EH state numbers to all blocks.

This patch allows the IR Verifier to detect missing and dangling funclet tokens. Non-conforming IR becomes illegal and miscompilations are detected early. In order to find funclet pad instructions for funclets that extend over multiple blocks, we have to calculate EH funclet colors. As coloring can be expensive, it runs on-demand and results are cached per function.

Reviewed By: efriedma

Differential Revision: https://reviews.llvm.org/D138123
2023-01-27 18:05:13 +01:00

58 lines
2.3 KiB
LLVM

; RUN: opt -mtriple x86_64-unknown-windows-msvc -passes=objc-arc -o - %s | llvm-dis -o - - | FileCheck %s
target triple = "x86_64-unknown-windows-msvc"
declare i32 @__CxxFrameHandler3(...)
declare dllimport ptr @objc_msgSend(ptr, ptr, ...) local_unnamed_addr
declare dllimport ptr @llvm.objc.retain(ptr returned) local_unnamed_addr
declare dllimport void @llvm.objc.release(ptr) local_unnamed_addr
declare dllimport ptr @llvm.objc.retainAutoreleasedReturnValue(ptr returned) local_unnamed_addr
declare dllimport ptr @llvm.objc.begin_catch(ptr) local_unnamed_addr
declare dllimport void @llvm.objc.end_catch() local_unnamed_addr
@llvm.objc.METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"m\00", align 1
@llvm.objc.SELECTOR_REFERENCES_ = private externally_initialized global ptr @llvm.objc.METH_VAR_NAME_, section ".objc_selrefs$B", align 8
define void @f(ptr %i) local_unnamed_addr personality ptr @__CxxFrameHandler3 {
entry:
%0 = tail call ptr @llvm.objc.retain(ptr %i)
%1 = load ptr, ptr @llvm.objc.SELECTOR_REFERENCES_, align 8, !invariant.load !0
%call = invoke ptr @objc_msgSend(ptr %0, ptr %1)
to label %invoke.cont unwind label %catch.dispatch, !clang.arc.no_objc_arc_exceptions !0
catch.dispatch: ; preds = %entry
%2 = catchswitch within none [label %catch] unwind to caller
invoke.cont: ; preds = %entry
%3 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call)
tail call void @llvm.objc.release(ptr %3) #0, !clang.imprecise_release !0
br label %eh.cont
eh.cont: ; preds = %invoke.cont, %catch
tail call void @llvm.objc.release(ptr %0) #0, !clang.imprecise_release !0
ret void
catch: ; preds = %catch.dispatch
%4 = catchpad within %2 [ptr null, i32 0, ptr null]
%exn.adjusted = tail call ptr @llvm.objc.begin_catch(ptr undef)
tail call void @llvm.objc.end_catch(), !clang.arc.no_objc_arc_exceptions !0
catchret from %4 to label %eh.cont
}
; CHECK-LABEL: @f
; CHECK-NOT: tail call ptr @llvm.objc.retain(ptr %i)
; CHECK: load ptr, ptr @llvm.objc.SELECTOR_REFERENCES_, align 8
; CHECK: eh.cont:
; CHECK-NOT: call void @llvm.objc.release(ptr
; CHECK: ret void
attributes #0 = { nounwind }
!0 = !{}