Skip to content

Commit

Permalink
Document boundscheck elimination mechanism.
Browse files Browse the repository at this point in the history
[ci skip]
  • Loading branch information
blakejohnson committed Jan 14, 2016
1 parent ab57cac commit 03a4e51
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
61 changes: 61 additions & 0 deletions doc/devdocs/boundscheck.rst
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.
1 change: 1 addition & 0 deletions doc/devdocs/julia.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
llvm
stdio
promote-op
boundscheck

0 comments on commit 03a4e51

Please sign in to comment.