Alan Donovan | 713699d | 2013-08-27 18:49:13 -0400 | [diff] [blame] | 1 | // Copyright 2013 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 5 | package ssa |
| 6 | |
| 7 | // This file defines the Const SSA value type. |
| 8 | |
| 9 | import ( |
| 10 | "fmt" |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 11 | "go/constant" |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 12 | "go/token" |
Alan Donovan | 542ffc7 | 2015-12-29 13:06:30 -0500 | [diff] [blame] | 13 | "go/types" |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 14 | "strconv" |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 15 | ) |
| 16 | |
| 17 | // NewConst returns a new constant of the specified value and type. |
| 18 | // val must be valid according to the specification of Const.Value. |
| 19 | // |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 20 | func NewConst(val constant.Value, typ types.Type) *Const { |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 21 | return &Const{typ, val} |
| 22 | } |
| 23 | |
Alan Donovan | c846ece | 2013-12-04 13:59:55 -0500 | [diff] [blame] | 24 | // intConst returns an 'int' constant that evaluates to i. |
| 25 | // (i is an int64 in case the host is narrower than the target.) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 26 | func intConst(i int64) *Const { |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 27 | return NewConst(constant.MakeInt64(i), tInt) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 28 | } |
| 29 | |
| 30 | // nilConst returns a nil constant of the specified type, which may |
| 31 | // be any reference type, including interfaces. |
| 32 | // |
| 33 | func nilConst(typ types.Type) *Const { |
Robert Griesemer | f50f6c8 | 2013-10-09 14:17:25 -0700 | [diff] [blame] | 34 | return NewConst(nil, typ) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 35 | } |
| 36 | |
Alan Donovan | de23e2b | 2014-06-13 17:34:07 -0400 | [diff] [blame] | 37 | // stringConst returns a 'string' constant that evaluates to s. |
| 38 | func stringConst(s string) *Const { |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 39 | return NewConst(constant.MakeString(s), tString) |
Alan Donovan | de23e2b | 2014-06-13 17:34:07 -0400 | [diff] [blame] | 40 | } |
| 41 | |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 42 | // zeroConst returns a new "zero" constant of the specified type, |
| 43 | // which must not be an array or struct type: the zero values of |
| 44 | // aggregates are well-defined but cannot be represented by Const. |
| 45 | // |
| 46 | func zeroConst(t types.Type) *Const { |
| 47 | switch t := t.(type) { |
| 48 | case *types.Basic: |
| 49 | switch { |
| 50 | case t.Info()&types.IsBoolean != 0: |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 51 | return NewConst(constant.MakeBool(false), t) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 52 | case t.Info()&types.IsNumeric != 0: |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 53 | return NewConst(constant.MakeInt64(0), t) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 54 | case t.Info()&types.IsString != 0: |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 55 | return NewConst(constant.MakeString(""), t) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 56 | case t.Kind() == types.UnsafePointer: |
| 57 | fallthrough |
| 58 | case t.Kind() == types.UntypedNil: |
| 59 | return nilConst(t) |
| 60 | default: |
| 61 | panic(fmt.Sprint("zeroConst for unexpected type:", t)) |
| 62 | } |
| 63 | case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: |
| 64 | return nilConst(t) |
| 65 | case *types.Named: |
| 66 | return NewConst(zeroConst(t.Underlying()).Value, t) |
| 67 | case *types.Array, *types.Struct, *types.Tuple: |
| 68 | panic(fmt.Sprint("zeroConst applied to aggregate:", t)) |
| 69 | } |
| 70 | panic(fmt.Sprint("zeroConst: unexpected ", t)) |
| 71 | } |
| 72 | |
Alan Donovan | b75a5a4 | 2014-01-15 13:51:50 -0500 | [diff] [blame] | 73 | func (c *Const) RelString(from *types.Package) string { |
| 74 | var s string |
Robert Griesemer | f50f6c8 | 2013-10-09 14:17:25 -0700 | [diff] [blame] | 75 | if c.Value == nil { |
Alan Donovan | b75a5a4 | 2014-01-15 13:51:50 -0500 | [diff] [blame] | 76 | s = "nil" |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 77 | } else if c.Value.Kind() == constant.String { |
| 78 | s = constant.StringVal(c.Value) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 79 | const max = 20 |
Alan Donovan | ba9c801 | 2014-03-11 18:24:39 -0400 | [diff] [blame] | 80 | // TODO(adonovan): don't cut a rune in half. |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 81 | if len(s) > max { |
| 82 | s = s[:max-3] + "..." // abbreviate |
| 83 | } |
Alan Donovan | b75a5a4 | 2014-01-15 13:51:50 -0500 | [diff] [blame] | 84 | s = strconv.Quote(s) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 85 | } else { |
Alan Donovan | b75a5a4 | 2014-01-15 13:51:50 -0500 | [diff] [blame] | 86 | s = c.Value.String() |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 87 | } |
Alan Donovan | b75a5a4 | 2014-01-15 13:51:50 -0500 | [diff] [blame] | 88 | return s + ":" + relType(c.Type(), from) |
Alan Donovan | 9fcd20e | 2013-11-15 09:21:48 -0500 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | func (c *Const) Name() string { |
Alan Donovan | b75a5a4 | 2014-01-15 13:51:50 -0500 | [diff] [blame] | 92 | return c.RelString(nil) |
Alan Donovan | 9fcd20e | 2013-11-15 09:21:48 -0500 | [diff] [blame] | 93 | } |
| 94 | |
Alan Donovan | b75a5a4 | 2014-01-15 13:51:50 -0500 | [diff] [blame] | 95 | func (c *Const) String() string { |
| 96 | return c.Name() |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | func (c *Const) Type() types.Type { |
| 100 | return c.typ |
| 101 | } |
| 102 | |
| 103 | func (c *Const) Referrers() *[]Instruction { |
| 104 | return nil |
| 105 | } |
| 106 | |
Alan Donovan | 04427c8 | 2014-06-11 13:14:06 -0400 | [diff] [blame] | 107 | func (c *Const) Parent() *Function { return nil } |
| 108 | |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 109 | func (c *Const) Pos() token.Pos { |
| 110 | return token.NoPos |
| 111 | } |
| 112 | |
| 113 | // IsNil returns true if this constant represents a typed or untyped nil value. |
| 114 | func (c *Const) IsNil() bool { |
Robert Griesemer | f50f6c8 | 2013-10-09 14:17:25 -0700 | [diff] [blame] | 115 | return c.Value == nil |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 116 | } |
| 117 | |
Alan Donovan | 542ffc7 | 2015-12-29 13:06:30 -0500 | [diff] [blame] | 118 | // TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp. |
| 119 | |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 120 | // Int64 returns the numeric value of this constant truncated to fit |
| 121 | // a signed 64-bit integer. |
| 122 | // |
| 123 | func (c *Const) Int64() int64 { |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 124 | switch x := constant.ToInt(c.Value); x.Kind() { |
| 125 | case constant.Int: |
| 126 | if i, ok := constant.Int64Val(x); ok { |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 127 | return i |
| 128 | } |
| 129 | return 0 |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 130 | case constant.Float: |
| 131 | f, _ := constant.Float64Val(x) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 132 | return int64(f) |
| 133 | } |
| 134 | panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) |
| 135 | } |
| 136 | |
| 137 | // Uint64 returns the numeric value of this constant truncated to fit |
| 138 | // an unsigned 64-bit integer. |
| 139 | // |
| 140 | func (c *Const) Uint64() uint64 { |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 141 | switch x := constant.ToInt(c.Value); x.Kind() { |
| 142 | case constant.Int: |
| 143 | if u, ok := constant.Uint64Val(x); ok { |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 144 | return u |
| 145 | } |
| 146 | return 0 |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 147 | case constant.Float: |
| 148 | f, _ := constant.Float64Val(x) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 149 | return uint64(f) |
| 150 | } |
| 151 | panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) |
| 152 | } |
| 153 | |
| 154 | // Float64 returns the numeric value of this constant truncated to fit |
| 155 | // a float64. |
| 156 | // |
| 157 | func (c *Const) Float64() float64 { |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 158 | f, _ := constant.Float64Val(c.Value) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 159 | return f |
| 160 | } |
| 161 | |
| 162 | // Complex128 returns the complex value of this constant truncated to |
| 163 | // fit a complex128. |
| 164 | // |
| 165 | func (c *Const) Complex128() complex128 { |
Alan Donovan | e96c4e2 | 2018-08-10 12:49:16 -0400 | [diff] [blame] | 166 | re, _ := constant.Float64Val(constant.Real(c.Value)) |
| 167 | im, _ := constant.Float64Val(constant.Imag(c.Value)) |
Alan Donovan | 732dbe9 | 2013-07-16 13:50:08 -0400 | [diff] [blame] | 168 | return complex(re, im) |
| 169 | } |