aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ir/val.go
blob: bfe7d2bb436c8999631fdbf364c7c766006118a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ir

import (
	"go/constant"
	"math"

	"cmd/compile/internal/base"
	"cmd/compile/internal/types"
)

func ConstType(n Node) constant.Kind {
	if n == nil || n.Op() != OLITERAL {
		return constant.Unknown
	}
	return n.Val().Kind()
}

// ConstValue returns the constant value stored in n as an interface{}.
// It returns int64s for ints and runes, float64s for floats,
// and complex128s for complex values.
func ConstValue(n Node) interface{} {
	switch v := n.Val(); v.Kind() {
	default:
		base.Fatalf("unexpected constant: %v", v)
		panic("unreachable")
	case constant.Bool:
		return constant.BoolVal(v)
	case constant.String:
		return constant.StringVal(v)
	case constant.Int:
		return IntVal(n.Type(), v)
	case constant.Float:
		return Float64Val(v)
	case constant.Complex:
		return complex(Float64Val(constant.Real(v)), Float64Val(constant.Imag(v)))
	}
}

// IntVal returns v converted to int64.
// Note: if t is uint64, very large values will be converted to negative int64.
func IntVal(t *types.Type, v constant.Value) int64 {
	if t.IsUnsigned() {
		if x, ok := constant.Uint64Val(v); ok {
			return int64(x)
		}
	} else {
		if x, ok := constant.Int64Val(v); ok {
			return x
		}
	}
	base.Fatalf("%v out of range for %v", v, t)
	panic("unreachable")
}

func Float64Val(v constant.Value) float64 {
	if x, _ := constant.Float64Val(v); !math.IsInf(x, 0) {
		return x + 0 // avoid -0 (should not be needed, but be conservative)
	}
	base.Fatalf("bad float64 value: %v", v)
	panic("unreachable")
}

func AssertValidTypeForConst(t *types.Type, v constant.Value) {
	if !ValidTypeForConst(t, v) {
		base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind())
	}
}

func ValidTypeForConst(t *types.Type, v constant.Value) bool {
	switch v.Kind() {
	case constant.Unknown:
		return OKForConst[t.Kind()]
	case constant.Bool:
		return t.IsBoolean()
	case constant.String:
		return t.IsString()
	case constant.Int:
		return t.IsInteger()
	case constant.Float:
		return t.IsFloat()
	case constant.Complex:
		return t.IsComplex()
	}

	base.Fatalf("unexpected constant kind: %v", v)
	panic("unreachable")
}

// NewLiteral returns a new untyped constant with value v.
func NewLiteral(v constant.Value) Node {
	return NewBasicLit(base.Pos, v)
}

func idealType(ct constant.Kind) *types.Type {
	switch ct {
	case constant.String:
		return types.UntypedString
	case constant.Bool:
		return types.UntypedBool
	case constant.Int:
		return types.UntypedInt
	case constant.Float:
		return types.UntypedFloat
	case constant.Complex:
		return types.UntypedComplex
	}
	base.Fatalf("unexpected Ctype: %v", ct)
	return nil
}

var OKForConst [types.NTYPE]bool

// CanInt64 reports whether it is safe to call Int64Val() on n.
func CanInt64(n Node) bool {
	if !IsConst(n, constant.Int) {
		return false
	}

	// if the value inside n cannot be represented as an int64, the
	// return value of Int64 is undefined
	_, ok := constant.Int64Val(n.Val())
	return ok
}

// Int64Val returns n as an int64.
// n must be an integer or rune constant.
func Int64Val(n Node) int64 {
	if !IsConst(n, constant.Int) {
		base.Fatalf("Int64Val(%v)", n)
	}
	x, ok := constant.Int64Val(n.Val())
	if !ok {
		base.Fatalf("Int64Val(%v)", n)
	}
	return x
}

// Uint64Val returns n as an uint64.
// n must be an integer or rune constant.
func Uint64Val(n Node) uint64 {
	if !IsConst(n, constant.Int) {
		base.Fatalf("Uint64Val(%v)", n)
	}
	x, ok := constant.Uint64Val(n.Val())
	if !ok {
		base.Fatalf("Uint64Val(%v)", n)
	}
	return x
}

// BoolVal returns n as a bool.
// n must be a boolean constant.
func BoolVal(n Node) bool {
	if !IsConst(n, constant.Bool) {
		base.Fatalf("BoolVal(%v)", n)
	}
	return constant.BoolVal(n.Val())
}

// StringVal returns the value of a literal string Node as a string.
// n must be a string constant.
func StringVal(n Node) string {
	if !IsConst(n, constant.String) {
		base.Fatalf("StringVal(%v)", n)
	}
	return constant.StringVal(n.Val())
}