mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-25 00:29:20 +00:00
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241009 91177308-0d34-0410-b5e6-96231b3b80d8
97 lines
2.8 KiB
ReStructuredText
97 lines
2.8 KiB
ReStructuredText
==============================
|
|
FaultMaps and implicit checks
|
|
==============================
|
|
|
|
.. contents::
|
|
:local:
|
|
:depth: 2
|
|
|
|
Motivation
|
|
==========
|
|
|
|
Code generated by managed language runtimes tend to have checks that
|
|
are required for safety but never fail in practice. In such cases, it
|
|
is profitable to make the non-failing case cheaper even if it makes
|
|
the failing case significantly more expensive. This asymmetry can be
|
|
exploited by folding such safety checks into operations that can be
|
|
made to fault reliably if the check would have failed, and recovering
|
|
from such a fault by using a signal handler.
|
|
|
|
For example, Java requires null checks on objects before they are read
|
|
from or written to. If the object is ``null`` then a
|
|
``NullPointerException`` has to be thrown, interrupting normal
|
|
execution. In practice, however, dereferencing a ``null`` pointer is
|
|
extremely rare in well-behaved Java programs, and typically the null
|
|
check can be folded into a nearby memory operation that operates on
|
|
the same memory location.
|
|
|
|
The Fault Map Section
|
|
=====================
|
|
|
|
Information about implicit checks generated by LLVM are put in a
|
|
special "fault map" section. On Darwin this section is named
|
|
``__llvm_faultmaps``.
|
|
|
|
The format of this section is
|
|
|
|
.. code-block:: none
|
|
|
|
Header {
|
|
uint8 : Fault Map Version (current version is 1)
|
|
uint8 : Reserved (expected to be 0)
|
|
uint16 : Reserved (expected to be 0)
|
|
}
|
|
uint32 : NumFunctions
|
|
FunctionInfo[NumFunctions] {
|
|
uint64 : FunctionAddress
|
|
uint32 : NumFaultingPCs
|
|
uint32 : Reserved (expected to be 0)
|
|
FunctionFaultInfo[NumFaultingPCs] {
|
|
uint32 : FaultKind = FaultMaps::FaultingLoad (only legal value currently)
|
|
uint32 : FaultingPCOffset
|
|
uint32 : HandlerPCOffset
|
|
}
|
|
}
|
|
|
|
|
|
The ``ImplicitNullChecks`` pass
|
|
===============================
|
|
|
|
The ``ImplicitNullChecks`` pass transforms explicit control flow for
|
|
checking if a pointer is ``null``, like:
|
|
|
|
.. code-block:: llvm
|
|
|
|
%ptr = call i32* @get_ptr()
|
|
%ptr_is_null = icmp i32* %ptr, null
|
|
br i1 %ptr_is_null, label %is_null, label %not_null
|
|
|
|
not_null:
|
|
%t = load i32, i32* %ptr
|
|
br label %do_something_with_t
|
|
|
|
is_null:
|
|
call void @HFC()
|
|
unreachable
|
|
|
|
to control flow implicit in the instruction loading or storing through
|
|
the pointer being null checked:
|
|
|
|
.. code-block:: llvm
|
|
|
|
%ptr = call i32* @get_ptr()
|
|
%t = load i32, i32* %ptr ;; handler-pc = label %is_null
|
|
br label %do_something_with_t
|
|
|
|
is_null:
|
|
call void @HFC()
|
|
unreachable
|
|
|
|
This transform happens at the ``MachineInstr`` level, not the LLVM IR
|
|
level (so the above example is only representative, not literal). The
|
|
``ImplicitNullChecks`` pass runs during codegen, if
|
|
``-enable-implicit-null-checks`` is passed to ``llc``.
|
|
|
|
The ``ImplicitNullChecks`` pass adds entries to the
|
|
``__llvm_faultmaps`` section described above as needed.
|