Commit 2d8181e7 authored by Austin Clements's avatar Austin Clements

cmd/compile: clarify unsigned interpretation of AuxInt

The way Value.AuxInt represents unsigned numbers is currently
documented in genericOps.go, which is not the most obvious place for
it. Move that documentation to Value.AuxInt. Furthermore, to make it
harder to use incorrectly, introduce a Value.AuxUnsigned accessor that
returns the zero-extended value of Value.AuxInt.

Change-Id: I85030c3c68761404058a430e0b1c7464591b2f42
Reviewed-on: https://go-review.googlesource.com/102597
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent a29e25b8
...@@ -17,8 +17,6 @@ package main ...@@ -17,8 +17,6 @@ package main
// all args take signed inputs, or don't care whether their inputs // all args take signed inputs, or don't care whether their inputs
// are signed or unsigned. // are signed or unsigned.
// Unused portions of AuxInt are filled by sign-extending the used portion.
// Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful.
var genericOps = []opData{ var genericOps = []opData{
// 2-input arithmetic // 2-input arithmetic
// Types must be consistent with Go typing. Add, for example, must take two values // Types must be consistent with Go typing. Add, for example, must take two values
......
...@@ -234,7 +234,6 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) { ...@@ -234,7 +234,6 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
r = reverseBits[r] r = reverseBits[r]
} }
if v != nil && w.isGenericIntConst() { if v != nil && w.isGenericIntConst() {
c := w.AuxInt
// Note: all the +1/-1 below could overflow/underflow. Either will // Note: all the +1/-1 below could overflow/underflow. Either will
// still generate correct results, it will just lead to imprecision. // still generate correct results, it will just lead to imprecision.
// In fact if there is overflow/underflow, the corresponding // In fact if there is overflow/underflow, the corresponding
...@@ -247,6 +246,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) { ...@@ -247,6 +246,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
lim := noLimit lim := noLimit
switch d { switch d {
case signed: case signed:
c := w.AuxInt
switch r { switch r {
case lt: case lt:
lim.max = c - 1 lim.max = c - 1
...@@ -279,17 +279,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) { ...@@ -279,17 +279,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
lim.umax = uint64(lim.max) lim.umax = uint64(lim.max)
} }
case unsigned: case unsigned:
var uc uint64 uc := w.AuxUnsigned()
switch w.Op {
case OpConst64:
uc = uint64(c)
case OpConst32:
uc = uint64(uint32(c))
case OpConst16:
uc = uint64(uint16(c))
case OpConst8:
uc = uint64(uint8(c))
}
switch r { switch r {
case lt: case lt:
lim.umax = uc - 1 lim.umax = uc - 1
......
...@@ -31,6 +31,10 @@ type Value struct { ...@@ -31,6 +31,10 @@ type Value struct {
// Auxiliary info for this value. The type of this information depends on the opcode and type. // Auxiliary info for this value. The type of this information depends on the opcode and type.
// AuxInt is used for integer values, Aux is used for other values. // AuxInt is used for integer values, Aux is used for other values.
// Floats are stored in AuxInt using math.Float64bits(f). // Floats are stored in AuxInt using math.Float64bits(f).
// Unused portions of AuxInt are filled by sign-extending the used portion,
// even if the represented value is unsigned.
// Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful.
// Use Value.AuxUnsigned to get the zero-extended value of AuxInt.
AuxInt int64 AuxInt int64
Aux interface{} Aux interface{}
...@@ -86,6 +90,25 @@ func (v *Value) AuxInt32() int32 { ...@@ -86,6 +90,25 @@ func (v *Value) AuxInt32() int32 {
return int32(v.AuxInt) return int32(v.AuxInt)
} }
// AuxUnsigned returns v.AuxInt as an unsigned value for OpConst*.
// v.AuxInt is always sign-extended to 64 bits, even if the
// represented value is unsigned. This undoes that sign extension.
func (v *Value) AuxUnsigned() uint64 {
c := v.AuxInt
switch v.Op {
case OpConst64:
return uint64(c)
case OpConst32:
return uint64(uint32(c))
case OpConst16:
return uint64(uint16(c))
case OpConst8:
return uint64(uint8(c))
}
v.Fatalf("op %s isn't OpConst*", v.Op)
return 0
}
func (v *Value) AuxFloat() float64 { func (v *Value) AuxFloat() float64 {
if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 { if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 {
v.Fatalf("op %s doesn't have a float aux field", v.Op) v.Fatalf("op %s doesn't have a float aux field", v.Op)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment