From 88469928233b20045117dd41c08caf75a82d589d Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Mon, 8 Jul 2013 17:33:51 -0400 Subject: [PATCH] go.tools/ssa: avoid redundant uint64 conversion of right operand of <<, >>. Also: add sanity check that no Instruction yields a Value of 'untyped' type. R=golang-dev, gri CC=golang-dev https://golang.org/cl/11011043 --- ssa/emit.go | 1 - ssa/interp/ops.go | 24 ++---------------------- ssa/interp/testdata/coverage.go | 10 ++++++++++ ssa/sanity.go | 14 +++++++++++++- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/ssa/emit.go b/ssa/emit.go index 142c2d2a69..b6ba298ad4 100644 --- a/ssa/emit.go +++ b/ssa/emit.go @@ -38,7 +38,6 @@ 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 = 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 6a6cf84e40..2afce9aea9 100644 --- a/ssa/interp/ops.go +++ b/ssa/interp/ops.go @@ -130,26 +130,6 @@ 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) { @@ -563,7 +543,7 @@ func binop(op token.Token, x, y value) value { } case token.SHL: - y := asUint64(y) + y := uint64(asInt(y)) switch x.(type) { case int: return x.(int) << y @@ -590,7 +570,7 @@ func binop(op token.Token, x, y value) value { } case token.SHR: - y := asUint64(y) + y := uint64(asInt(y)) switch x.(type) { case int: return x.(int) >> y diff --git a/ssa/interp/testdata/coverage.go b/ssa/interp/testdata/coverage.go index 0338383f78..d7d6940dd4 100644 --- a/ssa/interp/testdata/coverage.go +++ b/ssa/interp/testdata/coverage.go @@ -270,6 +270,16 @@ func main() { } } +type mybool bool + +func (mybool) f() {} + +func init() { + var x, y int + var b mybool = x == y // x==y is an untyped bool + b.f() +} + // Simple closures. func init() { b := 3 diff --git a/ssa/sanity.go b/ssa/sanity.go index 3b2b029951..2feed7aab0 100644 --- a/ssa/sanity.go +++ b/ssa/sanity.go @@ -160,11 +160,23 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { panic(fmt.Sprintf("Unknown instruction type: %T", instr)) } + // Check that value-defining instructions have valid types. if v, ok := instr.(Value); ok { - if v.Type() == nil { + t := v.Type() + if t == nil { s.errorf("no type: %s = %s", v.Name(), v) + } else if t == tRangeIter { + // not a proper type; ignore. + } else if b, ok := t.Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 { + s.errorf("instruction has 'untyped' result: %s = %s : %s", v.Name(), v, t) } } + + // TODO(adonovan): sanity-check Literals used as instruction Operands(), + // e.g. reject Literals with "untyped" types. + // + // All other non-Instruction Values can be found via their + // enclosing Function or Package. } func (s *sanity) checkFinalInstr(idx int, instr Instruction) {