mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
fe4a3fd086
Otherwise, the Win64 unwinder considers direct branches to such empty trailing BBs to be a branch out of the function. It treats such a branch as a tail call, which can only be part of an epilogue. If the unwinder misclassifies such a branch as part of the epilogue, it will fail to unwind the stack further. This can lead to bad stack traces, or failure to handle exceptions properly. This is described in https://llvm.org/PR45064#c4, and by the comment at the top of the X86AvoidTrailingCallPass.cpp file. It should be safe to insert int3 for such blocks. An empty trailing BB that reaches this pass is pretty much guaranteed to be unreachable. If a program executed such a block, it would fall off the end of the function. Most of the complexity in this patch comes from threading through the "EHFuncletEntry" boolean on the MIRParser and registering the pass so we can stop and start codegen around it. I used an MIR test because we should teach LLVM to optimize away these branches as a follow-up. Reviewed By: hans Differential Revision: https://reviews.llvm.org/D76531
108 lines
3.7 KiB
LLVM
108 lines
3.7 KiB
LLVM
; RUN: llc -mtriple=x86_64-windows-gnu %s -o - | FileCheck %s
|
|
|
|
; Based on this C++ code:
|
|
; struct as {
|
|
; as() { at = static_cast<int *>(operator new(sizeof(int))); }
|
|
; ~as() { operator delete(at); }
|
|
; int *at;
|
|
; };
|
|
; void am(int) {
|
|
; static as au;
|
|
; as av;
|
|
; throw 0;
|
|
; }
|
|
|
|
; optnone was added to ensure that branch folding and block layout are not
|
|
; disturbed. The key thing about this test is that it ends in an empty
|
|
; unreachable block, which forces us to scan back across blocks.
|
|
|
|
; CHECK: _Z2ami:
|
|
; CHECK: callq __cxa_throw
|
|
; CHECK: # %eh.resume
|
|
; CHECK: callq _Unwind_Resume
|
|
; CHECK-NEXT: # %unreachable
|
|
; CHECK-NEXT: int3
|
|
; CHECK-NEXT: .Lfunc_end0:
|
|
|
|
%struct.as = type { i32* }
|
|
|
|
@_ZZ2amiE2au = internal unnamed_addr global %struct.as zeroinitializer, align 8
|
|
@_ZGVZ2amiE2au = internal global i64 0, align 8
|
|
@_ZTIi = external constant i8*
|
|
|
|
define dso_local void @_Z2ami(i32 %0) noinline optnone personality i8* bitcast (i32 (...)* @__gxx_personality_seh0 to i8*) {
|
|
entry:
|
|
%1 = load atomic i8, i8* bitcast (i64* @_ZGVZ2amiE2au to i8*) acquire, align 8
|
|
%guard.uninitialized = icmp eq i8 %1, 0
|
|
br i1 %guard.uninitialized, label %init.check, label %init.end
|
|
|
|
init.check: ; preds = %entry
|
|
%2 = tail call i32 @__cxa_guard_acquire(i64* nonnull @_ZGVZ2amiE2au)
|
|
%tobool = icmp eq i32 %2, 0
|
|
br i1 %tobool, label %init.end, label %init
|
|
|
|
init: ; preds = %init.check
|
|
%call.i3 = invoke i8* @_Znwy(i64 4)
|
|
to label %invoke.cont unwind label %lpad
|
|
|
|
invoke.cont: ; preds = %init
|
|
store i8* %call.i3, i8** bitcast (%struct.as* @_ZZ2amiE2au to i8**), align 8
|
|
%3 = tail call i32 @atexit(void ()* nonnull @__dtor__ZZ2amiE2au)
|
|
tail call void @__cxa_guard_release(i64* nonnull @_ZGVZ2amiE2au)
|
|
br label %init.end
|
|
|
|
init.end: ; preds = %init.check, %invoke.cont, %entry
|
|
%call.i = tail call i8* @_Znwy(i64 4)
|
|
%exception = tail call i8* @__cxa_allocate_exception(i64 4)
|
|
%4 = bitcast i8* %exception to i32*
|
|
store i32 0, i32* %4, align 16
|
|
invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
|
to label %unreachable unwind label %lpad1
|
|
|
|
lpad: ; preds = %init
|
|
%5 = landingpad { i8*, i32 }
|
|
cleanup
|
|
%6 = extractvalue { i8*, i32 } %5, 0
|
|
%7 = extractvalue { i8*, i32 } %5, 1
|
|
tail call void @__cxa_guard_abort(i64* nonnull @_ZGVZ2amiE2au)
|
|
br label %eh.resume
|
|
|
|
lpad1: ; preds = %init.end
|
|
%8 = landingpad { i8*, i32 }
|
|
cleanup
|
|
%9 = extractvalue { i8*, i32 } %8, 0
|
|
%10 = extractvalue { i8*, i32 } %8, 1
|
|
tail call void @_ZdlPv(i8* %call.i)
|
|
br label %eh.resume
|
|
|
|
eh.resume: ; preds = %lpad1, %lpad
|
|
%exn.slot.0 = phi i8* [ %9, %lpad1 ], [ %6, %lpad ]
|
|
%ehselector.slot.0 = phi i32 [ %10, %lpad1 ], [ %7, %lpad ]
|
|
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0
|
|
%lpad.val2 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1
|
|
resume { i8*, i32 } %lpad.val2
|
|
|
|
unreachable: ; preds = %init.end
|
|
unreachable
|
|
}
|
|
|
|
declare dso_local i32 @__cxa_guard_acquire(i64*)
|
|
|
|
declare dso_local i32 @__gxx_personality_seh0(...)
|
|
|
|
declare dso_local void @__dtor__ZZ2amiE2au()
|
|
|
|
declare dso_local i32 @atexit(void ()*)
|
|
|
|
declare dso_local void @__cxa_guard_abort(i64*)
|
|
|
|
declare dso_local void @__cxa_guard_release(i64*)
|
|
|
|
declare dso_local i8* @__cxa_allocate_exception(i64)
|
|
|
|
declare dso_local void @__cxa_throw(i8*, i8*, i8*)
|
|
|
|
declare dso_local noalias i8* @_Znwy(i64)
|
|
|
|
declare dso_local void @_ZdlPv(i8*)
|