Page MenuHomePhabricator

Exception support for basic block sections
Needs ReviewPublic

Authored by rahmanl on Jan 30 2020, 12:57 PM.



This is part of the Propeller framework to do post link code layout optimizations. Please see the RFC here:!msg/llvm-dev/ef3mKzAdJ7U/1shV64BYBAAJ and the detailed RFC doc here:

This patch provides exception support for basic block sections by splitting the call-site table into call-site ranges corresponding to different basic block sections. Still all landing pads must reside in the same basic block section (which is guaranteed by the the core basic block section patch D73674 (ExceptionSection) ). Each call-site table will refer to the landing pad fragment by explicitly specifying @LPstart (which is omitted in the normal non-basic-block section case). All these call-site tables will share their action and type tables.

The C++ ABI somehow assumes that no landing pads point directly to LPStart (which works in the normal case since the function begin is never a landing pad), and uses LP.offset = 0 to specify no landing pad. In the case of basic block section where one section contains all the landing pads, the landing pad offset relative to LPStart could actually be zero. Thus, we avoid zero-offset landing pads by inserting a nop operation as the first non-CFI instruction in the exception section.

Background on Exception Handling in C++ ABI

Compiler emits an exception table for every function. When an exception is thrown, the stack unwinding library queries the unwind table (which includes the start and end of each function) to locate the exception table for that function.

The exception table includes a call site table for the function, which is used to guide the exception handling runtime to take the appropriate action upon an exception. Each call site record in this table is structured as follows:

CallSite--> Position of the call site (relative to the function entry)
CallSite length--> Length of the call site.
Landing Pad--> Position of the landing pad (relative to the landing pad fragment’s begin)
Action record offset--> Position of the first action record

The call site records partition a function into different pieces and describe what action must be taken for each callsite. The callsite fields are relative with respect to the start of the function (as captured in the unwind table).

The landing pad is a reference into the function and corresponds roughly to the catch block of a try/catch statement. When execution resumes at a landing pad, it receives an exception structure and a selector value corresponding to the type of the exception thrown, and executes similar to a switch-case statement. The landing pad field is relative to the beginning of the procedure fragment which includes all the landing pads (@LPStart). The C++ ABI requires all landing pads to be in the same fragment. Nonetheless, without basic block sections, @LPStart is the same as the function @Start (found in the unwind table) and can be omitted.

The action record offset is an index into the action table which includes information about which exception types are caught.

C++ Exceptions with Basic Block Sections
Basic block sections break the contiguity of a function fragment. Therefore, call sites must be specified relative to the beginning of the basic block section. On the other hand, the unwinding library should be able to find the corresponding callsites for each section. To do so, the .cfi_lsda directive for a section must point to the call site table for that section.

Conceptually, we emit the call site tables for sections sequentially in the exception table as if each section has its own exception table. In the example below, two sections result in the two call site tables (denoted by LSDA1 and LSDA2) placed next to each other. However, their callsite records will refer to records in the shared Action Table. We also emit the header fields (@LPStart and CallSite Table Length) for each call site table in order to place the call site tables in individual LSDAs.
Since every call site table has a single @LPStart pointer, the landing pads for all callsites in the corresponding section must reside in one section (not necessarily the same section). To make this easier, we decide to place all landing pads of the function in one section.

@LPStart---> Landing pad fragment ( LSDA1 points here)
CallSite Table Length---> Used to find the action table.
@LPStart---> Landing pad fragment ( LSDA2 points here)
CallSite Table Length

Action Table
Types Table

Diff Detail

Event Timeline

rahmanl created this revision.Jan 30 2020, 12:57 PM
rahmanl edited the summary of this revision. (Show Details)Jan 30 2020, 1:01 PM

Pseudo-randomly picking a few other possible reviewers - folks, if you know more authoritative/appropriate reviewers, do please delegate

rahmanl updated this revision to Diff 241586.Jan 30 2020, 2:47 PM

Remove the redundant else after return + sync in the changes in the parent patch.

rahmanl marked an inline comment as done.Jan 30 2020, 2:48 PM
rahmanl updated this revision to Diff 278274.Wed, Jul 15, 12:05 PM
rahmanl edited the summary of this revision. (Show Details)

This syncs and updates the patch with upstream and propeller changes.

rahmanl updated this revision to Diff 279442.Tue, Jul 21, 1:54 AM
rahmanl edited the summary of this revision. (Show Details)
rahmanl edited the summary of this revision. (Show Details)Tue, Jul 21, 1:59 AM
rahmanl updated this revision to Diff 279630.Tue, Jul 21, 2:16 PM

This update does some refactoring on the CallSiteRange struct and how it is initialized.

rahmanl updated this revision to Diff 283023.Tue, Aug 4, 1:58 PM
rahmanl added a subscriber: amharc.

Fix exception handling on PIC targets (Credit to @amharc for implementing the fix).

The idea is to use pc-relative encoding for LPStart in PIC mode, as absptr is
not possible.
The existing tests are updated to exercise the PIC mode.

rahmanl updated this revision to Diff 283129.Tue, Aug 4, 10:55 PM

Fix case style.