Index: llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -263,6 +263,16 @@ this->Options.NoTrapAfterNoreturn = true; } + if (TT.isOSWindows()) { + // Unwinding can get confused if the last instruction in an + // exception-handling region (function, funclet, try block, etc.) + // is a call. + // + // FIXME: We could elide the trap if the next instruction would be in + // the same region anyway. + this->Options.TrapUnreachable = true; + } + // Enable GlobalISel at or below EnableGlobalISelAt0. if (getOptLevel() <= EnableGlobalISelAtO) setGlobalISel(true); Index: llvm/trunk/test/CodeGen/AArch64/windows-trap.ll =================================================================== --- llvm/trunk/test/CodeGen/AArch64/windows-trap.ll +++ llvm/trunk/test/CodeGen/AArch64/windows-trap.ll @@ -0,0 +1,17 @@ +; RUN: llc -mtriple=aarch64-win32 %s -o - | FileCheck %s + +declare void @callee() noreturn + +; Make sure the call isn't the last instruction in the function; if it is, +; unwinding may break. +; +; (The instruction after the call doesn't have to be anything in particular, +; but trapping has the nice side-effect of catching bugs.) + +define void @test_unreachable() { +; CHECK-LABEL: test_unreachable: +; CHECK: bl callee +; CHECK-NEXT: brk #0x1 + call void @callee() noreturn + unreachable +}