1// Copyright 2015 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 ssa
6
7import (
8	"cmd/internal/obj"
9	"fmt"
10)
11
12// An Op encodes the specific operation that a Value performs.
13// Opcodes' semantics can be modified by the type and aux fields of the Value.
14// For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
15// Semantics of each op are described in the opcode files in gen/*Ops.go.
16// There is one file for generic (architecture-independent) ops and one file
17// for each architecture.
18type Op int32
19
20type opInfo struct {
21	name              string
22	reg               regInfo
23	auxType           auxType
24	argLen            int32 // the number of arguments, -1 if variable length
25	asm               obj.As
26	generic           bool      // this is a generic (arch-independent) opcode
27	rematerializeable bool      // this op is rematerializeable
28	commutative       bool      // this operation is commutative (e.g. addition)
29	resultInArg0      bool      // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
30	resultNotInArgs   bool      // outputs must not be allocated to the same registers as inputs
31	clobberFlags      bool      // this op clobbers flags register
32	call              bool      // is a function call
33	nilCheck          bool      // this op is a nil check on arg0
34	faultOnNilArg0    bool      // this op will fault if arg0 is nil (and aux encodes a small offset)
35	faultOnNilArg1    bool      // this op will fault if arg1 is nil (and aux encodes a small offset)
36	usesScratch       bool      // this op requires scratch memory space
37	hasSideEffects    bool      // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
38	zeroWidth         bool      // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width.
39	unsafePoint       bool      // this op is an unsafe point, i.e. not safe for async preemption
40	symEffect         SymEffect // effect this op has on symbol in aux
41	scale             uint8     // amd64/386 indexed load scale
42}
43
44type inputInfo struct {
45	idx  int     // index in Args array
46	regs regMask // allowed input registers
47}
48
49type outputInfo struct {
50	idx  int     // index in output tuple
51	regs regMask // allowed output registers
52}
53
54type regInfo struct {
55	// inputs encodes the register restrictions for an instruction's inputs.
56	// Each entry specifies an allowed register set for a particular input.
57	// They are listed in the order in which regalloc should pick a register
58	// from the register set (most constrained first).
59	// Inputs which do not need registers are not listed.
60	inputs []inputInfo
61	// clobbers encodes the set of registers that are overwritten by
62	// the instruction (other than the output registers).
63	clobbers regMask
64	// outputs is the same as inputs, but for the outputs of the instruction.
65	outputs []outputInfo
66}
67
68type auxType int8
69
70const (
71	auxNone         auxType = iota
72	auxBool                 // auxInt is 0/1 for false/true
73	auxInt8                 // auxInt is an 8-bit integer
74	auxInt16                // auxInt is a 16-bit integer
75	auxInt32                // auxInt is a 32-bit integer
76	auxInt64                // auxInt is a 64-bit integer
77	auxInt128               // auxInt represents a 128-bit integer.  Always 0.
78	auxFloat32              // auxInt is a float32 (encoded with math.Float64bits)
79	auxFloat64              // auxInt is a float64 (encoded with math.Float64bits)
80	auxString               // aux is a string
81	auxSym                  // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals)
82	auxSymOff               // aux is a symbol, auxInt is an offset
83	auxSymValAndOff         // aux is a symbol, auxInt is a ValAndOff
84	auxTyp                  // aux is a type
85	auxTypSize              // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
86	auxCCop                 // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan)
87	auxArchSpecific         // aux type is specific to a particular backend (see the relevant op for the actual type)
88)
89
90// A SymEffect describes the effect that an SSA Value has on the variable
91// identified by the symbol in its Aux field.
92type SymEffect int8
93
94const (
95	SymRead SymEffect = 1 << iota
96	SymWrite
97	SymAddr
98
99	SymRdWr = SymRead | SymWrite
100
101	SymNone SymEffect = 0
102)
103
104// A ValAndOff is used by the several opcodes. It holds
105// both a value and a pointer offset.
106// A ValAndOff is intended to be encoded into an AuxInt field.
107// The zero ValAndOff encodes a value of 0 and an offset of 0.
108// The high 32 bits hold a value.
109// The low 32 bits hold a pointer offset.
110type ValAndOff int64
111
112func (x ValAndOff) Val() int64 {
113	return int64(x) >> 32
114}
115func (x ValAndOff) Off() int64 {
116	return int64(int32(x))
117}
118func (x ValAndOff) Int64() int64 {
119	return int64(x)
120}
121func (x ValAndOff) String() string {
122	return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
123}
124
125// validVal reports whether the value can be used
126// as an argument to makeValAndOff.
127func validVal(val int64) bool {
128	return val == int64(int32(val))
129}
130
131// validOff reports whether the offset can be used
132// as an argument to makeValAndOff.
133func validOff(off int64) bool {
134	return off == int64(int32(off))
135}
136
137// validValAndOff reports whether we can fit the value and offset into
138// a ValAndOff value.
139func validValAndOff(val, off int64) bool {
140	if !validVal(val) {
141		return false
142	}
143	if !validOff(off) {
144		return false
145	}
146	return true
147}
148
149// makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field.
150func makeValAndOff(val, off int64) int64 {
151	if !validValAndOff(val, off) {
152		panic("invalid makeValAndOff")
153	}
154	return ValAndOff(val<<32 + int64(uint32(off))).Int64()
155}
156
157// offOnly returns the offset half of ValAndOff vo.
158// It is intended for use in rewrite rules.
159func offOnly(vo int64) int64 {
160	return ValAndOff(vo).Off()
161}
162
163// valOnly returns the value half of ValAndOff vo.
164// It is intended for use in rewrite rules.
165func valOnly(vo int64) int64 {
166	return ValAndOff(vo).Val()
167}
168
169func (x ValAndOff) canAdd(off int64) bool {
170	newoff := x.Off() + off
171	return newoff == int64(int32(newoff))
172}
173
174func (x ValAndOff) add(off int64) int64 {
175	if !x.canAdd(off) {
176		panic("invalid ValAndOff.add")
177	}
178	return makeValAndOff(x.Val(), x.Off()+off)
179}
180
181type BoundsKind uint8
182
183const (
184	BoundsIndex       BoundsKind = iota // indexing operation, 0 <= idx < len failed
185	BoundsIndexU                        // ... with unsigned idx
186	BoundsSliceAlen                     // 2-arg slicing operation, 0 <= high <= len failed
187	BoundsSliceAlenU                    // ... with unsigned high
188	BoundsSliceAcap                     // 2-arg slicing operation, 0 <= high <= cap failed
189	BoundsSliceAcapU                    // ... with unsigned high
190	BoundsSliceB                        // 2-arg slicing operation, 0 <= low <= high failed
191	BoundsSliceBU                       // ... with unsigned low
192	BoundsSlice3Alen                    // 3-arg slicing operation, 0 <= max <= len failed
193	BoundsSlice3AlenU                   // ... with unsigned max
194	BoundsSlice3Acap                    // 3-arg slicing operation, 0 <= max <= cap failed
195	BoundsSlice3AcapU                   // ... with unsigned max
196	BoundsSlice3B                       // 3-arg slicing operation, 0 <= high <= max failed
197	BoundsSlice3BU                      // ... with unsigned high
198	BoundsSlice3C                       // 3-arg slicing operation, 0 <= low <= high failed
199	BoundsSlice3CU                      // ... with unsigned low
200	BoundsKindCount
201)
202
203// boundsAPI determines which register arguments a bounds check call should use. For an [a:b:c] slice, we do:
204//   CMPQ c, cap
205//   JA   fail1
206//   CMPQ b, c
207//   JA   fail2
208//   CMPQ a, b
209//   JA   fail3
210//
211// fail1: CALL panicSlice3Acap (c, cap)
212// fail2: CALL panicSlice3B (b, c)
213// fail3: CALL panicSlice3C (a, b)
214//
215// When we register allocate that code, we want the same register to be used for
216// the first arg of panicSlice3Acap and the second arg to panicSlice3B. That way,
217// initializing that register once will satisfy both calls.
218// That desire ends up dividing the set of bounds check calls into 3 sets. This function
219// determines which set to use for a given panic call.
220// The first arg for set 0 should be the second arg for set 1.
221// The first arg for set 1 should be the second arg for set 2.
222func boundsABI(b int64) int {
223	switch BoundsKind(b) {
224	case BoundsSlice3Alen,
225		BoundsSlice3AlenU,
226		BoundsSlice3Acap,
227		BoundsSlice3AcapU:
228		return 0
229	case BoundsSliceAlen,
230		BoundsSliceAlenU,
231		BoundsSliceAcap,
232		BoundsSliceAcapU,
233		BoundsSlice3B,
234		BoundsSlice3BU:
235		return 1
236	case BoundsIndex,
237		BoundsIndexU,
238		BoundsSliceB,
239		BoundsSliceBU,
240		BoundsSlice3C,
241		BoundsSlice3CU:
242		return 2
243	default:
244		panic("bad BoundsKind")
245	}
246}
247