flan/spike/x86/p11-shift-edges.flan

86 lines
3.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;;; 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 width1, 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)