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:
|
// 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.
The
ssa.limitprove 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)provesuint(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
The perfect* version of this code is:
*within the constraints of what
limitcan 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.