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.
9 // copied from ../../amd64/reg.go
10 var regNamesAMD64 = []string{
50 // Make map from reg names to reg integers.
51 if len(regNamesAMD64) > 64 {
52 panic("too many registers")
54 num := map[string]int{}
55 for i, name := range regNamesAMD64 {
57 panic("register name " + name + " does not start with '.'")
61 buildReg := func(s string) regMask {
63 for _, r := range strings.Split(s, " ") {
64 if n, ok := num[r]; ok {
65 m |= regMask(1) << uint(n)
68 panic("register " + r + " not found")
73 // Common individual register masks
79 gp = buildReg("AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15")
80 fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15")
81 gpsp = gp | buildReg("SP")
82 gpspsb = gpsp | buildReg("SB")
83 flags = buildReg("FLAGS")
84 callerSave = gp | fp | flags
86 // Common slices of register masks
88 gponly = []regMask{gp}
89 fponly = []regMask{fp}
90 flagsonly = []regMask{flags}
95 gp01 = regInfo{inputs: []regMask{}, outputs: gponly}
96 gp01flags = regInfo{inputs: []regMask{}, outputs: gponly, clobbers: flags}
97 gp11 = regInfo{inputs: []regMask{gpsp}, outputs: gponly, clobbers: flags}
98 gp11nf = regInfo{inputs: []regMask{gpsp}, outputs: gponly} // nf: no flags clobbered
99 gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
100 gp21 = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: gponly, clobbers: flags}
101 gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
102 gp21shift = regInfo{inputs: []regMask{gpsp, cx}, outputs: []regMask{gp &^ cx}, clobbers: flags}
103 gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax},
104 clobbers: dx | flags}
105 gp11hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx},
106 clobbers: ax | flags}
107 gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx},
108 clobbers: ax | flags}
109 gp10 = regInfo{inputs: []regMask{gp}}
111 gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: flagsonly}
112 gp1flags = regInfo{inputs: []regMask{gpsp}, outputs: flagsonly}
113 flagsgp = regInfo{inputs: flagsonly, outputs: gponly}
114 readflags = regInfo{inputs: flagsonly, outputs: gponly}
115 flagsgpax = regInfo{inputs: flagsonly, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
117 gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
118 gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
120 gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
121 gpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, 0}}
123 fp01 = regInfo{inputs: []regMask{}, outputs: fponly}
124 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
125 fp21x15 = regInfo{inputs: []regMask{fp &^ x15, fp &^ x15},
126 clobbers: x15, outputs: []regMask{fp &^ x15}}
127 fpgp = regInfo{inputs: fponly, outputs: gponly}
128 gpfp = regInfo{inputs: gponly, outputs: fponly}
129 fp11 = regInfo{inputs: fponly, outputs: fponly}
130 fp2flags = regInfo{inputs: []regMask{fp, fp}, outputs: flagsonly}
131 // fp1flags = regInfo{inputs: fponly, outputs: flagsonly}
133 fpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: fponly}
134 fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: fponly}
136 fpstore = regInfo{inputs: []regMask{gpspsb, fp, 0}}
137 fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, 0}}
139 // TODO: most ops clobber flags
141 // Suffixes encode the bit width of various instructions.
142 // Q = 64 bit, L = 32 bit, W = 16 bit, B = 8 bit
144 // TODO: 2-address instructions. Mark ops as needing matching input/output regs.
145 var AMD64ops = []opData{
147 {name: "ADDSS", reg: fp21, asm: "ADDSS"}, // fp32 add
148 {name: "ADDSD", reg: fp21, asm: "ADDSD"}, // fp64 add
149 {name: "SUBSS", reg: fp21x15, asm: "SUBSS"}, // fp32 sub
150 {name: "SUBSD", reg: fp21x15, asm: "SUBSD"}, // fp64 sub
151 {name: "MULSS", reg: fp21, asm: "MULSS"}, // fp32 mul
152 {name: "MULSD", reg: fp21, asm: "MULSD"}, // fp64 mul
153 {name: "DIVSS", reg: fp21x15, asm: "DIVSS"}, // fp32 div
154 {name: "DIVSD", reg: fp21x15, asm: "DIVSD"}, // fp64 div
156 {name: "MOVSSload", reg: fpload, asm: "MOVSS"}, // fp32 load
157 {name: "MOVSDload", reg: fpload, asm: "MOVSD"}, // fp64 load
158 {name: "MOVSSconst", reg: fp01, asm: "MOVSS"}, // fp32 constant
159 {name: "MOVSDconst", reg: fp01, asm: "MOVSD"}, // fp64 constant
160 {name: "MOVSSloadidx4", reg: fploadidx, asm: "MOVSS"}, // fp32 load
161 {name: "MOVSDloadidx8", reg: fploadidx, asm: "MOVSD"}, // fp64 load
163 {name: "MOVSSstore", reg: fpstore, asm: "MOVSS"}, // fp32 store
164 {name: "MOVSDstore", reg: fpstore, asm: "MOVSD"}, // fp64 store
165 {name: "MOVSSstoreidx4", reg: fpstoreidx, asm: "MOVSS"}, // fp32 indexed by 4i store
166 {name: "MOVSDstoreidx8", reg: fpstoreidx, asm: "MOVSD"}, // fp64 indexed by 8i store
169 {name: "ADDQ", reg: gp21, asm: "ADDQ"}, // arg0 + arg1
170 {name: "ADDL", reg: gp21, asm: "ADDL"}, // arg0 + arg1
171 {name: "ADDW", reg: gp21, asm: "ADDW"}, // arg0 + arg1
172 {name: "ADDB", reg: gp21, asm: "ADDB"}, // arg0 + arg1
173 {name: "ADDQconst", reg: gp11, asm: "ADDQ", typ: "UInt64"}, // arg0 + auxint
174 {name: "ADDLconst", reg: gp11, asm: "ADDL"}, // arg0 + auxint
175 {name: "ADDWconst", reg: gp11, asm: "ADDW"}, // arg0 + auxint
176 {name: "ADDBconst", reg: gp11, asm: "ADDB"}, // arg0 + auxint
178 {name: "SUBQ", reg: gp21, asm: "SUBQ"}, // arg0 - arg1
179 {name: "SUBL", reg: gp21, asm: "SUBL"}, // arg0 - arg1
180 {name: "SUBW", reg: gp21, asm: "SUBW"}, // arg0 - arg1
181 {name: "SUBB", reg: gp21, asm: "SUBB"}, // arg0 - arg1
182 {name: "SUBQconst", reg: gp11, asm: "SUBQ"}, // arg0 - auxint
183 {name: "SUBLconst", reg: gp11, asm: "SUBL"}, // arg0 - auxint
184 {name: "SUBWconst", reg: gp11, asm: "SUBW"}, // arg0 - auxint
185 {name: "SUBBconst", reg: gp11, asm: "SUBB"}, // arg0 - auxint
187 {name: "MULQ", reg: gp21, asm: "IMULQ"}, // arg0 * arg1
188 {name: "MULL", reg: gp21, asm: "IMULL"}, // arg0 * arg1
189 {name: "MULW", reg: gp21, asm: "IMULW"}, // arg0 * arg1
190 {name: "MULB", reg: gp21, asm: "IMULW"}, // arg0 * arg1
191 {name: "MULQconst", reg: gp11, asm: "IMULQ"}, // arg0 * auxint
192 {name: "MULLconst", reg: gp11, asm: "IMULL"}, // arg0 * auxint
193 {name: "MULWconst", reg: gp11, asm: "IMULW"}, // arg0 * auxint
194 {name: "MULBconst", reg: gp11, asm: "IMULW"}, // arg0 * auxint
196 {name: "HMULL", reg: gp11hmul, asm: "IMULL"}, // (arg0 * arg1) >> width
197 {name: "HMULW", reg: gp11hmul, asm: "IMULW"}, // (arg0 * arg1) >> width
198 {name: "HMULB", reg: gp11hmul, asm: "IMULB"}, // (arg0 * arg1) >> width
199 {name: "HMULLU", reg: gp11hmul, asm: "MULL"}, // (arg0 * arg1) >> width
200 {name: "HMULWU", reg: gp11hmul, asm: "MULW"}, // (arg0 * arg1) >> width
201 {name: "HMULBU", reg: gp11hmul, asm: "MULB"}, // (arg0 * arg1) >> width
203 {name: "DIVQ", reg: gp11div, asm: "IDIVQ"}, // arg0 / arg1
204 {name: "DIVL", reg: gp11div, asm: "IDIVL"}, // arg0 / arg1
205 {name: "DIVW", reg: gp11div, asm: "IDIVW"}, // arg0 / arg1
206 {name: "DIVQU", reg: gp11div, asm: "DIVQ"}, // arg0 / arg1
207 {name: "DIVLU", reg: gp11div, asm: "DIVL"}, // arg0 / arg1
208 {name: "DIVWU", reg: gp11div, asm: "DIVW"}, // arg0 / arg1
210 {name: "MODQ", reg: gp11mod, asm: "IDIVQ"}, // arg0 % arg1
211 {name: "MODL", reg: gp11mod, asm: "IDIVL"}, // arg0 % arg1
212 {name: "MODW", reg: gp11mod, asm: "IDIVW"}, // arg0 % arg1
213 {name: "MODQU", reg: gp11mod, asm: "DIVQ"}, // arg0 % arg1
214 {name: "MODLU", reg: gp11mod, asm: "DIVL"}, // arg0 % arg1
215 {name: "MODWU", reg: gp11mod, asm: "DIVW"}, // arg0 % arg1
217 {name: "ANDQ", reg: gp21, asm: "ANDQ"}, // arg0 & arg1
218 {name: "ANDL", reg: gp21, asm: "ANDL"}, // arg0 & arg1
219 {name: "ANDW", reg: gp21, asm: "ANDW"}, // arg0 & arg1
220 {name: "ANDB", reg: gp21, asm: "ANDB"}, // arg0 & arg1
221 {name: "ANDQconst", reg: gp11, asm: "ANDQ"}, // arg0 & auxint
222 {name: "ANDLconst", reg: gp11, asm: "ANDL"}, // arg0 & auxint
223 {name: "ANDWconst", reg: gp11, asm: "ANDW"}, // arg0 & auxint
224 {name: "ANDBconst", reg: gp11, asm: "ANDB"}, // arg0 & auxint
226 {name: "ORQ", reg: gp21, asm: "ORQ"}, // arg0 | arg1
227 {name: "ORL", reg: gp21, asm: "ORL"}, // arg0 | arg1
228 {name: "ORW", reg: gp21, asm: "ORW"}, // arg0 | arg1
229 {name: "ORB", reg: gp21, asm: "ORB"}, // arg0 | arg1
230 {name: "ORQconst", reg: gp11, asm: "ORQ"}, // arg0 | auxint
231 {name: "ORLconst", reg: gp11, asm: "ORL"}, // arg0 | auxint
232 {name: "ORWconst", reg: gp11, asm: "ORW"}, // arg0 | auxint
233 {name: "ORBconst", reg: gp11, asm: "ORB"}, // arg0 | auxint
235 {name: "XORQ", reg: gp21, asm: "XORQ"}, // arg0 ^ arg1
236 {name: "XORL", reg: gp21, asm: "XORL"}, // arg0 ^ arg1
237 {name: "XORW", reg: gp21, asm: "XORW"}, // arg0 ^ arg1
238 {name: "XORB", reg: gp21, asm: "XORB"}, // arg0 ^ arg1
239 {name: "XORQconst", reg: gp11, asm: "XORQ"}, // arg0 ^ auxint
240 {name: "XORLconst", reg: gp11, asm: "XORL"}, // arg0 ^ auxint
241 {name: "XORWconst", reg: gp11, asm: "XORW"}, // arg0 ^ auxint
242 {name: "XORBconst", reg: gp11, asm: "XORB"}, // arg0 ^ auxint
244 {name: "CMPQ", reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1
245 {name: "CMPL", reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1
246 {name: "CMPW", reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1
247 {name: "CMPB", reg: gp2flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to arg1
248 {name: "CMPQconst", reg: gp1flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to auxint
249 {name: "CMPLconst", reg: gp1flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to auxint
250 {name: "CMPWconst", reg: gp1flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to auxint
251 {name: "CMPBconst", reg: gp1flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to auxint
253 {name: "UCOMISS", reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32
254 {name: "UCOMISD", reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64
256 {name: "TESTQ", reg: gp2flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0
257 {name: "TESTL", reg: gp2flags, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0
258 {name: "TESTW", reg: gp2flags, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0
259 {name: "TESTB", reg: gp2flags, asm: "TESTB", typ: "Flags"}, // (arg0 & arg1) compare to 0
260 {name: "TESTQconst", reg: gp1flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & auxint) compare to 0
261 {name: "TESTLconst", reg: gp1flags, asm: "TESTL", typ: "Flags"}, // (arg0 & auxint) compare to 0
262 {name: "TESTWconst", reg: gp1flags, asm: "TESTW", typ: "Flags"}, // (arg0 & auxint) compare to 0
263 {name: "TESTBconst", reg: gp1flags, asm: "TESTB", typ: "Flags"}, // (arg0 & auxint) compare to 0
265 {name: "SHLQ", reg: gp21shift, asm: "SHLQ"}, // arg0 << arg1, shift amount is mod 64
266 {name: "SHLL", reg: gp21shift, asm: "SHLL"}, // arg0 << arg1, shift amount is mod 32
267 {name: "SHLW", reg: gp21shift, asm: "SHLW"}, // arg0 << arg1, shift amount is mod 32
268 {name: "SHLB", reg: gp21shift, asm: "SHLB"}, // arg0 << arg1, shift amount is mod 32
269 {name: "SHLQconst", reg: gp11, asm: "SHLQ"}, // arg0 << auxint, shift amount 0-63
270 {name: "SHLLconst", reg: gp11, asm: "SHLL"}, // arg0 << auxint, shift amount 0-31
271 {name: "SHLWconst", reg: gp11, asm: "SHLW"}, // arg0 << auxint, shift amount 0-31
272 {name: "SHLBconst", reg: gp11, asm: "SHLB"}, // arg0 << auxint, shift amount 0-31
273 // Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
275 {name: "SHRQ", reg: gp21shift, asm: "SHRQ"}, // unsigned arg0 >> arg1, shift amount is mod 64
276 {name: "SHRL", reg: gp21shift, asm: "SHRL"}, // unsigned arg0 >> arg1, shift amount is mod 32
277 {name: "SHRW", reg: gp21shift, asm: "SHRW"}, // unsigned arg0 >> arg1, shift amount is mod 32
278 {name: "SHRB", reg: gp21shift, asm: "SHRB"}, // unsigned arg0 >> arg1, shift amount is mod 32
279 {name: "SHRQconst", reg: gp11, asm: "SHRQ"}, // unsigned arg0 >> auxint, shift amount 0-63
280 {name: "SHRLconst", reg: gp11, asm: "SHRL"}, // unsigned arg0 >> auxint, shift amount 0-31
281 {name: "SHRWconst", reg: gp11, asm: "SHRW"}, // unsigned arg0 >> auxint, shift amount 0-31
282 {name: "SHRBconst", reg: gp11, asm: "SHRB"}, // unsigned arg0 >> auxint, shift amount 0-31
284 {name: "SARQ", reg: gp21shift, asm: "SARQ"}, // signed arg0 >> arg1, shift amount is mod 64
285 {name: "SARL", reg: gp21shift, asm: "SARL"}, // signed arg0 >> arg1, shift amount is mod 32
286 {name: "SARW", reg: gp21shift, asm: "SARW"}, // signed arg0 >> arg1, shift amount is mod 32
287 {name: "SARB", reg: gp21shift, asm: "SARB"}, // signed arg0 >> arg1, shift amount is mod 32
288 {name: "SARQconst", reg: gp11, asm: "SARQ"}, // signed arg0 >> auxint, shift amount 0-63
289 {name: "SARLconst", reg: gp11, asm: "SARL"}, // signed arg0 >> auxint, shift amount 0-31
290 {name: "SARWconst", reg: gp11, asm: "SARW"}, // signed arg0 >> auxint, shift amount 0-31
291 {name: "SARBconst", reg: gp11, asm: "SARB"}, // signed arg0 >> auxint, shift amount 0-31
293 {name: "ROLQconst", reg: gp11, asm: "ROLQ"}, // arg0 rotate left auxint, rotate amount 0-63
294 {name: "ROLLconst", reg: gp11, asm: "ROLL"}, // arg0 rotate left auxint, rotate amount 0-31
295 {name: "ROLWconst", reg: gp11, asm: "ROLW"}, // arg0 rotate left auxint, rotate amount 0-15
296 {name: "ROLBconst", reg: gp11, asm: "ROLB"}, // arg0 rotate left auxint, rotate amount 0-7
299 {name: "NEGQ", reg: gp11, asm: "NEGQ"}, // -arg0
300 {name: "NEGL", reg: gp11, asm: "NEGL"}, // -arg0
301 {name: "NEGW", reg: gp11, asm: "NEGW"}, // -arg0
302 {name: "NEGB", reg: gp11, asm: "NEGB"}, // -arg0
304 {name: "NOTQ", reg: gp11, asm: "NOTQ"}, // ^arg0
305 {name: "NOTL", reg: gp11, asm: "NOTL"}, // ^arg0
306 {name: "NOTW", reg: gp11, asm: "NOTW"}, // ^arg0
307 {name: "NOTB", reg: gp11, asm: "NOTB"}, // ^arg0
309 {name: "SQRTSD", reg: fp11, asm: "SQRTSD"}, // sqrt(arg0)
311 {name: "SBBQcarrymask", reg: flagsgp, asm: "SBBQ"}, // (int64)(-1) if carry is set, 0 if carry is clear.
312 {name: "SBBLcarrymask", reg: flagsgp, asm: "SBBL"}, // (int32)(-1) if carry is set, 0 if carry is clear.
313 // Note: SBBW and SBBB are subsumed by SBBL
315 {name: "SETEQ", reg: readflags, asm: "SETEQ"}, // extract == condition from arg0
316 {name: "SETNE", reg: readflags, asm: "SETNE"}, // extract != condition from arg0
317 {name: "SETL", reg: readflags, asm: "SETLT"}, // extract signed < condition from arg0
318 {name: "SETLE", reg: readflags, asm: "SETLE"}, // extract signed <= condition from arg0
319 {name: "SETG", reg: readflags, asm: "SETGT"}, // extract signed > condition from arg0
320 {name: "SETGE", reg: readflags, asm: "SETGE"}, // extract signed >= condition from arg0
321 {name: "SETB", reg: readflags, asm: "SETCS"}, // extract unsigned < condition from arg0
322 {name: "SETBE", reg: readflags, asm: "SETLS"}, // extract unsigned <= condition from arg0
323 {name: "SETA", reg: readflags, asm: "SETHI"}, // extract unsigned > condition from arg0
324 {name: "SETAE", reg: readflags, asm: "SETCC"}, // extract unsigned >= condition from arg0
325 // Need different opcodes for floating point conditions because
326 // any comparison involving a NaN is always FALSE and thus
327 // the patterns for inverting conditions cannot be used.
328 {name: "SETEQF", reg: flagsgpax, asm: "SETEQ"}, // extract == condition from arg0
329 {name: "SETNEF", reg: flagsgpax, asm: "SETNE"}, // extract != condition from arg0
330 {name: "SETORD", reg: flagsgp, asm: "SETPC"}, // extract "ordered" (No Nan present) condition from arg0
331 {name: "SETNAN", reg: flagsgp, asm: "SETPS"}, // extract "unordered" (Nan present) condition from arg0
333 {name: "SETGF", reg: flagsgp, asm: "SETHI"}, // extract floating > condition from arg0
334 {name: "SETGEF", reg: flagsgp, asm: "SETCC"}, // extract floating >= condition from arg0
336 {name: "MOVBQSX", reg: gp11nf, asm: "MOVBQSX"}, // sign extend arg0 from int8 to int64
337 {name: "MOVBQZX", reg: gp11nf, asm: "MOVBQZX"}, // zero extend arg0 from int8 to int64
338 {name: "MOVWQSX", reg: gp11nf, asm: "MOVWQSX"}, // sign extend arg0 from int16 to int64
339 {name: "MOVWQZX", reg: gp11nf, asm: "MOVWQZX"}, // zero extend arg0 from int16 to int64
340 {name: "MOVLQSX", reg: gp11nf, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
341 {name: "MOVLQZX", reg: gp11nf, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64
343 // clobbers flags as liblink will rewrite these to XOR reg, reg if the constant is zero
344 // TODO: revisit when issue 12405 is fixed
345 {name: "MOVBconst", reg: gp01flags, asm: "MOVB", typ: "UInt8"}, // 8 low bits of auxint
346 {name: "MOVWconst", reg: gp01flags, asm: "MOVW", typ: "UInt16"}, // 16 low bits of auxint
347 {name: "MOVLconst", reg: gp01flags, asm: "MOVL", typ: "UInt32"}, // 32 low bits of auxint
348 {name: "MOVQconst", reg: gp01flags, asm: "MOVQ", typ: "UInt64"}, // auxint
350 {name: "CVTTSD2SL", reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32
351 {name: "CVTTSD2SQ", reg: fpgp, asm: "CVTTSD2SQ"}, // convert float64 to int64
352 {name: "CVTTSS2SL", reg: fpgp, asm: "CVTTSS2SL"}, // convert float32 to int32
353 {name: "CVTTSS2SQ", reg: fpgp, asm: "CVTTSS2SQ"}, // convert float32 to int64
354 {name: "CVTSL2SS", reg: gpfp, asm: "CVTSL2SS"}, // convert int32 to float32
355 {name: "CVTSL2SD", reg: gpfp, asm: "CVTSL2SD"}, // convert int32 to float64
356 {name: "CVTSQ2SS", reg: gpfp, asm: "CVTSQ2SS"}, // convert int64 to float32
357 {name: "CVTSQ2SD", reg: gpfp, asm: "CVTSQ2SD"}, // convert int64 to float64
358 {name: "CVTSD2SS", reg: fp11, asm: "CVTSD2SS"}, // convert float64 to float32
359 {name: "CVTSS2SD", reg: fp11, asm: "CVTSS2SD"}, // convert float32 to float64
361 {name: "PXOR", reg: fp21, asm: "PXOR"}, // exclusive or, applied to X regs for float negation.
363 {name: "LEAQ", reg: gp11sb}, // arg0 + auxint + offset encoded in aux
364 {name: "LEAQ1", reg: gp21sb}, // arg0 + arg1 + auxint
365 {name: "LEAQ2", reg: gp21sb}, // arg0 + 2*arg1 + auxint
366 {name: "LEAQ4", reg: gp21sb}, // arg0 + 4*arg1 + auxint
367 {name: "LEAQ8", reg: gp21sb}, // arg0 + 8*arg1 + auxint
369 // auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
370 {name: "MOVBload", reg: gpload, asm: "MOVB"}, // load byte from arg0+auxint+aux. arg1=mem
371 {name: "MOVBQSXload", reg: gpload, asm: "MOVBQSX"}, // ditto, extend to int64
372 {name: "MOVBQZXload", reg: gpload, asm: "MOVBQZX"}, // ditto, extend to uint64
373 {name: "MOVWload", reg: gpload, asm: "MOVW"}, // load 2 bytes from arg0+auxint+aux. arg1=mem
374 {name: "MOVLload", reg: gpload, asm: "MOVL"}, // load 4 bytes from arg0+auxint+aux. arg1=mem
375 {name: "MOVQload", reg: gpload, asm: "MOVQ"}, // load 8 bytes from arg0+auxint+aux. arg1=mem
376 {name: "MOVQloadidx8", reg: gploadidx, asm: "MOVQ"}, // load 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem
377 {name: "MOVBstore", reg: gpstore, asm: "MOVB", typ: "Mem"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem
378 {name: "MOVWstore", reg: gpstore, asm: "MOVW", typ: "Mem"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
379 {name: "MOVLstore", reg: gpstore, asm: "MOVL", typ: "Mem"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
380 {name: "MOVQstore", reg: gpstore, asm: "MOVQ", typ: "Mem"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
381 {name: "MOVQstoreidx8", reg: gpstoreidx, asm: "MOVQ"}, // store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem
383 // arg0 = (duff-adjusted) pointer to start of memory to zero
384 // arg1 = value to store (will always be zero)
386 // auxint = offset into duffzero code to start executing
391 inputs: []regMask{buildReg("DI"), buildReg("X0")},
392 clobbers: buildReg("DI FLAGS"),
395 {name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Float64"},
397 // arg0 = address of memory to zero
398 // arg1 = # of 8-byte words to zero
399 // arg2 = value to store (will always be zero)
405 inputs: []regMask{buildReg("DI"), buildReg("CX"), buildReg("AX")},
406 clobbers: buildReg("DI CX FLAGS"),
410 {name: "CALLstatic", reg: regInfo{clobbers: callerSave}}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
411 {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
412 {name: "CALLdefer", reg: regInfo{clobbers: callerSave}}, // call deferproc. arg0=mem, auxint=argsize, returns mem
413 {name: "CALLgo", reg: regInfo{clobbers: callerSave}}, // call newproc. arg0=mem, auxint=argsize, returns mem
414 {name: "CALLinter", reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
416 {name: "REPMOVSB", reg: regInfo{[]regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")}, buildReg("DI SI CX"), nil}}, // move arg2 bytes from arg1 to arg0. arg3=mem, returns memory
418 // (InvertFlags (CMPQ a b)) == (CMPQ b a)
419 // So if we want (SETL (CMPQ a b)) but we can't do that because a is a constant,
420 // then we do (SETL (InvertFlags (CMPQ b a))) instead.
421 // Rewrites will convert this to (SETG (CMPQ b a)).
422 // InvertFlags is a pseudo-op which can't appear in assembly output.
423 {name: "InvertFlags"}, // reverse direction of arg0
426 {name: "LoweredPanicNilCheck", reg: gp10},
427 {name: "LoweredGetG", reg: gp01}, // arg0=mem
428 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
429 // and sorts it to the very beginning of the block to prevent other
430 // use of DX (the closure pointer)
431 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("DX")}}},
434 var AMD64blocks = []blockData{
447 {name: "ORD"}, // FP, ordered comparison (parity zero)
448 {name: "NAN"}, // FP, unordered comparison (parity one)
451 archs = append(archs, arch{"AMD64", AMD64ops, AMD64blocks, regNamesAMD64})