[PATCH] D72225: Align branches within 32-Byte boundary(Prefix padding)

Kan Shengchen via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sat Jan 11 00:15:43 PST 2020


skan added a comment.

**Summary of the usage of `MCBoundaryAlignFragment`:**

As I commented in `MCFragment.h`, `MCBoundaryAlignFragment` is a placeholder fragment used to emit NOP or values to align a set of fragments within specific boundary. And in this application, the value is the segment prefix indeed. For example, let's say the code is

  pushl  %ebp
  pushl  %edi
  je  .L_0

and JCC is need to be aligned.
**1. Fragment Layout**
The corresponding fragment sequence will be
BoundaryAlign1 | Data1 | BoundaryAlign2 | Data2 | BoundaryAlign3 | Relax1

Data1 holds `pushl  %ebp`, Data2 holds `pushl  %edi`, Relax1 holds `je .L_0`. BoundaryAlign1 and BoundaryAlign2 are used to emit prefix,
BoundaryAlign3 is used to emit NOP.

**2. Determine the range of the fragments needed to be aligned**
`MCBoundaryAlignFragment` is designed to align a set of fragments within the same section as the BoundaryAlign. BoundaryAlign1~BoundaryAlign3 are used to align fragment Relax1.  Each BoundaryAlign has a member called `LastFragment`, which marks the end of the set of fragments, if we call the nearest backward `MCBoundaryAlignFragment` of `LastFragment` as `NBBF` (short for nearest backward BoundaryAlign fragment), then the set of fragments to be aligned is (NBBF, LastFragment].  In this example, the `LastFragment` is Relax1 and the `NBBF` is BoundaryAlign3.

**3. Relax the `MCBoundaryAlignFragment`**
**3.1 Prerequisites**
Before relaxation, we should guarantee that the BoundaryAlign fragment is in the same section as (NBBF, LastFragment], and each non-MCBoundaryAlignFragment in (BoundaryAlign, LastFragment] must have a fixed size after finite times of relaxation. For example, if the code is

  pushl  %ebp
  .align 16
  pushl  %edi
  je  .L_0

the corresponding fragment sequence will be
BoundaryAlign1 |  Data1 | Align1 | BoundaryAlign2 | Data2 | BoundaryAlign3 | Relax1

Align1 is `MCAlignFragment` that can grow and shrink, it is not guranteed to have a fixed size after finite times of relaxation, so the BoundaryAlign1's `LastFragment` should be NULL.
**3.2 How to relax**
Let's go back to the code

  pushl  %ebp
  pushl  %edi
  je  .L_0

BoundaryAlign1 | Data1 | BoundaryAlign2 | Data2 | BoundaryAlign3 | Relax1

`LastFragment`  = Relax1, `NBBF` = BoundaryAlign3.

The fragments are always relaxed from left to right, namely in each iteration, BoundaryAlign1 is relaxed first, then Data1 and then BoundaryAlign2. When we relax a BoundaryAlign, we will assume that all the BoundaryAlign in [this, LastFragment) are of size 0.  For example, let's say the size of BoundaryAlign1 and BoundaryAlign2 is **limited** by 1, and size of BoundaryAlign3 is not limited, and the boundary size is 32. 
In the **first** iteration and before Relax1 is relaxed, Relax1's offset is 0x1e and size is 2, so Relax1 needs 2-byte padding.

BoundaryAlign1(0) | Data1(1) | BoundaryAlign2(0) | Data2(1) | BoundaryAlign3(0) | Relax1(2, 0x1e)

After BoundaryAlign3 is relaxed, the sequence will be

BoundaryAlign1(1) | Data1(1) | BoundaryAlign2(1) | Data2(1) | BoundaryAlign3(0) | Relax1(2, 0x20)

In the **second** iteration and before Relax1 is relaxed, Relax1's offset may become 0x1a and size become 6.

BoundaryAlign1(1) | Data1(1) | BoundaryAlign2(1) | Data2(1) | BoundaryAlign3(0) | Relax1(6, 0x1a)

When relax BoudaryAlign1, we will assume Relax1's offset is 0x18 (0x1a -1 -1), so Relax1 needs 0-byte padding. After BoudaryAlign3 is relaxed,
the sequence will be

BoundaryAlign1(0) | Data1(1) | BoundaryAlign2(0) | Data2(1) | BoundaryAlign3(0) | Relax1(6, 0x18)

**Note**
If need to align fused jcc, 2 and 3 are same as above, only 1 is slightly different. When the code is

  pushl  %ebp
  pushl  %edi
  cmp  %eax, %ebp
  je  .L_0

The corresponding fragment sequence will be
BoundaryAlign1 | Data1 | BoundaryAlign2 | Data2 | BoundaryAlign3 | Data3 | Relax1

Data1 holds `pushl  %ebp`, Data2 holds `pushl  %edi`,  Data3 holds `cmp  %eax, %ebp`, Relax1 holds `je .L_0`. BoundaryAlign1 and BoundaryAlign2 are used to emit prefix, BoundaryAlign3 is used to emit NOP.   `LastFragment`  = Relax1, `NBBF` = BoundaryAlign3.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D72225/new/

https://reviews.llvm.org/D72225





More information about the llvm-commits mailing list