1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00
llvm-mirror/test/CodeGen/X86/win64-eh-empty-block.ll
Reid Kleckner fe4a3fd086 [Win64] Insert int3 into trailing empty BBs
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
2020-03-23 08:50:37 -07:00

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*)