Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Unified Diff: LOWERING.rst

Issue 1562543002: move .rst to docs (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: changes suggested by stichnot Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « DESIGN.rst ('k') | Makefile.standalone » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: LOWERING.rst
diff --git a/LOWERING.rst b/LOWERING.rst
deleted file mode 100644
index 190ff2393b0c52565e3275857c7d43b5a6a520e4..0000000000000000000000000000000000000000
--- a/LOWERING.rst
+++ /dev/null
@@ -1,239 +0,0 @@
-Target-specific lowering in ICE
-===============================
-
-This document discusses several issues around generating target-specific ICE
-instructions from high-level ICE instructions.
-
-Meeting register address mode constraints
------------------------------------------
-
-Target-specific instructions often require specific operands to be in physical
-registers. Sometimes one specific register is required, but usually any
-register in a particular register class will suffice, and that register class is
-defined by the instruction/operand type.
-
-The challenge is that ``Variable`` represents an operand that is either a stack
-location in the current frame, or a physical register. Register allocation
-happens after target-specific lowering, so during lowering we generally don't
-know whether a ``Variable`` operand will meet a target instruction's physical
-register requirement.
-
-To this end, ICE allows certain directives:
-
- * ``Variable::setWeightInfinite()`` forces a ``Variable`` to get some
- physical register (without specifying which particular one) from a
- register class.
-
- * ``Variable::setRegNum()`` forces a ``Variable`` to be assigned a specific
- physical register.
-
-These directives are described below in more detail. In most cases, though,
-they don't need to be explicity used, as the routines that create lowered
-instructions have reasonable defaults and simple options that control these
-directives.
-
-The recommended ICE lowering strategy is to generate extra assignment
-instructions involving extra ``Variable`` temporaries, using the directives to
-force suitable register assignments for the temporaries, and then let the
-register allocator clean things up.
-
-Note: There is a spectrum of *implementation complexity* versus *translation
-speed* versus *code quality*. This recommended strategy picks a point on the
-spectrum representing very low complexity ("splat-isel"), pretty good code
-quality in terms of frame size and register shuffling/spilling, but perhaps not
-the fastest translation speed since extra instructions and operands are created
-up front and cleaned up at the end.
-
-Ensuring a non-specific physical register
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The x86 instruction::
-
- mov dst, src
-
-needs at least one of its operands in a physical register (ignoring the case
-where ``src`` is a constant). This can be done as follows::
-
- mov reg, src
- mov dst, reg
-
-so long as ``reg`` is guaranteed to have a physical register assignment. The
-low-level lowering code that accomplishes this looks something like::
-
- Variable *Reg;
- Reg = Func->makeVariable(Dst->getType());
- Reg->setWeightInfinite();
- NewInst = InstX8632Mov::create(Func, Reg, Src);
- NewInst = InstX8632Mov::create(Func, Dst, Reg);
-
-``Cfg::makeVariable()`` generates a new temporary, and
-``Variable::setWeightInfinite()`` gives it infinite weight for the purpose of
-register allocation, thus guaranteeing it a physical register (though leaving
-the particular physical register to be determined by the register allocator).
-
-The ``_mov(Dest, Src)`` method in the ``TargetX8632`` class is sufficiently
-powerful to handle these details in most situations. Its ``Dest`` argument is
-an in/out parameter. If its input value is ``nullptr``, then a new temporary
-variable is created, its type is set to the same type as the ``Src`` operand, it
-is given infinite register weight, and the new ``Variable`` is returned through
-the in/out parameter. (This is in addition to the new temporary being the dest
-operand of the ``mov`` instruction.) The simpler version of the above example
-is::
-
- Variable *Reg = nullptr;
- _mov(Reg, Src);
- _mov(Dst, Reg);
-
-Preferring another ``Variable``'s physical register
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-(An older version of ICE allowed the lowering code to provide a register
-allocation hint: if a physical register is to be assigned to one ``Variable``,
-then prefer a particular ``Variable``'s physical register if available. This
-hint would be used to try to reduce the amount of register shuffling.
-Currently, the register allocator does this automatically through the
-``FindPreference`` logic.)
-
-Ensuring a specific physical register
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Some instructions require operands in specific physical registers, or produce
-results in specific physical registers. For example, the 32-bit ``ret``
-instruction needs its operand in ``eax``. This can be done with
-``Variable::setRegNum()``::
-
- Variable *Reg;
- Reg = Func->makeVariable(Src->getType());
- Reg->setWeightInfinite();
- Reg->setRegNum(Reg_eax);
- NewInst = InstX8632Mov::create(Func, Reg, Src);
- NewInst = InstX8632Ret::create(Func, Reg);
-
-Precoloring with ``Variable::setRegNum()`` effectively gives it infinite weight
-for register allocation, so the call to ``Variable::setWeightInfinite()`` is
-technically unnecessary, but perhaps documents the intention a bit more
-strongly.
-
-The ``_mov(Dest, Src, RegNum)`` method in the ``TargetX8632`` class has an
-optional ``RegNum`` argument to force a specific register assignment when the
-input ``Dest`` is ``nullptr``. As described above, passing in ``Dest=nullptr``
-causes a new temporary variable to be created with infinite register weight, and
-in addition the specific register is chosen. The simpler version of the above
-example is::
-
- Variable *Reg = nullptr;
- _mov(Reg, Src, Reg_eax);
- _ret(Reg);
-
-Disabling live-range interference
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-(An older version of ICE allowed an overly strong preference for another
-``Variable``'s physical register even if their live ranges interfered. This was
-risky, and currently the register allocator derives this automatically through
-the ``AllowOverlap`` logic.)
-
-Call instructions kill scratch registers
-----------------------------------------
-
-A ``call`` instruction kills the values in all scratch registers, so it's
-important that the register allocator doesn't allocate a scratch register to a
-``Variable`` whose live range spans the ``call`` instruction. ICE provides the
-``InstFakeKill`` pseudo-instruction to compactly mark such register kills. For
-each scratch register, a fake trivial live range is created that begins and ends
-in that instruction. The ``InstFakeKill`` instruction is inserted after the
-``call`` instruction. For example::
-
- CallInst = InstX8632Call::create(Func, ... );
- NewInst = InstFakeKill::create(Func, CallInst);
-
-The last argument to the ``InstFakeKill`` constructor links it to the previous
-call instruction, such that if its linked instruction is dead-code eliminated,
-the ``InstFakeKill`` instruction is eliminated as well. The linked ``call``
-instruction could be to a target known to be free of side effects, and therefore
-safe to remove if its result is unused.
-
-Instructions producing multiple values
---------------------------------------
-
-ICE instructions allow at most one destination ``Variable``. Some machine
-instructions produce more than one usable result. For example, the x86-32
-``call`` ABI returns a 64-bit integer result in the ``edx:eax`` register pair.
-Also, x86-32 has a version of the ``imul`` instruction that produces a 64-bit
-result in the ``edx:eax`` register pair. The x86-32 ``idiv`` instruction
-produces the quotient in ``eax`` and the remainder in ``edx``, though generally
-only one or the other is needed in the lowering.
-
-To support multi-dest instructions, ICE provides the ``InstFakeDef``
-pseudo-instruction, whose destination can be precolored to the appropriate
-physical register. For example, a ``call`` returning a 64-bit result in
-``edx:eax``::
-
- CallInst = InstX8632Call::create(Func, RegLow, ... );
- NewInst = InstFakeKill::create(Func, CallInst);
- Variable *RegHigh = Func->makeVariable(IceType_i32);
- RegHigh->setRegNum(Reg_edx);
- NewInst = InstFakeDef::create(Func, RegHigh);
-
-``RegHigh`` is then assigned into the desired ``Variable``. If that assignment
-ends up being dead-code eliminated, the ``InstFakeDef`` instruction may be
-eliminated as well.
-
-Managing dead-code elimination
-------------------------------
-
-ICE instructions with a non-nullptr ``Dest`` are subject to dead-code
-elimination. However, some instructions must not be eliminated in order to
-preserve side effects. This applies to most function calls, volatile loads, and
-loads and integer divisions where the underlying language and runtime are
-relying on hardware exception handling.
-
-ICE facilitates this with the ``InstFakeUse`` pseudo-instruction. This forces a
-use of its source ``Variable`` to keep that variable's definition alive. Since
-the ``InstFakeUse`` instruction has no ``Dest``, it will not be eliminated.
-
-Here is the full example of the x86-32 ``call`` returning a 32-bit integer
-result::
-
- Variable *Reg = Func->makeVariable(IceType_i32);
- Reg->setRegNum(Reg_eax);
- CallInst = InstX8632Call::create(Func, Reg, ... );
- NewInst = InstFakeKill::create(Func, CallInst);
- NewInst = InstFakeUse::create(Func, Reg);
- NewInst = InstX8632Mov::create(Func, Result, Reg);
-
-Without the ``InstFakeUse``, the entire call sequence could be dead-code
-eliminated if its result were unused.
-
-One more note on this topic. These tools can be used to allow a multi-dest
-instruction to be dead-code eliminated only when none of its results is live.
-The key is to use the optional source parameter of the ``InstFakeDef``
-instruction. Using pseudocode::
-
- t1:eax = call foo(arg1, ...)
- InstFakeKill // eax, ecx, edx
- t2:edx = InstFakeDef(t1)
- v_result_low = t1
- v_result_high = t2
-
-If ``v_result_high`` is live but ``v_result_low`` is dead, adding ``t1`` as an
-argument to ``InstFakeDef`` suffices to keep the ``call`` instruction live.
-
-Instructions modifying source operands
---------------------------------------
-
-Some native instructions may modify one or more source operands. For example,
-the x86 ``xadd`` and ``xchg`` instructions modify both source operands. Some
-analysis needs to identify every place a ``Variable`` is modified, and it uses
-the presence of a ``Dest`` variable for this analysis. Since ICE instructions
-have at most one ``Dest``, the ``xadd`` and ``xchg`` instructions need special
-treatment.
-
-A ``Variable`` that is not the ``Dest`` can be marked as modified by adding an
-``InstFakeDef``. However, this is not sufficient, as the ``Variable`` may have
-no more live uses, which could result in the ``InstFakeDef`` being dead-code
-eliminated. The solution is to add an ``InstFakeUse`` as well.
-
-To summarize, for every source ``Variable`` that is not equal to the
-instruction's ``Dest``, append an ``InstFakeDef`` and ``InstFakeUse``
-instruction to provide the necessary analysis information.
« no previous file with comments | « DESIGN.rst ('k') | Makefile.standalone » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698