/
op.go
157 lines (135 loc) · 5.2 KB
/
op.go
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
// Copyright 2015 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 ssa
import (
"cmd/internal/obj"
"fmt"
)
// An Op encodes the specific operation that a Value performs.
// Opcodes' semantics can be modified by the type and aux fields of the Value.
// For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
// Semantics of each op are described in the opcode files in gen/*Ops.go.
// There is one file for generic (architecture-independent) ops and one file
// for each architecture.
type Op int32
type opInfo struct {
name string
reg regInfo
auxType auxType
argLen int32 // the number of arguments, -1 if variable length
asm obj.As
generic bool // this is a generic (arch-independent) opcode
rematerializeable bool // this op is rematerializeable
commutative bool // this operation is commutative (e.g. addition)
resultInArg0 bool // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
resultNotInArgs bool // outputs must not be allocated to the same registers as inputs
clobberFlags bool // this op clobbers flags register
call bool // is a function call
nilCheck bool // this op is a nil check on arg0
faultOnNilArg0 bool // this op will fault if arg0 is nil (and aux encodes a small offset)
faultOnNilArg1 bool // this op will fault if arg1 is nil (and aux encodes a small offset)
usesScratch bool // this op requires scratch memory space
hasSideEffects bool // for "reasons", not to be eliminated. E.g., atomic store, #19182.
symEffect SymEffect // effect this op has on symbol in aux
}
type inputInfo struct {
idx int // index in Args array
regs regMask // allowed input registers
}
type outputInfo struct {
idx int // index in output tuple
regs regMask // allowed output registers
}
type regInfo struct {
inputs []inputInfo // ordered in register allocation order
clobbers regMask
outputs []outputInfo // ordered in register allocation order
}
type auxType int8
const (
auxNone auxType = iota
auxBool // auxInt is 0/1 for false/true
auxInt8 // auxInt is an 8-bit integer
auxInt16 // auxInt is a 16-bit integer
auxInt32 // auxInt is a 32-bit integer
auxInt64 // auxInt is a 64-bit integer
auxInt128 // auxInt represents a 128-bit integer. Always 0.
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
auxString // aux is a string
auxSym // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals)
auxSymOff // aux is a symbol, auxInt is an offset
auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
auxTyp // aux is a type
auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan)
auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
)
// A SymEffect describes the effect that an SSA Value has on the variable
// identified by the symbol in its Aux field.
type SymEffect int8
const (
SymRead SymEffect = 1 << iota
SymWrite
SymAddr
SymRdWr = SymRead | SymWrite
SymNone SymEffect = 0
)
// A ValAndOff is used by the several opcodes. It holds
// both a value and a pointer offset.
// A ValAndOff is intended to be encoded into an AuxInt field.
// The zero ValAndOff encodes a value of 0 and an offset of 0.
// The high 32 bits hold a value.
// The low 32 bits hold a pointer offset.
type ValAndOff int64
func (x ValAndOff) Val() int64 {
return int64(x) >> 32
}
func (x ValAndOff) Off() int64 {
return int64(int32(x))
}
func (x ValAndOff) Int64() int64 {
return int64(x)
}
func (x ValAndOff) String() string {
return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
}
// validVal reports whether the value can be used
// as an argument to makeValAndOff.
func validVal(val int64) bool {
return val == int64(int32(val))
}
// validOff reports whether the offset can be used
// as an argument to makeValAndOff.
func validOff(off int64) bool {
return off == int64(int32(off))
}
// validValAndOff reports whether we can fit the value and offset into
// a ValAndOff value.
func validValAndOff(val, off int64) bool {
if !validVal(val) {
return false
}
if !validOff(off) {
return false
}
return true
}
// makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field.
func makeValAndOff(val, off int64) int64 {
if !validValAndOff(val, off) {
panic("invalid makeValAndOff")
}
return ValAndOff(val<<32 + int64(uint32(off))).Int64()
}
func (x ValAndOff) canAdd(off int64) bool {
newoff := x.Off() + off
return newoff == int64(int32(newoff))
}
func (x ValAndOff) add(off int64) int64 {
if !x.canAdd(off) {
panic("invalid ValAndOff.add")
}
return makeValAndOff(x.Val(), x.Off()+off)
}