| 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.
|
|
|