[llvm] r249522 - [X86] Emit .cfi_escape GNU_ARGS_SIZE when adjusting the stack before calls

Kuperstein, Michael M via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 11 03:57:08 PDT 2015


Err, I'm sorry, that's wrong - Darwin shouldn't change code generation based on -g either.

So, that means I see the following options:

1) Always force FP for -Os. 
This (and please correct me if I'm wrong) should fix all functional problems, including Darwin, but looks really drastic.

2) Disable the optimization completely on Darwin ( :-( ). 
Emit cfi_def_cfa_offset for each stack adjustment when using debug info. 
When there is no debug info, but EH is enabled, then do one of:
2a) Force FP.
2b) Emit cfi_def_cfa_offset before each call site.
2c) Disable the optimization.

It looks like this is what GCC does is to default to -fno-omit-frame-pointer (option 1) when compiling for size.
If specifically passed "-Os -fomit-frame-pointer", it emits cfi_def_cfa_offset after each stack adjustment.

Michael

-----Original Message-----
From: Kuperstein, Michael M 
Sent: Sunday, October 11, 2015 09:47
To: 'friss at apple.com'; rnk at google.com
Cc: llvm-commits at lists.llvm.org; Kreitzer, David L
Subject: RE: [llvm] r249522 - [X86] Emit .cfi_escape GNU_ARGS_SIZE when adjusting the stack before calls

Ah, I see.

So,  I think we have three separate cases here.
a) "Darwin + Any unwind info + No FP" will probably have to disable the optimization entirely. 

b) "Not Darwin + debug info + No FP" will have to emit a cfi_def_cfa_offset after each stack adjustment. 
To the best of my understanding, "-g" should not affect code generation, so disabling the optimization only because we're emitting debug info doesn't sound like a viable option. 

c) "Not Darwin + EH + No FP" - this is the hard one. 
One option is to have -Os force FP in the presence of Dwarf EH, but that seems like a big hammer with rather unpredictable consequences. 
Another is to disable the optimization whenever we have EH. 
The third is to emit a .cfi_def_cfa_offset before outgoing calls.

Any thoughts on what may be best?

Just for reference, this is what GCC 5.2 does here for Dave's f2(): 

For -O2, it actually uses pushes (we don't), but sets .cfi_def_cfa_offset after each adjustment:
f2(int, int, int):
.LFB12:
	.file 1 "/tmp/gcc-explorer-compiler115911-66-1rl2lxh/example.cpp"
	.loc 1 4 0
	.cfi_startproc
	subl	$24, %esp
	.cfi_def_cfa_offset 28
	.loc 1 5 0
	pushl	$4
	.cfi_def_cfa_offset 32
	call	__cxa_allocate_exception
.LVL1:
	movl	32(%esp), %edx
	addl	36(%esp), %edx
	addl	40(%esp), %edx
	addl	$12, %esp
	.cfi_def_cfa_offset 20
	movl	%edx, (%eax)
	pushl	$0
	.cfi_def_cfa_offset 24
	pushl	typeinfo for int
	.cfi_def_cfa_offset 28
	pushl	%eax
	.cfi_def_cfa_offset 32
	call	__cxa_throw
.LVL2:
	.cfi_endproc

For -Os, it forces FP:

f2(int, int, int):
.LFB0:
	.file 1 "/tmp/gcc-explorer-compiler115911-66-ua61g3/example.cpp"
	.loc 1 4 0
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$20, %esp
	.loc 1 5 0
	pushl	$4
	call	__cxa_allocate_exception
.LVL1:
	movl	8(%ebp), %edx
	addl	12(%ebp), %edx
	addl	$12, %esp
	addl	16(%ebp), %edx
	movl	%edx, (%eax)
	pushl	$0
	pushl	typeinfo for int
	pushl	%eax
	call	__cxa_throw
.LVL2:
	.cfi_endproc

-----Original Message-----
From: friss at apple.com [mailto:friss at apple.com] 
Sent: Thursday, October 08, 2015 18:55
To: Kuperstein, Michael M
Cc: llvm-commits at lists.llvm.org; Kreitzer, David L
Subject: Re: [llvm] r249522 - [X86] Emit .cfi_escape GNU_ARGS_SIZE when adjusting the stack before calls


> On Oct 8, 2015, at 8:40 AM, Kreitzer, David L <david.l.kreitzer at intel.com> wrote:
> 
> Debuggers do not require DW_CFA_gnu_args_size in order to correctly unwind the stack. DW_CFA_gnu_args_size helps the EH runtime set the stack pointer when transferring control to a handler following an exception.
> 
> But Fred might be saying something different. In a routine without a frame pointer (or more precisely, in a routine that uses a stack-pointer-based CFA), every adjustment to the stack pointer needs to be described in the unwind information.

Yes, that’s my point. Note that if you do emit all the CFI adjustments, we will hit the same issue we had with EH compact encoding. Thus if you decide to do that, the check I just added to disable the optimization in some cases on Darwin needs to become more strict. (Another naive approach would be to simply not apply the optimization when there is no frame pointer and we are generating some kind of unwinding info, be it EH or debug_frame). 

Fred

> So, for example, if the CFA is %esp+28 prior to a push, I would expect to see a .cfa_def_cfa_offset 32 directive following the push. Failing to do that will cause unwinders to fail at any point in the program where the CFA is incorrect.
> 
> It doesn't look like these CFA directives are being generated correctly following the X86 call frame optimization. Michael, try the following program with "clang++ -m32 -Os". This fails for me unless I manually add the correct .cfi_def_cfa_offset directives before the call to __cxa_throw and before the call to f2.
> 
> It's also worth pointing out that for the purposes of synchronous EH, it is only necessary that the CFA be set correctly at outgoing calls. That can help reduce the number of CFA directives that you need. If you need the ability to unwind the stack at any arbitrary instruction, though, e.g. for debugging or asynchronous EH, you are pretty much stuck with a CFA directive at each stack adjust.
> 
> - Dave
> 
> ---- t.cpp ----
> #include <stdio.h>
> 
> void f2(int a, int b, int c)
> {
>  throw a + b + c;
> }
> 
> __attribute__((noinline))
> void f1()
> {
>  f2(1, 2, 3);
> }
> 
> int main()
> {
>  try { f1(); }
>  catch(int x) { printf("caught %d\n", x); }  return 0; }
> ---------------
> 
> From: Kuperstein, Michael M
> Sent: Thursday, October 08, 2015 2:50 AM
> To: friss at apple.com; Kreitzer, David L
> Cc: llvm-commits at lists.llvm.org
> Subject: RE: [llvm] r249522 - [X86] Emit .cfi_escape GNU_ARGS_SIZE 
> when adjusting the stack before calls
> 
> It is my understand that debuggers don’t require it.
> Dave, could you elaborate?
> 
> Thanks,
>   Michael
> 
> From: friss at apple.com [mailto:friss at apple.com]
> Sent: Thursday, October 08, 2015 09:28
> To: Kuperstein, Michael M
> Cc: llvm-commits at lists.llvm.org
> Subject: Re: [llvm] r249522 - [X86] Emit .cfi_escape GNU_ARGS_SIZE 
> when adjusting the stack before calls
> 
> 
> On Oct 7, 2015, at 9:17 PM, Kuperstein, Michael M <michael.m.kuperstein at intel.com> wrote:
> 
> Yes, we won’t emit GNU_ARGS_SIZE CFI if there are no landing pads in the function (it’s not necessary in that case – in fact it is only necessary just before an invoke), so disabling based on that should be fine. 
> 
> I sent a patch to do that. I’m wondering though: EH isn’t the only consumer of unwinding info. Debuggers and symbolizers will try to unwind the stack. If you don’t have a frame pointer, won’t you break these use cases if you have no CFI annotations for these pushes?
> 
> Fred
> 
> From: friss at apple.com [mailto:friss at apple.com]
> Sent: Thursday, October 08, 2015 01:00
> To: Kuperstein, Michael M
> Cc: llvm-commits at lists.llvm.org
> Subject: Re: [llvm] r249522 - [X86] Emit .cfi_escape GNU_ARGS_SIZE 
> when adjusting the stack before calls
>  
>  
> On Oct 7, 2015, at 2:41 PM, Kuperstein, Michael M <michael.m.kuperstein at intel.com> wrote:
>  
> Hi Fred,
> 
> Sorry for the breakage, I realize how annoying this sort of thing is 
> to debug. :-\
>  
> No worries, it wasn’t the most bizarre thing I had to debug lately :-)
> 
> 
> I'll try to figure out what to do about the assert. My first thought is that it may be overly conservative, and we should just be skipping CFI directives, regardless of whether they're marked FrameSetup.
> Do you happen to have a testcase handy?
>  
> Not a reduced one that I could send out, sorry. And I don’t have much time right now to work on that. I would expect that if the first thing in the function is call, this should trigger quite easily. I should be able to work on a test case tomorrow. 
> 
> 
> To disable it on Darwin (are there other platforms that use compact_unwind?), the best place would be in X86CallFrameOptimization::isLegal().
> In any case, even for Darwin, you only need to disable it if !MF.getMMI().getLandingPads().empty(), right?
>  
> As soon as you emit a GNU_ARGS_size CFI, it confuses the compact unwind emission, so I think we need to avoid getting into that case completely (if the compiler can’t synthesize compact unwind desc, the linker will give strange warnings). Does the above condition cover all these cases?
>  
> Fred
> 
> 
> Michael
> 
> -----Original Message-----
> From: friss at apple.com [mailto:friss at apple.com]
> Sent: Thursday, October 08, 2015 00:10
> To: Kuperstein, Michael M
> Cc: llvm-commits at lists.llvm.org
> Subject: Re: [llvm] r249522 - [X86] Emit .cfi_escape GNU_ARGS_SIZE 
> when adjusting the stack before calls
> 
> Hi Michael,
> 
> I just spent quite some time debugging an issue that should be fixed by that patch, unfortunately there are 2 issues with it:
> 
> - You can end up generating an args size directive right after the prologue, which means the assert in that function of DwarfDebug.cpp will sometimes fire:
> 
> static DebugLoc findPrologueEndLoc(const MachineFunction *MF) {  // 
> First known non-DBG_VALUE and non-frame setup location marks  // the 
> beginning of the function body.
>  for (const auto &MBB : *MF)
>    for (const auto &MI : MBB)
>      if (!MI.isDebugValue() && !MI.getFlag(MachineInstr::FrameSetup) &&
>          MI.getDebugLoc()) {
>        // Did the target forget to set the FrameSetup flag for CFI insns?
>        assert(!MI.isCFIInstruction() &&
>               "First non-frame-setup instruction is a CFI instruction.");
>        return MI.getDebugLoc();
>      }
>  return DebugLoc();
> }
> 
> - Darwin uses compact_unwind, and a dynamic SP during the function can’t really be described by that (because if you look at the code, we currently emit one compact unwind entry per function. Not sure if the runtime depends on that or if we could emit multiple ones). So the exception handling is still totally broken on Darwin.
> 
> At least as a short-term thing, what’s the right place to just disable the push optimizations on Darwin (or maybe any platform that uses compact_unwind) when the function needs an EH description?
> 
> Fred
> 
> 
> On Oct 7, 2015, at 12:01 AM, Michael Kuperstein via llvm-commits <llvm-commits at lists.llvm.org> wrote:
> 
> Author: mkuper
> Date: Wed Oct  7 02:01:31 2015
> New Revision: 249522
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=249522&view=rev
> Log:
> [X86] Emit .cfi_escape GNU_ARGS_SIZE when adjusting the stack before 
> calls
> 
> When outgoing function arguments are passed using push instructions, 
> and EH is enabled, we may need to indicate to the stack unwinder that 
> the stack pointer was adjusted before the call.
> 
> This should fix the exception handling issues in PR24792.
> 
> Differential Revision: http://reviews.llvm.org/D13132
> 
> Added:
>   llvm/trunk/test/CodeGen/X86/push-cfi-obj.ll
>   llvm/trunk/test/CodeGen/X86/push-cfi.ll
> Modified:
>   llvm/trunk/include/llvm/MC/MCDwarf.h
>   llvm/trunk/include/llvm/MC/MCStreamer.h
>   llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
>   llvm/trunk/lib/MC/MCAsmStreamer.cpp
>   llvm/trunk/lib/MC/MCDwarf.cpp
>   llvm/trunk/lib/MC/MCStreamer.cpp
>   llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
> 
> Modified: llvm/trunk/include/llvm/MC/MCDwarf.h
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCDwarf
> .h?rev=249522&r1=249521&r2=249522&view=diff
> ======================================================================
> ========
> --- llvm/trunk/include/llvm/MC/MCDwarf.h (original)
> +++ llvm/trunk/include/llvm/MC/MCDwarf.h Wed Oct  7 02:01:31 2015
> @@ -340,7 +340,8 @@ public:
>    OpRestore,
>    OpUndefined,
>    OpRegister,
> -    OpWindowSave
> +    OpWindowSave,
> +    OpGnuArgsSize
>  };
> 
> private:
> @@ -454,6 +455,11 @@ public:
>    return MCCFIInstruction(OpEscape, L, 0, 0, Vals);  }
> 
> +  /// \brief A special wrapper for .cfi_escape that indicates 
> + GNU_ARGS_SIZE  static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size) {
> +    return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, "");  }
> +
>  OpType getOperation() const { return Operation; }  MCSymbol 
> *getLabel() const { return Label; }
> 
> @@ -473,7 +479,7 @@ public:
>  int getOffset() const {
>    assert(Operation == OpDefCfa || Operation == OpOffset ||
>           Operation == OpRelOffset || Operation == OpDefCfaOffset ||
> -           Operation == OpAdjustCfaOffset);
> +           Operation == OpAdjustCfaOffset || Operation == 
> + OpGnuArgsSize);
>    return Offset;
>  }
> 
> 
> Modified: llvm/trunk/include/llvm/MC/MCStreamer.h
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCStrea
> mer.h?rev=249522&r1=249521&r2=249522&view=diff
> ======================================================================
> ========
> --- llvm/trunk/include/llvm/MC/MCStreamer.h (original)
> +++ llvm/trunk/include/llvm/MC/MCStreamer.h Wed Oct  7 02:01:31 2015
> @@ -661,6 +661,7 @@ public:
>  virtual void EmitCFIRelOffset(int64_t Register, int64_t Offset);  
> virtual void EmitCFIAdjustCfaOffset(int64_t Adjustment);  virtual void 
> EmitCFIEscape(StringRef Values);
> +  virtual void EmitCFIGnuArgsSize(int64_t Size);
>  virtual void EmitCFISignalFrame();
>  virtual void EmitCFIUndefined(int64_t Register);  virtual void 
> EmitCFIRegister(int64_t Register1, int64_t Register2);
> 
> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/
> AsmPrinterDwarf.cpp?rev=249522&r1=249521&r2=249522&view=diff
> ======================================================================
> ========
> --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp (original)
> +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp Wed Oct  7
> +++ 02:01:31 2015
> @@ -246,6 +246,12 @@ void AsmPrinter::emitCFIInstruction(cons
>  case MCCFIInstruction::OpSameValue:
>    OutStreamer->EmitCFISameValue(Inst.getRegister());
>    break;
> +  case MCCFIInstruction::OpGnuArgsSize:
> +    OutStreamer->EmitCFIGnuArgsSize(Inst.getOffset());
> +    break;
> +  case MCCFIInstruction::OpEscape:
> +    OutStreamer->EmitCFIEscape(Inst.getValues());
> +    break;
>  }
> }
> 
> 
> Modified: llvm/trunk/lib/MC/MCAsmStreamer.cpp
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAsmStreamer.cp
> p?rev=249522&r1=249521&r2=249522&view=diff
> ======================================================================
> ========
> --- llvm/trunk/lib/MC/MCAsmStreamer.cpp (original)
> +++ llvm/trunk/lib/MC/MCAsmStreamer.cpp Wed Oct  7 02:01:31 2015
> @@ -29,6 +29,7 @@
> #include "llvm/Support/ErrorHandling.h"
> #include "llvm/Support/Format.h"
> #include "llvm/Support/FormattedStream.h"
> +#include "llvm/Support/LEB128.h"
> #include "llvm/Support/MathExtras.h"
> #include "llvm/Support/Path.h"
> #include <cctype>
> @@ -210,6 +211,8 @@ public:
>  void EmitCFISameValue(int64_t Register) override;  void 
> EmitCFIRelOffset(int64_t Register, int64_t Offset) override;  void 
> EmitCFIAdjustCfaOffset(int64_t Adjustment) override;
> +  void EmitCFIEscape(StringRef Values) override;  void 
> + EmitCFIGnuArgsSize(int64_t Size) override;
>  void EmitCFISignalFrame() override;
>  void EmitCFIUndefined(int64_t Register) override;  void 
> EmitCFIRegister(int64_t Register1, int64_t Register2) override; @@ 
> -1010,6 +1013,32 @@ void MCAsmStreamer::EmitCFIDefCfaOffset(
>  EmitEOL();
> }
> 
> +static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef
> +Values) {
> +  OS << "\t.cfi_escape ";
> +  if (!Values.empty()) {
> +    size_t e = Values.size() - 1;
> +    for (size_t i = 0; i < e; ++i)
> +      OS << format("0x%02x", uint8_t(Values[i])) << ", ";
> +    OS << format("0x%02x", uint8_t(Values[e]));
> +  }
> +}
> +
> +void MCAsmStreamer::EmitCFIEscape(StringRef Values) {
> +  MCStreamer::EmitCFIEscape(Values);
> +  PrintCFIEscape(OS, Values);
> +  EmitEOL();
> +}
> +
> +void MCAsmStreamer::EmitCFIGnuArgsSize(int64_t Size) {
> +  MCStreamer::EmitCFIGnuArgsSize(Size);
> +  
> +  uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size };  unsigned Len 
> + = encodeULEB128(Size, Buffer + 1) + 1;
> +  
> +  PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len));
> +  EmitEOL();
> +}
> +
> void MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) {  
> MCStreamer::EmitCFIDefCfaRegister(Register);
>  OS << "\t.cfi_def_cfa_register ";
> 
> Modified: llvm/trunk/lib/MC/MCDwarf.cpp
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCDwarf.cpp?rev=
> 249522&r1=249521&r2=249522&view=diff
> ======================================================================
> ========
> --- llvm/trunk/lib/MC/MCDwarf.cpp (original)
> +++ llvm/trunk/lib/MC/MCDwarf.cpp Wed Oct  7 02:01:31 2015
> @@ -1147,6 +1147,11 @@ void FrameEmitterImpl::EmitCFIInstructio
>    Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1);
>    return;
>  }
> +  case MCCFIInstruction::OpGnuArgsSize: {
> +    Streamer.EmitIntValue(dwarf::DW_CFA_GNU_args_size, 1);
> +    Streamer.EmitULEB128IntValue(Instr.getOffset());
> +    return;
> +  }
>  case MCCFIInstruction::OpEscape:
>    Streamer.EmitBytes(Instr.getValues());
>    return;
> 
> Modified: llvm/trunk/lib/MC/MCStreamer.cpp
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCStreamer.cpp?r
> ev=249522&r1=249521&r2=249522&view=diff
> ======================================================================
> ========
> --- llvm/trunk/lib/MC/MCStreamer.cpp (original)
> +++ llvm/trunk/lib/MC/MCStreamer.cpp Wed Oct  7 02:01:31 2015
> @@ -359,6 +359,14 @@ void MCStreamer::EmitCFIEscape(StringRef
>  CurFrame->Instructions.push_back(Instruction);
> }
> 
> +void MCStreamer::EmitCFIGnuArgsSize(int64_t Size) {
> +  MCSymbol *Label = EmitCFICommon();
> +  MCCFIInstruction Instruction = 
> +    MCCFIInstruction::createGnuArgsSize(Label, Size);
> +  MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
> +  CurFrame->Instructions.push_back(Instruction);
> +}
> +
> void MCStreamer::EmitCFISignalFrame() {  EnsureValidDwarfFrame();  
> MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
> 
> Modified: llvm/trunk/lib/Target/X86/X86FrameLowering.cpp
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Frame
> Lowering.cpp?rev=249522&r1=249521&r2=249522&view=diff
> ======================================================================
> ========
> --- llvm/trunk/lib/Target/X86/X86FrameLowering.cpp (original)
> +++ llvm/trunk/lib/Target/X86/X86FrameLowering.cpp Wed Oct  7 02:01:31
> +++ 2015
> @@ -2073,8 +2073,6 @@ eliminateCallFramePseudoInstr(MachineFun
>    // If the stack pointer can be changed after prologue, turn the
>    // adjcallstackup instruction into a 'sub ESP, <amt>' and the
>    // adjcallstackdown instruction into 'add ESP, <amt>'
> -    if (Amount == 0)
> -      return;
> 
>    // We need to keep the stack aligned properly.  To do this, we round the
>    // amount of space needed for the outgoing arguments up to the next 
> @@ -2082,6 +2080,25 @@ eliminateCallFramePseudoInstr(MachineFun
>    unsigned StackAlign = getStackAlignment();
>    Amount = RoundUpToAlignment(Amount, StackAlign);
> 
> +    // If we have any exception handlers in this function, and we adjust
> +    // the SP before calls, we may need to indicate this to the unwinder,
> +    // using GNU_ARGS_SIZE. Note that this may be necessary
> +    // even when Amount == 0, because the preceding function may have
> +    // set a non-0 GNU_ARGS_SIZE.
> +    // TODO: We don't need to reset this between subsequent functions,
> +    // if it didn't change.
> +    bool HasDwarfEHHandlers =
> +      !MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
> +      !MF.getMMI().getLandingPads().empty();
> +
> +    if (HasDwarfEHHandlers && !isDestroy && 
> +        MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences())
> +      BuildCFI(MBB, I, DL,
> +               MCCFIInstruction::createGnuArgsSize(nullptr, Amount));
> +
> +    if (Amount == 0)
> +      return;
> +
>    // Factor out the amount that gets handled inside the sequence
>    // (Pushes of argument for frame setup, callee pops for frame destroy)
>    Amount -= InternalAmt;
> 
> Added: llvm/trunk/test/CodeGen/X86/push-cfi-obj.ll
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/push-c
> fi-obj.ll?rev=249522&view=auto
> ======================================================================
> ========
> --- llvm/trunk/test/CodeGen/X86/push-cfi-obj.ll (added)
> +++ llvm/trunk/test/CodeGen/X86/push-cfi-obj.ll Wed Oct  7 02:01:31
> +++ 2015
> @@ -0,0 +1,38 @@
> +; RUN: llc < %s -mtriple=i686-pc-linux -filetype=obj | llvm-readobj 
> +-s -sr -sd | FileCheck %s
> +
> +; CHECK:         Index: 8
> +; CHECK-NEXT:    Name: .eh_frame (41)
> +; CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
> +; CHECK-NEXT:    Flags [ (0x2)
> +; CHECK-NEXT:      SHF_ALLOC (0x2)
> +; CHECK-NEXT:    ]
> +; CHECK-NEXT:    Address: 0x0
> +; CHECK-NEXT:    Offset: 0x64
> +; CHECK-NEXT:    Size: 60
> +; CHECK-NEXT:    Link: 0
> +; CHECK-NEXT:    Info: 0
> +; CHECK-NEXT:    AddressAlignment: 4
> +; CHECK-NEXT:    EntrySize: 0
> +; CHECK-NEXT:    Relocations [
> +; CHECK-NEXT:    ]
> +; CHECK-NEXT:    SectionData (
> +; CHECK-NEXT:      0000: 1C000000 00000000 017A504C 5200017C  |.........zPLR..||
> +; CHECK-NEXT:      0010: 08070000 00000000 1B0C0404 88010000  |................|
> +; CHECK-NEXT:      0020: 18000000 24000000 00000000 19000000  |....$...........|
> +; CHECK-NEXT:      0030: 04000000 00430E10 2E100000           |.....C......|
> +; CHECK-NEXT:    )
> +
> +declare i32 @__gxx_personality_v0(...) declare void @good(i32 %a, i32 
> +%b, i32 %c, i32 %d)
> +
> +define void @test() optsize personality i8* bitcast (i32 (...)*
> + at __gxx_personality_v0 to i8*) {
> +entry:
> +  invoke void @good(i32 1, i32 2, i32 3, i32 4)
> +          to label %continue unwind label %cleanup
> +continue:
> +  ret void
> +cleanup:  
> +  landingpad { i8*, i32 }
> +     cleanup
> +  ret void
> +}
> 
> Added: llvm/trunk/test/CodeGen/X86/push-cfi.ll
> URL: 
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/push-c
> fi.ll?rev=249522&view=auto
> ======================================================================
> ========
> --- llvm/trunk/test/CodeGen/X86/push-cfi.ll (added)
> +++ llvm/trunk/test/CodeGen/X86/push-cfi.ll Wed Oct  7 02:01:31 2015
> @@ -0,0 +1,143 @@
> +; RUN: llc < %s -mtriple=i686-pc-linux | FileCheck %s
> +
> +declare i32 @__gxx_personality_v0(...) declare void @good(i32 %a, i32 
> +%b, i32 %c, i32 %d) declare void @large(i32 %a, i32 %b, i32 %c, i32 
> +%d, i32 %e, i32 %f) declare void @empty()
> +
> +; We use an invoke, and expect a .cfi_escape GNU_ARGS_SIZE with size
> +16 ; before the invocation ; CHECK-LABEL: test1:
> +; CHECK: .cfi_escape 0x2e, 0x10
> +; CHECK-NEXT: pushl   $4
> +; CHECK-NEXT: pushl   $3
> +; CHECK-NEXT: pushl   $2
> +; CHECK-NEXT: pushl   $1
> +; CHECK-NEXT: call
> +; CHECK-NEXT: addl $16, %esp
> +define void @test1() optsize personality i8* bitcast (i32 (...)*
> + at __gxx_personality_v0 to i8*) {
> +entry:
> +  invoke void @good(i32 1, i32 2, i32 3, i32 4)
> +          to label %continue unwind label %cleanup
> +continue:
> +  ret void
> +cleanup:  
> +  landingpad { i8*, i32 }
> +     cleanup
> +  ret void
> +}
> +
> +; If the function has no handlers, we don't need to generate 
> +GNU_ARGS_SIZE, ; even if it has an unwind table.
> +; CHECK-LABEL: test2:
> +; CHECK-NOT: .cfi_escape
> +; CHECK: pushl   $4
> +; CHECK-NEXT: pushl   $3
> +; CHECK-NEXT: pushl   $2
> +; CHECK-NEXT: pushl   $1
> +; CHECK-NEXT: call
> +; CHECK-NEXT: addl $16, %esp
> +define void @test2() optsize personality i8* bitcast (i32 (...)*
> + at __gxx_personality_v0 to i8*) {
> +entry:
> +  call void @good(i32 1, i32 2, i32 3, i32 4)
> +  ret void
> +}
> +
> +; If we did not end up using any pushes, no need for GNU_ARGS_SIZE 
> +anywhere ; CHECK-LABEL: test3:
> +; CHECK-NOT: .cfi_escape
> +; CHECK-NOT: pushl
> +; CHECK: retl
> +define void @test3() optsize personality i8* bitcast (i32 (...)*
> + at __gxx_personality_v0 to i8*) {
> +entry:
> +  invoke void @empty()
> +          to label %continue unwind label %cleanup
> +continue:
> +  ret void
> +cleanup:  
> +  landingpad { i8*, i32 }
> +     cleanup
> +  ret void
> +}
> +
> +; Different sized stacks need different GNU_ARGS_SIZEs ; CHECK-LABEL: 
> +test4:
> +; CHECK: .cfi_escape 0x2e, 0x10
> +; CHECK-NEXT: pushl   $4
> +; CHECK-NEXT: pushl   $3
> +; CHECK-NEXT: pushl   $2
> +; CHECK-NEXT: pushl   $1
> +; CHECK-NEXT: call
> +; CHECK-NEXT: addl $16, %esp
> +; CHECK: .cfi_escape 0x2e, 0x20
> +; CHECK-NEXT: subl    $8, %esp
> +; CHECK-NEXT: pushl   $11
> +; CHECK-NEXT: pushl   $10
> +; CHECK-NEXT: pushl   $9
> +; CHECK-NEXT: pushl   $8
> +; CHECK-NEXT: pushl   $7
> +; CHECK-NEXT: pushl   $6
> +; CHECK-NEXT: calll   large
> +; CHECK-NEXT: addl $32, %esp
> +define void @test4() optsize personality i8* bitcast (i32 (...)*
> + at __gxx_personality_v0 to i8*) {
> +entry:
> +  invoke void @good(i32 1, i32 2, i32 3, i32 4)
> +          to label %continue1 unwind label %cleanup
> +continue1:
> +  invoke void @large(i32 6, i32 7, i32 8, i32 9, i32 10, i32 11)
> +          to label %continue2 unwind label %cleanup
> +continue2:
> +  ret void          
> +cleanup:  
> +  landingpad { i8*, i32 }
> +     cleanup
> +  ret void
> +}
> +
> +; If we did use pushes, we need to reset GNU_ARGS_SIZE before a call 
> +; without parameters ; CHECK-LABEL: test5:
> +; CHECK: .cfi_escape 0x2e, 0x10
> +; CHECK-NEXT: pushl   $4
> +; CHECK-NEXT: pushl   $3
> +; CHECK-NEXT: pushl   $2
> +; CHECK-NEXT: pushl   $1
> +; CHECK-NEXT: call
> +; CHECK-NEXT: addl $16, %esp
> +; CHECK: .cfi_escape 0x2e, 0x00
> +; CHECK-NEXT: call
> +define void @test5() optsize personality i8* bitcast (i32 (...)*
> + at __gxx_personality_v0 to i8*) {
> +entry:
> +  invoke void @good(i32 1, i32 2, i32 3, i32 4)
> +          to label %continue1 unwind label %cleanup
> +continue1:
> +  invoke void @empty()
> +          to label %continue2 unwind label %cleanup
> +continue2:
> +  ret void          
> +cleanup:  
> +  landingpad { i8*, i32 }
> +     cleanup
> +  ret void
> +}
> +
> +; This is actually inefficient - we don't need to repeat the .cfi_escape twice.
> +; CHECK-LABEL: test6:
> +; CHECK: .cfi_escape 0x2e, 0x10
> +; CHECK: call
> +; CHECK: .cfi_escape 0x2e, 0x10
> +; CHECK: call
> +define void @test6() optsize personality i8* bitcast (i32 (...)*
> + at __gxx_personality_v0 to i8*) {
> +entry:
> +  invoke void @good(i32 1, i32 2, i32 3, i32 4)
> +          to label %continue1 unwind label %cleanup
> +continue1:
> +  invoke void @good(i32 5, i32 6, i32 7, i32 8)
> +          to label %continue2 unwind label %cleanup
> +continue2:
> +  ret void          
> +cleanup:  
> +  landingpad { i8*, i32 }
> +     cleanup
> +  ret void
> +}
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> 
> ---------------------------------------------------------------------
> Intel Israel (74) Limited
> 
> This e-mail and any attachments may contain confidential material for 
> the sole use of the intended recipient(s). Any review or distribution 
> by others is strictly prohibited. If you are not the intended 
> recipient, please contact the sender and delete all copies.
>  
> ---------------------------------------------------------------------
> Intel Israel (74) Limited
> This e-mail and any attachments may contain confidential material for 
> the sole use of the intended recipient(s). Any review or distribution 
> by others is strictly prohibited. If you are not the intended 
> recipient, please contact the sender and delete all copies.
> 

---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


More information about the llvm-commits mailing list