Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
swiftshader
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
swiftshader
Commits
3018545a
Commit
3018545a
authored
Jan 12, 2015
by
Jim Stichnoth
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Subzero: Update the lowering documentation.
BUG= none R=jvoung@chromium.org Review URL:
https://codereview.chromium.org/846763002
parent
1d62cf08
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
54 additions
and
144 deletions
+54
-144
LOWERING.rst
LOWERING.rst
+54
-144
No files found.
LOWERING.rst
View file @
3018545a
...
@@ -18,7 +18,7 @@ happens after target-specific lowering, so during lowering we generally don't
...
@@ -18,7 +18,7 @@ happens after target-specific lowering, so during lowering we generally don't
know whether a ``Variable`` operand will meet a target instruction's physical
know whether a ``Variable`` operand will meet a target instruction's physical
register requirement.
register requirement.
To this end, ICE allows certain
hints/
directives:
To this end, ICE allows certain directives:
* ``Variable::setWeightInfinite()`` forces a ``Variable`` to get some
* ``Variable::setWeightInfinite()`` forces a ``Variable`` to get some
physical register (without specifying which particular one) from a
physical register (without specifying which particular one) from a
...
@@ -27,18 +27,15 @@ To this end, ICE allows certain hints/directives:
...
@@ -27,18 +27,15 @@ To this end, ICE allows certain hints/directives:
* ``Variable::setRegNum()`` forces a ``Variable`` to be assigned a specific
* ``Variable::setRegNum()`` forces a ``Variable`` to be assigned a specific
physical register.
physical register.
* ``Variable::setPreferredRegister()`` registers a preference for a physical
These directives are described below in more detail. In most cases, though,
register based on another ``Variable``'s physical register assignment.
they don't need to be explicity used, as the routines that create lowered
instructions have reasonable defaults and simple options that control these
These hints/directives are described below in more detail. In most cases,
directives.
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 hints/directives.
The recommended ICE lowering strategy is to generate extra assignment
The recommended ICE lowering strategy is to generate extra assignment
instructions involving extra ``Variable`` temporaries, using the
instructions involving extra ``Variable`` temporaries, using the
directives to
hints/directives to force suitable register assignments for the temporaries, and
force suitable register assignments for the temporaries, and then let the
then let the global
register allocator clean things up.
register allocator clean things up.
Note: There is a spectrum of *implementation complexity* versus *translation
Note: There is a spectrum of *implementation complexity* versus *translation
speed* versus *code quality*. This recommended strategy picks a point on the
speed* versus *code quality*. This recommended strategy picks a point on the
...
@@ -47,8 +44,8 @@ quality in terms of frame size and register shuffling/spilling, but perhaps not
...
@@ -47,8 +44,8 @@ quality in terms of frame size and register shuffling/spilling, but perhaps not
the fastest translation speed since extra instructions and operands are created
the fastest translation speed since extra instructions and operands are created
up front and cleaned up at the end.
up front and cleaned up at the end.
Ensuring
some
physical register
Ensuring
a non-specific
physical register
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^
The x86 instruction::
The x86 instruction::
...
@@ -71,71 +68,31 @@ low-level lowering code that accomplishes this looks something like::
...
@@ -71,71 +68,31 @@ low-level lowering code that accomplishes this looks something like::
``Cfg::makeVariable()`` generates a new temporary, and
``Cfg::makeVariable()`` generates a new temporary, and
``Variable::setWeightInfinite()`` gives it infinite weight for the purpose of
``Variable::setWeightInfinite()`` gives it infinite weight for the purpose of
register allocation, thus guaranteeing it a physical register.
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
The ``_mov(Dest, Src)`` method in the ``TargetX8632`` class is sufficiently
powerful to handle these details in most situations. Its ``Dest`` argument is
powerful to handle these details in most situations. Its ``Dest`` argument is
an in/out parameter. If its input value is ``
NULL
``, then a new temporary
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
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
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
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
operand of the ``mov`` instruction.) The simpler version of the above example
is::
is::
Variable *Reg =
NULL
;
Variable *Reg =
nullptr
;
_mov(Reg, Src);
_mov(Reg, Src);
_mov(Dst, Reg);
_mov(Dst, Reg);
Preferring another ``Variable``'s physical register
Preferring another ``Variable``'s physical register
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
One problem with this example is that the register allocator usually just
(An older version of ICE allowed the lowering code to provide a register
assigns the first available register to a live range. If this instruction ends
allocation hint: if a physical register is to be assigned to one ``Variable``,
the live range of ``src``, this may lead to code like the following::
then prefer a particular ``Variable``'s physical register if available. This
hint would be used to try to reduce the amount of register shuffling.
mov reg:eax, src:esi
Currently, the register allocator does this automatically through the
mov dst:edi, reg:eax
``FindPreference`` logic.)
Since the first instruction happens to end the live range of ``src:esi``, it
would be better to assign ``esi`` to ``reg``::
mov reg:esi, src:esi
mov dst:edi, reg:esi
The first instruction, ``mov esi, esi``, is a redundant assignment and will
ultimately be elided, leaving just ``mov edi, esi``.
We can tell the register allocator to prefer the register assigned to a
different ``Variable``, using ``Variable::setPreferredRegister()``::
Variable *Reg;
Reg = Func->makeVariable(Dst->getType());
Reg->setWeightInfinite();
Reg->setPreferredRegister(Src);
NewInst = InstX8632Mov::create(Func, Reg, Src);
NewInst = InstX8632Mov::create(Func, Dst, Reg);
Or more simply::
Variable *Reg = NULL;
_mov(Reg, Src);
_mov(Dst, Reg);
Reg->setPreferredRegister(llvm::dyn_cast<Variable>(Src));
The usefulness of ``setPreferredRegister()`` is tied into the implementation of
the register allocator. ICE uses linear-scan register allocation, which sorts
live ranges by starting point and assigns registers in that order. Using
``B->setPreferredRegister(A)`` only helps when ``A`` has already been assigned a
register by the time ``B`` is being considered. For an assignment ``B=A``, this
is usually a safe assumption because ``B``'s live range begins at this
instruction but ``A``'s live range must have started earlier. (There may be
exceptions for variables that are no longer in SSA form.) But
``A->setPreferredRegister(B)`` is unlikely to help unless ``B`` has been
precolored. In summary, generally the best practice is to use a pattern like::
NewInst = InstX8632Mov::create(Func, Dst, Src);
Dst->setPreferredRegister(Src);
//Src->setPreferredRegister(Dst); -- unlikely to have any effect
Ensuring a specific physical register
Ensuring a specific physical register
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
@@ -159,83 +116,42 @@ strongly.
...
@@ -159,83 +116,42 @@ strongly.
The ``_mov(Dest, Src, RegNum)`` method in the ``TargetX8632`` class has an
The ``_mov(Dest, Src, RegNum)`` method in the ``TargetX8632`` class has an
optional ``RegNum`` argument to force a specific register assignment when the
optional ``RegNum`` argument to force a specific register assignment when the
input ``Dest`` is ``
NULL``. As described above, passing in ``Dest=NULL`` causes
input ``Dest`` is ``
nullptr``. As described above, passing in ``Dest=nullptr``
a new temporary variable to be created with infinite register weight, and in
causes a new temporary variable to be created with infinite register weight, and
addition the specific register is chosen. The simpler version of the above
in
addition the specific register is chosen. The simpler version of the above
example is::
example is::
Variable *Reg =
NULL
;
Variable *Reg =
nullptr
;
_mov(Reg, Src, Reg_eax);
_mov(Reg, Src, Reg_eax);
_ret(Reg);
_ret(Reg);
Disabling live-range interference
Disabling live-range interference
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Another problem with the "``mov reg,src; mov dst,reg``" example happens when
(An older version of ICE allowed an overly strong preference for another
the instructions do *not* end the live range of ``src``. In this case, the live
``Variable``'s physical register even if their live ranges interfered. This was
ranges of ``reg`` and ``src`` interfere, so they can't get the same physical
risky, and currently the register allocator derives this automatically through
register despite the explicit preference. However, ``reg`` is meant to be an
the ``AllowOverlap`` logic.)
alias of ``src`` so they needn't be considered to interfere with each other.
This can be expressed via the second (bool) argument of
``setPreferredRegister()``::
Variable *Reg;
Call instructions kill scratch registers
Reg = Func->makeVariable(Dst->getType());
----------------------------------------
Reg->setWeightInfinite();
Reg->setPreferredRegister(Src, true);
NewInst = InstX8632Mov::create(Func, Reg, Src);
NewInst = InstX8632Mov::create(Func, Dst, Reg);
This should be used with caution and probably only for these short-live-range
A ``call`` instruction kills the values in all scratch registers, so it's
temporaries, otherwise the classic "lost copy" or "lost swap" problem may be
important that the register allocator doesn't allocate a scratch register to a
encountered.
``Variable`` whose live range spans the ``call`` instruction. ICE provides the
``InstFakeKill`` pseudo-instruction to compactly mark such register kills. For
Instructions with register side effects
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::
Some instructions produce unwanted results in other registers, or otherwise kill
preexisting values in other registers. For example, a ``call`` kills the
scratch registers. Also, the x86-32 ``idiv`` instruction produces the quotient
in ``eax`` and the remainder in ``edx``, but generally only one of those is
needed in the lowering. It's important that the register allocator doesn't
allocate that register to a live range that spans the instruction.
ICE provides the ``InstFakeKill`` pseudo-instruction to mark such register
kills. For each of the instruction's source variables, 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, ... );
CallInst = InstX8632Call::create(Func, ... );
VarList KilledRegs;
NewInst = InstFakeKill::create(Func, CallInst);
KilledRegs.push_back(eax);
KilledRegs.push_back(ecx);
KilledRegs.push_back(edx);
NewInst = InstFakeKill::create(Func, KilledRegs, CallInst);
The last argument to the ``InstFakeKill`` constructor links it to the previous
The last argument to the ``InstFakeKill`` constructor links it to the previous
call instruction, such that if its linked instruction is dead-code eliminated,
call instruction, such that if its linked instruction is dead-code eliminated,
the ``InstFakeKill`` instruction is eliminated as well.
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
The killed register arguments need to be assigned a physical register via
safe to remove if its result is unused.
``Variable::setRegNum()`` for this to be effective. To avoid a massive
proliferation of ``Variable`` temporaries, the ``TargetLowering`` object caches
one precolored ``Variable`` for each physical register::
CallInst = InstX8632Call::create(Func, ... );
VarList KilledRegs;
Variable *eax = Func->getTarget()->getPhysicalRegister(Reg_eax);
Variable *ecx = Func->getTarget()->getPhysicalRegister(Reg_ecx);
Variable *edx = Func->getTarget()->getPhysicalRegister(Reg_edx);
KilledRegs.push_back(eax);
KilledRegs.push_back(ecx);
KilledRegs.push_back(edx);
NewInst = InstFakeKill::create(Func, KilledRegs, CallInst);
On first glance, it may seem unnecessary to explicitly kill the register that
returns the ``call`` return value. However, if for some reason the ``call``
result ends up being unused, dead-code elimination could remove dead assignments
and incorrectly expose the return value register to a register allocation
assignment spanning the call, which would be incorrect.
Instructions producing multiple values
Instructions producing multiple values
--------------------------------------
--------------------------------------
...
@@ -244,7 +160,9 @@ ICE instructions allow at most one destination ``Variable``. Some machine
...
@@ -244,7 +160,9 @@ ICE instructions allow at most one destination ``Variable``. Some machine
instructions produce more than one usable result. For example, the x86-32
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.
``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
Also, x86-32 has a version of the ``imul`` instruction that produces a 64-bit
result in the ``edx:eax`` register pair.
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``
To support multi-dest instructions, ICE provides the ``InstFakeDef``
pseudo-instruction, whose destination can be precolored to the appropriate
pseudo-instruction, whose destination can be precolored to the appropriate
...
@@ -252,8 +170,7 @@ physical register. For example, a ``call`` returning a 64-bit result in
...
@@ -252,8 +170,7 @@ physical register. For example, a ``call`` returning a 64-bit result in
``edx:eax``::
``edx:eax``::
CallInst = InstX8632Call::create(Func, RegLow, ... );
CallInst = InstX8632Call::create(Func, RegLow, ... );
...
NewInst = InstFakeKill::create(Func, CallInst);
NewInst = InstFakeKill::create(Func, KilledRegs, CallInst);
Variable *RegHigh = Func->makeVariable(IceType_i32);
Variable *RegHigh = Func->makeVariable(IceType_i32);
RegHigh->setRegNum(Reg_edx);
RegHigh->setRegNum(Reg_edx);
NewInst = InstFakeDef::create(Func, RegHigh);
NewInst = InstFakeDef::create(Func, RegHigh);
...
@@ -262,14 +179,14 @@ physical register. For example, a ``call`` returning a 64-bit result in
...
@@ -262,14 +179,14 @@ physical register. For example, a ``call`` returning a 64-bit result in
ends up being dead-code eliminated, the ``InstFakeDef`` instruction may be
ends up being dead-code eliminated, the ``InstFakeDef`` instruction may be
eliminated as well.
eliminated as well.
Prevent
ing dead-code elimination
Manag
ing dead-code elimination
------------------------------
--
------------------------------
ICE instructions with a non-
NULL ``Dest`` are subject to dead-code elimination.
ICE instructions with a non-
nullptr ``Dest`` are subject to dead-code
However, some instructions must not be eliminated in order to preserve side
elimination. However, some instructions must not be eliminated in order to
effects. This applies to most function calls, volatile loads, and loads
and
preserve side effects. This applies to most function calls, volatile loads,
and
integer divisions where the underlying language and runtime are relying on
loads and integer divisions where the underlying language and runtime are
hardware exception handling.
relying on
hardware exception handling.
ICE facilitates this with the ``InstFakeUse`` pseudo-instruction. This forces a
ICE facilitates this with the ``InstFakeUse`` pseudo-instruction. This forces a
use of its source ``Variable`` to keep that variable's definition alive. Since
use of its source ``Variable`` to keep that variable's definition alive. Since
...
@@ -281,14 +198,7 @@ result::
...
@@ -281,14 +198,7 @@ result::
Variable *Reg = Func->makeVariable(IceType_i32);
Variable *Reg = Func->makeVariable(IceType_i32);
Reg->setRegNum(Reg_eax);
Reg->setRegNum(Reg_eax);
CallInst = InstX8632Call::create(Func, Reg, ... );
CallInst = InstX8632Call::create(Func, Reg, ... );
VarList KilledRegs;
NewInst = InstFakeKill::create(Func, CallInst);
Variable *eax = Func->getTarget()->getPhysicalRegister(Reg_eax);
Variable *ecx = Func->getTarget()->getPhysicalRegister(Reg_ecx);
Variable *edx = Func->getTarget()->getPhysicalRegister(Reg_edx);
KilledRegs.push_back(eax);
KilledRegs.push_back(ecx);
KilledRegs.push_back(edx);
NewInst = InstFakeKill::create(Func, KilledRegs, CallInst);
NewInst = InstFakeUse::create(Func, Reg);
NewInst = InstFakeUse::create(Func, Reg);
NewInst = InstX8632Mov::create(Func, Result, Reg);
NewInst = InstX8632Mov::create(Func, Result, Reg);
...
@@ -301,7 +211,7 @@ The key is to use the optional source parameter of the ``InstFakeDef``
...
@@ -301,7 +211,7 @@ The key is to use the optional source parameter of the ``InstFakeDef``
instruction. Using pseudocode::
instruction. Using pseudocode::
t1:eax = call foo(arg1, ...)
t1:eax = call foo(arg1, ...)
InstFakeKill
(eax, ecx, edx)
InstFakeKill
// eax, ecx, edx
t2:edx = InstFakeDef(t1)
t2:edx = InstFakeDef(t1)
v_result_low = t1
v_result_low = t1
v_result_high = t2
v_result_high = t2
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment