-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Description
The ssa.limit prove code widely assume that the positive half of the signed domain map to the bottom half of the unsigned domain.
But it also often assume that if a signed number reaches in the negative signed half it has no unsigned mapping while this is not true.
In fact the negative half of the signed domain perfectly maps to the top half of the unsigned domain.
The problem only exists at the discontinuity between maxint & minint.
In other words for always negative number int(x) < int(y) proves uint(x) < uint(y).
For one concrete example, applying the mathematical truth spelled out by the sentence above:
go/src/cmd/compile/internal/ssa/prove.go
Lines 571 to 577 in 0d0d5c9
| // signed <-> unsigned propagation | |
| if lim.min >= 0 { | |
| lim = lim.unsignedMinMax(uint64(lim.min), uint64(lim.max)) | |
| } | |
| if fitsInBitsU(lim.umax, uint(8*v.Type.Size()-1)) { | |
| lim = lim.signedMinMax(int64(lim.umin), int64(lim.umax)) | |
| } |
The perfect* version of this code is:
// signed <-> unsigned propagation
bitsize := v.Type.Size()*8
if sign(lim.min) == sign(lim.max) {
lim = lim.unsignedMinMax(convertIntWithBitsize[uint64](lim.min, bitsize), convertIntWithBitsize[uint64](lim.max, bitsize))
}
intUmin, intUmax := convertIntWithBitsize[int64](lim.umin, bitsize), convertIntWithBitsize[int64](lim.umax, bitsize)
if sign(intUmin) == sign(intUmax) {
lim = lim.signedMinMax(intUmin, intUmax)
}*within the constraints of what limit can model.
I wished we wouldn't have to write workarounds like 03fcb33 does.
It shouldn't be too hard to fix because each occurrence of this "bug" since the current code is never wrong, but it is sometimes too conservative.
So each occurrence can be fixed in a vacuum.