diff --git a/doc/range-limits.md b/doc/range-limits.md new file mode 100644 index 00000000..cd7cf8bb --- /dev/null +++ b/doc/range-limits.md @@ -0,0 +1,148 @@ +Immediate Range Limits in VIXL +============================== + +VIXL's macro assembler tries to increase the range of branches and literal loads +automatically for you, but applications must still be aware of these extended +limits, and stay within them, in order to ensure valid code is generated. + +In debug builds, assertions prevent exceeding these limits at run time. In +release builds, for performance reasons, the application is responsible for +staying within the limits. + +You should decide what corrections should be applied in your application if it +exceeds these limits. + +Terms +----- + +**Bind** assigning an address to a label such that the instructions that refer +to the label can be assigned PC-relative offsets. + +**Forward** a forward branch or load literal will refer to a location that will +be bound later in code generation, ie. at a higher address. + +**Backward** a backward branch or load literal refers to a location that has +already been bound earlier in code generation, ie. at a lower address. + +**Instruction range** the range of values that can be encoded in the instruction +to be generated. Outside the instruction range, additional instructions may be +generated to increase the range, branching further than would be possible in +one instruction, for example. + +**Veneer** a sequence of additional instructions produced to increase the +instruction range. + +**Adjusted PC** the PC including its architecturally-defined offset. In AArch32 +T32, this is the current PC plus four bytes. In AArch64, there is no adjustment; +Adjusted PC is equal to PC. + +AArch64 +------- + +### Branches + +All instructions and targets must be aligned to the instruction size, four +bytes. + +#### Unconditional immediate branches (`B`) + +* Unconditional immediate branches have an instruction range of -134,217,728 to ++134,217,724 bytes from the current PC. +* No veneers are applied to unconditional immediate branches to extend their +instruction range. +* Callers can use the function `IsValidImmPCOffset(UncondBranchType, offset)` to +check `offset` (in units of instruction) is within the instruction range. + +#### Conditional branches (`B.cond`) and compare-and-branch (`CBZ`, `CBNZ`) + +* Conditional branch and compare-and-branch instructions have the same +instruction range. +* The instruction range is -1,048,576 to +1,048,574 bytes from the current PC. +* Veneers are applied to extend the range to -134,217,724 to +135,266,298 bytes +from the current PC. + * Unconditional branch range minus one instruction backwards. + * Unconditional branch range plus conditional branch range forwards. +* Callers can use the functions `IsValidImmPCOffset(CondBranchType, offset)` and +`IsValidImmPCOffset(CompareBranchType, offset)` to check `offset` (in units of +instruction) is within the instruction range. + +#### Test-and-branch (`TBZ`, `TBNZ`) + +* Test-and-branch instructions have an instruction range of -32,768 to 32,764 +bytes from the current PC. +* Veneers are applied to extend the range to -134,217,728 to +135,299,062 bytes +from the current PC. + * Unconditional branch range minus one instruction backwards. + * Unconditional branch range plus test-and-branch range forwards. +* Callers can use the function `IsValidImmPCOffset(TestBranchType, offset)` to +check `offset` (in units of instruction) is within the instruction range. + +### Literals + +#### Compute PC-relative address (`ADR`) + +* Compute PC-relative address instructions have an instruction range of +-1,048,576 to +1,048,575 bytes from the current PC. +* No veneers are applied to extend the instruction range. +* Callers can use `IsInt21(offset)` to check `offset` (in bytes) is within the +instruction range. + +#### Load from PC-relative address (`LDR`) + +* Load from PC-relative address instructions have an instruction range of +-1,048,576 to +1,048,572 bytes from the current PC. The offset must be four-byte +aligned. +* Automatically-placed literals (eg. those created by `Ldr(reg, literal_value)`) +will be emitted into code such that they are in range of the instructions that +refer to them. +* Veneers are not applied to manually-placed literals, ie. those created by +`Literal x(value)` and emitted by `place()`. +* Callers can use `IsInt19(offset)` to check `offset` (in units of instruction) +is within the instruction range. + +AArch32 +------- + +Limits stated in this section relate to the T32 instruction encodings only. + +### Branches + +#### Unconditional immediate branches (`B`) + +* Unconditional immediate branches have an instruction range of -16,777,216 to ++16,777,214 bytes from the current adjusted PC. +* Veneers are applied to forward branches to extend them to an unlimited range. +* No veneers are applied to backward branches. + +#### Conditional immediate branches (`B`) + +* Conditional immediate branches have an instruction range of -1,048,576 to ++1,048,574 bytes from the current adjusted PC. +* Veneers are applied to forward branches to extend them to an unlimited range. +* Veneers are applied to backward branches to extend the range to that of +unconditional immediate branches, -16,777,216 bytes from the current adjusted +PC. + +#### Compare and branch (`CBZ`, `CBNZ`) + +* Compare and branch has an instruction range of 0 to +126 bytes from the +current adjusted PC. +* Veneers are applied to forward branches to extend them to an unlimited range. +* Veneers are applied to backward branches to extend the range to that of +unconditional immediate branches, -16,777,216 bytes from the current adjusted +PC. + +### Literals + +#### Compute/load PC-relative address (`ADR`, `LDR`) + +* Compute and load PC-relative address instructions have the same instruction +range. +* The instruction range is -4,095 to +4,095 bytes from the current adjusted PC. +The PC is aligned down to a four-byte boundary before the offset is added. +* Automatically-placed literals (ie. those created by `Literal x(value)`) +will be emitted into code such that they are in range of the instructions that +refer to them. +* Veneers are not applied to manually-placed literals, ie. those created by +`Literal x(value, RawLiteral::kManuallyPlaced)` and emitted by `Place()`. +