aboutsummaryrefslogtreecommitdiff
path: root/go/ssa/interp/ops.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/ssa/interp/ops.go')
-rw-r--r--go/ssa/interp/ops.go32
1 files changed, 30 insertions, 2 deletions
diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go
index 6af7847c0..3bc6a4e32 100644
--- a/go/ssa/interp/ops.go
+++ b/go/ssa/interp/ops.go
@@ -137,6 +137,26 @@ func asUint64(x value) uint64 {
panic(fmt.Sprintf("cannot convert %T to uint64", x))
}
+// asUnsigned returns the value of x, which must be an integer type, as its equivalent unsigned type,
+// and returns true if x is non-negative.
+func asUnsigned(x value) (value, bool) {
+ switch x := x.(type) {
+ case int:
+ return uint(x), x >= 0
+ case int8:
+ return uint8(x), x >= 0
+ case int16:
+ return uint16(x), x >= 0
+ case int32:
+ return uint32(x), x >= 0
+ case int64:
+ return uint64(x), x >= 0
+ case uint, uint8, uint32, uint64, uintptr:
+ return x, true
+ }
+ panic(fmt.Sprintf("cannot convert %T to unsigned", x))
+}
+
// zero returns a new "zero" value of the specified type.
func zero(t types.Type) value {
switch t := t.(type) {
@@ -576,7 +596,11 @@ func binop(op token.Token, t types.Type, x, y value) value {
}
case token.SHL:
- y := asUint64(y)
+ u, ok := asUnsigned(y)
+ if !ok {
+ panic("negative shift amount")
+ }
+ y := asUint64(u)
switch x.(type) {
case int:
return x.(int) << y
@@ -603,7 +627,11 @@ func binop(op token.Token, t types.Type, x, y value) value {
}
case token.SHR:
- y := asUint64(y)
+ u, ok := asUnsigned(y)
+ if !ok {
+ panic("negative shift amount")
+ }
+ y := asUint64(u)
switch x.(type) {
case int:
return x.(int) >> y