lightning
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Lightning] Example with putarg


From: Paulo César Pereira de Andrade
Subject: Re: [Lightning] Example with putarg
Date: Wed, 13 Sep 2017 16:29:26 -0400

2017-09-07 4:30 GMT-04:00 Marc Nieper-Wißkirchen <address@hidden>:
> Hi Paulo,

  Hi Marc,

  I said I would look into it recently in another (private) email, and had some
ideas of what could be wrong.

> I've did some more experiments with putarg. To recapitulate: The manual
> warns that register arguments have volatile values but does not specify
> exactly when the value may be overwritten.

  Actually, I believe there is nothing wrong. But likely there is some
misinterpretation of what happens when there is a jump to a register
or an indirect jump to an absolute address (not a jit_label_t*), or, what
lightning consider as live range or how it computes it.

> In the factorial example in the manual, the following code snippet is
> contained:
>
> putargr R0, ac          ! Update the accumulator
> subi R1, R1, 1          ! argument -= 1
> putargr R1, in          ! Update the argument
>
> Thus, it is assumed that the "subi" instruction does not overwrite the value
> in "ac". But this is a very dangerous assumption.
>
> If the constant 1 was replaced by a constant not fitting in a
> 32-bit-integer, at least on x64, a scratch register is needed, which may be
> taken from the list of argument registers. And in fact, the following
> (stupid) example produces "wrong" code on x64:
>
> proc:
> prolog
> tramp 64
>
> arg $a
> arg $b
> arg $c
> arg $d
> arg $e
> arg $f
>
> getarg %r0 $a
> getarg %r1 $b
> getarg %r(3) $c
>
> putargr %r0 $d
> putargr %r0 $e
> putargr %r0 $f
>
> putargr %r0 $c
> subi %r1 %r1 123456789123456 // Overwrites %r9, which is $f
> putargr %r1 $a
> putargr %r2 $b
>
> jmpr %r(3)
> epilog
>
> I see only two ways out here: Either the documentation should state that
> register arguments can be overwritten by *any* instruction except for
> "jmpr", "st(x)" and "ld(x)" (the latter are needed to transfer back the
> register arguments to non-volatile memory), or GNU lightning should make
> register arguments non-volatile if it cannot prove that they are dead.
>
> In the first case, the factorial example should be rewritten, by moving the
> subi instruction before the first putargr.
>
> The latter case is, in my opinion, a much better solution. First of all, it
> abstracts away part of the difference between register arguments and stack
> arguments because the latter are always non-volatile. Secondly, a GNU
> lightning's functions are modeled as C functions (without varargs, though),
> it would meet the expectation that arguments are preserved throughout a
> function (can be read using getarg and written using putarg, throughout)
> much like callee-saved register as arguments to C functions can also be
> accessed at any time.

  If an argument is not used, and it is in a register, the register is used
for temporaries, but argument registers are used last, when running
out of temporaries. This was a tough decision, but without these assumptions,
lightning would need to spill/reload *all* temporaries.
  BTW, actually, not yet released version of lightning, with several bug
fixes, supports varargs functions :) See the test case at:
http://git.savannah.gnu.org/cgit/lightning.git/tree/check/va_list.tst

> (On machines with register arguments, this also allows user code to make use
> of these registers, which were otherwise mostly wasted.)

  Lets suppose I run your example, with --enable-devel-disassembler, and
in the check subdirectory of a git checkout:
"""
$ cat t.tst
.disasm
.code
proc:
        prolog
        tramp 64
        arg $a
        arg $b
        arg $c
        arg $d
        arg $e
        arg $f
        getarg %r0 $a
        getarg %r1 $b
        getarg %r(3) $c
        putargr %r0 $d
        putargr %r0 $e
        putargr %r0 $f
        putargr %r0 $c
        subi %r1 %r1 123456789123456 // Overwrites %r9, which is $f
        putargr %r1 $a
        putargr %r2 $b
        jmpr %r(3)
        epilog

$  ./lightning -v t.tst
        #note t.tst:3
L1: %r11 %rbx %r13 %r14 %r15 %rdx %rsi %rdi %rsp %rbp /* prolog */
        arg #1
        arg #2
        arg #3
        arg #4
        arg #5
        arg #6
        getarg_l %rax #1
         \__ movr %rax %rdi
        getarg_l %r10 #2
         \__ movr %r10 %rsi
        getarg_l %r12 #3
         \__ movr %r12 %rdx
        putargr %rax #4
         \__ movr %rcx %rax
        putargr %rax #5
         \__ movr %r8 %rax
        putargr %rax #6
         \__ movr %r9 %rax
        putargr %rax #3
         \__ movr %rdx %rax
        subi %r10 %r10 0x7048860f9180
        putargr %r10 #1
         \__ movr %rdi %r10
        putargr %r11 #2
         \__ movr %rsi %r11
    jmpr %r12
L2: /* epilog */
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        #note t.tst:3
L1: %r11 %rbx %r13 %r14 %r15 %rdx %rsi %rdi %rsp %rbp /* prolog */
        arg #1
        arg #2
        arg #3
        arg #4
        arg #5
        arg #6
        getarg_l %rax #1
         \__ movr %rax %rdi
# :t.tst:3
    0x7fb1b537f000      mov    %rdi,%rax
        getarg_l %r10 #2
         \__ movr %r10 %rsi
    0x7fb1b537f003      mov    %rsi,%r10
        getarg_l %r12 #3
         \__ movr %r12 %rdx
    0x7fb1b537f006      mov    %rdx,%r12
        putargr %rax #4
         \__ movr %rcx %rax
    0x7fb1b537f009      mov    %rax,%rcx
        putargr %rax #5
         \__ movr %r8 %rax
    0x7fb1b537f00c      mov    %rax,%r8
        putargr %rax #6
         \__ movr %r9 %rax
    0x7fb1b537f00f      mov    %rax,%r9
        putargr %rax #3
         \__ movr %rdx %rax
    0x7fb1b537f012      mov    %rax,%rdx
        subi %r10 %r10 0x7048860f9180
    0x7fb1b537f015      movabs $0x7048860f9180,%r9
    0x7fb1b537f01f      sub    %r9,%r10
        putargr %r10 #1
         \__ movr %rdi %r10
    0x7fb1b537f022      mov    %r10,%rdi
        putargr %r11 #2
         \__ movr %rsi %r11
    0x7fb1b537f025      mov    %r11,%rsi
    jmpr %r12
    0x7fb1b537f028      rex.WB jmpq *%r12
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"""
%r9 is clobbered, but as you can see, its value is not used.
Now suppose I pretend %r9 value is used:

"""
$ diff -u t.tst t1.tst
--- t.tst       2017-09-13 13:05:18.899883342 -0400
+++ t1.tst      2017-09-13 13:07:52.984889243 -0400
@@ -17,6 +17,7 @@
        putargr %r0 $f
        putargr %r0 $c
        subi %r1 %r1 123456789123456 // Overwrites %r9, which is $f
+       getarg %r0 $f
        putargr %r1 $a
        putargr %r2 $b
        jmpr %r(3)
$ ./lightning -v t1.tst
        #note t1.tst:3
L1: %r11 %rbx %r13 %r14 %r15 %rdx %rsi %rdi %rsp %rbp /* prolog */
        arg #1
        arg #2
        arg #3
        arg #4
        arg #5
        arg #6
        getarg_l %rax #1
         \__ movr %rax %rdi
        getarg_l %r10 #2
         \__ movr %r10 %rsi
        getarg_l %r12 #3
         \__ movr %r12 %rdx
        putargr %rax #4
         \__ movr %rcx %rax
        putargr %rax #5
         \__ movr %r8 %rax
        putargr %rax #6
         \__ movr %r9 %rax
        putargr %rax #3
         \__ movr %rdx %rax
        subi %r10 %r10 0x7048860f9180
        getarg_l %rax #6
         \__ movr %rax %r9
        putargr %r10 #1
         \__ movr %rdi %r10
        putargr %r11 #2
         \__ movr %rsi %r11
    jmpr %r12
L2: /* epilog */
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        #note t1.tst:3
L1: %r11 %rbx %r13 %r14 %r15 %rdx %rsi %rdi %rsp %rbp /* prolog */
        arg #1
        arg #2
        arg #3
        arg #4
        arg #5
        arg #6
        getarg_l %rax #1
         \__ movr %rax %rdi
# :t1.tst:3
    0x7f2198a82000      mov    %rdi,%rax
        getarg_l %r10 #2
         \__ movr %r10 %rsi
    0x7f2198a82003      mov    %rsi,%r10
        getarg_l %r12 #3
         \__ movr %r12 %rdx
    0x7f2198a82006      mov    %rdx,%r12
        putargr %rax #4
         \__ movr %rcx %rax
    0x7f2198a82009      mov    %rax,%rcx
        putargr %rax #5
         \__ movr %r8 %rax
    0x7f2198a8200c      mov    %rax,%r8
        putargr %rax #6
         \__ movr %r9 %rax
    0x7f2198a8200f      mov    %rax,%r9
        putargr %rax #3
         \__ movr %rdx %rax
    0x7f2198a82012      mov    %rax,%rdx
        subi %r10 %r10 0x7048860f9180
    0x7f2198a82015      movabs $0x7048860f9180,%r8
    0x7f2198a8201f      sub    %r8,%r10
        getarg_l %rax #6
         \__ movr %rax %r9
    0x7f2198a82022      mov    %r9,%rax
        putargr %r10 #1
         \__ movr %rdi %r10
    0x7f2198a82025      mov    %r10,%rdi
        putargr %r11 #2
         \__ movr %rsi %r11
    0x7f2198a82028      mov    %r11,%rsi
    jmpr %r12
    0x7f2198a8202b      rex.WB jmpq *%r12
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"""
  Now it overwrites %r8, because it is not used. So, lets
pretend all argument registers are used *after* the subi:

"""
$ diff -u t.tst t2.tst
--- t.tst       2017-09-13 13:05:18.899883342 -0400
+++ t2.tst      2017-09-13 13:09:44.664893519 -0400
@@ -17,6 +17,12 @@
        putargr %r0 $f
        putargr %r0 $c
        subi %r1 %r1 123456789123456 // Overwrites %r9, which is $f
+       getarg %r0 $a
+       getarg %r0 $b
+       getarg %r0 $c
+       getarg %r0 $d
+       getarg %r0 $e
+       getarg %r0 $f
        putargr %r1 $a
        putargr %r2 $b
        jmpr %r(3)

$ ./lightning -v t2.tst
        #note t2.tst:3
L1: %r11 %rbx %r13 %r14 %r15 %rdx %rsi %rdi %rsp %rbp /* prolog */
        arg #1
        arg #2
        arg #3
        arg #4
        arg #5
        arg #6
        getarg_l %rax #1
         \__ movr %rax %rdi
        getarg_l %r10 #2
         \__ movr %r10 %rsi
        getarg_l %r12 #3
         \__ movr %r12 %rdx
        putargr %rax #4
         \__ movr %rcx %rax
        putargr %rax #5
         \__ movr %r8 %rax
        putargr %rax #6
         \__ movr %r9 %rax
        putargr %rax #3
         \__ movr %rdx %rax
        subi %r10 %r10 0x7048860f9180
        getarg_l %rax #1
         \__ movr %rax %rdi
        getarg_l %rax #2
         \__ movr %rax %rsi
        getarg_l %rax #3
         \__ movr %rax %rdx
        getarg_l %rax #4
         \__ movr %rax %rcx
        getarg_l %rax #5
         \__ movr %rax %r8
        getarg_l %rax #6
         \__ movr %rax %r9
        putargr %r10 #1
         \__ movr %rdi %r10
        putargr %r11 #2
         \__ movr %rsi %r11
    jmpr %r12
L2: /* epilog */
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        #note t2.tst:3
L1: %r11 %rbx %r13 %r14 %r15 %rdx %rsi %rdi %rsp %rbp /* prolog */
        arg #1
        arg #2
        arg #3
        arg #4
        arg #5
        arg #6
        getarg_l %rax #1
         \__ movr %rax %rdi
# :t2.tst:3
    0x7f7e99eb6000      mov    %rdi,%rax
        getarg_l %r10 #2
         \__ movr %r10 %rsi
    0x7f7e99eb6003      mov    %rsi,%r10
        getarg_l %r12 #3
         \__ movr %r12 %rdx
    0x7f7e99eb6006      mov    %rdx,%r12
        putargr %rax #4
         \__ movr %rcx %rax
    0x7f7e99eb6009      mov    %rax,%rcx
        putargr %rax #5
         \__ movr %r8 %rax
    0x7f7e99eb600c      mov    %rax,%r8
        putargr %rax #6
         \__ movr %r9 %rax
    0x7f7e99eb600f      mov    %rax,%r9
        putargr %rax #3
         \__ movr %rdx %rax
    0x7f7e99eb6012      mov    %rax,%rdx
        subi %r10 %r10 0x7048860f9180
    0x7f7e99eb6015      mov    %rax,-0x10(%rbp)
    0x7f7e99eb6019      movabs $0x7048860f9180,%rax
    0x7f7e99eb6023      sub    %rax,%r10
    0x7f7e99eb6026      mov    -0x10(%rbp),%rax
        getarg_l %rax #1
         \__ movr %rax %rdi
    0x7f7e99eb602a      mov    %rdi,%rax
        getarg_l %rax #2
         \__ movr %rax %rsi
    0x7f7e99eb602d      mov    %rsi,%rax
        getarg_l %rax #3
         \__ movr %rax %rdx
    0x7f7e99eb6030      mov    %rdx,%rax
        getarg_l %rax #4
         \__ movr %rax %rcx
    0x7f7e99eb6033      mov    %rcx,%rax
        getarg_l %rax #5
         \__ movr %rax %r8
    0x7f7e99eb6036      mov    %r8,%rax
        getarg_l %rax #6
         \__ movr %rax %r9
    0x7f7e99eb6039      mov    %r9,%rax
        putargr %r10 #1
         \__ movr %rdi %r10
    0x7f7e99eb603c      mov    %r10,%rdi
        putargr %r11 #2
         \__ movr %rsi %r11
    0x7f7e99eb603f      mov    %r11,%rsi
    jmpr %r12
    0x7f7e99eb6042      rex.WB jmpq *%r12
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"""
  And now, it uses %rax as a temporary, saving/restoring it
during the operation.

  I believe the problem was that your initial example never called "getarg $f".
That would be enough, either before or after the "subi", to make the code
consider it live.

  You cannot expect it to follow a "jmpr %r(3)" when computing the liveness
state of a register, *but* it will follow a "jmpi proc" or equivalent
jump to label,
when computing a live register.

> Marc

Thanks,
Paulo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]