go.tools/ssa: s/Literal/Const/g, s/Constant/NamedConst/g

(Motivation: "Literal" is a syntactic property, not a semantic one.)

Also: delete a "TODO: opt" that the lifting pass already does for us.

R=gri
CC=golang-dev
https://golang.org/cl/11351043
This commit is contained in:
Alan Donovan 2013-07-16 13:50:08 -04:00
parent 80ec883f7b
commit 732dbe9ff8
15 changed files with 277 additions and 279 deletions

View File

@ -55,10 +55,10 @@ var (
tEface = new(types.Interface)
// SSA Value constants.
vZero = intLiteral(0)
vOne = intLiteral(1)
vTrue = NewLiteral(exact.MakeBool(true), tBool)
vFalse = NewLiteral(exact.MakeBool(false), tBool)
vZero = intConst(0)
vOne = intConst(1)
vTrue = NewConst(exact.MakeBool(true), tBool)
vFalse = NewConst(exact.MakeBool(false), tBool)
)
// builder holds state associated with the package currently being built.
@ -126,7 +126,7 @@ func (b *builder) cond(fn *Function, e ast.Expr, t, f *BasicBlock) {
}
switch cond := b.expr(fn, e).(type) {
case *Literal:
case *Const:
// Dispatch constant conditions statically.
if exact.BoolVal(cond.Value) {
emitJump(fn, t)
@ -313,7 +313,7 @@ func (b *builder) builtin(fn *Function, name string, args []ast.Expr, typ types.
t := deref(fn.Pkg.typeOf(args[0])).Underlying()
if at, ok := t.(*types.Array); ok {
b.expr(fn, args[0]) // for effects only
return intLiteral(at.Len())
return intConst(at.Len())
}
// Otherwise treat as normal.
@ -547,11 +547,11 @@ func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) {
//
func (b *builder) expr(fn *Function, e ast.Expr) Value {
if v := fn.Pkg.info.ValueOf(e); v != nil {
lit := NewLiteral(v, fn.Pkg.typeOf(e))
c := NewConst(v, fn.Pkg.typeOf(e))
if id, ok := unparen(e).(*ast.Ident); ok {
emitDebugRef(fn, id, lit)
emitDebugRef(fn, id, c)
}
return lit
return c
}
switch e := e.(type) {
@ -933,7 +933,7 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx
st := sig.Params().At(np).Type().(*types.Slice)
vt := st.Elem()
if len(varargs) == 0 {
args = append(args, nilLiteral(st))
args = append(args, nilConst(st))
} else {
// Replace a suffix of args with a slice containing it.
at := types.NewArray(vt, int64(len(varargs)))
@ -942,7 +942,7 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx
for i, arg := range varargs {
iaddr := &IndexAddr{
X: a,
Index: intLiteral(int64(i)),
Index: intConst(int64(i)),
}
iaddr.setType(types.NewPointer(vt))
fn.emit(iaddr)
@ -1120,8 +1120,6 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
for _, id := range spec.Names {
if !isBlankIdent(id) {
lhs := fn.addLocalForIdent(id)
// TODO(adonovan): opt: use zero literal in
// lieu of load, if type permits.
if fn.debugInfo() {
emitDebugRef(fn, id, emitLoad(fn, lhs))
}
@ -1201,7 +1199,7 @@ func (b *builder) arrayLen(fn *Function, elts []ast.Expr) int64 {
var i int64 = -1
for _, e := range elts {
if kv, ok := e.(*ast.KeyValueExpr); ok {
i = b.expr(fn, kv.Key).(*Literal).Int64()
i = b.expr(fn, kv.Key).(*Const).Int64()
} else {
i++
}
@ -1258,17 +1256,17 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ
array = addr
}
var idx *Literal
var idx *Const
for _, e := range e.Elts {
if kv, ok := e.(*ast.KeyValueExpr); ok {
idx = b.expr(fn, kv.Key).(*Literal)
idx = b.expr(fn, kv.Key).(*Const)
e = kv.Value
} else {
var idxval int64
if idx != nil {
idxval = idx.Int64() + 1
}
idx = intLiteral(idxval)
idx = intConst(idxval)
}
iaddr := &IndexAddr{
X: array,
@ -1286,7 +1284,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ
}
case *types.Map:
m := &MakeMap{Reserve: intLiteral(int64(len(e.Elts)))}
m := &MakeMap{Reserve: intConst(int64(len(e.Elts)))}
m.setPos(e.Lbrace)
m.setType(typ)
emitStore(fn, addr, fn.emit(m))
@ -1474,7 +1472,7 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
casetype = fn.Pkg.typeOf(cond)
var condv Value
if casetype == tUntypedNil {
condv = emitCompare(fn, token.EQL, x, nilLiteral(x.Type()), token.NoPos)
condv = emitCompare(fn, token.EQL, x, nilConst(x.Type()), token.NoPos)
} else {
yok := emitTypeTest(fn, x, casetype, token.NoPos)
ti = emitExtract(fn, yok, 0, casetype)
@ -1616,7 +1614,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
}
body := fn.newBasicBlock("select.body")
next := fn.newBasicBlock("select.next")
emitIf(fn, emitCompare(fn, token.EQL, idx, intLiteral(int64(state)), token.NoPos), body, next)
emitIf(fn, emitCompare(fn, token.EQL, idx, intConst(int64(state)), token.NoPos), body, next)
fn.currentBlock = body
fn.targets = &targets{
tail: fn.targets,
@ -1741,7 +1739,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
// data dependence upon x, permitting later dead-code
// elimination if x is pure, static unrolling, etc.
// Ranging over a nil *array may have >0 iterations.
length = intLiteral(arr.Len())
length = intConst(arr.Len())
} else {
// length = len(x).
var c Call
@ -1752,7 +1750,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
}
index := fn.addLocal(tInt, token.NoPos)
emitStore(fn, index, intLiteral(-1))
emitStore(fn, index, intConst(-1))
loop = fn.newBasicBlock("rangeindex.loop")
emitJump(fn, loop)

145
ssa/const.go Normal file
View File

@ -0,0 +1,145 @@
package ssa
// This file defines the Const SSA value type.
import (
"fmt"
"go/token"
"strconv"
"code.google.com/p/go.tools/go/exact"
"code.google.com/p/go.tools/go/types"
)
// NewConst returns a new constant of the specified value and type.
// val must be valid according to the specification of Const.Value.
//
func NewConst(val exact.Value, typ types.Type) *Const {
return &Const{typ, val}
}
// intConst returns an untyped integer constant that evaluates to i.
func intConst(i int64) *Const {
return NewConst(exact.MakeInt64(i), types.Typ[types.UntypedInt])
}
// nilConst returns a nil constant of the specified type, which may
// be any reference type, including interfaces.
//
func nilConst(typ types.Type) *Const {
return NewConst(exact.MakeNil(), typ)
}
// zeroConst returns a new "zero" constant of the specified type,
// which must not be an array or struct type: the zero values of
// aggregates are well-defined but cannot be represented by Const.
//
func zeroConst(t types.Type) *Const {
switch t := t.(type) {
case *types.Basic:
switch {
case t.Info()&types.IsBoolean != 0:
return NewConst(exact.MakeBool(false), t)
case t.Info()&types.IsNumeric != 0:
return NewConst(exact.MakeInt64(0), t)
case t.Info()&types.IsString != 0:
return NewConst(exact.MakeString(""), t)
case t.Kind() == types.UnsafePointer:
fallthrough
case t.Kind() == types.UntypedNil:
return nilConst(t)
default:
panic(fmt.Sprint("zeroConst for unexpected type:", t))
}
case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
return nilConst(t)
case *types.Named:
return NewConst(zeroConst(t.Underlying()).Value, t)
case *types.Array, *types.Struct, *types.Tuple:
panic(fmt.Sprint("zeroConst applied to aggregate:", t))
}
panic(fmt.Sprint("zeroConst: unexpected ", t))
}
func (c *Const) Name() string {
var s string
if c.Value.Kind() == exact.String {
s = exact.StringVal(c.Value)
const max = 20
if len(s) > max {
s = s[:max-3] + "..." // abbreviate
}
s = strconv.Quote(s)
} else {
s = c.Value.String()
}
return s + ":" + c.typ.String()
}
func (c *Const) Type() types.Type {
return c.typ
}
func (c *Const) Referrers() *[]Instruction {
return nil
}
func (c *Const) Pos() token.Pos {
return token.NoPos
}
// IsNil returns true if this constant represents a typed or untyped nil value.
func (c *Const) IsNil() bool {
return c.Value.Kind() == exact.Nil
}
// Int64 returns the numeric value of this constant truncated to fit
// a signed 64-bit integer.
//
func (c *Const) Int64() int64 {
switch x := c.Value; x.Kind() {
case exact.Int:
if i, ok := exact.Int64Val(x); ok {
return i
}
return 0
case exact.Float:
f, _ := exact.Float64Val(x)
return int64(f)
}
panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
}
// Uint64 returns the numeric value of this constant truncated to fit
// an unsigned 64-bit integer.
//
func (c *Const) Uint64() uint64 {
switch x := c.Value; x.Kind() {
case exact.Int:
if u, ok := exact.Uint64Val(x); ok {
return u
}
return 0
case exact.Float:
f, _ := exact.Float64Val(x)
return uint64(f)
}
panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
}
// Float64 returns the numeric value of this constant truncated to fit
// a float64.
//
func (c *Const) Float64() float64 {
f, _ := exact.Float64Val(c.Value)
return f
}
// Complex128 returns the complex value of this constant truncated to
// fit a complex128.
//
func (c *Const) Complex128() complex128 {
re, _ := exact.Float64Val(exact.Real(c.Value))
im, _ := exact.Float64Val(exact.Imag(c.Value))
return complex(re, im)
}

View File

@ -89,9 +89,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
pkg.Members[name] = &Type{object: obj}
case *types.Const:
c := &Constant{
c := &NamedConst{
object: obj,
Value: NewLiteral(obj.Val(), obj.Type()),
Value: NewConst(obj.Val(), obj.Type()),
}
pkg.values[obj] = c.Value
pkg.Members[name] = c

View File

@ -57,7 +57,7 @@
// *Capture ✔
// *ChangeInterface ✔ ✔
// *ChangeType ✔ ✔
// *Constant (const)
// *Const
// *Convert ✔ ✔
// *Defer ✔
// *Extract ✔ ✔
@ -70,7 +70,6 @@
// *Index ✔ ✔
// *IndexAddr ✔ ✔
// *Jump ✔
// *Literal ✔
// *Lookup ✔ ✔
// *MakeChan ✔ ✔
// *MakeClosure ✔ ✔
@ -78,6 +77,7 @@
// *MakeMap ✔ ✔
// *MakeSlice ✔ ✔
// *MapUpdate ✔
// *NamedConst ✔ (const)
// *Next ✔ ✔
// *Panic ✔
// *Parameter ✔

View File

@ -110,9 +110,9 @@ func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
y = emitConv(f, y, x.Type())
} else if _, ok := yt.(*types.Interface); ok {
x = emitConv(f, x, y.Type())
} else if _, ok := x.(*Literal); ok {
} else if _, ok := x.(*Const); ok {
x = emitConv(f, x, y.Type())
} else if _, ok := y.(*Literal); ok {
} else if _, ok := y.(*Const); ok {
y = emitConv(f, y, x.Type())
} else {
// other cases, e.g. channels. No-op.
@ -188,9 +188,9 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
return emitTypeAssert(f, val, typ, token.NoPos)
}
// Untyped nil literal? Return interface-typed nil literal.
// Untyped nil constant? Return interface-typed nil constant.
if ut_src == tUntypedNil {
return nilLiteral(typ)
return nilConst(typ)
}
// Convert (non-nil) "untyped" literals to their default type.
@ -203,13 +203,13 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
return f.emit(mi)
}
// Conversion of a literal to a non-interface type results in
// a new literal of the destination type and (initially) the
// Conversion of a constant to a non-interface type results in
// a new constant of the destination type and (initially) the
// same abstract value. We don't compute the representation
// change yet; this defers the point at which the number of
// possible representations explodes.
if l, ok := val.(*Literal); ok {
return NewLiteral(l.Value, typ)
if c, ok := val.(*Const); ok {
return NewConst(c.Value, typ)
}
// A representation-changing conversion.

View File

@ -110,8 +110,8 @@ func (fr *frame) get(key ssa.Value) value {
return nil
case *ssa.Function, *ssa.Builtin:
return key
case *ssa.Literal:
return literalValue(key)
case *ssa.Const:
return constValue(key)
case *ssa.Global:
if r, ok := fr.i.globals[key]; ok {
return r

View File

@ -20,60 +20,60 @@ type targetPanic struct {
// If the target program calls exit, the interpreter panics with this type.
type exitPanic int
// literalValue returns the value of the literal with the
// dynamic type tag appropriate for l.Type().
func literalValue(l *ssa.Literal) value {
if l.IsNil() {
return zero(l.Type()) // typed nil
// constValue returns the value of the constant with the
// dynamic type tag appropriate for c.Type().
func constValue(c *ssa.Const) value {
if c.IsNil() {
return zero(c.Type()) // typed nil
}
// By destination type:
switch t := l.Type().Underlying().(type) {
switch t := c.Type().Underlying().(type) {
case *types.Basic:
// TODO(adonovan): eliminate untyped literals from SSA form.
// TODO(adonovan): eliminate untyped constants from SSA form.
switch t.Kind() {
case types.Bool, types.UntypedBool:
return exact.BoolVal(l.Value)
return exact.BoolVal(c.Value)
case types.Int, types.UntypedInt:
// Assume sizeof(int) is same on host and target.
return int(l.Int64())
return int(c.Int64())
case types.Int8:
return int8(l.Int64())
return int8(c.Int64())
case types.Int16:
return int16(l.Int64())
return int16(c.Int64())
case types.Int32, types.UntypedRune:
return int32(l.Int64())
return int32(c.Int64())
case types.Int64:
return l.Int64()
return c.Int64()
case types.Uint:
// Assume sizeof(uint) is same on host and target.
return uint(l.Uint64())
return uint(c.Uint64())
case types.Uint8:
return uint8(l.Uint64())
return uint8(c.Uint64())
case types.Uint16:
return uint16(l.Uint64())
return uint16(c.Uint64())
case types.Uint32:
return uint32(l.Uint64())
return uint32(c.Uint64())
case types.Uint64:
return l.Uint64()
return c.Uint64()
case types.Uintptr:
// Assume sizeof(uintptr) is same on host and target.
return uintptr(l.Uint64())
return uintptr(c.Uint64())
case types.Float32:
return float32(l.Float64())
return float32(c.Float64())
case types.Float64, types.UntypedFloat:
return l.Float64()
return c.Float64()
case types.Complex64:
return complex64(l.Complex128())
return complex64(c.Complex128())
case types.Complex128, types.UntypedComplex:
return l.Complex128()
return c.Complex128()
case types.String, types.UntypedString:
if l.Value.Kind() == exact.String {
return exact.StringVal(l.Value)
if c.Value.Kind() == exact.String {
return exact.StringVal(c.Value)
}
return string(rune(l.Int64()))
return string(rune(c.Int64()))
case types.UnsafePointer:
panic("unsafe.Pointer literal") // not possible
panic("unsafe.Pointer constant") // not possible
case types.UntypedNil:
// nil was handled above.
}
@ -84,13 +84,13 @@ func literalValue(l *ssa.Literal) value {
switch et.Kind() {
case types.Byte: // string -> []byte
var v []value
for _, b := range []byte(exact.StringVal(l.Value)) {
for _, b := range []byte(exact.StringVal(c.Value)) {
v = append(v, b)
}
return v
case types.Rune: // string -> []rune
var v []value
for _, r := range []rune(exact.StringVal(l.Value)) {
for _, r := range []rune(exact.StringVal(c.Value)) {
v = append(v, r)
}
return v
@ -98,7 +98,7 @@ func literalValue(l *ssa.Literal) value {
}
}
panic(fmt.Sprintf("literalValue: Value.(type)=%T Type()=%s", l.Value, l.Type()))
panic(fmt.Sprintf("constValue: Value.(type)=%T Type()=%s", c.Value, c.Type()))
}
// asInt converts x, which must be an integer, to an int suitable for
@ -161,7 +161,7 @@ func zero(t types.Type) value {
if t.Info()&types.IsUntyped != 0 {
// TODO(adonovan): make it an invariant that
// this is unreachable. Currently some
// literals have 'untyped' types when they
// constants have 'untyped' types when they
// should be defaulted by the typechecker.
t = ssa.DefaultType(t).(*types.Basic)
}

View File

@ -115,7 +115,7 @@ func lift(fn *Function) {
// buildDomTree. For example:
//
// - Alloc never loaded? Eliminate.
// - Alloc never stored? Replace all loads with a zero literal.
// - Alloc never stored? Replace all loads with a zero constant.
// - Alloc stored once? Replace loads with dominating store;
// don't forget that an Alloc is itself an effective store
// of zero.
@ -187,8 +187,8 @@ func lift(fn *Function) {
// renaming maps an alloc (keyed by index) to its replacement
// value. Initially the renaming contains nil, signifying the
// zero literal of the appropriate type; we construct the
// Literal lazily at most once on each path through the domtree.
// zero constant of the appropriate type; we construct the
// Const lazily at most once on each path through the domtree.
// TODO(adonovan): opt: cache per-function not per subtree.
renaming := make([]Value, numAllocs)
@ -304,8 +304,8 @@ type newPhiMap map[*BasicBlock][]newPhi
//
func liftAlloc(df domFrontier, alloc *Alloc, newPhis newPhiMap) bool {
// Don't lift aggregates into registers, because we don't have
// a way to express their zero-literals.
// TODO(adonovan): define zero-literals for aggregates, or
// a way to express their zero-constants.
// TODO(adonovan): define zero-constants for aggregates, or
// add a separate SRA pass. Lifting aggregates is an
// important optimisation for pointer analysis because the
// extra indirection really hurts precision under Das's
@ -426,7 +426,7 @@ func replaceAll(x, y Value) {
func renamed(renaming []Value, alloc *Alloc) Value {
v := renaming[alloc.index]
if v == nil {
v = zeroLiteral(deref(alloc.Type()))
v = zeroConst(deref(alloc.Type()))
renaming[alloc.index] = v
}
return v

View File

@ -1,145 +0,0 @@
package ssa
// This file defines the Literal SSA value type.
import (
"fmt"
"go/token"
"strconv"
"code.google.com/p/go.tools/go/exact"
"code.google.com/p/go.tools/go/types"
)
// NewLiteral returns a new literal of the specified value and type.
// val must be valid according to the specification of Literal.Value.
//
func NewLiteral(val exact.Value, typ types.Type) *Literal {
return &Literal{typ, val}
}
// intLiteral returns an untyped integer literal that evaluates to i.
func intLiteral(i int64) *Literal {
return NewLiteral(exact.MakeInt64(i), types.Typ[types.UntypedInt])
}
// nilLiteral returns a nil literal of the specified type, which may
// be any reference type, including interfaces.
//
func nilLiteral(typ types.Type) *Literal {
return NewLiteral(exact.MakeNil(), typ)
}
// zeroLiteral returns a new "zero" literal of the specified type,
// which must not be an array or struct type: the zero values of
// aggregates are well-defined but cannot be represented by Literal.
//
func zeroLiteral(t types.Type) *Literal {
switch t := t.(type) {
case *types.Basic:
switch {
case t.Info()&types.IsBoolean != 0:
return NewLiteral(exact.MakeBool(false), t)
case t.Info()&types.IsNumeric != 0:
return NewLiteral(exact.MakeInt64(0), t)
case t.Info()&types.IsString != 0:
return NewLiteral(exact.MakeString(""), t)
case t.Kind() == types.UnsafePointer:
fallthrough
case t.Kind() == types.UntypedNil:
return nilLiteral(t)
default:
panic(fmt.Sprint("zeroLiteral for unexpected type:", t))
}
case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
return nilLiteral(t)
case *types.Named:
return NewLiteral(zeroLiteral(t.Underlying()).Value, t)
case *types.Array, *types.Struct:
panic(fmt.Sprint("zeroLiteral applied to aggregate:", t))
}
panic(fmt.Sprint("zeroLiteral: unexpected ", t))
}
func (l *Literal) Name() string {
var s string
if l.Value.Kind() == exact.String {
s = exact.StringVal(l.Value)
const maxLit = 20
if len(s) > maxLit {
s = s[:maxLit-3] + "..." // abbreviate
}
s = strconv.Quote(s)
} else {
s = l.Value.String()
}
return s + ":" + l.typ.String()
}
func (l *Literal) Type() types.Type {
return l.typ
}
func (l *Literal) Referrers() *[]Instruction {
return nil
}
func (l *Literal) Pos() token.Pos {
return token.NoPos
}
// IsNil returns true if this literal represents a typed or untyped nil value.
func (l *Literal) IsNil() bool {
return l.Value.Kind() == exact.Nil
}
// Int64 returns the numeric value of this literal truncated to fit
// a signed 64-bit integer.
//
func (l *Literal) Int64() int64 {
switch x := l.Value; x.Kind() {
case exact.Int:
if i, ok := exact.Int64Val(x); ok {
return i
}
return 0
case exact.Float:
f, _ := exact.Float64Val(x)
return int64(f)
}
panic(fmt.Sprintf("unexpected literal value: %T", l.Value))
}
// Uint64 returns the numeric value of this literal truncated to fit
// an unsigned 64-bit integer.
//
func (l *Literal) Uint64() uint64 {
switch x := l.Value; x.Kind() {
case exact.Int:
if u, ok := exact.Uint64Val(x); ok {
return u
}
return 0
case exact.Float:
f, _ := exact.Float64Val(x)
return uint64(f)
}
panic(fmt.Sprintf("unexpected literal value: %T", l.Value))
}
// Float64 returns the numeric value of this literal truncated to fit
// a float64.
//
func (l *Literal) Float64() float64 {
f, _ := exact.Float64Val(l.Value)
return f
}
// Complex128 returns the complex value of this literal truncated to
// fit a complex128.
//
func (l *Literal) Complex128() complex128 {
re, _ := exact.Float64Val(exact.Real(l.Value))
im, _ := exact.Float64Val(exact.Imag(l.Value))
return complex(re, im)
}

View File

@ -47,7 +47,7 @@ func relName(v Value, i Instruction) string {
// This method is provided only for debugging.
// It never appears in disassembly, which uses Value.Name().
func (v *Literal) String() string {
func (v *Const) String() string {
return v.Name()
}
@ -379,7 +379,7 @@ func (p *Package) DumpTo(w io.Writer) {
sort.Strings(names)
for _, name := range names {
switch mem := p.Members[name].(type) {
case *Constant:
case *NamedConst:
fmt.Fprintf(w, " const %-*s %s = %s\n", maxname, name, mem.Name(), mem.Value.Name())
case *Function:

View File

@ -173,8 +173,8 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
}
}
// TODO(adonovan): sanity-check Literals used as instruction Operands(),
// e.g. reject Literals with "untyped" types.
// TODO(adonovan): sanity-check Consts used as instruction Operands(),
// e.g. reject Consts with "untyped" types.
//
// All other non-Instruction Values can be found via their
// enclosing Function or Package.

View File

@ -201,7 +201,7 @@ func (prog *Program) Package(obj *types.Package) *Package {
// packageLevelValue returns the package-level value corresponding to
// the specified named object, which may be a package-level const
// (*Literal), var (*Global) or func (*Function) of some package in
// (*Const), var (*Global) or func (*Function) of some package in
// prog. It returns nil if the object is not found.
//
func (prog *Program) packageLevelValue(obj types.Object) Value {
@ -233,21 +233,21 @@ func (prog *Program) FuncValue(obj *types.Func) Value {
}
// ConstValue returns the SSA Value denoted by the source-level named
// constant obj. The result may be a *Literal, or nil if not found.
// constant obj. The result may be a *Const, or nil if not found.
//
func (prog *Program) ConstValue(obj *types.Const) *Literal {
func (prog *Program) ConstValue(obj *types.Const) *Const {
// TODO(adonovan): opt: share (don't reallocate)
// Literals for const objects.
// Consts for const objects.
// Universal constant? {true,false,nil}
if obj.Parent() == types.Universe {
return NewLiteral(obj.Val(), obj.Type())
return NewConst(obj.Val(), obj.Type())
}
// Package-level named constant?
if v := prog.packageLevelValue(obj); v != nil {
return v.(*Literal)
return v.(*Const)
}
return NewLiteral(obj.Val(), obj.Type())
return NewConst(obj.Val(), obj.Type())
}
// VarValue returns the SSA Value that corresponds to a specific

View File

@ -25,7 +25,7 @@ func TestObjValueLookup(t *testing.T) {
}
// Maps each var Ident (represented "name:linenum") to the
// kind of ssa.Value we expect (represented "Literal", "&Alloc").
// kind of ssa.Value we expect (represented "Constant", "&Alloc").
expectations := make(map[string]string)
// Find all annotations of form x::BinOp, &y::Alloc, etc.
@ -127,20 +127,20 @@ func checkFuncValue(t *testing.T, prog *ssa.Program, obj *types.Func) {
}
func checkConstValue(t *testing.T, prog *ssa.Program, obj *types.Const) {
lit := prog.ConstValue(obj)
// fmt.Printf("ConstValue(%s) = %s\n", obj, lit) // debugging
if lit == nil {
c := prog.ConstValue(obj)
// fmt.Printf("ConstValue(%s) = %s\n", obj, c) // debugging
if c == nil {
t.Errorf("ConstValue(%s) == nil", obj)
return
}
if !types.IsIdentical(lit.Type(), obj.Type()) {
t.Errorf("ConstValue(%s).Type() == %s", obj, lit.Type())
if !types.IsIdentical(c.Type(), obj.Type()) {
t.Errorf("ConstValue(%s).Type() == %s", obj, c.Type())
return
}
if obj.Name() != "nil" {
if !exact.Compare(lit.Value, token.EQL, obj.Val()) {
if !exact.Compare(c.Value, token.EQL, obj.Val()) {
t.Errorf("ConstValue(%s).Value (%s) != %s",
obj, lit.Value, obj.Val())
obj, c.Value, obj.Val())
return
}
}

View File

@ -50,7 +50,7 @@ type Package struct {
info *importer.PackageInfo // package ASTs and type information
}
// A Member is a member of a Go package, implemented by *Constant,
// A Member is a member of a Go package, implemented by *NamedConst,
// *Global, *Function, or *Type; they are created by package-level
// const, var, func and type declarations respectively.
//
@ -100,18 +100,18 @@ type Type struct {
object *types.TypeName
}
// A Constant is a Member of Package representing a package-level
// constant value.
// A NamedConst is a Member of Package representing a package-level
// named constant value.
//
// Pos() returns the position of the declaring ast.ValueSpec.Names[*]
// identifier.
//
// NB: a Constant is not a Value; it contains a literal Value, which
// NB: a NamedConst is not a Value; it contains a constant Value, which
// it augments with the name and position of its 'const' declaration.
//
type Constant struct {
type NamedConst struct {
object *types.Const
Value *Literal
Value *Const
pos token.Pos
}
@ -123,7 +123,7 @@ type Value interface {
//
// This is the same as the source name for Parameters,
// Builtins, Functions, Captures, Globals and some Allocs.
// For literals, it is a representation of the literal's value
// For constants, it is a representation of the constant's value
// and type. For all other Values this is the name of the
// virtual register defined by the instruction.
//
@ -151,7 +151,7 @@ type Value interface {
//
// Referrers is currently only defined for the function-local
// values Capture, Parameter and all value-defining instructions.
// It returns nil for Function, Builtin, Literal and Global.
// It returns nil for Function, Builtin, Const and Global.
//
// Instruction.Operands contains the inverse of this relation.
Referrers() *[]Instruction
@ -358,22 +358,22 @@ type Parameter struct {
referrers []Instruction
}
// A Literal represents the value of a constant expression.
// A Const represents the value of a constant expression.
//
// It may have a nil, boolean, string or numeric (integer, fraction or
// complex) value, or a []byte or []rune conversion of a string
// literal.
// constant.
//
// Literals may be of named types. A literal's underlying type can be
// Consts may be of named types. A constant's underlying type can be
// a basic type, possibly one of the "untyped" types, or a slice type
// whose elements' underlying type is byte or rune. A nil literal can
// whose elements' underlying type is byte or rune. A nil constant can
// have any reference type: interface, map, channel, pointer, slice,
// or function---but not "untyped nil".
//
// All source-level constant expressions are represented by a Literal
// All source-level constant expressions are represented by a Const
// of equal type and value.
//
// Value holds the exact value of the literal, independent of its
// Value holds the exact value of the constant, independent of its
// Type(), using the same representation as package go/exact uses for
// constants.
//
@ -384,7 +384,7 @@ type Parameter struct {
// "hello":untyped string
// 3+4i:MyComplex
//
type Literal struct {
type Const struct {
typ types.Type
Value exact.Value
}
@ -619,7 +619,7 @@ type ChangeInterface struct {
// Use Program.MethodSet(X.Type()) to find the method-set of X.
//
// To construct the zero value of an interface type T, use:
// NewLiteral(exact.MakeNil(), T, pos)
// NewConst(exact.MakeNil(), T, pos)
//
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
// from an explicit conversion in the source.
@ -1384,14 +1384,14 @@ func (t *Type) String() string {
return fmt.Sprintf("%s.%s", t.object.Pkg().Path(), t.object.Name())
}
func (c *Constant) Name() string { return c.object.Name() }
func (c *Constant) Pos() token.Pos { return c.object.Pos() }
func (c *Constant) String() string {
func (c *NamedConst) Name() string { return c.object.Name() }
func (c *NamedConst) Pos() token.Pos { return c.object.Pos() }
func (c *NamedConst) String() string {
return fmt.Sprintf("%s.%s", c.object.Pkg().Path(), c.object.Name())
}
func (c *Constant) Type() types.Type { return c.object.Type() }
func (c *Constant) Token() token.Token { return token.CONST }
func (c *Constant) Object() types.Object { return c.object }
func (c *NamedConst) Type() types.Type { return c.object.Type() }
func (c *NamedConst) Token() token.Token { return token.CONST }
func (c *NamedConst) Object() types.Object { return c.object }
// Func returns the package-level function of the specified name,
// or nil if not found.
@ -1412,8 +1412,8 @@ func (p *Package) Var(name string) (g *Global) {
// Const returns the package-level constant of the specified name,
// or nil if not found.
//
func (p *Package) Const(name string) (c *Constant) {
c, _ = p.Members[name].(*Constant)
func (p *Package) Const(name string) (c *NamedConst) {
c, _ = p.Members[name].(*NamedConst)
return
}

View File

@ -35,28 +35,28 @@ type S struct {
}
func main() {
var v0 int = 1 // v0::Literal (simple local value spec)
if v0 > 0 { // v0::Literal
v0 = 2 // v0::Literal
var v0 int = 1 // v0::Const (simple local value spec)
if v0 > 0 { // v0::Const
v0 = 2 // v0::Const
}
print(v0) // v0::Phi
// v1 is captured and thus implicitly address-taken.
var v1 int = 1 // v1::Literal
v1 = 2 // v1::Literal
var v1 int = 1 // v1::Const
v1 = 2 // v1::Const
fmt.Println(v1) // v1::UnOp (load)
f := func(param int) { // f::MakeClosure param::Parameter
if y := 1; y > 0 { // y::Literal
if y := 1; y > 0 { // y::Const
print(v1, param) // v1::UnOp (load) param::Parameter
}
param = 2 // param::Literal
println(param) // param::Literal
param = 2 // param::Const
println(param) // param::Const
}
f(0) // f::MakeClosure
var v2 int // v2::Literal (implicitly zero-initialized local value spec)
print(v2) // v2::Literal
var v2 int // v2::Const (implicitly zero-initialized local value spec)
print(v2) // v2::Const
m := make(map[string]int) // m::MakeMap
@ -68,9 +68,9 @@ func main() {
v3++ // v3::BinOp (assign with op)
v3 += 2 // v3::BinOp (assign with op)
v5, v6 := false, "" // v5::Literal v6::Literal (defining assignment)
print(v5) // v5::Literal
print(v6) // v6::Literal
v5, v6 := false, "" // v5::Const v6::Const (defining assignment)
print(v5) // v5::Const
print(v6) // v6::Const
var v7 S // v7::UnOp (load from Alloc)
v7.x = 1 // &v7::Alloc
@ -88,8 +88,8 @@ func main() {
v10 := &v9 // v10::Alloc &v9::Alloc
var v11 *J = nil // v11::Literal
v11.method() // v11::Literal
var v11 *J = nil // v11::Const
v11.method() // v11::Const
var v12 J // v12::UnOp (load from Alloc)
v12.method() // &v12::Alloc (implicitly address-taken)
@ -100,7 +100,7 @@ func main() {
println(v13) // v13::nil
}
switch x := 1; x { // x::Literal
switch x := 1; x { // x::Const
case v0: // v0::Phi
}
@ -108,10 +108,10 @@ func main() {
v++ // v::BinOp
}
if y := 0; y > 1 { // y::Literal y::Literal
if y := 0; y > 1 { // y::Const y::Const
}
var i interface{} // i::Literal (nil interface)
var i interface{} // i::Const (nil interface)
i = 1 // i::MakeInterface
switch i := i.(type) { // i::MakeInterface i::MakeInterface
case int: