master: Encode the remaining bmi1/2 instructions, movbe

stassats via Sbcl-commits <[email protected]> Wed, 29 Jul 2026 02:11:35 +0000
Newsgroups gmane.lisp.steel-bank.cvs
Message-ID <[email protected]>
The branch "master" has been updated in SBCL:
       via  773469344bcb9da70284f722f0d1a414796dfa7e (commit)
      from  76d957fcc77c2782f831a9d70dce383b7820b958 (commit)

- Log -----------------------------------------------------------------
commit 773469344bcb9da70284f722f0d1a414796dfa7e
Author: Stas Boukarev <[email protected]>
Date:   Wed Jul 29 04:51:07 2026 +0300

    Encode the remaining bmi1/2 instructions, movbe
---
 src/compiler/x86-64/avx2-insts.lisp | 58 ++++++++++++++++++++++++++-----------
 src/compiler/x86-64/insts.lisp      | 35 ++++++++++++++++++++++
 2 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/src/compiler/x86-64/avx2-insts.lisp b/src/compiler/x86-64/avx2-insts.lisp
index a8d2334d4..74700ff60 100644
--- a/src/compiler/x86-64/avx2-insts.lisp
+++ b/src/compiler/x86-64/avx2-insts.lisp
@@ -381,7 +381,8 @@
                     (xmm-size thing))
                    (t
                     0)))
-          (r (if (null reg)
+          (r (if (or (null reg)
+                     (integerp reg))
                  0
                  (reg-7-p (reg-id reg))))
           (x (cond ((and (ea-p thing)
@@ -1690,46 +1691,52 @@ REG is the source (encoded in ModR/M.r/m).
      (emit-sse-inst-2byte segment dst src #xf3 #x38 #xf6
                           :operand-size size))))
 
-;;;; BMI2 instructions (VEX-encoded GPR operations)
+;;;; BMI1/2 instructions (VEX-encoded GPR operations)
 ;;;; All use VEX.LZ (L=0). W=1 for 64-bit, W=0 for 32-bit.
 
 ;;; Shifts with shift count in GPR (no flag side effects, not serialized on CL)
 ;;; SHRX/SHLX/SARX r64a, r/m64, r64b
 ;;;   dst = reg field, src = r/m, count = vvvv
-(macrolet ((def (name prefix)
-             `(define-instruction ,name (segment &prefix prefix dst src count)
-                ,@(avx2-inst-printer-list 'vex-gpr prefix #xF7
+(macrolet ((def (name prefix opcode third-op-name)
+             `(define-instruction ,name (segment &prefix prefix dst src ,third-op-name)
+                ,@(avx2-inst-printer-list 'vex-gpr prefix opcode
+                                          :printer '(:name :tab reg ", " reg/mem ", " vvvv)
                                           :nds t
                                           :opcode-prefix #x0f38)
                 (:emitter
-                 (emit-avx2-inst segment src dst ,prefix #xF7
+                 (emit-avx2-inst segment src dst ,prefix ,opcode
                                  :opcode-prefix #x0f38
-                                 :vvvv count
+                                 :vvvv ,third-op-name
                                  :l 0
                                  :w (ecase (pick-operand-size prefix dst src)
                                       (:qword 1)
                                       (:dword 0)))))))
-  (def shrx #xF2)
-  (def shlx #x66)
-  (def sarx #xF3))
+  (def shrx #xF2 #xF7 count)
+  (def shlx #x66 #xF7 count)
+  (def sarx #xF3 #xF7 count)
+  (def bzhi nil #xF5 position)
+  (def bextr nil #xF7 control))
 
 ;;; PEXT/PDEP r64a, r64b, r/m64
 ;;;   dst = reg field, src = vvvv, mask = r/m
-(macrolet ((def (name prefix)
-             `(define-instruction ,name (segment &prefix prefix dst src mask)
-                ,@(avx2-inst-printer-list 'vex-gpr prefix #xF5
+(macrolet ((def (name prefix opcode &optional (third-op-name 'src2)
+                                              printer)
+             `(define-instruction ,name (segment &prefix prefix dst src ,third-op-name)
+                ,@(avx2-inst-printer-list 'vex-gpr prefix opcode
                                           :nds t
+                                          :printer printer
                                           :opcode-prefix #x0f38)
                 (:emitter
-                 (emit-avx2-inst segment mask dst ,prefix #xF5
+                 (emit-avx2-inst segment ,third-op-name dst ,prefix ,opcode
                                  :opcode-prefix #x0f38
                                  :vvvv src
                                  :l 0
-                                 :w (ecase (pick-operand-size prefix dst mask)
+                                 :w (ecase (pick-operand-size prefix dst src)
                                       (:qword 1)
                                       (:dword 0)))))))
-  (def pext #xF3)
-  (def pdep #xF2))
+  (def pext #xF3 #xF5 mask)
+  (def pdep #xF2 #xF5 mask)
+  (def andn nil #xF2))
 
 ;;; RORX r64a, r/m64, imm8
 ;;;   dst = reg field, src = r/m, count = imm8, no vvvv
@@ -1746,4 +1753,21 @@ REG is the source (encoded in ModR/M.r/m).
   . #.(avx2-inst-printer-list 'vex-gpr #xF2 #xF0
                               :opcode-prefix #x0f3a
                               :printer '(:name :tab reg ", " reg/mem)))
+(macrolet ((def (name reg)
+             `(define-instruction ,name (segment &prefix prefix dst src)
+                ,@(avx2-inst-printer-list 'vex-gpr nil #xF3
+                                          :opcode-prefix #x0f38
+                                          :more-fields `((reg ,reg))
+                                          :printer '(:name :tab vvvv ", " reg/mem))
+                (:emitter
+                 (emit-avx2-inst segment src ,reg nil #xF3
+                                 :opcode-prefix #x0f38
+                                 :vvvv dst
+                                 :l 0
+                                 :w (ecase (pick-operand-size prefix dst src)
+                                      (:qword 1)
+                                      (:dword 0)))))))
+  (def blsr 1)
+  (def blsmsk 2)
+  (def blsi 3))
 
diff --git a/src/compiler/x86-64/insts.lisp b/src/compiler/x86-64/insts.lisp
index 465adb277..2ea66f9d9 100644
--- a/src/compiler/x86-64/insts.lisp
+++ b/src/compiler/x86-64/insts.lisp
@@ -1527,6 +1527,41 @@
         (t
             (error "bogus arguments to MOV: ~S ~S" dst src))))
 
+(define-instruction-format (movbe 32
+                            :default-printer
+                            `(:name :tab reg ", " reg/mem))
+  (prefix  :field (byte 16 0)    :value #x380F)
+  (op      :field (byte 8 16))
+  (reg/mem :fields (list (byte 2 30) (byte 3 24))
+                                :type 'reg/mem)
+  (reg     :field (byte 3 27)   :type 'reg))
+
+(define-instruction movbe (segment &prefix prefix dst src)
+  (:printer movbe ((op #xF0))
+            '(:name :tab reg ", " reg/mem))
+  (:printer movbe ((op #xF1))
+            '(:name :tab reg/mem ", " reg))
+  (:emitter
+   (let* ((size (pick-operand-size prefix dst src))
+          (src (sized-thing src size))
+          (dst (sized-thing dst size)))
+     (when (eq size :byte)
+       (error "MOVBE does not support 8-bit operands: ~S ~S" dst src))
+     (cond ((and (gpr-p dst) (not (gpr-p src)))
+            (emit-prefixes segment src dst size)
+            (emit-byte segment #x0F)
+            (emit-byte segment #x38)
+            (emit-byte segment #xF0)
+            (emit-ea segment src dst))
+           ((and (gpr-p src) (not (gpr-p dst)))
+            (emit-prefixes segment dst src size)
+            (emit-byte segment #x0F)
+            (emit-byte segment #x38)
+            (emit-byte segment #xF1)
+            (emit-ea segment dst src))
+           (t
+            (error "Invalid arguments to MOVBE: ~S ~S (requires one GPR and one memory operand)" dst src))))))
+
 ;;; MOVABS is not a mnemonic according to the CPU vendors, but every (dis)assembler
 ;;; in popular use chooses this mnemonic instead of MOV with an 8-byte operand.
 ;;; (Even with Intel-compatible syntax, LLVM produces MOVABS).

-----------------------------------------------------------------------


hooks/post-receive
-- 
SBCL