86 lines
3.2 KiB
Plaintext
86 lines
3.2 KiB
Plaintext
;;;; A shift whose count reaches the operand's own width, at every width.
|
||
;;;;
|
||
;;;; This backend computes every integer in a full 64-bit register and narrows
|
||
;;;; only on the way to memory, so the shift instruction it emits is the 64-bit
|
||
;;;; one whatever the type says. The hardware masks a 64-bit shift's count to
|
||
;;;; 63 — not to 31, 15 or 7 — so for every width below 64 the mask the
|
||
;;;; language promises (count masked to width−1, which is what emit writes into
|
||
;;;; the IR) has to be emitted by hand. Without it a count of 32 on an i32
|
||
;;;; shifts the value clean out of the low half and stores zero, where the rule
|
||
;;;; says the count is 0 and the value comes back unchanged.
|
||
;;;;
|
||
;;;; Every count is a global and never a literal: the checker rejects a literal
|
||
;;;; count that is out of range — that is a typo, not a program — so the only
|
||
;;;; shift that can reach either backend out of range is a computed one, and a
|
||
;;;; literal would be folded away before the code under test ran anyway.
|
||
|
||
(defvar i8min i8 -128)
|
||
(defvar i16min i16 -32768)
|
||
(defvar i32min i32 -2147483648)
|
||
(defvar i64min i64 -9223372036854775808)
|
||
(defvar u8hi u8 255)
|
||
(defvar u16hi u16 65535)
|
||
(defvar u32hi u32 4294967295)
|
||
(defvar one8 i8 1)
|
||
(defvar one16 i16 1)
|
||
(defvar one32 i32 1)
|
||
(defvar oneu8 u8 1)
|
||
(defvar oneu16 u16 1)
|
||
(defvar oneu32 u32 1)
|
||
(defvar one64 i64 1)
|
||
|
||
(defvar c8 i8 8)
|
||
(defvar c9 i8 9)
|
||
(defvar cu8 u8 8)
|
||
(defvar c16 i16 16)
|
||
(defvar cu16 u16 17)
|
||
(defvar c32 i32 32)
|
||
(defvar c33 i32 33)
|
||
(defvar cu32 u32 32)
|
||
(defvar cu33 u32 33)
|
||
(defvar c64 i64 64)
|
||
(defvar c65 i64 65)
|
||
|
||
(defn main [] i32
|
||
;; ── The count exactly at the width: masks to 0, so nothing moves ──
|
||
(println (<< one8 c8))
|
||
(println (<< one16 c16))
|
||
(println (<< one32 c32))
|
||
(println (<< oneu8 cu8))
|
||
(println (<< oneu32 cu32))
|
||
(println (<< one64 c64))
|
||
|
||
;; ── The sign bit, shifted by the width ────────────────────────────
|
||
;; An arithmetic shift of a negative number by a count the hardware would
|
||
;; read as the full width answers all-ones; masked, it answers the value.
|
||
(println (<< i8min c8))
|
||
(println (>> i8min c8))
|
||
(println (<< i16min c16))
|
||
(println (>> i16min c16))
|
||
(println (<< i32min c32))
|
||
(println (>> i32min c32))
|
||
(println (<< i64min c64))
|
||
(println (>> i64min c64))
|
||
|
||
;; ── The same edge unsigned, where the shift is logical ────────────
|
||
(println (>> u8hi cu8))
|
||
(println (>> u16hi cu16)) ; 17, one past the width: masks to 1
|
||
(println (>> u32hi cu32))
|
||
(println (<< u32hi cu33)) ; 33 masks to 1: the top of u32 doubled, wrapped
|
||
|
||
;; ── One past the width, where the masked count is 1 ───────────────
|
||
(println (<< one8 c9))
|
||
(println (<< one32 c33))
|
||
(println (<< one64 c65))
|
||
|
||
;; ── And the ordinary counts, which never needed a mask ────────────
|
||
(println (<< one32 one32))
|
||
(println (>> i32min one32))
|
||
(println (>> u32hi oneu32))
|
||
(println (>> i8min one8))
|
||
(println (>> u8hi oneu8))
|
||
(println (<< one16 one16))
|
||
(println (>> i16min one16))
|
||
(println (>> u16hi oneu16))
|
||
0)
|