I found that this type specifier suffers from personality disorder.
Nathan Froyd invented the specifier as an easy way to specify (:constant)
vop arg type restrictions so that the third argument to a
'-ref-with-offset' need not be loaded into a TN.
But in fact the DISPLACEMENT-BOUNDS function only works provided that you
don't go at all near the edge, which is the very thing it purports to
compute.
The bug is that users of the type state bytes-per-element, but it certainly
seems to expect a number of *bits* per element because the first thing
computed is
(let* (... (bytes-per-element (ceiling element-size sb!vm:n-byte-bits))
...
So which is the better convention for conceivable use-cases - Bits or bytes?
Clearly it's got issues as things stand.
Trying it with the parameters for a SINGLE-FLOAT as per current code, we
have:
(typexpand '(constant-displacement other-pointer-lowtag 4
vector-data-offset))
=> (INTEGER -2147483647 2147483648)
The correct upper bound for the constant offset is much smaller as this
example shows:
SB-VM> (disassemble '(lambda (x y) (data-vector-ref-with-offset (truly-the
(simple-array single-float 1) x) (truly-the fixnum y) 536870911)))
0313EA0F: F30F10847AFDFFFF7F MOVSS XMM0, [RDX+RDI*2+2147483645] ;
no-arg-parsing entry point
Go one higher and you've got a problem. Thankfully EMIT-SIGNED-DWORD
signals an error in this situation.
Not only that, I think the adjustment for lowtag and data-offset looks
fishy, but it's hard to know since it's already off. We're trying to tell
the function that the machine instruction is going to have an additive
fudge factor in the EA, and it's supposed to adjust its output accordingly,
but it seems to me that it compensates in the wrong direction, which is to
say, if I've understand the usage convention correctly.