Dear Marc,
Here is something that is really key for some lowlevel things: I wish to do the equivalent of the C expression * ((byte*) x) in the Scheme world, i.e. the same as something like MOV AL,[EAX] .
So, something like the C variant:
for (int i = 12345; i < 12445; i++) print("%i ",* ((byte*) i));
would, if we call the read operator ##sysmem-byteref , be expressed in Scheme as something like:
(let loop ((i 12345)) (if (< i 12445) (begin (print (##sysmem-byteref i) " ") (loop (##fxnum+ i 1)))))
We can call the write operator ##sysmem-byte-set! . Also it would be of great benefit to have one for 16bit, one for 32bit, one for 48bit and one for 64bit words.
I think it's justified that there is some way to reach this with highest efficiency, i.e. a way that does this inlined in the code thus producing something like * ((byte*) x) / MOV AL,[EAX] .
Indeed this would provide of good efficiency on 64bit machines only, where fixnums can go up to ~10^18 (unlike 32bit machines where it's ~0.5 * 10^9, so pointers would generally be bignums).
Is this in place already, if not how is it best implemented? (with ##c-codeand some magick around it perhaps; I'd suppose with ##c-lambda there's always some handling around that would make it clearly more than a single-cpu-instruction operation, even if compiled with (declare (not safe)) ).
I may not be correct about this one but I got the impression that ##u8vector-ref/set! would *not* work for this, though perhaps a u8vector object could be produced that is immovable and has zero as its offset memory address?
Thanks, Mikael
Afficher les réponses par date
Hallo,
On Thu, Aug 9, 2012 at 9:30 PM, Mikael mikael.rcv@gmail.com wrote:
Here is something that is really key for some lowlevel things: I wish to do the equivalent of the C expression * ((byte*) x) in the Scheme world, i.e. the same as something like MOV AL,[EAX] .
This is not really Scheme, it is C, which can be done via a very short C extension.
Ah, I just realized:
In order for ##sysmem-byteref and ##sysmem-byte-set! to be implementable as single CPU instruction operations, the pointer argument must be required to be fixnum only.
This is really fine.
2012/8/9 Alex Queiroz asandroq@gmail.com
This is not really Scheme, it is C, which can be done via a very short C extension.
Well, it can certainly be Scheme if you want it to be Scheme, and I'm at a point where I really want this to be Scheme.
I don't want it to be a C extension, at least not in the ordinary sense where there's some kind of FFI barrier between the Scheme and C code, that at least makes a C function call out of the operation and thus adds a CALL addr and a RET (= 2 ops!) to the MOV sth,[sth] op. Also, I'd happy that the compiler would inline this when in compiled mode by itself, just like it does with ##u8vector-ref/set!.
I.e., I just want direct, unprotected access straight to the RAM at the CPU's ordinary speed for it.
Just to see, I just dug into how ##u8vector-ref works, and what I got is that in code with or without (declare (standard-bindings) (extended-bindings)) , ##u8vector-ref and also ##fxnum+ are not inlined in the output code.
Is this correct Marc?
(I suppose I did not get this right, bc Gambit's performance goals are to keep those kind of as fast as in C, and for that inlining is required?)
Also I checked what assembly is actually generated from resolving the memory address of a u8vector ___SCMOBJ in the C world, and it's only two assembly operations, neat!
(an AND -4 and an ADD 4 to the register with the ___SCMOBJ value in it, to get the contained pointer value)
Mikael
2012/8/9 Mikael More mikael.more@gmail.com
Ah, I just realized:
In order for ##sysmem-byteref and ##sysmem-byte-set! to be implementable as single CPU instruction operations, the pointer argument must be required to be fixnum only.
This is really fine.
2012/8/9 Alex Queiroz asandroq@gmail.com
This is not really Scheme, it is C, which can be done via a very short C extension.
Well, it can certainly be Scheme if you want it to be Scheme, and I'm at a point where I really want this to be Scheme.
I don't want it to be a C extension, at least not in the ordinary sense where there's some kind of FFI barrier between the Scheme and C code, that at least makes a C function call out of the operation and thus adds a CALL addr and a RET (= 2 ops!) to the MOV sth,[sth] op. Also, I'd happy that the compiler would inline this when in compiled mode by itself, just like it does with ##u8vector-ref/set!.
I.e., I just want direct, unprotected access straight to the RAM at the CPU's ordinary speed for it.
I don't know what you want to do, but this code:
(declare (standard-bindings) (extended-bindings) (not interrupts-enabled) (not safe))
(define (u8transfer in out) (do ((i (fx- (u8vector-length in) 1) (fx- i 1))) ((fx< i 0)) (u8vector-set! out i (u8vector-ref in i))))
expands to
[Bradley-Luciers-MacBook-Pro:~/Downloads] lucier% gsc -cc-options "-save-temps" -keep-c -expansion fxtest.scm Expansion:
(define u8transfer (lambda (in out) (letrec ((do-temp.0 (lambda (in out i) (if ('#<procedure #2 ##fx<> i 0) #!void (let ((begin-temp.1 ('#<procedure #3 ##u8vector-set!> out i ('#<procedure #4 ##u8vector-ref> in i)))) (do-temp.0 in out ('#<procedure #5 ##fx-> i 1))))))) (let ((i ('#<procedure #5 ##fx-> ('#<procedure #6 ##u8vector-length> in) 1))) (if ('#<procedure #2 ##fx<> i 0) #!void (let ((begin-temp.1 ('#<procedure #3 ##u8vector-set!> out i ('#<procedure #4 ##u8vector-ref> in i)))) (do-temp.0 in out ('#<procedure #5 ##fx-> i 1))))))))
and the inner loop is
L14: movq %rdx, %rax sarq $2, %rax subq $4, %rdx movzbl 7(%rsi,%rax), %ecx leaq 0(,%rcx,4), %r8 movb %cl, 7(%r9,%rax) jns L14
which seems to have about 1 extra instruction (I don't know what the load effective address is doing there).
Brad
Hi Brad,
Thank you for pointing it out - very funny.
I re-ran the test with varied compiler declares set, inspired by your test. In all cases was standard-bindings and extended-bindings on.
With safe off and interrupts off: The u8vector-ref fx+ etc are both inlined indeed, independent of if they're ##-prefixed or not. They generate equivalent C and assembly outputs. This is the same thing as your test shows.
So this is exactly the expected behavior, it's inlined, great.
Here comes something funny:
With safe is on and interrupts off: The only difference with the previous one in expansion, is that u8vector-length now (not ##-prefixed) now brings with it a u8vector? test call. And here's what's funny: it appears to me that each evaluation step is made by putting on the stack, together with the host procedure's state, an instruction for the respective procedure (##u8vector-ref ##fx+ etc.) to be invoked, and then the host procedure returns. In this mode, ##u8vector-ref ##fx+ etc. are not inlined. There seem to be some conditions that can make the host procedure not return, but I didn't quite understand until now what happens in those cases, i.e. if some kind of jump or call to ##u8vector-ref is made directly without a return being made or alike.
This is really funny, I though just using ##-prefixes on procedures was enough for exactly those calls to be executed with the highest speed, but apparently that was not the case. I'd be interested what the motivation for this is, perhaps some kind of safety mechanism for stack overflows??
Why can't ##u8vector-ref ##fx+ etc. be inlined, wouldn't that somehow contribute??
With safe off and interrupts on: Same as safe off and interrupts off, plus three interrupt checks.
With safe on and interrupts on: Same as safe on and interupts off, plus six interrupt checks.
Regarding the possibility of using ##u8vector-ref for accessing arbitrary memory addresses, I'm starting to think that clearly can be done, though the details would need to be worked out. A pure ##sysmem-byte-ref would be slightly faster though, as it would not need the operation of adding together the "zeroref-u8vector"'s base address (0) with the requested offset.
Best regards, Mikael
(In the assembly, highlighted the central loop with yellow. In the first test it's clear to me exactly which it is, in the second test it's only an approximate guess.)
*First test, safe off, using procedures under their ordinary names and by their ##-prefixed names respectively, both produce equivalent C and assembly output*
Code variant 1:
(declare (standard-bindings) (extended-bindings) (not interrupts-enabled) (not safe) )
(define (inc-u8v u with-what) (let ((l (u8vector-length u))) (##c-code "asm("noop");") (##c-code "asm("noop");") (let loop ((at 0)) (if (fx< at l) (begin (u8vector-set! u at (fx+ (u8vector-ref u at) 123)) (loop (fx+ at 1))))) (##c-code "asm("noop");") ))
Code variant 2:
(declare (standard-bindings) (extended-bindings) (not interrupts-enabled) (not safe) )
(define (inc-u8v u with-what) (let ((l (u8vector-length u))) (##c-code "asm("noop");") (##c-code "asm("noop");") (let loop ((at 0)) (if (##fx< at l) (begin (##u8vector-set! u at (##fx+ (##u8vector-ref u at) 123)) (loop (##fx+ at 1))))) (##c-code "asm("noop");") ))
Expansion:
(define inc-u8v (lambda (u with-what) (let ((l ('#<procedure #2 ##u8vector-length> u))) (let ((begin-temp.3 ('#<procedure #3 ##c-code> "asm("noop");"))) (let ((begin-temp.2 ('#<procedure #3 ##c-code> "asm("noop");"))) (let ((begin-temp.1 (letrec ((loop (lambda (u l at) (if ('#<procedure #4 ##fx<> at l) (let ((begin-temp.0 ('#<procedure #5 ##u8vector-set!> u at ('#<procedure #6 ##fx+> ('#<procedure #7 ##u8vector-ref> u at) 123)))) (loop u l ('#<procedure #6 ##fx+> at 1))) #!void)))) (loop u l 0)))) ('#<procedure #3 ##c-code> "asm("noop");")))))))
Assembly:
.file "t1.c" .intel_syntax .text .align 2 .type _Z12___init_procv, @function _Z12___init_procv: .LFB17: push %ebp .LCFI0: mov %ebp, %esp .LCFI1: mov %eax, DWORD PTR ___lp add %eax, 16 mov DWORD PTR ___G__20_t1, %eax mov %eax, DWORD PTR ___G__20_t1 mov DWORD PTR ___G__20_t1+4, %eax mov %eax, 0 pop %ebp ret .LFE17: .size _Z12___init_procv, .-_Z12___init_procv .globl __gxx_personality_v0 .align 2 .globl ____20_t1 .type ____20_t1, @function ____20_t1: .LFB18: push %ebp .LCFI2: mov %ebp, %esp .LCFI3: mov %eax, OFFSET FLAT:___module_descr pop %ebp ret .LFE18: .size ____20_t1, .-____20_t1 .align 2 .type _Z15___H_inc_2d_u8vP25___processor_state_struct, @function _Z15___H_inc_2d_u8vP25___processor_state_struct: .LFB16: push %ebp .LCFI4: mov %ebp, %esp .LCFI5: sub %esp, 60 .LCFI6: cmp DWORD PTR [%ebp+8], 0 sete %al movzx %eax, %al test %eax, %eax je .L6 mov DWORD PTR [%ebp-60], OFFSET FLAT:_ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl jmp .L8 .L6: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+24] mov DWORD PTR [%ebp-48], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+8] mov DWORD PTR [%ebp-44], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+36] mov DWORD PTR [%ebp-40], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+40] mov DWORD PTR [%ebp-36], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+44] mov DWORD PTR [%ebp-32], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+48] mov DWORD PTR [%ebp-28], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+52] mov DWORD PTR [%ebp-24], %eax mov %eax, DWORD PTR ___lp add %eax, 48 mov DWORD PTR [%ebp-52], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+56] mov DWORD PTR [%ebp-56], %eax mov %eax, DWORD PTR [%ebp-56] add %eax, 7 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-20], %eax .L9: jmp [DWORD PTR [%ebp-20]] .L10: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+76] cmp %eax, 2 sete %al movzx %eax, %al test %eax, %eax jne .L11 mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-52] mov DWORD PTR [%eax+60], %edx mov %eax, DWORD PTR ___gstate+292 mov DWORD PTR [%ebp-56], %eax jmp .L13 .L11: mov %eax, DWORD PTR [%ebp-36] dec %eax mov %eax, DWORD PTR [%eax] shr %eax, 8 sal %eax, 2 mov DWORD PTR [%ebp-32], %eax #APP noop noop #NO_APP mov %eax, DWORD PTR [%ebp-44] sub %eax, 4 mov %edx, DWORD PTR [%ebp-40] mov DWORD PTR [%eax], %edx mov DWORD PTR [%ebp-28], 0 mov %eax, DWORD PTR [%ebp-52] add %eax, 16 mov DWORD PTR [%ebp-40], %eax sub DWORD PTR [%ebp-44], 16 mov %edx, DWORD PTR [%ebp-32] cmp DWORD PTR [%ebp-28], %edx jge .L14 .L15: mov %eax, DWORD PTR [%ebp-28] sar %eax, 2 mov %edx, %eax mov %eax, DWORD PTR [%ebp-36] lea %eax, [%edx+%eax] add %eax, 3 movzx %eax, BYTE PTR [%eax] movzx %eax, %al sal %eax, 2 mov DWORD PTR [%ebp-24], %eax add DWORD PTR [%ebp-24], 492 mov %eax, DWORD PTR [%ebp-28] sar %eax, 2 mov %edx, %eax mov %eax, DWORD PTR [%ebp-36] lea %eax, [%edx+%eax] lea %edx, [%eax+3] mov %eax, DWORD PTR [%ebp-24] sar %eax, 2 mov BYTE PTR [%edx], %al add DWORD PTR [%ebp-28], 4 mov %eax, DWORD PTR [%ebp-32] cmp DWORD PTR [%ebp-28], %eax jl .L15 .L14: mov DWORD PTR [%ebp-36], -18 mov %edx, DWORD PTR [%ebp-40] mov DWORD PTR [%ebp-56], %edx jmp .L16 .L17: #APP noop #NO_APP mov %eax, DWORD PTR [%ebp-4] mov DWORD PTR [%ebp-36], %eax add DWORD PTR [%ebp-44], 16 mov %eax, DWORD PTR [%ebp-44] sub %eax, 4 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-56], %eax .L16: mov %eax, DWORD PTR [%ebp-56] add %eax, 11 mov %eax, DWORD PTR [%eax] cmp %eax, OFFSET FLAT:_Z15___H_inc_2d_u8vP25___processor_state_struct sete %al movzx %eax, %al test %eax, %eax je .L13 mov %eax, DWORD PTR [%ebp-56] add %eax, 7 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-20], %eax jmp .L9 .L13: mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-56] mov DWORD PTR [%eax+56], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-48] mov DWORD PTR [%eax+24], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-44] mov DWORD PTR [%eax+8], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-40] mov DWORD PTR [%eax+36], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-36] mov DWORD PTR [%eax+40], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-32] mov DWORD PTR [%eax+44], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-28] mov DWORD PTR [%eax+48], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-24] mov DWORD PTR [%eax+52], %edx mov %eax, DWORD PTR [%ebp-56] mov DWORD PTR [%ebp-60], %eax .L8: mov %eax, DWORD PTR [%ebp-60] leave ret .LFE16: .size _Z15___H_inc_2d_u8vP25___processor_state_struct, .-_Z15___H_inc_2d_u8vP25___processor_state_struct .align 2 .type _Z11___H__20_t1P25___processor_state_struct, @function _Z11___H__20_t1P25___processor_state_struct: .LFB15: push %ebp .LCFI7: mov %ebp, %esp .LCFI8: sub %esp, 20 .LCFI9: cmp DWORD PTR [%ebp+8], 0 sete %al movzx %eax, %al test %eax, %eax je .L21 mov DWORD PTR [%ebp-20], OFFSET FLAT:_ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl jmp .L23 .L21: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+36] mov DWORD PTR [%ebp-8], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+40] mov DWORD PTR [%ebp-4], %eax mov %eax, DWORD PTR ___lp add %eax, 16 mov DWORD PTR [%ebp-12], %eax .L24: .L25: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+76] test %eax, %eax sete %al movzx %eax, %al test %eax, %eax jne .L26 mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-12] mov DWORD PTR [%eax+60], %edx mov %eax, DWORD PTR ___gstate+292 mov DWORD PTR [%ebp-16], %eax jmp .L28 .L26: mov %eax, DWORD PTR [%ebp-12] add %eax, 32 mov DWORD PTR ___G_inc_2d_u8v, %eax mov DWORD PTR [%ebp-4], -18 mov %edx, DWORD PTR [%ebp-8] mov DWORD PTR [%ebp-16], %edx .L29: mov %eax, DWORD PTR [%ebp-16] add %eax, 11 mov %eax, DWORD PTR [%eax] cmp %eax, OFFSET FLAT:_Z11___H__20_t1P25___processor_state_struct sete %al movzx %eax, %al test %eax, %eax je .L28 jmp .L24 .L28: mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-16] mov DWORD PTR [%eax+56], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-4] mov DWORD PTR [%eax+40], %edx mov %eax, DWORD PTR [%ebp-16] mov DWORD PTR [%ebp-20], %eax .L23: mov %eax, DWORD PTR [%ebp-20] leave ret .LFE15: .size _Z11___H__20_t1P25___processor_state_struct, .-_Z11___H__20_t1P25___processor_state_struct .section .rodata .LC0: .string " t1" .data .align 32 .type ___module_descr, @object .size ___module_descr, 136 ___module_descr: .long 406002 .long 0 .long .LC0 .long 1 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long ___lp .long ___lbl_tbl .long 5 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long _Z12___init_procv .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .local ___lp .comm ___lp,4,4 .align 4 .type _ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl, @object .size _ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl, 16 _ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl: .long 0 .long .L10 .long .L17 .long 0 .align 4 .type _ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl, @object .size _ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl, 12 _ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl: .long 0 .long .L25 .long 0 .align 32 .type ___lbl_tbl, @object .size ___lbl_tbl, 96 ___lbl_tbl: .long 1030 .long -2 .long .LC0 .long 0 .long 118 .long 0 .long 0 .long _Z11___H__20_t1P25___processor_state_struct .long 2054 .long -2 .long 0 .long 0 .long 630 .long 0 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 4101 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 0 .long 0 .long 0 .long 0 .ident "GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)" .section .note.GNU-stack,"",@progbits
Second test, safe is on, using ##-prefixed procedure name variants
Code:
(declare (standard-bindings) (extended-bindings) (not interrupts-enabled) ; (not safe) )
(define (inc-u8v u with-what) (let ((l (u8vector-length u))) (##c-code "asm("noop");") (##c-code "asm("noop");") (let loop ((at 0)) (if (##fx< at l) (begin (##u8vector-set! u at (##fx+ (##u8vector-ref u at) 123)) (loop (##fx+ at 1))))) (##c-code "asm("noop");") ))
Expansion:
(define inc-u8v (lambda (u with-what) (let ((l (if ('#<procedure #2 ##u8vector?> u) ('#<procedure #3 ##u8vector-length> u) ('#<procedure #4 u8vector-length> u)))) (let ((begin-temp.3 ('#<procedure #5 ##c-code> "asm("noop");"))) (let ((begin-temp.2 ('#<procedure #5 ##c-code> "asm("noop");"))) (let ((begin-temp.1 (letrec ((loop (lambda (u l at) (if ('#<procedure #6 ##fx<> at l) (let ((begin-temp.0 ('#<procedure #7 ##u8vector-set!> u at ('#<procedure #8 ##fx+> ('#<procedure #9 ##u8vector-ref> u at) 123)))) (loop u l ('#<procedure #8 ##fx+> at 1))) #!void)))) (loop u l 0)))) ('#<procedure #5 ##c-code> "asm("noop");")))))))
Assembly:
.file "t1.c" .intel_syntax .text .align 2 .type _Z12___init_procv, @function _Z12___init_procv: .LFB17: push %ebp .LCFI0: mov %ebp, %esp .LCFI1: mov %eax, DWORD PTR ___lp add %eax, 16 mov DWORD PTR ___G__20_t1, %eax mov %eax, DWORD PTR ___G__20_t1 mov DWORD PTR ___G__20_t1+4, %eax mov %eax, 0 pop %ebp ret .LFE17: .size _Z12___init_procv, .-_Z12___init_procv .globl __gxx_personality_v0 .align 2 .globl ____20_t1 .type ____20_t1, @function ____20_t1: .LFB18: push %ebp .LCFI2: mov %ebp, %esp .LCFI3: mov %eax, OFFSET FLAT:___module_descr pop %ebp ret .LFE18: .size ____20_t1, .-____20_t1 .align 2 .type _Z15___H_inc_2d_u8vP25___processor_state_struct, @function _Z15___H_inc_2d_u8vP25___processor_state_struct: .LFB16: push %ebp .LCFI4: mov %ebp, %esp .LCFI5: sub %esp, 68 .LCFI6: cmp DWORD PTR [%ebp+8], 0 sete %al movzx %eax, %al test %eax, %eax je .L6 mov DWORD PTR [%ebp-68], OFFSET FLAT:_ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl jmp .L8 .L6: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+24] mov DWORD PTR [%ebp-48], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+8] mov DWORD PTR [%ebp-44], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+36] mov DWORD PTR [%ebp-40], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+40] mov DWORD PTR [%ebp-36], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+44] mov DWORD PTR [%ebp-32], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+48] mov DWORD PTR [%ebp-28], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+52] mov DWORD PTR [%ebp-24], %eax mov %eax, DWORD PTR ___lp add %eax, 48 mov DWORD PTR [%ebp-56], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+56] mov DWORD PTR [%ebp-60], %eax mov %eax, DWORD PTR [%ebp-60] add %eax, 7 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-20], %eax .L9: jmp [DWORD PTR [%ebp-20]] .L10: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+76] cmp %eax, 2 sete %al movzx %eax, %al test %eax, %eax jne .L11 mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-56] mov DWORD PTR [%eax+60], %edx mov %eax, DWORD PTR ___gstate+292 mov DWORD PTR [%ebp-60], %eax jmp .L13 .L11: mov %edx, DWORD PTR [%ebp-36] mov DWORD PTR [%ebp-52], %edx mov %eax, DWORD PTR [%ebp-52] and %eax, 3 cmp %eax, 1 jne .L14 mov %eax, DWORD PTR [%ebp-52] dec %eax mov %eax, DWORD PTR [%eax] and %eax, 248 cmp %eax, 168 je .L16 .L14: mov BYTE PTR [%ebp-61], 1 jmp .L17 .L16: mov BYTE PTR [%ebp-61], 0 .L17: movzx %eax, BYTE PTR [%ebp-61] test %al, %al jne .L18 mov %eax, DWORD PTR [%ebp-36] dec %eax mov %eax, DWORD PTR [%eax] shr %eax, 8 sal %eax, 2 mov DWORD PTR [%ebp-32], %eax jmp .L20 .L21: mov %eax, DWORD PTR [%ebp-36] mov DWORD PTR [%ebp-32], %eax mov %eax, DWORD PTR [%ebp-44] add %eax, 24 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-36], %eax mov %eax, DWORD PTR [%ebp-44] add %eax, 28 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-40], %eax add DWORD PTR [%ebp-44], 32 .L20: #APP noop noop #NO_APP mov %eax, DWORD PTR [%ebp-44] sub %eax, 4 mov %edx, DWORD PTR [%ebp-40] mov DWORD PTR [%eax], %edx mov DWORD PTR [%ebp-28], 0 mov %eax, DWORD PTR [%ebp-56] add %eax, 112 mov DWORD PTR [%ebp-40], %eax sub DWORD PTR [%ebp-44], 16 .L22: mov %eax, DWORD PTR [%ebp-44] sub %eax, 4 mov %edx, DWORD PTR [%ebp-40] mov DWORD PTR [%eax], %edx mov %eax, DWORD PTR [%ebp-44] sub %eax, 8 mov %edx, DWORD PTR [%ebp-36] mov DWORD PTR [%eax], %edx mov %eax, DWORD PTR [%ebp-44] sub %eax, 12 mov %edx, DWORD PTR [%ebp-32] mov DWORD PTR [%eax], %edx mov %eax, DWORD PTR [%ebp-44] sub %eax, 16 mov %edx, DWORD PTR [%ebp-28] mov DWORD PTR [%eax], %edx mov %eax, DWORD PTR [%ebp-28] mov DWORD PTR [%ebp-36], %eax mov %edx, DWORD PTR [%ebp-56] add %edx, 32 mov DWORD PTR [%ebp-40], %edx sub DWORD PTR [%ebp-44], 32 mov %eax, DWORD PTR [%ebp+8] mov DWORD PTR [%eax+76], 2 mov %eax, DWORD PTR ___G__23__23_fx_3c_+4 mov DWORD PTR [%ebp-60], %eax jmp .L23 .L24: cmp DWORD PTR [%ebp-36], -2 je .L25 mov %eax, DWORD PTR [%ebp-44] add %eax, 16 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-32], %eax mov %eax, DWORD PTR [%ebp-44] add %eax, 24 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-36], %eax mov %edx, DWORD PTR [%ebp-56] add %edx, 48 mov DWORD PTR [%ebp-40], %edx mov %eax, DWORD PTR [%ebp+8] mov DWORD PTR [%eax+76], 2 mov %eax, DWORD PTR ___G__23__23_u8vector_2d_ref+4 mov DWORD PTR [%ebp-60], %eax jmp .L23 .L27: mov DWORD PTR [%ebp-32], 492 mov %edx, DWORD PTR [%ebp-56] add %edx, 64 mov DWORD PTR [%ebp-40], %edx mov %eax, DWORD PTR [%ebp+8] mov DWORD PTR [%eax+76], 2 mov %eax, DWORD PTR ___G__23__23_fx_2b_+4 mov DWORD PTR [%ebp-60], %eax jmp .L23 .L28: mov %edx, DWORD PTR [%ebp-36] mov DWORD PTR [%ebp-28], %edx mov %eax, DWORD PTR [%ebp-44] add %eax, 16 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-32], %eax mov %eax, DWORD PTR [%ebp-44] add %eax, 24 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-36], %eax mov %eax, DWORD PTR [%ebp-56] add %eax, 80 mov DWORD PTR [%ebp-40], %eax mov %eax, DWORD PTR [%ebp+8] mov DWORD PTR [%eax+76], 3 mov %edx, DWORD PTR ___G__23__23_u8vector_2d_set_21_+4 mov DWORD PTR [%ebp-60], %edx jmp .L23 .L29: mov %eax, DWORD PTR [%ebp-44] add %eax, 16 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-36], %eax mov DWORD PTR [%ebp-32], 4 mov %eax, DWORD PTR [%ebp-56] add %eax, 96 mov DWORD PTR [%ebp-40], %eax mov %eax, DWORD PTR [%ebp+8] mov DWORD PTR [%eax+76], 2 mov %edx, DWORD PTR ___G__23__23_fx_2b_+4 mov DWORD PTR [%ebp-60], %edx jmp .L23 .L30: mov %eax, DWORD PTR [%ebp-36] mov DWORD PTR [%ebp-28], %eax mov %eax, DWORD PTR [%ebp-44] add %eax, 20 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-32], %eax mov %eax, DWORD PTR [%ebp-44] add %eax, 24 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-36], %eax mov %eax, DWORD PTR [%ebp-44] add %eax, 28 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-40], %eax add DWORD PTR [%ebp-44], 32 jmp .L22 .L25: mov DWORD PTR [%ebp-36], -18 add DWORD PTR [%ebp-44], 32 mov %eax, DWORD PTR [%ebp-44] sub %eax, 4 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-60], %eax jmp .L23 .L31: #APP noop #NO_APP mov %edx, DWORD PTR [%ebp-4] mov DWORD PTR [%ebp-36], %edx add DWORD PTR [%ebp-44], 16 mov %eax, DWORD PTR [%ebp-44] sub %eax, 4 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-60], %eax jmp .L23 .L18: mov %eax, DWORD PTR [%ebp-44] sub %eax, 4 mov %edx, DWORD PTR [%ebp-40] mov DWORD PTR [%eax], %edx mov %eax, DWORD PTR [%ebp-44] sub %eax, 8 mov %edx, DWORD PTR [%ebp-36] mov DWORD PTR [%eax], %edx mov %eax, DWORD PTR [%ebp-56] add %eax, 16 mov DWORD PTR [%ebp-40], %eax sub DWORD PTR [%ebp-44], 32 mov %eax, DWORD PTR [%ebp+8] mov DWORD PTR [%eax+76], 1 mov %edx, DWORD PTR ___G_u8vector_2d_length+4 mov DWORD PTR [%ebp-60], %edx .L23: mov %eax, DWORD PTR [%ebp-60] add %eax, 11 mov %eax, DWORD PTR [%eax] cmp %eax, OFFSET FLAT:_Z15___H_inc_2d_u8vP25___processor_state_struct sete %al movzx %eax, %al test %eax, %eax je .L13 mov %eax, DWORD PTR [%ebp-60] add %eax, 7 mov %eax, DWORD PTR [%eax] mov DWORD PTR [%ebp-20], %eax jmp .L9 .L13: mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-60] mov DWORD PTR [%eax+56], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-48] mov DWORD PTR [%eax+24], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-44] mov DWORD PTR [%eax+8], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-40] mov DWORD PTR [%eax+36], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-36] mov DWORD PTR [%eax+40], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-32] mov DWORD PTR [%eax+44], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-28] mov DWORD PTR [%eax+48], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-24] mov DWORD PTR [%eax+52], %edx mov %eax, DWORD PTR [%ebp-60] mov DWORD PTR [%ebp-68], %eax .L8: mov %eax, DWORD PTR [%ebp-68] leave ret .LFE16: .size _Z15___H_inc_2d_u8vP25___processor_state_struct, .-_Z15___H_inc_2d_u8vP25___processor_state_struct .align 2 .type _Z11___H__20_t1P25___processor_state_struct, @function _Z11___H__20_t1P25___processor_state_struct: .LFB15: push %ebp .LCFI7: mov %ebp, %esp .LCFI8: sub %esp, 20 .LCFI9: cmp DWORD PTR [%ebp+8], 0 sete %al movzx %eax, %al test %eax, %eax je .L35 mov DWORD PTR [%ebp-20], OFFSET FLAT:_ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl jmp .L37 .L35: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+36] mov DWORD PTR [%ebp-8], %eax mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+40] mov DWORD PTR [%ebp-4], %eax mov %eax, DWORD PTR ___lp add %eax, 16 mov DWORD PTR [%ebp-12], %eax .L38: .L39: mov %eax, DWORD PTR [%ebp+8] mov %eax, DWORD PTR [%eax+76] test %eax, %eax sete %al movzx %eax, %al test %eax, %eax jne .L40 mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-12] mov DWORD PTR [%eax+60], %edx mov %eax, DWORD PTR ___gstate+292 mov DWORD PTR [%ebp-16], %eax jmp .L42 .L40: mov %eax, DWORD PTR [%ebp-12] add %eax, 32 mov DWORD PTR ___G_inc_2d_u8v, %eax mov DWORD PTR [%ebp-4], -18 mov %edx, DWORD PTR [%ebp-8] mov DWORD PTR [%ebp-16], %edx .L43: mov %eax, DWORD PTR [%ebp-16] add %eax, 11 mov %eax, DWORD PTR [%eax] cmp %eax, OFFSET FLAT:_Z11___H__20_t1P25___processor_state_struct sete %al movzx %eax, %al test %eax, %eax je .L42 jmp .L38 .L42: mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-16] mov DWORD PTR [%eax+56], %edx mov %eax, DWORD PTR [%ebp+8] mov %edx, DWORD PTR [%ebp-4] mov DWORD PTR [%eax+40], %edx mov %eax, DWORD PTR [%ebp-16] mov DWORD PTR [%ebp-20], %eax .L37: mov %eax, DWORD PTR [%ebp-20] leave ret .LFE15: .size _Z11___H__20_t1P25___processor_state_struct, .-_Z11___H__20_t1P25___processor_state_struct .section .rodata .LC0: .string " t1" .data .align 32 .type ___module_descr, @object .size ___module_descr, 136 ___module_descr: .long 406002 .long 0 .long .LC0 .long 1 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long ___lp .long ___lbl_tbl .long 11 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long _Z12___init_procv .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .long 0 .local ___lp .comm ___lp,4,4 .align 32 .type _ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl, @object .size _ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl, 40 _ZZ15___H_inc_2d_u8vP25___processor_state_structE11___hlbl_tbl: .long 0 .long .L10 .long .L21 .long .L24 .long .L27 .long .L28 .long .L29 .long .L30 .long .L31 .long 0 .align 4 .type _ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl, @object .size _ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl, 12 _ZZ11___H__20_t1P25___processor_state_structE11___hlbl_tbl: .long 0 .long .L39 .long 0 .align 32 .type ___lbl_tbl, @object .size ___lbl_tbl, 192 ___lbl_tbl: .long 1030 .long -2 .long .LC0 .long 0 .long 118 .long 0 .long 0 .long _Z11___H__20_t1P25___processor_state_struct .long 8198 .long -2 .long 0 .long 0 .long 630 .long 0 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 12309 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 61461 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 61461 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 61461 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 61461 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 28693 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 3198 .long 4101 .long 0 .long _Z15___H_inc_2d_u8vP25___processor_state_struct .long 0 .long 0 .long 0 .long 0 .ident "GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)" .section .note.GNU-stack,"",@progbits
2012/8/9 Bradley Lucier lucier@math.purdue.edu
I don't know what you want to do, but this code:
(declare (standard-bindings) (extended-bindings) (not interrupts-enabled) (not safe))
(define (u8transfer in out) (do ((i (fx- (u8vector-length in) 1) (fx- i 1))) ((fx< i 0)) (u8vector-set! out i (u8vector-ref in i))))
expands to
[Bradley-Luciers-MacBook-Pro:~/Downloads] lucier% gsc -cc-options "-save-temps" -keep-c -expansion fxtest.scm Expansion:
(define u8transfer (lambda (in out) (letrec ((do-temp.0 (lambda (in out i) (if ('#<procedure #2 ##fx<> i 0) #!void (let ((begin-temp.1 ('#<procedure #3 ##u8vector-set!> out i ('#<procedure #4 ##u8vector-ref> in i)))) (do-temp.0 in out ('#<procedure #5 ##fx-> i 1))))))) (let ((i ('#<procedure #5 ##fx-> ('#<procedure #6 ##u8vector-length> in) 1))) (if ('#<procedure #2 ##fx<> i 0) #!void (let ((begin-temp.1 ('#<procedure #3 ##u8vector-set!> out i ('#<procedure #4 ##u8vector-ref> in i)))) (do-temp.0 in out ('#<procedure #5 ##fx-> i 1))))))))
and the inner loop is
L14: movq %rdx, %rax sarq $2, %rax subq $4, %rdx movzbl 7(%rsi,%rax), %ecx leaq 0(,%rcx,4), %r8 movb %cl, 7(%r9,%rax) jns L14
which seems to have about 1 extra instruction (I don't know what the load effective address is doing there).
Brad