* Fix broken fragment identifiers.
* Use relative links when possible.
* Remove unused {#mainpage} from index.md
* Use consistent formatting for subheaders; e.g.
Use:
## Subheader
Instead of:
Subheader
----------
This is necessary to compute PHI types before processing their blocks.
ECMA-335 guarantees empty operand stacks on MSIL offset back edges.
Update the reader document.
Remove tail block if it's unreached.
This fixes all current verification errors in Roslyn build.
When merging operand stacks the types of the corresponding values may be
different. The CLI spec allows merging of nativeint and int32 (resulting in nativeint),
float and double (resulting in double), and GC pointers (resulting in the closest
common supertype).
In order to be able to use JitInfo->mergeClasses (that handles finding closest common
supertype) we need to be able to map back from llvm types to class handles. I added
ReverseClassTypeMap for that.
Since our processing of basic blocks depends on the types of values on the stack we
need to complete stack merging and finalize PHI instructions before processing
join blocks. To do that I changes the order of flow graph processing from depth-first
preorder to reverse postorder.
Closes#373.
Generate an explicit compare+branch+conditional-throw before each integer
divide.
Add a mock configuration flag UseExplicitZeroDivideChecks alongside
UseExplicitNullChecks to facilitate future experiments on what code
size/shape would look like with checks implicit in divide operations.
Closes#64
For integer cases, add explicit inline tests immediately prior to
conversion that branch to a block that throws OverflowException if the
source is out-of-bounds.
For floating-point cases, invoke the appropriate runtime helper (with
possibly an up-conversion from float to double first and possibly an
integer narrowing after).
Resolves#48
Map these to the appropriate LLVM intrinsics that detect overflow and
compute results together.
Also annotate the invalid type/opcode combinations in the operator map
(floats don't have bitwise operations or unsigned or overflow variants).
Closes#65
For each finally, generate a continuation selector variable, and end the
finally with a switch that jumps to a continuation based on the selector.
For each leave instruction, set the selector variables appropriately for
each finally handler being exited before jumping to the innermost finally.
These explicit sequences match what Clang generates for gotos across
cleanups and what the WinEHPrepare funclet extractor will expect to see.
The 'default' case for each switch targets a block with just an
Unreachable in it (again following Clang's example).
The instructions to set the selector variables are generated and inserted
in the IR during first-pass flow-graph building. I've added a map to the
reader objects tracking where selector stores have been inserted at which
MSIL offsets, updated fgNodeGetEndInsertIRNode to consult the map, and
updated a few places that were manually grabbing a block's terminator to
instead call fgNodeGetEndInsertIRNode, so that 2nd pass IR insertion can
use the correct insertion point when it adds IR to these blocks.
The switch instruction itself (and selector load feeding it) is generated
when processing the first leave across a particular finally, and inserted
when processing the first endfinally for that finally. Since a finally
region can have an arbitrary number of endfinally instructions, endfinally
becomes a branch that targets a block that holds the switch, so that all
endfinally instructions for a given finally can branch to the shared
switch.
Resolves#260
Adds an architcture document and block diagrams for both the JIT and AOT architecture. I've added
some beginning thoughts on the arch but would like some review/comment from owners in the particular areas.
Generate explicit compare+branch+throw sequences to check for null
derefrence on loads and stores. LLVM IR does not support annotating
loads/stores as exception-bearing, and additionally this approach may
simplify runtime porting to other targets since we'll generate explicit
machine code for these tests and the runtime won't need to mess with
machine traps. The llilc-jit-eh.md document contains more information
about the approach/rationale.
Introduce a mock configuration flag, UseExplicitNullChecks, on the Reader
object (this leaves the old codepaths accessible to facilitate future
experiments).
Extend the existing makeStore wrapper around LLVMBuilder::CreateStore, and
add a similar makeLoad wrapper around LLVMBuilder::CreateLoad. These
wrappers take an AddressMayBeNull parameter, and generate the null check
when the address may be null and UseExplicitNullChecks is true (which it
always is).
Transitively propagate the AddressMayBeNull parameter up through any
callers that are sometimes invoked to generate loads/stores for
known-non-null pointers and sometimes for maybe-null pointers.
For each method that now takes an AddressMayBeNull parameter, default that
parameter to true and add a -NonNull sibling method that passes false;
this makes the callsites more readable.
Null checks are always emitted as an exact equality comparison against 0.
For operations such as ldfld/stfld/ldlen, the check is performed against
the base pointer (before adding the field offset), which will catch any
null object references.
This test may not exactly match the Windows machine trap behavior when
unsafe code is involved (though it does conform to the ECMA spec); in
particular, ldind/ldfld/stind/stfld with a managed pointer base that is
nonzero but in the guard page would raise a NullReferenceException from
the machine trap but will not be caught by the checks inserted here.
This is a deliberate decision made after consultation with the CoreCLR
team; the approach does guarantee that null dereferences from verifiable
code will raise NullReferenceException (verifiable code cannot produce a
nonzero managed pointer pointing into the guard page), and if unsafe code
is used to construct not-quite-zero addresses which are subsequently
dereferenced, it is acceptable for such dereferences to
FailFast/SegFault/CoreDump/etc rather than raise NullReferenceException.
I've verified that there are no diffs if I recompile with the
UseExplicitNullChecks flag set to false.
Closes#203Resolves#204Closes#63
This change documents the ReaderStack class in reader.h.
In addition to providing this documentation I've eliminated
unnecessary complexity in the ReaderStack iteration
interface. Previously they were using a pointer to an incomplete C++
class, ReaderStackIterator, as their iterator state but the client was
just using the space of such pointers to hold an index into the stack
(hence requiring a lot of casting and making the assumption that a
size_t will fit in a pointer--which is likely to always be true but is
nevertheless somewhat of a hack).
Instead I've made ReaderStackIterator a typedef to size_t and pass
such values as references in the API. I believe the result is a lot
cleaner.
Closes#143.
In more detail:
Modified LLILC's CMakeLists.txt to
1. Add an LLILC_ENABLE_DOXYGEN option (ON by default)
2. configure a Doxygen configuration file.
3. Add a custom target, doxygen-llilc, to run doxygen.
In addition a file, Documentation/index.dox, is added that has the main page
for the LLILC Doxygen output.
To use you need to do the following:
1. Install Doxygen
2. Install Graphviz, ensuring that dot is on your path.
3. In your LLVM source directory, edit the CMakeLists.txt file so that LLVM_ENABLE_DOXYGEN is ON, or alternately when you run cmake give it an option to enable it.
4. After you configure LLVM you can open the LLVM.sln file, right click on doxygen-llilc, and select "build". You do not need to build LLVM before doing this.