(define-arithmetic-method 'FIXNUM-LSH fixnum-methods/2-args
(lambda (target source1 source2 overflow?)
- overflow? ;ignore
- (prefix-instructions!
- (LAP ,@(load-machine-register! source1 eax)
- ,@(load-machine-register! source2 ecx)))
- (rtl-target:=machine-register! target eax)
- (LAP ,@(invoke-hook/call entry:compiler-fixnum-shift))))
+ overflow? ;ignore
+ ;++ This is suboptimal in the cases when SOURCE1 is stored only in
+ ;++ ecx or when SOURCE2 is stored only in eax, and either one is
+ ;++ dead (which is often the case). In such cases, this generates
+ ;++ code to needlessly save the dead pseudo-registers into their
+ ;++ homes simply because they were stored in eax and ecx. It'd be
+ ;++ nice to have a variant of LOAD-MACHINE-REGISTER! for multiple
+ ;++ sources and targets, which would compute a parallel assignment
+ ;++ using machine registers if available for temporaries, or the
+ ;++ homes of pseudo-registers if not.
+ (let* ((load-eax (load-machine-register! source1 eax))
+ (load-ecx (load-machine-register! source2 ecx)))
+ (delete-dead-registers!)
+ (rtl-target:=machine-register! target eax)
+ (LAP ,@load-eax
+ ,@load-ecx
+ ;; Clearing the map is not necessary because the hook uses
+ ;; only eax and ecx. If the hook were changed, it would be
+ ;; necessary to clear the map first.
+ ,@(invoke-hook/call entry:compiler-fixnum-shift)))))
\f
(define (do-division target source1 source2 result-reg)
(prefix-instructions! (load-machine-register! source1 eax))
(define-arithmetic-method 'FIXNUM-LSH fixnum-methods/2-args
(lambda (target source1 source2 overflow?)
- overflow? ;ignore
- (prefix-instructions!
- (LAP ,@(load-machine-register! source1 rax)
- ,@(load-machine-register! source2 rcx)))
- (rtl-target:=machine-register! target rax)
- (LAP ,@(invoke-hook/call entry:compiler-fixnum-shift))))
+ overflow? ;ignore
+ ;++ This is suboptimal in the cases when SOURCE1 is stored only in
+ ;++ rcx or when SOURCE2 is stored only in rax, and either one is
+ ;++ dead (which is often the case). In such cases, this generates
+ ;++ code to needlessly save the dead pseudo-registers into their
+ ;++ homes simply because they were stored in rax and rcx. It'd be
+ ;++ nice to have a variant of LOAD-MACHINE-REGISTER! for multiple
+ ;++ sources and targets, which would compute a parallel assignment
+ ;++ using machine registers if available for temporaries, or the
+ ;++ homes of pseudo-registers if not.
+ (let* ((load-rax (load-machine-register! source1 rax))
+ (load-rcx (load-machine-register! source2 rcx)))
+ (delete-dead-registers!)
+ (rtl-target:=machine-register! target rax)
+ (LAP ,@load-rax
+ ,@load-rcx
+ ;; Clearing the map is not necessary because the hook uses
+ ;; only rax and rcx. If the hook were changed, it would be
+ ;; necessary to clear the map first.
+ ,@(invoke-hook/call entry:compiler-fixnum-shift)))))
\f
(define (do-division target source1 source2 result-reg)
(prefix-instructions! (load-machine-register! source1 rax))
define_jump_indirection(nofp_modulo,39)
\f
# Input and output in eax, shift count in ecx, all detagged fixnums.
-# Return address is at the top of the stack.
+# Return address is at the top of the stack, untagged. This hook must
+# not use any registers other than eax and ecx; if it does, the code
+# to generate calls to it, in compiler/machines/i386/rulfix.scm, must
+# clear the register map first.
define_hook_label(fixnum_shift)
OP(sar,l) TW(IMM(TC_LENGTH),REG(ecx))
define_jump_indirection(generic_modulo,39)
\f
# Input and output in rax, shift count in rcx, all detagged fixnums.
-# Return address is at the top of the stack.
+# Return address is at the top of the stack, untagged. This hook must
+# not use any registers other than rax and rcx; if it does, the code
+# to generate calls to it, in compiler/machines/x86-64/rulfix.scm,
+# must clear the register map first.
define_hook_label(fixnum_shift)
OP(sar,q) TW(IMM(TC_LENGTH),REG(rcx))