-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Document boundscheck elimination mechanism.
[ci skip]
- Loading branch information
1 parent
ab57cac
commit 03a4e51
Showing
2 changed files
with
62 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
.. _devdocs-subarrays: | ||
|
||
.. currentmodule:: Base | ||
|
||
************************** | ||
Bounds checking | ||
************************** | ||
|
||
Like many modern programming languages, Julia uses bounds checking to ensure | ||
program safety when accessing arrays. In tight inner loops or other performance | ||
critical situations, you may wish to skip these bounds checks to improve runtime | ||
performance. For instance, in order to emit vectorized (SIMD) instructions, your | ||
loop body cannot contain branches, and thus cannot contain bounds checks. | ||
Consequently, Julia includes an ``@inbounds(...)`` macro to tell the compiler to | ||
skip such bounds checks within the given block. For the built-in ``Array`` type, | ||
the magic happens inside the ``arrayref`` and ``arrayset`` intrinsics. | ||
User-defined array types instead use the ``@boundscheck(...)`` macro to achieve | ||
context-sensitive code selection. | ||
|
||
Eliding bounds checks | ||
--------------------- | ||
|
||
The ``@boundscheck(...)`` macro marks blocks of code that perform bounds | ||
checking. When such blocks appear inside of an ``@inbounds(...)`` block, the | ||
compiler removes these blocks. When the ``@boundscheck(...)`` is nested inside | ||
of a calling function containing an ``@inbounds(...)``, the compiler will remove | ||
the ``@boundscheck`` block *only if it is inlined* into the calling function. | ||
For example, you might write the method ``sum`` as:: | ||
|
||
function sum(A::AbstractArray) | ||
r = zero(eltype(A)) | ||
for i = 1:length(A) | ||
@inbounds r += A[i] | ||
end | ||
return r | ||
end | ||
|
||
With a custom array-like type ``MyArray`` having:: | ||
|
||
@inline getindex(A::MyArray, i::Real) = (@boundscheck checkbounds(A,i); A.data[to_index(i)]) | ||
|
||
Then when ``getindex`` is inlined into ``sum``, the call to ``checkbounds(A,i)`` | ||
will be elided. If your function contains multiple layers of inlining, only | ||
``@boundscheck`` blocks at most one level of inlining deeper are eliminated. The | ||
rule prevents unintended changes in program behavior from code further up the | ||
stack. | ||
|
||
|
||
Propagating inbounds | ||
-------------------- | ||
|
||
There may be certain scenarios where for code-organization reasons you want more | ||
than one layer between the ``@inbounds`` and ``@boundscheck`` declarations. For | ||
instance, the default ``getindex`` methods have the chain | ||
``getindex(A::AbstractArray, i::Real)`` calls | ||
``getindex(linearindexing(A), A, i)`` calls | ||
``_getindex(::LinearFast, A, i)``. | ||
|
||
To override the "one layer of inlining" rule, a function may be marked with | ||
``@propagate_inbounds`` to propagate an inbounds context (or out of bounds | ||
context) through one additional layer of inlining. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,3 +22,4 @@ | |
llvm | ||
stdio | ||
promote-op | ||
boundscheck |