summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-04-17 21:48:32 -0700
committerKaz Kylheku <kaz@kylheku.com>2018-04-17 21:48:32 -0700
commitc3dfe168dffab763a1e24df97317b2662bc3702f (patch)
tree1741d8d2c8f950a541cf350a4b43014c7062e802
parent4c4ee99804a254530c350ed739bfc237332de34b (diff)
downloadtxr-c3dfe168dffab763a1e24df97317b2662bc3702f.tar.gz
txr-c3dfe168dffab763a1e24df97317b2662bc3702f.tar.bz2
txr-c3dfe168dffab763a1e24df97317b2662bc3702f.zip
asm: deal with too large d regs in getv/setv.
Only registers d00 through d3f can now fit into a small operand, but the setv, getv and derived instructions only take a small operand as the name. If a function accesses more than 64 dynamic variables, it can't be compiled and assembled. (Fewer, if it uses symbols for anything else.) The approach we take here is to relax the name operand in getv and setv: it can be a large or small operand. When assembling these instructions, we check the size: if the operand is large, we emit an extra mov instruction to move the operand to a register that is itself a small operand. Then we use that register as the operand. To do this, we need a dedicated assembler temporary register, like the "at" register on MIPS. We reserve t1 as the assembler temporary; the compiler must be adjusted not to use it. Future task: the following optimization is possible: the machine code can be scanned for uses of d registers. The d registers can be globally renumbered/reassigned (along with a rearrangement of the order of the datavec) such that the getv and setv instructions can use the lowest-numbered d registers, minimizing or eliminating these extra mov instructions. * share/txr/stdlib/asm.tl (operand-to-exp): New function. (op-getv, op-setv): Change name operand from rs to r, allowing a large operand. If the operand is large, emit the extra mov instruction into the temp register, and designate that register as the name for the getv/setv. * share/txr/stdlib/compiler.tl (compiler): Initialize t register counter to 2 rather than 1 so we don't allocate the assembler temporary t001. (compiler check-treg-leak): The balance check must cover a deficit of two registers now: t000 and t001.
-rw-r--r--share/txr/stdlib/asm.tl19
-rw-r--r--share/txr/stdlib/compiler.tl4
2 files changed, 19 insertions, 4 deletions
diff --git a/share/txr/stdlib/asm.tl b/share/txr/stdlib/asm.tl
index eafc322d..ed7ae1a0 100644
--- a/share/txr/stdlib/asm.tl
+++ b/share/txr/stdlib/asm.tl
@@ -285,6 +285,15 @@
(1 (intern (fmt "d~,02X" ix)))
(t (intern (fmt "v~,02X~,03X" (ssucc lv) ix))))))
+(defun operand-to-exp (val)
+ (with-lev-idx (lv ix) val
+ (caseql lv
+ (0 (if (zerop ix)
+ nil
+ ^(t ,ix)))
+ (1 ^(d ,ix))
+ (t ^(v ,lv ,ix)))))
+
(defun bits-to-obj (bits width)
(let ((tag (logtrunc bits 2))
(val (ash bits -2)))
@@ -676,7 +685,10 @@
(defopcode op-getv getv auto
(:method asm (me asm syntax)
me.(chk-arg-count 2 syntax)
- (tree-bind (reg name) asm.(parse-args me syntax '(d rs))
+ (tree-bind (reg name) asm.(parse-args me syntax '(d r))
+ (unless (small-op-p name)
+ asm.(asm-one ^(mov (t 1) ,(operand-to-exp name)))
+ (set name 1))
asm.(put-insn me.code (enc-small-op name) reg)))
(:method dis (me asm name reg)
^(,me.symbol ,(operand-to-sym reg) ,(small-op-to-sym name))))
@@ -694,7 +706,10 @@
(defopcode op-setv setv auto
(:method asm (me asm syntax)
me.(chk-arg-count 2 syntax)
- (tree-bind (reg name) asm.(parse-args me syntax '(r rs))
+ (tree-bind (reg name) asm.(parse-args me syntax '(r r))
+ (unless (small-op-p name)
+ asm.(asm-one ^(mov (t 1) ,(operand-to-exp name)))
+ (set name 1))
asm.(put-insn me.code (enc-small-op name) reg)))
(:method dis (me asm name reg)
^(,me.symbol ,(operand-to-sym reg) ,(small-op-to-sym name))))
diff --git a/share/txr/stdlib/compiler.tl b/share/txr/stdlib/compiler.tl
index 0571e10c..f649b8e9 100644
--- a/share/txr/stdlib/compiler.tl
+++ b/share/txr/stdlib/compiler.tl
@@ -107,7 +107,7 @@
(compile-only
(defstruct compiler nil
- (treg-cntr 1)
+ (treg-cntr 2)
(dreg-cntr 0)
(fidx-cntr 0)
(nlev 2)
@@ -215,7 +215,7 @@
me.(free-treg treg)))
(defmeth compiler check-treg-leak (me)
- (let ((balance (- (pred me.treg-cntr) (len me.tregs))))
+ (let ((balance (- (ppred me.treg-cntr) (len me.tregs))))
(unless (zerop balance)
(error "t-register leak in compiler: ~s outstanding" balance))))