[llvm] r351370 - [COFF, ARM64] Implement support for SEH extensions __try/__except/__finally
Mandeep Singh Grang via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 16 11:52:59 PST 2019
Author: mgrang
Date: Wed Jan 16 11:52:59 2019
New Revision: 351370
URL: http://llvm.org/viewvc/llvm-project?rev=351370&view=rev
Log:
[COFF, ARM64] Implement support for SEH extensions __try/__except/__finally
Summary:
This patch supports MS SEH extensions __try/__except/__finally. The intrinsics localescape and localrecover are responsible for communicating escaped static allocas from the try block to the handler.
We need to preserve frame pointers for SEH. So we create a new function/property HasLocalEscape.
Reviewers: rnk, compnerd, mstorsjo, TomTan, efriedma, ssijaric
Reviewed By: rnk, efriedma
Subscribers: smeenai, jrmuizel, alex, majnemer, ssijaric, ehsan, dmajor, kristina, javed.absar, kristof.beyls, chrib, llvm-commits
Differential Revision: https://reviews.llvm.org/D53540
Added:
llvm/trunk/test/CodeGen/AArch64/seh-finally.ll
llvm/trunk/test/CodeGen/AArch64/seh-localescape.ll
Modified:
llvm/trunk/include/llvm/CodeGen/MachineFunction.h
llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp
llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/trunk/lib/Target/AArch64/AArch64AsmPrinter.cpp
llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp
llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp
llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp
Modified: llvm/trunk/include/llvm/CodeGen/MachineFunction.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineFunction.h?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/MachineFunction.h (original)
+++ llvm/trunk/include/llvm/CodeGen/MachineFunction.h Wed Jan 16 11:52:59 2019
@@ -329,6 +329,7 @@ class MachineFunction {
bool CallsUnwindInit = false;
bool HasEHScopes = false;
bool HasEHFunclets = false;
+ bool HasLocalEscape = false;
/// List of C++ TypeInfo used.
std::vector<const GlobalValue *> TypeInfos;
@@ -811,6 +812,9 @@ public:
bool hasEHFunclets() const { return HasEHFunclets; }
void setHasEHFunclets(bool V) { HasEHFunclets = V; }
+ bool hasLocalEscape() const { return HasLocalEscape; }
+ void setHasLocalEscape(bool V) { HasLocalEscape = V; }
+
/// Find or create an LandingPadInfo for the specified MachineBasicBlock.
LandingPadInfo &getOrCreateLandingPadInfo(MachineBasicBlock *LandingPad);
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/WinException.cpp Wed Jan 16 11:52:59 2019
@@ -545,15 +545,17 @@ void WinException::emitCSpecificHandlerT
OS.AddComment(Comment);
};
- // Emit a label assignment with the SEH frame offset so we can use it for
- // llvm.eh.recoverfp.
- StringRef FLinkageName =
- GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());
- MCSymbol *ParentFrameOffset =
- Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);
- const MCExpr *MCOffset =
- MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx);
- Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset);
+ if (!isAArch64) {
+ // Emit a label assignment with the SEH frame offset so we can use it for
+ // llvm.eh.recoverfp.
+ StringRef FLinkageName =
+ GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());
+ MCSymbol *ParentFrameOffset =
+ Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);
+ const MCExpr *MCOffset =
+ MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx);
+ Asm->OutStreamer->EmitAssignment(ParentFrameOffset, MCOffset);
+ }
// Use the assembler to compute the number of table entries through label
// difference and division.
@@ -937,6 +939,9 @@ void WinException::emitEHRegistrationOff
if (FI != INT_MAX) {
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
unsigned UnusedReg;
+ // FIXME: getFrameIndexReference needs to match the behavior of
+ // AArch64RegisterInfo::hasBasePointer in which one of the scenarios where
+ // SP is used is if frame size >= 256.
Offset = TFI->getFrameIndexReference(*Asm->MF, FI, UnusedReg);
}
Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Wed Jan 16 11:52:59 2019
@@ -6183,6 +6183,8 @@ SelectionDAGBuilder::visitIntrinsicCall(
.addFrameIndex(FI);
}
+ MF.setHasLocalEscape(true);
+
return nullptr;
}
Modified: llvm/trunk/lib/Target/AArch64/AArch64AsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64AsmPrinter.cpp?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64AsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64AsmPrinter.cpp Wed Jan 16 11:52:59 2019
@@ -694,6 +694,34 @@ void AArch64AsmPrinter::EmitInstruction(
switch (MI->getOpcode()) {
default:
break;
+ case AArch64::MOVMCSym: {
+ unsigned DestReg = MI->getOperand(0).getReg();
+ const MachineOperand &MO_Sym = MI->getOperand(1);
+ MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym);
+ MCOperand Hi_MCSym, Lo_MCSym;
+
+ Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S);
+ Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC);
+
+ MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym);
+ MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym);
+
+ MCInst MovZ;
+ MovZ.setOpcode(AArch64::MOVZXi);
+ MovZ.addOperand(MCOperand::createReg(DestReg));
+ MovZ.addOperand(Hi_MCSym);
+ MovZ.addOperand(MCOperand::createImm(16));
+ EmitToStreamer(*OutStreamer, MovZ);
+
+ MCInst MovK;
+ MovK.setOpcode(AArch64::MOVKXi);
+ MovK.addOperand(MCOperand::createReg(DestReg));
+ MovK.addOperand(MCOperand::createReg(DestReg));
+ MovK.addOperand(Lo_MCSym);
+ MovK.addOperand(MCOperand::createImm(0));
+ EmitToStreamer(*OutStreamer, MovK);
+ return;
+ }
case AArch64::MOVIv2d_ns:
// If the target has <rdar://problem/16473581>, lower this
// instruction to movi.16b instead.
Modified: llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp Wed Jan 16 11:52:59 2019
@@ -228,6 +228,10 @@ bool AArch64FrameLowering::hasFP(const M
MFI.getMaxCallFrameSize() > DefaultSafeSPDisplacement)
return true;
+ // Win64 SEH requires frame pointer if funclets are present.
+ if (MF.hasLocalEscape())
+ return true;
+
return false;
}
Modified: llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp Wed Jan 16 11:52:59 2019
@@ -2743,6 +2743,34 @@ SDValue AArch64TargetLowering::LowerINTR
case Intrinsic::aarch64_neon_umin:
return DAG.getNode(ISD::UMIN, dl, Op.getValueType(),
Op.getOperand(1), Op.getOperand(2));
+
+ case Intrinsic::localaddress: {
+ // Returns one of the stack, base, or frame pointer registers, depending on
+ // which is used to reference local variables.
+ MachineFunction &MF = DAG.getMachineFunction();
+ const AArch64RegisterInfo *RegInfo = Subtarget->getRegisterInfo();
+ unsigned Reg;
+ if (RegInfo->hasBasePointer(MF))
+ Reg = RegInfo->getBaseRegister();
+ else // This function handles the SP or FP case.
+ Reg = RegInfo->getFrameRegister(MF);
+ return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg,
+ Op.getSimpleValueType());
+ }
+
+ case Intrinsic::eh_recoverfp: {
+ // FIXME: This needs to be implemented to correctly handle highly aligned
+ // stack objects. For now we simply return the incoming FP. Refer D53541
+ // for more details.
+ SDValue FnOp = Op.getOperand(1);
+ SDValue IncomingFPOp = Op.getOperand(2);
+ GlobalAddressSDNode *GSD = dyn_cast<GlobalAddressSDNode>(FnOp);
+ auto *Fn = dyn_cast_or_null<Function>(GSD ? GSD->getGlobal() : nullptr);
+ if (!Fn)
+ report_fatal_error(
+ "llvm.eh.recoverfp must take a function as the first argument");
+ return IncomingFPOp;
+ }
}
}
Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td Wed Jan 16 11:52:59 2019
@@ -133,6 +133,10 @@ def UseNegativeImmediates
: Predicate<"false">, AssemblerPredicate<"!FeatureNoNegativeImmediates",
"NegativeImmediates">;
+def AArch64LocalRecover : SDNode<"ISD::LOCAL_RECOVER",
+ SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
+ SDTCisInt<1>]>>;
+
//===----------------------------------------------------------------------===//
// AArch64-specific DAG Nodes.
@@ -6801,5 +6805,8 @@ def : Pat<(AArch64tcret tglobaladdr:$dst
def : Pat<(AArch64tcret texternalsym:$dst, (i32 timm:$FPDiff)),
(TCRETURNdi texternalsym:$dst, imm:$FPDiff)>;
+def MOVMCSym : Pseudo<(outs GPR64:$dst), (ins i64imm:$sym), []>, Sched<[]>;
+def : Pat<(i64 (AArch64LocalRecover mcsym:$sym)), (MOVMCSym mcsym:$sym)>;
+
include "AArch64InstrAtomics.td"
include "AArch64SVEInstrInfo.td"
Modified: llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp?rev=351370&r1=351369&r2=351370&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp Wed Jan 16 11:52:59 2019
@@ -466,6 +466,13 @@ void AArch64RegisterInfo::eliminateFrame
// Modify MI as necessary to handle as much of 'Offset' as possible
Offset = TFI->resolveFrameIndexReference(MF, FrameIndex, FrameReg);
+
+ if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE) {
+ MachineOperand &FI = MI.getOperand(FIOperandNum);
+ FI.ChangeToImmediate(Offset);
+ return;
+ }
+
if (rewriteAArch64FrameIndex(MI, FIOperandNum, FrameReg, Offset, TII))
return;
Added: llvm/trunk/test/CodeGen/AArch64/seh-finally.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/seh-finally.ll?rev=351370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/seh-finally.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/seh-finally.ll Wed Jan 16 11:52:59 2019
@@ -0,0 +1,67 @@
+; RUN: llc -mtriple arm64-windows -o - %s | FileCheck %s
+
+; Function Attrs: noinline optnone uwtable
+define dso_local i32 @foo() {
+entry:
+; CHECK-LABEL: foo
+; CHECK: orr w8, wzr, #0x1
+; CHECK: mov w0, wzr
+; CHECK: mov x1, x29
+; CHECK: .set .Lfoo$frame_escape_0, -4
+; CHECK: stur w8, [x29, #-4]
+; CHECK: bl "?fin$0 at 0@foo@@"
+; CHECK: ldur w0, [x29, #-4]
+
+ %count = alloca i32, align 4
+ call void (...) @llvm.localescape(i32* %count)
+ store i32 0, i32* %count, align 4
+ %0 = load i32, i32* %count, align 4
+ %add = add nsw i32 %0, 1
+ store i32 %add, i32* %count, align 4
+ %1 = call i8* @llvm.localaddress()
+ call void @"?fin$0 at 0@foo@@"(i8 0, i8* %1)
+ %2 = load i32, i32* %count, align 4
+ ret i32 %2
+}
+
+define internal void @"?fin$0 at 0@foo@@"(i8 %abnormal_termination, i8* %frame_pointer) {
+entry:
+; CHECK-LABEL: @"?fin$0 at 0@foo@@"
+; CHECK: sub sp, sp, #16
+; CHECK: str x1, [sp, #8]
+; CHECK: strb w0, [sp, #7]
+; CHECK: movz x8, #:abs_g1_s:.Lfoo$frame_escape_0
+; CHECK: movk x8, #:abs_g0_nc:.Lfoo$frame_escape_0
+; CHECK: add x8, x1, x8
+; CHECK: ldr w9, [x8]
+; CHECK: add w9, w9, #1
+; CHECK: str w9, [x8]
+
+ %frame_pointer.addr = alloca i8*, align 8
+ %abnormal_termination.addr = alloca i8, align 1
+ %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @foo to i8*), i8* %frame_pointer, i32 0)
+ %count = bitcast i8* %0 to i32*
+ store i8* %frame_pointer, i8** %frame_pointer.addr, align 8
+ store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1
+ %1 = zext i8 %abnormal_termination to i32
+ %cmp = icmp eq i32 %1, 0
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %2 = load i32, i32* %count, align 4
+ %add = add nsw i32 %2, 1
+ store i32 %add, i32* %count, align 4
+ br label %if.end
+
+if.end: ; preds = %if.then, %entry
+ ret void
+}
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localrecover(i8*, i8*, i32)
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localaddress()
+
+; Function Attrs: nounwind
+declare void @llvm.localescape(...)
Added: llvm/trunk/test/CodeGen/AArch64/seh-localescape.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/seh-localescape.ll?rev=351370&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/seh-localescape.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/seh-localescape.ll Wed Jan 16 11:52:59 2019
@@ -0,0 +1,30 @@
+; RUN: llc -mtriple arm64-windows %s -o - | FileCheck %s
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local i32 @foo() {
+entry:
+; CHECK-LABEL: foo
+; CHECK: .set .Lfoo$frame_escape_0, -4
+
+ %count = alloca i32, align 4
+ call void (...) @llvm.localescape(i32* %count)
+ ret i32 0
+}
+
+define internal i32 @"?filt$0 at 0@foo@@"(i8* %exception_pointers, i8* %frame_pointer) {
+entry:
+; CHECK-LABEL: @"?filt$0 at 0@foo@@"
+; CHECK: movz x8, #:abs_g1_s:.Lfoo$frame_escape_0
+; CHECK: movk x8, #:abs_g0_nc:.Lfoo$frame_escape_0
+
+ %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @foo to i8*), i8* %frame_pointer, i32 0)
+ %count = bitcast i8* %0 to i32*
+ %1 = load i32, i32* %count, align 4
+ ret i32 %1
+}
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localrecover(i8*, i8*, i32) #2
+
+; Function Attrs: nounwind
+declare void @llvm.localescape(...) #3
More information about the llvm-commits
mailing list