[llvm-dev] Providing correct unwind info in function epilogue
Violeta Vukobrat via llvm-dev
llvm-dev at lists.llvm.org
Mon Jan 11 08:04:41 PST 2016
Hi all,
We have been working on a solution for the problem of incorrect unwind
info in function epilogue, reported in:
http://lists.llvm.org/pipermail/llvm-dev/2015-August/089378.html.
The cause of the problem are missing CFI instructions that update the
rule for calculating CFA in the epilogue. We added the instructions for
updating the CFA calculation rule in the
X86FrameLowering::emitEpilogue() method:
- for the case without FP, we added a cfi_def_cfa_offset instruction
each time the stack pointer is changed
- and for the case when FP is used, we added a cfi_def_cfa instruction
when frame pointer is 'pop'-ed (to use stack pointer register and
initial offset for CFA calculation from then on).
These changes enabled the generation of correct unwind info for the
function epilogue, for the case when epilogue is the last basic block in
a function.
However, there are a few cases that cause problems with this solution,
and all of them have epilogue somewhere in the middle of the function,
and not as the last basic block:
1. Problem when there are EH instructions below the epilogue.
Example: a few tests in test-suite that have EH that physically
comes after epilogue block. In the following example:
0: 53 push %rbx
1: 0f b6 05 00 00 00 00 movzbl 0x0(%rip),%eax # 8
<_Z6throwsv+0x8>
8: 83 e0 01 and $0x1,%eax
b: 83 f8 01 cmp $0x1,%eax
e: 74 07 je 17 <_Z6throwsv+0x17>
10: b8 7b 00 00 00 mov $0x7b,%eax
15: 5b pop %rbx
16: c3 retq
17: bf 04 00 00 00 mov $0x4,%edi
1c: e8 00 00 00 00 callq 21 <_Z6throwsv+0x21>
21: c7 00 07 00 00 00 movl $0x7,(%rax)
27: be 00 00 00 00 mov $0x0,%esi
...
code after 'retq' instruction (location 16) has the CFA calculation
rule set after the 'pop' instruction at (location 15). However, it
should have the CFA calculation rule set by the prologue ('push'
instruction at location 0), and not by the epilogue.
2. Problems that shrink wrapping pass can potentially cause:
2.1. Place prologue and epilogue somewhere in the middle of the
function (not as the first/last blocks)
2.2. Separate the 'return' instruction from the rest of the
epilogue. Its physical position in the function can be above or below
the epilogue.
2.3. After inserting prologue and epilogue code, some of the later
passes can reorder them and merge them with other basic blocks.
3. Problem when multiple epilogues exist in a function.
In order to solve the described problems, and provide correct rules for
calculating CFA at each instruction in the function, we started
implementing a new pass. This pass should run after all basic block
merging and reordering are done (once basic blocks are in their final
order).
The pass goes through all basic blocks in the function and sets the
correct cfi_def_cfa_offset at the beginning of each basic block. Because
this introduces excess cfi instructions, the ones that are not necessary
are eliminated (e.g. consecutive cfi_def_cfa_offset instructions with
same offset value).
This is a work in progress, as we still need to add support for
setting correct register at the beginning of each basic block (that is
needed because we use cfi_def_cfa instruction for the case when FP is used).
We plan to upload a patch for review once we have a working solution,
but for now, we wanted to see if anyone has any ideas or comments. Do
you agree that this pass implementation is a right way to solve this issue?
--
Violeta Vukobrat
Software Engineer
RT-RK Computer Based Systems LLC
www.rt-rk.com
More information about the llvm-dev
mailing list