diff --git a/ssa/emit.go b/ssa/emit.go index b6ba298a..a0e908bb 100644 --- a/ssa/emit.go +++ b/ssa/emit.go @@ -38,6 +38,11 @@ func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token. switch op { case token.SHL, token.SHR: x = emitConv(f, x, t) + // y may be signed or an 'untyped' constant. + // TODO(adonovan): whence signed values? + if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUnsigned == 0 { + y = emitConv(f, y, types.Typ[types.Uint64]) + } case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT: x = emitConv(f, x, t) diff --git a/ssa/interp/ops.go b/ssa/interp/ops.go index 2afce9ae..0e86cabf 100644 --- a/ssa/interp/ops.go +++ b/ssa/interp/ops.go @@ -30,6 +30,7 @@ func literalValue(l *ssa.Literal) value { // By destination type: switch t := l.Type().Underlying().(type) { case *types.Basic: + // TODO(adonovan): eliminate untyped literals from SSA form. switch t.Kind() { case types.Bool, types.UntypedBool: return exact.BoolVal(l.Value) @@ -130,6 +131,26 @@ func asInt(x value) int { panic(fmt.Sprintf("cannot convert %T to int", x)) } +// asUint64 converts x, which must be an unsigned integer, to a uint64 +// suitable for use as a bitwise shift count. +func asUint64(x value) uint64 { + switch x := x.(type) { + case uint: + return uint64(x) + case uint8: + return uint64(x) + case uint16: + return uint64(x) + case uint32: + return uint64(x) + case uint64: + return x + case uintptr: + return uint64(x) + } + panic(fmt.Sprintf("cannot convert %T to uint64", x)) +} + // zero returns a new "zero" value of the specified type. func zero(t types.Type) value { switch t := t.(type) { @@ -543,7 +564,7 @@ func binop(op token.Token, x, y value) value { } case token.SHL: - y := uint64(asInt(y)) + y := asUint64(y) switch x.(type) { case int: return x.(int) << y @@ -570,7 +591,7 @@ func binop(op token.Token, x, y value) value { } case token.SHR: - y := uint64(asInt(y)) + y := asUint64(y) switch x.(type) { case int: return x.(int) >> y