Re: master: Fix immediate construction on loongarch, riscv
Stas Boukarev <[email protected]> Sun, 22 Feb 2026 16:56:42 +0300
| Newsgroups | gmane.lisp.steel-bank.cvs,gmane.lisp.steel-bank.devel |
|---|---|
| Message-ID | <CAF63=10UGN2GXzvn93Hv2nzxR+moeSiN7U3n04VQxXf7ZjmRNQ@mail.gmail.com> |
I just want to get things moving, not optimize them. clang just loads things from memory. On Sun, Feb 22, 2026 at 1:27 PM Charles Zhang <[email protected]> wrote: > > Just a note: If a temp register is allocated anyway, the generic case can just be done by loading the high 32 bits into the temp register, 32 bits into the target register, and adding. > > On Sunday, February 22, 2026, 3:59 AM, stassats via Sbcl-commits <[email protected]> wrote: > > The branch "master" has been updated in SBCL: > via fcc91d51a57bc79921d0bbe4ff7b4f2abc372317 (commit) > from 5bf2decc30b259ac8dfb3ac1d052fd90e14a4e84 (commit) > > - Log ----------------------------------------------------------------- > commit fcc91d51a57bc79921d0bbe4ff7b4f2abc372317 > Author: Stas Boukarev <[email protected]> > Date: Sun Feb 22 03:26:59 2026 +0300 > > Fix immediate construction on loongarch, riscv > > Where large immediates are constructed by adding and shifting left. > Intermediate values might not be properly tagged for a descriptor > register. > --- > src/assembly/riscv/assem-rtns.lisp | 4 +- > src/compiler/loongarch64/insts.lisp | 90 +++++++++++++++++++++---------------- > src/compiler/riscv/insts.lisp | 87 +++++++++++++++++++---------------- > src/compiler/riscv/vm.lisp | 9 ++-- > 4 files changed, 109 insertions(+), 81 deletions(-) > > diff --git a/src/assembly/riscv/assem-rtns.lisp b/src/assembly/riscv/assem-rtns.lisp > index f61171d1e..5a1b023b2 100644 > --- a/src/assembly/riscv/assem-rtns.lisp > +++ b/src/assembly/riscv/assem-rtns.lisp > @@ -266,7 +266,7 @@ > > ;; Don't want these to overlap with C args. > (:temp pa-temp non-descriptor-reg nl6-offset) > - (:temp temp non-descriptor-reg nl7-offset)) > + (:temp temp non-descriptor-reg tmp-offset)) > (save-c-registers) > > (initialize-boxed-regs (list function arg-ptr nargs #+sb-thread tls-ptr)) > @@ -313,7 +313,7 @@ > (:temp value0-pass (any-reg) (result-reg-offset 0)) > (:temp value1-pass (any-reg) (result-reg-offset 1)) > (:temp pa-temp (any-reg) nl6-offset) > - (:temp temp (any-reg) nl7-offset)) > + (:temp temp (unsigned-reg) tmp-offset)) > ;; The C stack frame and argument registers should have already been > ;; set up in Lisp. > > diff --git a/src/compiler/loongarch64/insts.lisp b/src/compiler/loongarch64/insts.lisp > index b74cc318d..df4f1c44c 100644 > --- a/src/compiler/loongarch64/insts.lisp > +++ b/src/compiler/loongarch64/insts.lisp > @@ -783,10 +783,11 @@ > (u-and-i-inst-immediate immediate) > (cond ((zerop hi) > (inst addi.d rd zero-tn immediate)) > + ((zerop lo) > + (inst lu12i.w rd hi)) > (t > - (inst lu12i.w rd hi) > - (unless (zerop lo) > - (inst addi.d rd rd lo)))))) > + (inst lu12i.w t7-tn hi) > + (inst addi.d rd t7-tn lo))))) > > ;;;; li should optimization by lu32i, lu52i > (defun %li (reg value) > @@ -799,63 +800,76 @@ > (integer-length (integer-length value)) > (2^k (ash 1 integer-length)) > (2^.k-1 (ash 1 (1- integer-length))) > - (complement (mod (lognot value) (ash 1 64)))) > + (complement (mod (lognot value) (ash 1 64))) > + ;; Intermediate unboxed values might be inappropriate for a > + ;; boxed target register > + (tmp t7-tn)) > (cond ((zerop (logand (1+ value) value)) > ;; Common special case: the immediate is of the form #xfff... > - (inst addi.d reg zero-tn -1) > - (unless (= integer-length 64) > - (inst srli.d reg reg (- 64 integer-length)))) > + (inst addi.d tmp zero-tn -1) > + (aver (/= integer-length 64)) > + (inst srli.d reg tmp (- 64 integer-length))) > ((let ((delta (- 2^k value))) > (and (typep (ash delta (- 64 integer-length)) 'short-immediate) > (logand delta (1- delta)))) > ;; Common special case: the immediate is of the form > ;; #x00fff...00, where there are a small number of > ;; zeroes at the end. > - (inst addi.d reg zero-tn (ash (- value 2^k) (- 64 integer-length))) > - (inst srli.d reg reg (- 64 integer-length))) > + (inst addi.d tmp zero-tn (ash (- value 2^k) (- 64 integer-length))) > + (inst srli.d reg tmp (- 64 integer-length))) > ((zerop (logand complement (1+ complement))) > ;; #xfffffff...00000 > - (inst addi.d reg zero-tn -1) > - (inst slli.d reg reg (integer-length complement))) > + (inst addi.d tmp zero-tn -1) > + (inst slli.d reg tmp (integer-length complement))) > ((typep (- value 2^k) 'short-immediate) > ;; Common special case: loading an immediate which is a > ;; signed 12 bit constant away from a power of 2. > (cond ((= integer-length 64) > (inst addi.d reg zero-tn (- value 2^k))) > (t > - (inst addi.d reg zero-tn 1) > - (inst slli.d reg reg integer-length) > - (inst addi.d reg reg (- value 2^k))))) > + (inst addi.d tmp zero-tn 1) > + (inst slli.d tmp tmp integer-length) > + (inst addi.d reg tmp (- value 2^k))))) > ((typep (- value 2^.k-1) 'short-immediate) > ;; Common special case: loading an immediate which is a > ;; signed 12 bit constant away from a power of 2. > - (inst addi.d reg zero-tn 1) > - (inst slli.d reg reg (1- integer-length)) > - (unless (= value 2^.k-1) > - (inst addi.d reg reg (- value 2^.k-1)))) > + (inst addi.d tmp zero-tn 1) > + (cond ((= value 2^.k-1) > + (inst slli.d reg tmp (1- integer-length))) > + (t > + (inst slli.d tmp tmp (1- integer-length)) > + (inst addi.d reg tmp (- value 2^.k-1))))) > (t > ;; The "generic" case. > ;; Load in the first 31 non zero most significant bits. > - (let ((chunk (ldb (byte 12 (- integer-length 31)) value))) > - (inst lu12i.w reg (ldb (byte 20 (- integer-length 19)) value)) > - (cond ((= (1- (ash 1 12)) chunk) > - (inst addi.d reg reg (1- (ash 1 11))) > - (inst addi.d reg reg (1- (ash 1 11))) > - (inst addi.d reg reg 1)) > - ((logbitp 11 chunk) > - (inst addi.d reg reg (1- (ash 1 11))) > - (inst addi.d reg reg (- chunk (1- (ash 1 11))))) > - (t > - (inst addi.d reg reg chunk)))) > - ;; Now we need to load in the rest of the bits properly, in > - ;; chunks of 11 to avoid sign extension. > - (do ((i (- integer-length 31) (- i 11))) > - ((< i 11) > - (inst slli.d reg reg i) > - (unless (zerop (ldb (byte i 0) value)) > - (inst addi.d reg reg (ldb (byte i 0) value)))) > - (inst slli.d reg reg 11) > - (inst addi.d reg reg (ldb (byte 11 (- i 11)) value))))))) > + (let ((chunk (ldb (byte 12 (- integer-length 31)) value)) > + instructions) > + (flet ((add-inst (m d o1 o2) > + ;; Gotta know which instruction is the last one > + ;; to put REG as its destination > + (push (list m d o1 o2) instructions))) > + (inst lu12i.w tmp (ldb (byte 20 (- integer-length 19)) value)) > + (cond ((= (1- (ash 1 12)) chunk) > + (inst addi.d tmp tmp (1- (ash 1 11))) > + (inst addi.d tmp tmp (1- (ash 1 11))) > + (add-inst 'addi.d tmp tmp 1)) > + ((logbitp 11 chunk) > + (inst addi.d tmp tmp (1- (ash 1 11))) > + (add-inst 'addi.d tmp tmp (- chunk (1- (ash 1 11))))) > + (t > + (add-inst 'addi.d tmp tmp chunk))) > + ;; Now we need to load in the rest of the bits properly, in > + ;; chunks of 11 to avoid sign extension. > + (do ((i (- integer-length 31) (- i 11))) > + ((< i 11) > + (add-inst 'slli.d tmp tmp i) > + (unless (zerop (ldb (byte i 0) value)) > + (add-inst 'addi.d tmp tmp (ldb (byte i 0) value)))) > + (add-inst 'slli.d tmp tmp 11) > + (add-inst 'addi.d tmp tmp (ldb (byte 11 (- i 11)) value))) > + (setf (second (car instructions)) reg) > + (loop for (m d o1 o2) in (reverse instructions) > + do (inst* m d o1 o2)))))))) > (fixup > (inst lu12i.w reg value) > (inst addi.d reg reg value)))) > diff --git a/src/compiler/riscv/insts.lisp b/src/compiler/riscv/insts.lisp > index 04ff8098c..e7135c811 100644 > --- a/src/compiler/riscv/insts.lisp > +++ b/src/compiler/riscv/insts.lisp > @@ -19,7 +19,7 @@ > sb-vm::registers sb-vm::float-registers > sb-vm::zero > sb-vm::zero-offset > - sb-vm::lip-tn sb-vm::zero-tn > + sb-vm::lip-tn sb-vm::zero-tn sb-vm::tmp-tn > sb-vm::code-tn > sb-vm::tn-byte-offset > ;; Types > @@ -441,10 +441,11 @@ > (u-and-i-inst-immediate immediate) > (cond ((zerop hi) > (inst addi rd zero-tn immediate)) > + ((zerop lo) > + (inst lui rd hi)) > (t > - (inst lui rd hi) > - (unless (zerop lo) > - (inst addi rd rd lo)))))) > + (inst lui tmp-tn hi) > + (inst addi rd tmp-tn lo))))) > > (defun %li (reg value) > (etypecase value > @@ -457,63 +458,73 @@ > (integer-length (integer-length value)) > (2^k (ash 1 integer-length)) > (2^.k-1 (ash 1 (1- integer-length))) > - (complement (mod (lognot value) (ash 1 64)))) > + (complement (mod (lognot value) (ash 1 64))) > + (tmp tmp-tn)) > (cond ((zerop (logand (1+ value) value)) > ;; Common special case: the immediate is of the form #xfff... > (inst addi reg zero-tn -1) > - (unless (= integer-length 64) > - (inst srli reg reg (- 64 integer-length)))) > + (inst srli reg reg (- 64 integer-length))) > ((let ((delta (- 2^k value))) > (and (typep (ash delta (- 64 integer-length)) 'short-immediate) > (logand delta (1- delta)))) > ;; Common special case: the immediate is of the form > ;; #x00fff...00, where there are a small number of > ;; zeroes at the end. > - (inst addi reg zero-tn (ash (- value 2^k) (- 64 integer-length))) > - (inst srli reg reg (- 64 integer-length))) > + (inst addi tmp zero-tn (ash (- value 2^k) (- 64 integer-length))) > + (inst srli reg tmp (- 64 integer-length))) > ((zerop (logand complement (1+ complement))) > ;; #xfffffff...00000 > - (inst addi reg zero-tn -1) > - (inst slli reg reg (integer-length complement))) > + (inst addi tmp zero-tn -1) > + (inst slli reg tmp (integer-length complement))) > ((typep (- value 2^k) 'short-immediate) > ;; Common special case: loading an immediate which is a > ;; signed 12 bit constant away from a power of 2. > (cond ((= integer-length 64) > (inst addi reg zero-tn (- value 2^k))) > (t > - (inst addi reg zero-tn 1) > - (inst slli reg reg integer-length) > - (inst addi reg reg (- value 2^k))))) > + (inst addi tmp zero-tn 1) > + (inst slli tmp tmp integer-length) > + (inst addi reg tmp (- value 2^k))))) > ((typep (- value 2^.k-1) 'short-immediate) > ;; Common special case: loading an immediate which is a > ;; signed 12 bit constant away from a power of 2. > - (inst addi reg zero-tn 1) > - (inst slli reg reg (1- integer-length)) > - (unless (= value 2^.k-1) > - (inst addi reg reg (- value 2^.k-1)))) > + (inst addi tmp zero-tn 1) > + (cond ((= value 2^.k-1) > + (inst slli reg tmp (1- integer-length))) > + (t > + (inst slli tmp tmp (1- integer-length)) > + (inst addi reg tmp (- value 2^.k-1))))) > (t > ;; The "generic" case. > ;; Load in the first 31 non zero most significant bits. > - (let ((chunk (ldb (byte 12 (- integer-length 31)) value))) > - (inst lui reg (ldb (byte 20 (- integer-length 19)) value)) > - (cond ((= (1- (ash 1 12)) chunk) > - (inst addi reg reg (1- (ash 1 11))) > - (inst addi reg reg (1- (ash 1 11))) > - (inst addi reg reg 1)) > - ((logbitp 11 chunk) > - (inst addi reg reg (1- (ash 1 11))) > - (inst addi reg reg (- chunk (1- (ash 1 11))))) > - (t > - (inst addi reg reg chunk)))) > - ;; Now we need to load in the rest of the bits properly, in > - ;; chunks of 11 to avoid sign extension. > - (do ((i (- integer-length 31) (- i 11))) > - ((< i 11) > - (inst slli reg reg i) > - (unless (zerop (ldb (byte i 0) value)) > - (inst addi reg reg (ldb (byte i 0) value)))) > - (inst slli reg reg 11) > - (inst addi reg reg (ldb (byte 11 (- i 11)) value))))))) > + (let ((chunk (ldb (byte 12 (- integer-length 31)) value)) > + instructions) > + (flet ((add-inst (m d o1 o2) > + ;; Gotta know which instruction is the last one > + ;; to put REG as its destination > + (push (list m d o1 o2) instructions))) > + (inst lui tmp (ldb (byte 20 (- integer-length 19)) value)) > + (cond ((= (1- (ash 1 12)) chunk) > + (inst addi tmp tmp (1- (ash 1 11))) > + (inst addi tmp tmp (1- (ash 1 11))) > + (add-inst 'addi tmp tmp 1)) > + ((logbitp 11 chunk) > + (inst addi tmp tmp (1- (ash 1 11))) > + (add-inst 'addi tmp tmp (- chunk (1- (ash 1 11))))) > + (t > + (add-inst 'addi tmp tmp chunk))) > + ;; Now we need to load in the rest of the bits properly, in > + ;; chunks of 11 to avoid sign extension. > + (do ((i (- integer-length 31) (- i 11))) > + ((< i 11) > + (add-inst 'slli tmp tmp i) > + (unless (zerop (ldb (byte i 0) value)) > + (add-inst 'addi tmp tmp (ldb (byte i 0) value)))) > + (add-inst 'slli tmp tmp 11) > + (add-inst 'addi tmp tmp (ldb (byte 11 (- i 11)) value))) > + (setf (second (car instructions)) reg) > + (loop for (m d o1 o2) in (reverse instructions) > + do (inst* m d o1 o2)))))))) > (fixup > (inst lui reg value) > (inst addi reg reg value)))) > diff --git a/src/compiler/riscv/vm.lisp b/src/compiler/riscv/vm.lisp > index c0a58f0ae..3950e56ec 100644 > --- a/src/compiler/riscv/vm.lisp > +++ b/src/compiler/riscv/vm.lisp > @@ -65,7 +65,8 @@ > (defreg l0 22) ; s6 > (defreg nl6 23) ; s7 > (defreg l1 24) ; s8 > - (defreg nl7 25) ; s9 > + ;; A register needed to load constants into descriptor-regs > + (defreg tmp 25) ; s9 > (defreg #-sb-thread l2 #+sb-thread thread 26) ; s10 > > (defreg cfunc 27) ; s11 > @@ -74,7 +75,7 @@ > (defreg code 30) ; t5 > (defreg nargs 31) ; t6 > > - (defregset non-descriptor-regs nl0 nl1 nl2 ra nl3 nl4 nl5 nl6 nl7 nargs nfp cfunc) > + (defregset non-descriptor-regs nl0 nl1 nl2 ra nl3 nl4 nl5 nl6 nargs nfp cfunc) > (defregset descriptor-regs a0 a1 a2 a3 a4 a5 l0 l1 #-sb-thread l2 ocfp lexenv) > (defregset reserve-descriptor-regs lexenv) > (defregset reserve-non-descriptor-regs cfunc) > @@ -210,7 +211,9 @@ > (defregtn ocfp any-reg) > (defregtn nfp any-reg) > > - (defregtn ra any-reg)) > + (defregtn ra any-reg) > + > + (defregtn tmp unsigned-reg)) > > ;;; If VALUE can be represented as an immediate constant, then return the > ;;; appropriate SC number, otherwise return NIL. > > ----------------------------------------------------------------------- > > > hooks/post-receive > -- > SBCL > > > _______________________________________________ > Sbcl-commits mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/sbcl-commits _______________________________________________ Sbcl-commits mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-commits