From d110e2b4a3b6f443997ddb23fdb98020f28f84d2 Mon Sep 17 00:00:00 2001 From: Quentin Colombet Date: Wed, 9 Dec 2015 23:08:18 +0000 Subject: [PATCH] [X86] Enable shrink-wrapping by default, but keep it disabled for stack frames without a frame pointer when unwind may happen. This is a workaround for a bug in the way we emit the CFI directives for frameless unwind information. See PR25614. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255175 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86FrameLowering.cpp | 6 ++ lib/Target/X86/X86FrameLowering.h | 3 + test/CodeGen/X86/avx-splat.ll | 10 +- test/CodeGen/X86/tail-opts.ll | 2 +- test/CodeGen/X86/x86-shrink-wrap-unwind.ll | 153 +++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 test/CodeGen/X86/x86-shrink-wrap-unwind.ll diff --git a/lib/Target/X86/X86FrameLowering.cpp b/lib/Target/X86/X86FrameLowering.cpp index 2e7ed58e340..8695a0e2967 100644 --- a/lib/Target/X86/X86FrameLowering.cpp +++ b/lib/Target/X86/X86FrameLowering.cpp @@ -2595,6 +2595,12 @@ bool X86FrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const { return !flagsNeedToBePreservedBeforeTheTerminators(MBB); } +bool X86FrameLowering::enableShrinkWrapping(const MachineFunction &MF) const { + // If we may need to emit frameless compact unwind information, give + // up as this is currently broken: PR25614. + return MF.getFunction()->hasFnAttribute(Attribute::NoUnwind) || hasFP(MF); +} + MachineBasicBlock::iterator X86FrameLowering::restoreWin32EHStackPointers( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL, bool RestoreSP) const { diff --git a/lib/Target/X86/X86FrameLowering.h b/lib/Target/X86/X86FrameLowering.h index 68dc8edfd43..3ab41b4a578 100644 --- a/lib/Target/X86/X86FrameLowering.h +++ b/lib/Target/X86/X86FrameLowering.h @@ -134,6 +134,9 @@ public: /// \p MBB will be correctly handled by the target. bool canUseAsEpilogue(const MachineBasicBlock &MBB) const override; + /// Returns true if the target will correctly handle shrink wrapping. + bool enableShrinkWrapping(const MachineFunction &MF) const override; + /// convertArgMovsToPushes - This method tries to convert a call sequence /// that uses sub and mov instructions to put the argument onto the stack /// into a series of pushes. diff --git a/test/CodeGen/X86/avx-splat.ll b/test/CodeGen/X86/avx-splat.ll index 70dabe44144..37eacc87c3f 100644 --- a/test/CodeGen/X86/avx-splat.ll +++ b/test/CodeGen/X86/avx-splat.ll @@ -57,19 +57,19 @@ entry: define <8 x float> @funcE() nounwind { ; CHECK-LABEL: funcE: ; CHECK: ## BB#0: ## %for_exit499 -; CHECK-NEXT: pushq %rbp -; CHECK-NEXT: movq %rsp, %rbp -; CHECK-NEXT: andq $-32, %rsp -; CHECK-NEXT: subq $1312, %rsp ## imm = 0x520 ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: ## implicit-def: %YMM0 ; CHECK-NEXT: testb %al, %al ; CHECK-NEXT: jne LBB4_2 ; CHECK-NEXT: ## BB#1: ## %load.i1247 +; CHECK-NEXT: pushq %rbp +; CHECK-NEXT: movq %rsp, %rbp +; CHECK-NEXT: andq $-32, %rsp +; CHECK-NEXT: subq $1312, %rsp ## imm = 0x520 ; CHECK-NEXT: vbroadcastss {{[0-9]+}}(%rsp), %ymm0 -; CHECK-NEXT: LBB4_2: ## %__load_and_broadcast_32.exit1249 ; CHECK-NEXT: movq %rbp, %rsp ; CHECK-NEXT: popq %rbp +; CHECK-NEXT: LBB4_2: ## %__load_and_broadcast_32.exit1249 ; CHECK-NEXT: retq allocas: %udx495 = alloca [18 x [18 x float]], align 32 diff --git a/test/CodeGen/X86/tail-opts.ll b/test/CodeGen/X86/tail-opts.ll index c522ba60d6b..bf778e5bad2 100644 --- a/test/CodeGen/X86/tail-opts.ll +++ b/test/CodeGen/X86/tail-opts.ll @@ -277,8 +277,8 @@ declare fastcc %union.tree_node* @default_conversion(%union.tree_node*) nounwind ; CHECK-LABEL: foo: ; CHECK: callq func -; CHECK-NEXT: .LBB4_2: ; CHECK-NEXT: popq +; CHECK-NEXT: .LBB4_2: ; CHECK-NEXT: ret define void @foo(i1* %V) nounwind { diff --git a/test/CodeGen/X86/x86-shrink-wrap-unwind.ll b/test/CodeGen/X86/x86-shrink-wrap-unwind.ll new file mode 100644 index 00000000000..7c00f407b1e --- /dev/null +++ b/test/CodeGen/X86/x86-shrink-wrap-unwind.ll @@ -0,0 +1,153 @@ +; RUN: llc %s -o - | FileCheck %s --check-prefix=CHECK +; +; This test checks that we do not use shrink-wrapping when +; the function does not have any frame pointer and may unwind. +; This is a workaround for a limitation in the emission of +; the CFI directives, that are not correct in such case. +; PR25614 +; +; Note: This test cannot be merged with the shrink-wrapping tests +; because the booleans set on the command line take precedence on +; the target logic that disable shrink-wrapping. +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "x86_64-apple-macosx" + + +; No shrink-wrapping should occur here, until the CFI information are fixed. +; CHECK-LABEL: framelessUnwind: +; +; Prologue code. +; (What we push does not matter. It should be some random sratch register.) +; CHECK: pushq +; +; Compare the arguments and jump to exit. +; After the prologue is set. +; CHECK: movl %edi, [[ARG0CPY:%e[a-z]+]] +; CHECK-NEXT: cmpl %esi, [[ARG0CPY]] +; CHECK-NEXT: jge [[EXIT_LABEL:LBB[0-9_]+]] +; +; Store %a in the alloca. +; CHECK: movl [[ARG0CPY]], 4(%rsp) +; Set the alloca address in the second argument. +; CHECK-NEXT: leaq 4(%rsp), %rsi +; Set the first argument to zero. +; CHECK-NEXT: xorl %edi, %edi +; CHECK-NEXT: callq _doSomething +; +; CHECK: [[EXIT_LABEL]]: +; +; Without shrink-wrapping, epilogue is in the exit block. +; Epilogue code. (What we pop does not matter.) +; CHECK-NEXT: popq +; +; CHECK-NEXT: retq +define i32 @framelessUnwind(i32 %a, i32 %b) #0 { + %tmp = alloca i32, align 4 + %tmp2 = icmp slt i32 %a, %b + br i1 %tmp2, label %true, label %false + +true: + store i32 %a, i32* %tmp, align 4 + %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) + br label %false + +false: + %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ] + ret i32 %tmp.0 +} + +declare i32 @doSomething(i32, i32*) + +attributes #0 = { "no-frame-pointer-elim"="false" } + +; Shrink-wrapping should occur here. We have a frame pointer. +; CHECK-LABEL: frameUnwind: +; +; Compare the arguments and jump to exit. +; No prologue needed. +; +; Compare the arguments and jump to exit. +; After the prologue is set. +; CHECK: movl %edi, [[ARG0CPY:%e[a-z]+]] +; CHECK-NEXT: cmpl %esi, [[ARG0CPY]] +; CHECK-NEXT: jge [[EXIT_LABEL:LBB[0-9_]+]] +; +; Prologue code. +; CHECK: pushq %rbp +; CHECK: movq %rsp, %rbp +; +; Store %a in the alloca. +; CHECK: movl [[ARG0CPY]], -4(%rbp) +; Set the alloca address in the second argument. +; CHECK-NEXT: leaq -4(%rbp), %rsi +; Set the first argument to zero. +; CHECK-NEXT: xorl %edi, %edi +; CHECK-NEXT: callq _doSomething +; +; Epilogue code. (What we pop does not matter.) +; CHECK: popq %rbp +; +; CHECK: [[EXIT_LABEL]]: +; CHECK-NEXT: retq +define i32 @frameUnwind(i32 %a, i32 %b) #1 { + %tmp = alloca i32, align 4 + %tmp2 = icmp slt i32 %a, %b + br i1 %tmp2, label %true, label %false + +true: + store i32 %a, i32* %tmp, align 4 + %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) + br label %false + +false: + %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ] + ret i32 %tmp.0 +} + +attributes #1 = { "no-frame-pointer-elim"="true" } + +; Shrink-wrapping should occur here. We do not have to unwind. +; CHECK-LABEL: framelessnoUnwind: +; +; Compare the arguments and jump to exit. +; No prologue needed. +; +; Compare the arguments and jump to exit. +; After the prologue is set. +; CHECK: movl %edi, [[ARG0CPY:%e[a-z]+]] +; CHECK-NEXT: cmpl %esi, [[ARG0CPY]] +; CHECK-NEXT: jge [[EXIT_LABEL:LBB[0-9_]+]] +; +; Prologue code. +; (What we push does not matter. It should be some random sratch register.) +; CHECK: pushq +; +; Store %a in the alloca. +; CHECK: movl [[ARG0CPY]], 4(%rsp) +; Set the alloca address in the second argument. +; CHECK-NEXT: leaq 4(%rsp), %rsi +; Set the first argument to zero. +; CHECK-NEXT: xorl %edi, %edi +; CHECK-NEXT: callq _doSomething +; +; Epilogue code. +; CHECK-NEXT: addq +; +; CHECK: [[EXIT_LABEL]]: +; CHECK-NEXT: retq +define i32 @framelessnoUnwind(i32 %a, i32 %b) #2 { + %tmp = alloca i32, align 4 + %tmp2 = icmp slt i32 %a, %b + br i1 %tmp2, label %true, label %false + +true: + store i32 %a, i32* %tmp, align 4 + %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) + br label %false + +false: + %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ] + ret i32 %tmp.0 +} + +attributes #2 = { "no-frame-pointer-elim"="false" nounwind } -- 2.11.0