(in-package "SB-ROTATE-BYTE")


;;; 32-bit rotates

(define-vop (%32bit-rotate-byte/c)
  (:policy :fast-safe)
  (:translate %unsigned-32-rotate-byte)
  (:note "inline 32-bit constant rotation")
  (:args (integer :scs (sb-vm::unsigned-reg) :target result))
  (:info count)
  (:arg-types (:constant (integer -31 31)) sb-vm::unsigned-num)
  (:results (result :scs (sb-vm::unsigned-reg)))
  (:result-types sb-vm::unsigned-num)
  (:generator 5
    (aver (not (= count 0)))
    (move result integer)
    (if (> count 0)
        (inst rol (sb-vm::reg-in-size result :dword) count)
        (inst ror (sb-vm::reg-in-size result :dword) count))))

(define-vop (%32bit-rotate-byte)
  (:policy :fast-safe)
  (:translate %unsigned-32-rotate-byte)
  (:args (count :scs (sb-vm::signed-reg) :target rcx)
         (integer :scs (sb-vm::unsigned-reg) :target result))
  (:arg-types sb-vm::tagged-num sb-vm::unsigned-num)
  (:temporary (:sc sb-vm::signed-reg :offset sb-vm::rcx-offset)
              rcx)
  (:results (result :scs (sb-vm::unsigned-reg) :from :load))
  (:result-types sb-vm::unsigned-num)
  (:generator 10
    (let ((label (gen-label))
          (end (gen-label)))
      (move result integer)
      (move rcx count)
      (inst cmp (sb-vm::reg-in-size rcx :dword) 0)
      (inst jmp :ge label)
      (inst neg (sb-vm::reg-in-size rcx :dword))
      (inst ror (sb-vm::reg-in-size result :dword) :cl)
      (inst jmp end)
      (emit-label label)
      (inst rol (sb-vm::reg-in-size result :dword) :cl)
      (emit-label end))))

;;; 64-bit rotates

(define-vop (%64bit-rotate-byte/c)
  (:policy :fast-safe)
  (:translate %unsigned-64-rotate-byte)
  (:note "inline 64-bit constant rotation")
  (:args (integer :scs (sb-vm::unsigned-reg) :target result))
  (:info count)
  (:arg-types (:constant (integer -63 63)) sb-vm::unsigned-num)
  (:results (result :scs (sb-vm::unsigned-reg)))
  (:result-types sb-vm::unsigned-num)
  (:generator 5
    (aver (not (= count 0)))
    (move result integer)
    (if (> count 0)
        (inst rol result count)
        (inst ror result (- count)))))

(define-vop (%64bit-rotate-byte)
  (:policy :fast-safe)
  (:translate %unsigned-64-rotate-byte)
  (:args (count :scs (sb-vm::signed-reg) :target rcx)
         (integer :scs (sb-vm::unsigned-reg) :target result))
  (:arg-types sb-vm::tagged-num sb-vm::unsigned-num)
  (:temporary (:sc sb-vm::signed-reg :offset sb-vm::rcx-offset)
              rcx)
  (:results (result :scs (sb-vm::unsigned-reg) :from :load))
  (:result-types sb-vm::unsigned-num)
  (:generator 10
    (let ((label (gen-label))
          (end (gen-label)))
      (move result integer)
      (move rcx count)
      (inst cmp rcx 0)
      (inst jmp :ge label)
      (inst neg rcx)
      (inst ror result :cl)
      (inst jmp end)
      (emit-label label)
      (inst rol result :cl)
      (emit-label end))))
