liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
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
// 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.
   zeroWidth         bool      // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width.
   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 encodes the register restrictions for an instruction's inputs.
   // Each entry specifies an allowed register set for a particular input.
   // They are listed in the order in which regalloc should pick a register
   // from the register set (most constrained first).
   // Inputs which do not need registers are not listed.
   inputs []inputInfo
   // clobbers encodes the set of registers that are overwritten by
   // the instruction (other than the output registers).
   clobbers regMask
   // outputs is the same as inputs, but for the outputs of the instruction.
   outputs []outputInfo
}
 
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)
}