1// Copyright 2009 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
5package ir
6
7import (
8	"go/constant"
9	"math"
10
11	"cmd/compile/internal/base"
12	"cmd/compile/internal/types"
13)
14
15func ConstType(n Node) constant.Kind {
16	if n == nil || n.Op() != OLITERAL {
17		return constant.Unknown
18	}
19	return n.Val().Kind()
20}
21
22// ConstValue returns the constant value stored in n as an interface{}.
23// It returns int64s for ints and runes, float64s for floats,
24// and complex128s for complex values.
25func ConstValue(n Node) interface{} {
26	switch v := n.Val(); v.Kind() {
27	default:
28		base.Fatalf("unexpected constant: %v", v)
29		panic("unreachable")
30	case constant.Bool:
31		return constant.BoolVal(v)
32	case constant.String:
33		return constant.StringVal(v)
34	case constant.Int:
35		return IntVal(n.Type(), v)
36	case constant.Float:
37		return Float64Val(v)
38	case constant.Complex:
39		return complex(Float64Val(constant.Real(v)), Float64Val(constant.Imag(v)))
40	}
41}
42
43// IntVal returns v converted to int64.
44// Note: if t is uint64, very large values will be converted to negative int64.
45func IntVal(t *types.Type, v constant.Value) int64 {
46	if t.IsUnsigned() {
47		if x, ok := constant.Uint64Val(v); ok {
48			return int64(x)
49		}
50	} else {
51		if x, ok := constant.Int64Val(v); ok {
52			return x
53		}
54	}
55	base.Fatalf("%v out of range for %v", v, t)
56	panic("unreachable")
57}
58
59func Float64Val(v constant.Value) float64 {
60	if x, _ := constant.Float64Val(v); !math.IsInf(x, 0) {
61		return x + 0 // avoid -0 (should not be needed, but be conservative)
62	}
63	base.Fatalf("bad float64 value: %v", v)
64	panic("unreachable")
65}
66
67func AssertValidTypeForConst(t *types.Type, v constant.Value) {
68	if !ValidTypeForConst(t, v) {
69		base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind())
70	}
71}
72
73func ValidTypeForConst(t *types.Type, v constant.Value) bool {
74	switch v.Kind() {
75	case constant.Unknown:
76		return OKForConst[t.Kind()]
77	case constant.Bool:
78		return t.IsBoolean()
79	case constant.String:
80		return t.IsString()
81	case constant.Int:
82		return t.IsInteger()
83	case constant.Float:
84		return t.IsFloat()
85	case constant.Complex:
86		return t.IsComplex()
87	}
88
89	base.Fatalf("unexpected constant kind: %v", v)
90	panic("unreachable")
91}
92
93// NewLiteral returns a new untyped constant with value v.
94func NewLiteral(v constant.Value) Node {
95	return NewBasicLit(base.Pos, v)
96}
97
98func idealType(ct constant.Kind) *types.Type {
99	switch ct {
100	case constant.String:
101		return types.UntypedString
102	case constant.Bool:
103		return types.UntypedBool
104	case constant.Int:
105		return types.UntypedInt
106	case constant.Float:
107		return types.UntypedFloat
108	case constant.Complex:
109		return types.UntypedComplex
110	}
111	base.Fatalf("unexpected Ctype: %v", ct)
112	return nil
113}
114
115var OKForConst [types.NTYPE]bool
116
117// CanInt64 reports whether it is safe to call Int64Val() on n.
118func CanInt64(n Node) bool {
119	if !IsConst(n, constant.Int) {
120		return false
121	}
122
123	// if the value inside n cannot be represented as an int64, the
124	// return value of Int64 is undefined
125	_, ok := constant.Int64Val(n.Val())
126	return ok
127}
128
129// Int64Val returns n as an int64.
130// n must be an integer or rune constant.
131func Int64Val(n Node) int64 {
132	if !IsConst(n, constant.Int) {
133		base.Fatalf("Int64Val(%v)", n)
134	}
135	x, ok := constant.Int64Val(n.Val())
136	if !ok {
137		base.Fatalf("Int64Val(%v)", n)
138	}
139	return x
140}
141
142// Uint64Val returns n as an uint64.
143// n must be an integer or rune constant.
144func Uint64Val(n Node) uint64 {
145	if !IsConst(n, constant.Int) {
146		base.Fatalf("Uint64Val(%v)", n)
147	}
148	x, ok := constant.Uint64Val(n.Val())
149	if !ok {
150		base.Fatalf("Uint64Val(%v)", n)
151	}
152	return x
153}
154
155// BoolVal returns n as a bool.
156// n must be a boolean constant.
157func BoolVal(n Node) bool {
158	if !IsConst(n, constant.Bool) {
159		base.Fatalf("BoolVal(%v)", n)
160	}
161	return constant.BoolVal(n.Val())
162}
163
164// StringVal returns the value of a literal string Node as a string.
165// n must be a string constant.
166func StringVal(n Node) string {
167	if !IsConst(n, constant.String) {
168		base.Fatalf("StringVal(%v)", n)
169	}
170	return constant.StringVal(n.Val())
171}
172