[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

help understanding assembler

Jim Newton

1/5/2016 12:42:00 PM

Can someone help me figure out whether SBCL or any other cl compiler is able to
compile something like the following to an auto-increment instruction.

(prog1 i (incf i))

and similarly

(prog1 (svref arr i) (incf i))
and
(prog1 (sequence:elt seq i) (incf i))

In both cases the variable i is a fixnum, but I could possibly make it more restrictive if it would help.

I have a code generator which in some cases produces this in what seems like a critical part of the code.
Is there something I can do to assure that these types of expressions get compiled as concisely as possible.

I guess in some cases the variable i might be large so that incrementing it becomes a bignum. I could have my code generator create two code paths, if that would help, one for "small" integers and one for "large" ones.


6 Answers

Antsan

1/5/2016 4:36:00 PM

0

Am Dienstag, 5. Januar 2016 13:42:30 UTC+1 schrieb Jim Newton:
> Can someone help me figure out whether SBCL or any other cl compiler is able to
> compile something like the following to an auto-increment instruction.
>
> (prog1 i (incf i))
>
> and similarly
>
> (prog1 (svref arr i) (incf i))
> and
> (prog1 (sequence:elt seq i) (incf i))
>
> In both cases the variable i is a fixnum, but I could possibly make it more restrictive if it would help.
>
> I have a code generator which in some cases produces this in what seems like a critical part of the code.
> Is there something I can do to assure that these types of expressions get compiled as concisely as possible.
>
> I guess in some cases the variable i might be large so that incrementing it becomes a bignum. I could have my code generator create two code paths, if that would help, one for "small" integers and one for "large" ones.

On SBCL:

CL-USER> (disassemble (lambda (i)
(declare (type fixnum i)
(optimize (speed 3)
(debug 0)
(safety 0)))
(prog1 i (incf i))))
; disassembly for (LAMBDA (I))
; Size: 12 bytes. Origin: #xB5CDD84
; 84: 8BC1 MOV EAX, ECX ; no-arg-parsing entry point
; 86: 83C104 ADD ECX, 4
; 89: 8BD0 MOV EDX, EAX
; 8B: 8BE5 MOV ESP, EBP
; 8D: F8 CLC
; 8E: 5D POP EBP
; 8F: C3 RET
NIL

Doesn't seem like it's optimizing to a single instruction. I have no idea what
else you could do to optimize further.

The other examples could be checked likewise. Just insert all free variables
into the lambda list of your lambda.

Jim Newton

1/5/2016 4:56:00 PM

0

It looks like even promising that the integer is between 0 and 1000 also fails
to allow the compiler to use the post-increment instruction. (at least in SBCL)

(disassemble (lambda (i)
(declare (type (integer 0 1000) i)
(optimize (speed 3)
(debug 0)
(safety 0)))
(prog1 i (incf i))))
; disassembly for (LAMBDA (I))
; Size: 19 bytes. Origin: #x12FBB34052
; 52: 488BC1 MOV RAX, RCX ; no-arg-parsing entry point
; 55: 4883C102 ADD RCX, 2
; 59: 488BC8 MOV RCX, RAX
; 5C: 488BD1 MOV RDX, RCX
; 5F: 488BE5 MOV RSP, RBP
; 62: F8 CLC
; 63: 5D POP RBP
; 64: C3 RET
NIL

Jim Newton

1/5/2016 5:00:00 PM

0

BTW, how would I like the compiler output to look. I don't know enough about x86 code
to really know what to look for. It should be something similar to what C compiles to by using the x++ syntax.


> (disassemble (lambda (i)
> (declare (type (integer 0 1000) i)
> (optimize (speed 3)
> (debug 0)
> (safety 0)))
> (prog1 i (incf i))))
> ; disassembly for (LAMBDA (I))
> ; Size: 19 bytes. Origin: #x12FBB34052
> ; 52: 488BC1 MOV RAX, RCX ; no-arg-parsing entry point
> ; 55: 4883C102 ADD RCX, 2
> ; 59: 488BC8 MOV RCX, RAX
> ; 5C: 488BD1 MOV RDX, RCX
> ; 5F: 488BE5 MOV RSP, RBP
> ; 62: F8 CLC
> ; 63: 5D POP RBP
> ; 64: C3 RET
> NIL

rwiker

1/5/2016 8:50:00 PM

0

Jim Newton <jimka.issy@gmail.com> writes:

> It looks like even promising that the integer is between 0 and 1000 also fails
> to allow the compiler to use the post-increment instruction. (at least in SBCL)
>
> (disassemble (lambda (i)
> (declare (type (integer 0 1000) i)
> (optimize (speed 3)
> (debug 0)
> (safety 0)))
> (prog1 i (incf i))))
> ; disassembly for (LAMBDA (I))
> ; Size: 19 bytes. Origin: #x12FBB34052
> ; 52: 488BC1 MOV RAX, RCX ; no-arg-parsing entry point
> ; 55: 4883C102 ADD RCX, 2
> ; 59: 488BC8 MOV RCX, RAX
> ; 5C: 488BD1 MOV RDX, RCX
> ; 5F: 488BE5 MOV RSP, RBP
> ; 62: F8 CLC
> ; 63: 5D POP RBP
> ; 64: C3 RET
> NIL

A few things:

1) You're incrementing a value passed as a parameter, then returning the
previous value. The value will only be updated in the caller if the
value is passed by reference (and maybe not even then). In that case, a
sufficiently smart compiler may also skip the increment.

2) Using a fixnum instead of a restricted integer may be better for
encouraging the compiler to use simple register operations.

3) If you're working on tagged values, a simple inc is actually
implementing as adding a value which depends on the tag length. E.g, if
the tag length is 3 bits and even/odd integers have the tags 000/100, an
inc (or 1+) operations may look like "add eax,4" (the latter is from
running the form below through Lispworks 7.0 (32-bit, OSX)).

(disassemble
(compile nil
(lambda (i)
(declare (type (integer 0 1000) i)
(optimize (speed 3)
(debug 0)
(safety 0)))
(prog1 (incf i)))))

=>
0: 55 push ebp
1: 89E5 move ebp, esp
3: 83C004 add eax, 4
6: FD std
7: C9 leave
8: C3 ret
9: 90 nop

However, if you return i instead, the disassembly looks like

(disassemble
(compile nil
(lambda (i)
(declare (type (integer 0 1000) i)
(optimize (speed 3)
(debug 0)
(safety 0)))
(prog1 i (incf i)))))

=>
0: 55 push ebp
1: 89E5 move ebp, esp
3: FD std
4: C9 leave
5: C3 ret

No sign of an increment, because the new value is not used.

Jim Newton

1/5/2016 9:24:00 PM

0


> No sign of an increment, because the new value is not used.

Hi Raymond, obviously the goal is not to compile this simple function. We just tried to choose a simple function to make it humanly possible to read the compiled output.
In reality, the increment is in a much larger piece of code which doesn't suffer from this
issue of not using the incremented value.

In my original case it was something like

(some-loop
...
(F (svref ary (prog1 i (incf i))))
...
)

Barry Margolin

1/5/2016 9:44:00 PM

0

In article <02ea42be-8cba-412b-9fd4-7d3d2aec08a4@googlegroups.com>,
Jim Newton <jimka.issy@gmail.com> wrote:

> > No sign of an increment, because the new value is not used.
>
> Hi Raymond, obviously the goal is not to compile this simple function. We
> just tried to choose a simple function to make it humanly possible to read
> the compiled output.
> In reality, the increment is in a much larger piece of code which doesn't
> suffer from this
> issue of not using the incremented value.
>
> In my original case it was something like
>
> (some-loop
> ...
> (F (svref ary (prog1 i (incf i))))
> ...
> )

The problem is that the compiler may generate different code depending
on whether the value is used. So disasembling that simple function may
not show you what kind of code would be generated in the real function.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***