What version of Go are you using (go version
)?
$ go version 1.17.0
Does this issue reproduce with the latest release?
yes
What did you do?
See https://go.godbolt.org/z/o5PqscasE for code.
On line 11/12 panics when endreg
, is bigger than 29.
On line 15 it is checked that h
is negative.
On line 16 there is a branch that panics on negative -h
.
This might make sense if h
could be -128, but it cant because of the check on line 11.
What did you expect to see?
I expected the go compiler to combine these checks and to avoid the extra branch+2 instructions.
What did you see instead?
Out of the assembly I gather that the go compiler fails to link line 15 with 16.
The gc also check the same thing twice, it also fails to see that h < 0
is the same as -h >= 0
.
https://go.godbolt.org/z/hsMnMa1W1 does what I expect, and the gc manages to proof that -h
is less than 0x1f
, but more importantly also that -h
is non-negative.
Comment From: JAicewizard
another example: https://godbolt.org/z/Ge9887jEr
Comment From: JAicewizard
Ive been investigating this second example.
Posit32es2.Int64 method(Posit32es2) func() int64
b1:
v1 = InitMem <mem>
v6 = Arg <Posit32es2> {a} (a[Posit32es2])
v8 = Const64 <int64> [0]
v9 = StructSelect <uint32> [0] v6
v10 = Const64 <uint> [2]
v11 = Lsh32x64 <uint32> [false] v9 v10
v12 = Const32 <uint32> [-2147483648]
v13 = Or32 <uint32> v11 v12 (afracP1[uint32])
v16 = Const32 <int32> [0]
v17 = Less32 <bool> v9 v16
v26 = Const32 <int32> [-1]
If v17 -> b3 b2
b2: <- b1
v31 = MakeResult <int64,mem> v8 v1
Ret v31
b3: <- b1
v19 = Neg32 <int32> v9
v21 = Add32 <int32> v26 v19 (sft[int32])
v23 = Leq32 <bool> v16 v21
If v23 -> b4 b5 (likely)
b4: <- b3
v27 = Rsh32Ux32 <uint32> [false] v13 v21 (ret[uint32])
v28 = ZeroExt32to64 <int64> v27
v29 = MakeResult <int64,mem> v28 v1
Ret v29
b5: <- b3
v25 = StaticLECall <mem> {AuxCall{runtime.panicshift}} v1
Exit v25
at b5 it has a proof tree as follows:
extra
/ \
32 9
/ \\ // \
{empty} 8/16 {empty}
It fails to utilize the intermediary values.
I added have a small patch that enables the compiler to add more data to the prove DAG, its very specific ATM but could be more general: https://github.com/JAicewizard/go/tree/add_backwards_checks_ssa.
This adds checks in the SSA pass where if the first argument to a conditional is a 0 constant, and the second happens to be inverted from another variable that happened to already be compared to 0, it adds the knowlege that the inverted value it is <
/>
than 0 (and only for 32 bits, and when its the 3rd block :P). This could be added for more constants, and in more advanced transformations.
I dont know how to actually run benchmarks in the gc, I get a bunch of "cannot access internal package" errors.
Comment From: gopherbot
Change https://go.dev/cl/599096 mentions this issue: cmd/compile: rewrite the constant parts of the prove pass