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	"math/big"
11
12	"cmd/compile/internal/base"
13	"cmd/compile/internal/types"
14	"cmd/internal/src"
15)
16
17// NewBool returns an OLITERAL representing b as an untyped boolean.
18func NewBool(pos src.XPos, b bool) Node {
19	return NewBasicLit(pos, types.UntypedBool, constant.MakeBool(b))
20}
21
22// NewInt returns an OLITERAL representing v as an untyped integer.
23func NewInt(pos src.XPos, v int64) Node {
24	return NewBasicLit(pos, types.UntypedInt, constant.MakeInt64(v))
25}
26
27// NewString returns an OLITERAL representing s as an untyped string.
28func NewString(pos src.XPos, s string) Node {
29	return NewBasicLit(pos, types.UntypedString, constant.MakeString(s))
30}
31
32// NewUintptr returns an OLITERAL representing v as a uintptr.
33func NewUintptr(pos src.XPos, v int64) Node {
34	return NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(v))
35}
36
37// NewZero returns a zero value of the given type.
38func NewZero(pos src.XPos, typ *types.Type) Node {
39	switch {
40	case typ.HasNil():
41		return NewNilExpr(pos, typ)
42	case typ.IsInteger():
43		return NewBasicLit(pos, typ, intZero)
44	case typ.IsFloat():
45		return NewBasicLit(pos, typ, floatZero)
46	case typ.IsComplex():
47		return NewBasicLit(pos, typ, complexZero)
48	case typ.IsBoolean():
49		return NewBasicLit(pos, typ, constant.MakeBool(false))
50	case typ.IsString():
51		return NewBasicLit(pos, typ, constant.MakeString(""))
52	case typ.IsArray() || typ.IsStruct():
53		// TODO(mdempsky): Return a typechecked expression instead.
54		return NewCompLitExpr(pos, OCOMPLIT, typ, nil)
55	}
56
57	base.FatalfAt(pos, "unexpected type: %v", typ)
58	panic("unreachable")
59}
60
61var (
62	intZero     = constant.MakeInt64(0)
63	floatZero   = constant.ToFloat(intZero)
64	complexZero = constant.ToComplex(intZero)
65)
66
67// NewOne returns an OLITERAL representing 1 with the given type.
68func NewOne(pos src.XPos, typ *types.Type) Node {
69	var val constant.Value
70	switch {
71	case typ.IsInteger():
72		val = intOne
73	case typ.IsFloat():
74		val = floatOne
75	case typ.IsComplex():
76		val = complexOne
77	default:
78		base.FatalfAt(pos, "%v cannot represent 1", typ)
79	}
80
81	return NewBasicLit(pos, typ, val)
82}
83
84var (
85	intOne     = constant.MakeInt64(1)
86	floatOne   = constant.ToFloat(intOne)
87	complexOne = constant.ToComplex(intOne)
88)
89
90const (
91	// Maximum size in bits for big.Ints before signaling
92	// overflow and also mantissa precision for big.Floats.
93	ConstPrec = 512
94)
95
96func BigFloat(v constant.Value) *big.Float {
97	f := new(big.Float)
98	f.SetPrec(ConstPrec)
99	switch u := constant.Val(v).(type) {
100	case int64:
101		f.SetInt64(u)
102	case *big.Int:
103		f.SetInt(u)
104	case *big.Float:
105		f.Set(u)
106	case *big.Rat:
107		f.SetRat(u)
108	default:
109		base.Fatalf("unexpected: %v", u)
110	}
111	return f
112}
113
114// ConstOverflow reports whether constant value v is too large
115// to represent with type t.
116func ConstOverflow(v constant.Value, t *types.Type) bool {
117	switch {
118	case t.IsInteger():
119		bits := uint(8 * t.Size())
120		if t.IsUnsigned() {
121			x, ok := constant.Uint64Val(v)
122			return !ok || x>>bits != 0
123		}
124		x, ok := constant.Int64Val(v)
125		if x < 0 {
126			x = ^x
127		}
128		return !ok || x>>(bits-1) != 0
129	case t.IsFloat():
130		switch t.Size() {
131		case 4:
132			f, _ := constant.Float32Val(v)
133			return math.IsInf(float64(f), 0)
134		case 8:
135			f, _ := constant.Float64Val(v)
136			return math.IsInf(f, 0)
137		}
138	case t.IsComplex():
139		ft := types.FloatForComplex(t)
140		return ConstOverflow(constant.Real(v), ft) || ConstOverflow(constant.Imag(v), ft)
141	}
142	base.Fatalf("ConstOverflow: %v, %v", v, t)
143	panic("unreachable")
144}
145
146// IsConstNode reports whether n is a Go language constant (as opposed to a
147// compile-time constant).
148//
149// Expressions derived from nil, like string([]byte(nil)), while they
150// may be known at compile time, are not Go language constants.
151func IsConstNode(n Node) bool {
152	return n.Op() == OLITERAL
153}
154
155func IsSmallIntConst(n Node) bool {
156	if n.Op() == OLITERAL {
157		v, ok := constant.Int64Val(n.Val())
158		return ok && int64(int32(v)) == v
159	}
160	return false
161}
162