2015-06-06 16:03:33 -07:00
// 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.
2016-04-05 15:11:08 +10:00
// +build ignore
2015-06-06 16:03:33 -07:00
package main
2015-06-14 11:38:46 -07:00
import "strings"
2015-06-06 16:03:33 -07:00
2016-03-29 16:39:53 -07:00
// Notes:
// - Integer types live in the low portion of registers. Upper portions are junk.
// - Boolean types use the low-order byte of a register. 0=false, 1=true.
// Upper bytes are junk.
// - Floating-point types live in the low natural slot of an sse2 register.
// Unused portions are junk.
// - We do not use AH,BH,CH,DH registers.
// - When doing sub-register operations, we try to write the whole
// destination register to avoid a partial-register write.
// - Unused portions of AuxInt (or the Val portion of ValAndOff) are
// filled by sign-extending the used portion. Users of AuxInt which interpret
// AuxInt as unsigned (e.g. shifts) must be careful.
2017-08-28 12:57:52 -07:00
// - All SymOff opcodes require their offset to fit in an int32.
2016-03-29 16:39:53 -07:00
// Suffixes encode the bit width of various instructions.
// Q (quad word) = 64 bit
// L (long word) = 32 bit
// W (word) = 16 bit
// B (byte) = 8 bit
2015-06-06 16:03:33 -07:00
// copied from ../../amd64/reg.go
var regNamesAMD64 = [ ] string {
2016-03-22 09:43:28 -07:00
"AX" ,
"CX" ,
"DX" ,
"BX" ,
"SP" ,
"BP" ,
"SI" ,
"DI" ,
"R8" ,
"R9" ,
"R10" ,
"R11" ,
"R12" ,
"R13" ,
"R14" ,
"R15" ,
"X0" ,
"X1" ,
"X2" ,
"X3" ,
"X4" ,
"X5" ,
"X6" ,
"X7" ,
"X8" ,
"X9" ,
"X10" ,
"X11" ,
"X12" ,
"X13" ,
"X14" ,
"X15" ,
2015-06-06 16:03:33 -07:00
2019-10-16 19:10:06 -04:00
// If you add registers, update asyncPreempt in runtime
2015-06-06 16:03:33 -07:00
// pseudo-registers
2016-03-22 09:43:28 -07:00
"SB" ,
2015-06-06 16:03:33 -07:00
}
func init ( ) {
// Make map from reg names to reg integers.
if len ( regNamesAMD64 ) > 64 {
panic ( "too many registers" )
}
num := map [ string ] int { }
for i , name := range regNamesAMD64 {
2016-03-22 09:43:28 -07:00
num [ name ] = i
2015-06-06 16:03:33 -07:00
}
buildReg := func ( s string ) regMask {
m := regMask ( 0 )
for _ , r := range strings . Split ( s , " " ) {
if n , ok := num [ r ] ; ok {
m |= regMask ( 1 ) << uint ( n )
continue
}
panic ( "register " + r + " not found" )
}
return m
}
2015-08-06 09:34:54 -07:00
// Common individual register masks
var (
2015-08-17 17:46:06 -05:00
ax = buildReg ( "AX" )
2015-08-11 12:51:33 -07:00
cx = buildReg ( "CX" )
2015-08-17 17:46:06 -05:00
dx = buildReg ( "DX" )
2019-02-06 14:12:36 -08:00
bx = buildReg ( "BX" )
2015-08-11 12:51:33 -07:00
gp = buildReg ( "AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15" )
fp = buildReg ( "X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15" )
gpsp = gp | buildReg ( "SP" )
gpspsb = gpsp | buildReg ( "SB" )
2016-08-04 06:57:34 -04:00
callerSave = gp | fp
2015-08-06 09:34:54 -07:00
)
// Common slices of register masks
var (
2016-08-04 06:57:34 -04:00
gponly = [ ] regMask { gp }
fponly = [ ] regMask { fp }
2015-08-06 09:34:54 -07:00
)
// Common regInfo
var (
2018-10-23 14:05:38 -07:00
gp01 = regInfo { inputs : nil , outputs : gponly }
gp11 = regInfo { inputs : [ ] regMask { gp } , outputs : gponly }
gp11sp = regInfo { inputs : [ ] regMask { gpsp } , outputs : gponly }
gp11sb = regInfo { inputs : [ ] regMask { gpspsb } , outputs : gponly }
gp21 = regInfo { inputs : [ ] regMask { gp , gp } , outputs : gponly }
gp21sp = regInfo { inputs : [ ] regMask { gpsp , gp } , outputs : gponly }
gp21sb = regInfo { inputs : [ ] regMask { gpspsb , gpsp } , outputs : gponly }
gp21shift = regInfo { inputs : [ ] regMask { gp , cx } , outputs : [ ] regMask { gp } }
gp11div = regInfo { inputs : [ ] regMask { ax , gpsp &^ dx } , outputs : [ ] regMask { ax , dx } }
gp21hmul = regInfo { inputs : [ ] regMask { ax , gpsp } , outputs : [ ] regMask { dx } , clobbers : ax }
gp21flags = regInfo { inputs : [ ] regMask { gp , gp } , outputs : [ ] regMask { gp , 0 } }
gp2flags1flags = regInfo { inputs : [ ] regMask { gp , gp , 0 } , outputs : [ ] regMask { gp , 0 } }
2015-08-06 09:34:54 -07:00
2018-01-03 14:38:55 -08:00
gp2flags = regInfo { inputs : [ ] regMask { gpsp , gpsp } }
gp1flags = regInfo { inputs : [ ] regMask { gpsp } }
gp0flagsLoad = regInfo { inputs : [ ] regMask { gpspsb , 0 } }
gp1flagsLoad = regInfo { inputs : [ ] regMask { gpspsb , gpsp , 0 } }
flagsgp = regInfo { inputs : nil , outputs : gponly }
2016-03-11 00:10:52 -05:00
2018-10-23 14:05:38 -07:00
gp11flags = regInfo { inputs : [ ] regMask { gp } , outputs : [ ] regMask { gp , 0 } }
gp1flags1flags = regInfo { inputs : [ ] regMask { gp , 0 } , outputs : [ ] regMask { gp , 0 } }
2016-03-11 00:10:52 -05:00
2016-08-04 06:57:34 -04:00
readflags = regInfo { inputs : nil , outputs : gponly }
flagsgpax = regInfo { inputs : nil , clobbers : ax , outputs : [ ] regMask { gp &^ ax } }
2015-08-06 09:34:54 -07:00
gpload = regInfo { inputs : [ ] regMask { gpspsb , 0 } , outputs : gponly }
2017-02-10 13:17:20 -06:00
gp21load = regInfo { inputs : [ ] regMask { gp , gpspsb , 0 } , outputs : gponly }
2015-08-06 09:34:54 -07:00
gploadidx = regInfo { inputs : [ ] regMask { gpspsb , gpsp , 0 } , outputs : gponly }
2018-03-05 20:59:40 +01:00
gp21pax = regInfo { inputs : [ ] regMask { gp &^ ax , gp } , outputs : [ ] regMask { gp &^ ax } , clobbers : ax }
2015-08-06 09:34:54 -07:00
2016-02-04 15:53:33 -08:00
gpstore = regInfo { inputs : [ ] regMask { gpspsb , gpsp , 0 } }
gpstoreconst = regInfo { inputs : [ ] regMask { gpspsb , 0 } }
gpstoreidx = regInfo { inputs : [ ] regMask { gpspsb , gpsp , gpsp , 0 } }
gpstoreconstidx = regInfo { inputs : [ ] regMask { gpspsb , gpsp , 0 } }
2017-02-19 00:16:27 -08:00
gpstorexchg = regInfo { inputs : [ ] regMask { gp , gpspsb , 0 } , outputs : [ ] regMask { gp } }
2016-08-25 16:02:57 -07:00
cmpxchg = regInfo { inputs : [ ] regMask { gp , ax , gp , 0 } , outputs : [ ] regMask { gp , 0 } , clobbers : ax }
2015-08-12 16:38:11 -04:00
2016-08-31 12:35:32 -07:00
fp01 = regInfo { inputs : nil , outputs : fponly }
fp21 = regInfo { inputs : [ ] regMask { fp , fp } , outputs : fponly }
2018-09-25 03:10:33 -04:00
fp31 = regInfo { inputs : [ ] regMask { fp , fp , fp } , outputs : fponly }
2017-02-10 13:17:20 -06:00
fp21load = regInfo { inputs : [ ] regMask { fp , gpspsb , 0 } , outputs : fponly }
2015-08-18 14:39:26 -04:00
fpgp = regInfo { inputs : fponly , outputs : gponly }
gpfp = regInfo { inputs : gponly , outputs : fponly }
fp11 = regInfo { inputs : fponly , outputs : fponly }
2016-08-04 06:57:34 -04:00
fp2flags = regInfo { inputs : [ ] regMask { fp , fp } }
2015-08-12 16:38:11 -04:00
fpload = regInfo { inputs : [ ] regMask { gpspsb , 0 } , outputs : fponly }
fploadidx = regInfo { inputs : [ ] regMask { gpspsb , gpsp , 0 } , outputs : fponly }
fpstore = regInfo { inputs : [ ] regMask { gpspsb , fp , 0 } }
fpstoreidx = regInfo { inputs : [ ] regMask { gpspsb , gpsp , fp , 0 } }
2015-08-06 09:34:54 -07:00
)
2015-06-06 16:03:33 -07:00
var AMD64ops = [ ] opData {
2015-08-12 16:38:11 -04:00
// fp ops
2016-03-10 13:05:56 -08:00
{ name : "ADDSS" , argLength : 2 , reg : fp21 , asm : "ADDSS" , commutative : true , resultInArg0 : true } , // fp32 add
{ name : "ADDSD" , argLength : 2 , reg : fp21 , asm : "ADDSD" , commutative : true , resultInArg0 : true } , // fp64 add
2016-08-31 12:35:32 -07:00
{ name : "SUBSS" , argLength : 2 , reg : fp21 , asm : "SUBSS" , resultInArg0 : true } , // fp32 sub
{ name : "SUBSD" , argLength : 2 , reg : fp21 , asm : "SUBSD" , resultInArg0 : true } , // fp64 sub
2016-03-10 13:05:56 -08:00
{ name : "MULSS" , argLength : 2 , reg : fp21 , asm : "MULSS" , commutative : true , resultInArg0 : true } , // fp32 mul
{ name : "MULSD" , argLength : 2 , reg : fp21 , asm : "MULSD" , commutative : true , resultInArg0 : true } , // fp64 mul
2016-08-31 12:35:32 -07:00
{ name : "DIVSS" , argLength : 2 , reg : fp21 , asm : "DIVSS" , resultInArg0 : true } , // fp32 div
{ name : "DIVSD" , argLength : 2 , reg : fp21 , asm : "DIVSD" , resultInArg0 : true } , // fp64 div
2016-02-27 08:04:48 -06:00
2017-03-09 14:46:43 -08:00
{ name : "MOVSSload" , argLength : 2 , reg : fpload , asm : "MOVSS" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } , // fp32 load
{ name : "MOVSDload" , argLength : 2 , reg : fpload , asm : "MOVSD" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } , // fp64 load
{ name : "MOVSSconst" , reg : fp01 , asm : "MOVSS" , aux : "Float32" , rematerializeable : true } , // fp32 constant
{ name : "MOVSDconst" , reg : fp01 , asm : "MOVSD" , aux : "Float64" , rematerializeable : true } , // fp64 constant
2019-03-09 12:41:34 -08:00
{ name : "MOVSSloadidx1" , argLength : 3 , reg : fploadidx , asm : "MOVSS" , scale : 1 , aux : "SymOff" , symEffect : "Read" } , // fp32 load indexed by i
{ name : "MOVSSloadidx4" , argLength : 3 , reg : fploadidx , asm : "MOVSS" , scale : 4 , aux : "SymOff" , symEffect : "Read" } , // fp32 load indexed by 4*i
{ name : "MOVSDloadidx1" , argLength : 3 , reg : fploadidx , asm : "MOVSD" , scale : 1 , aux : "SymOff" , symEffect : "Read" } , // fp64 load indexed by i
{ name : "MOVSDloadidx8" , argLength : 3 , reg : fploadidx , asm : "MOVSD" , scale : 8 , aux : "SymOff" , symEffect : "Read" } , // fp64 load indexed by 8*i
2017-03-09 14:46:43 -08:00
{ name : "MOVSSstore" , argLength : 3 , reg : fpstore , asm : "MOVSS" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Write" } , // fp32 store
{ name : "MOVSDstore" , argLength : 3 , reg : fpstore , asm : "MOVSD" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Write" } , // fp64 store
2019-03-09 12:41:34 -08:00
{ name : "MOVSSstoreidx1" , argLength : 4 , reg : fpstoreidx , asm : "MOVSS" , scale : 1 , aux : "SymOff" , symEffect : "Write" } , // fp32 indexed by i store
{ name : "MOVSSstoreidx4" , argLength : 4 , reg : fpstoreidx , asm : "MOVSS" , scale : 4 , aux : "SymOff" , symEffect : "Write" } , // fp32 indexed by 4i store
{ name : "MOVSDstoreidx1" , argLength : 4 , reg : fpstoreidx , asm : "MOVSD" , scale : 1 , aux : "SymOff" , symEffect : "Write" } , // fp64 indexed by i store
{ name : "MOVSDstoreidx8" , argLength : 4 , reg : fpstoreidx , asm : "MOVSD" , scale : 8 , aux : "SymOff" , symEffect : "Write" } , // fp64 indexed by 8i store
2017-03-09 14:46:43 -08:00
2018-05-08 09:11:00 -07:00
{ name : "ADDSSload" , argLength : 3 , reg : fp21load , asm : "ADDSS" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp32 arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "ADDSDload" , argLength : 3 , reg : fp21load , asm : "ADDSD" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp64 arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "SUBSSload" , argLength : 3 , reg : fp21load , asm : "SUBSS" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp32 arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "SUBSDload" , argLength : 3 , reg : fp21load , asm : "SUBSD" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp64 arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "MULSSload" , argLength : 3 , reg : fp21load , asm : "MULSS" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp32 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "MULSDload" , argLength : 3 , reg : fp21load , asm : "MULSD" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp64 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
2018-06-21 10:14:18 +00:00
{ name : "DIVSSload" , argLength : 3 , reg : fp21load , asm : "DIVSS" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp32 arg0 / tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "DIVSDload" , argLength : 3 , reg : fp21load , asm : "DIVSD" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , symEffect : "Read" } , // fp64 arg0 / tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
2017-02-10 13:17:20 -06:00
2015-07-28 16:04:50 -07:00
// binary ops
2018-05-08 09:11:00 -07:00
{ name : "ADDQ" , argLength : 2 , reg : gp21sp , asm : "ADDQ" , commutative : true , clobberFlags : true } , // arg0 + arg1
{ name : "ADDL" , argLength : 2 , reg : gp21sp , asm : "ADDL" , commutative : true , clobberFlags : true } , // arg0 + arg1
{ name : "ADDQconst" , argLength : 1 , reg : gp11sp , asm : "ADDQ" , aux : "Int32" , typ : "UInt64" , clobberFlags : true } , // arg0 + auxint
{ name : "ADDLconst" , argLength : 1 , reg : gp11sp , asm : "ADDL" , aux : "Int32" , clobberFlags : true } , // arg0 + auxint
{ name : "ADDQconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "ADDQ" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // add ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "ADDLconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "ADDL" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // add ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
2016-08-04 06:57:34 -04:00
{ name : "SUBQ" , argLength : 2 , reg : gp21 , asm : "SUBQ" , resultInArg0 : true , clobberFlags : true } , // arg0 - arg1
{ name : "SUBL" , argLength : 2 , reg : gp21 , asm : "SUBL" , resultInArg0 : true , clobberFlags : true } , // arg0 - arg1
2017-08-28 12:57:52 -07:00
{ name : "SUBQconst" , argLength : 1 , reg : gp11 , asm : "SUBQ" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 - auxint
2016-08-04 06:57:34 -04:00
{ name : "SUBLconst" , argLength : 1 , reg : gp11 , asm : "SUBL" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 - auxint
{ name : "MULQ" , argLength : 2 , reg : gp21 , asm : "IMULQ" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 * arg1
{ name : "MULL" , argLength : 2 , reg : gp21 , asm : "IMULL" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 * arg1
2018-03-09 23:09:46 +03:00
{ name : "MULQconst" , argLength : 1 , reg : gp11 , asm : "IMUL3Q" , aux : "Int32" , clobberFlags : true } , // arg0 * auxint
{ name : "MULLconst" , argLength : 1 , reg : gp11 , asm : "IMUL3L" , aux : "Int32" , clobberFlags : true } , // arg0 * auxint
2016-08-04 06:57:34 -04:00
2018-01-27 11:55:34 +01:00
{ name : "MULLU" , argLength : 2 , reg : regInfo { inputs : [ ] regMask { ax , gpsp } , outputs : [ ] regMask { ax , 0 } , clobbers : dx } , typ : "(UInt32,Flags)" , asm : "MULL" , commutative : true , clobberFlags : true } , // Let x = arg0*arg1 (full 32x32->64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x.
{ name : "MULQU" , argLength : 2 , reg : regInfo { inputs : [ ] regMask { ax , gpsp } , outputs : [ ] regMask { ax , 0 } , clobbers : dx } , typ : "(UInt64,Flags)" , asm : "MULQ" , commutative : true , clobberFlags : true } , // Let x = arg0*arg1 (full 64x64->128 unsigned multiply). Returns uint64(x), and flags set to overflow if uint64(x) != x.
2020-01-07 09:27:18 -08:00
// HMULx[U] are intentionally not marked as commutative, even though they are.
// This is because they have asymmetric register requirements.
// There are rewrite rules to try to place arguments in preferable slots.
{ name : "HMULQ" , argLength : 2 , reg : gp21hmul , asm : "IMULQ" , clobberFlags : true } , // (arg0 * arg1) >> width
{ name : "HMULL" , argLength : 2 , reg : gp21hmul , asm : "IMULL" , clobberFlags : true } , // (arg0 * arg1) >> width
{ name : "HMULQU" , argLength : 2 , reg : gp21hmul , asm : "MULQ" , clobberFlags : true } , // (arg0 * arg1) >> width
{ name : "HMULLU" , argLength : 2 , reg : gp21hmul , asm : "MULL" , clobberFlags : true } , // (arg0 * arg1) >> width
2016-08-04 06:57:34 -04:00
{ name : "AVGQU" , argLength : 2 , reg : gp21 , commutative : true , resultInArg0 : true , clobberFlags : true } , // (arg0 + arg1) / 2 as unsigned, all 64 result bits
2018-08-06 19:50:38 +10:00
// For DIVQ, DIVL and DIVW, AuxInt non-zero means that the divisor has been proved to be not -1.
{ name : "DIVQ" , argLength : 2 , reg : gp11div , typ : "(Int64,Int64)" , asm : "IDIVQ" , aux : "Bool" , clobberFlags : true } , // [arg0 / arg1, arg0 % arg1]
{ name : "DIVL" , argLength : 2 , reg : gp11div , typ : "(Int32,Int32)" , asm : "IDIVL" , aux : "Bool" , clobberFlags : true } , // [arg0 / arg1, arg0 % arg1]
{ name : "DIVW" , argLength : 2 , reg : gp11div , typ : "(Int16,Int16)" , asm : "IDIVW" , aux : "Bool" , clobberFlags : true } , // [arg0 / arg1, arg0 % arg1]
2016-08-04 06:57:34 -04:00
{ name : "DIVQU" , argLength : 2 , reg : gp11div , typ : "(UInt64,UInt64)" , asm : "DIVQ" , clobberFlags : true } , // [arg0 / arg1, arg0 % arg1]
{ name : "DIVLU" , argLength : 2 , reg : gp11div , typ : "(UInt32,UInt32)" , asm : "DIVL" , clobberFlags : true } , // [arg0 / arg1, arg0 % arg1]
{ name : "DIVWU" , argLength : 2 , reg : gp11div , typ : "(UInt16,UInt16)" , asm : "DIVW" , clobberFlags : true } , // [arg0 / arg1, arg0 % arg1]
2018-10-23 14:05:38 -07:00
{ name : "NEGLflags" , argLength : 1 , reg : gp11flags , typ : "(UInt32,Flags)" , asm : "NEGL" , resultInArg0 : true } , // -arg0, flags set for 0-arg0.
// The following 4 add opcodes return the low 64 bits of the sum in the first result and
// the carry (the 65th bit) in the carry flag.
2018-10-23 14:38:22 -07:00
{ name : "ADDQcarry" , argLength : 2 , reg : gp21flags , typ : "(UInt64,Flags)" , asm : "ADDQ" , commutative : true , resultInArg0 : true } , // r = arg0+arg1
{ name : "ADCQ" , argLength : 3 , reg : gp2flags1flags , typ : "(UInt64,Flags)" , asm : "ADCQ" , commutative : true , resultInArg0 : true } , // r = arg0+arg1+carry(arg2)
{ name : "ADDQconstcarry" , argLength : 1 , reg : gp11flags , typ : "(UInt64,Flags)" , asm : "ADDQ" , aux : "Int32" , resultInArg0 : true } , // r = arg0+auxint
{ name : "ADCQconst" , argLength : 2 , reg : gp1flags1flags , typ : "(UInt64,Flags)" , asm : "ADCQ" , aux : "Int32" , resultInArg0 : true } , // r = arg0+auxint+carry(arg1)
// The following 4 add opcodes return the low 64 bits of the difference in the first result and
// the borrow (if the result is negative) in the carry flag.
{ name : "SUBQborrow" , argLength : 2 , reg : gp21flags , typ : "(UInt64,Flags)" , asm : "SUBQ" , resultInArg0 : true } , // r = arg0-arg1
{ name : "SBBQ" , argLength : 3 , reg : gp2flags1flags , typ : "(UInt64,Flags)" , asm : "SBBQ" , resultInArg0 : true } , // r = arg0-(arg1+carry(arg2))
{ name : "SUBQconstborrow" , argLength : 1 , reg : gp11flags , typ : "(UInt64,Flags)" , asm : "SUBQ" , aux : "Int32" , resultInArg0 : true } , // r = arg0-auxint
{ name : "SBBQconst" , argLength : 2 , reg : gp1flags1flags , typ : "(UInt64,Flags)" , asm : "SBBQ" , aux : "Int32" , resultInArg0 : true } , // r = arg0-(auxint+carry(arg1))
2017-03-30 03:30:22 +00:00
{ name : "MULQU2" , argLength : 2 , reg : regInfo { inputs : [ ] regMask { ax , gpsp } , outputs : [ ] regMask { dx , ax } } , commutative : true , asm : "MULQ" , clobberFlags : true } , // arg0 * arg1, returns (hi, lo)
{ name : "DIVQU2" , argLength : 3 , reg : regInfo { inputs : [ ] regMask { dx , ax , gpsp } , outputs : [ ] regMask { ax , dx } } , asm : "DIVQ" , clobberFlags : true } , // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r)
2016-10-06 15:43:47 -04:00
2018-06-27 02:46:17 +00:00
{ name : "ANDQ" , argLength : 2 , reg : gp21 , asm : "ANDQ" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 & arg1
{ name : "ANDL" , argLength : 2 , reg : gp21 , asm : "ANDL" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 & arg1
{ name : "ANDQconst" , argLength : 1 , reg : gp11 , asm : "ANDQ" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 & auxint
{ name : "ANDLconst" , argLength : 1 , reg : gp11 , asm : "ANDL" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 & auxint
{ name : "ANDQconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "ANDQ" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "ANDLconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "ANDL" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "ORQ" , argLength : 2 , reg : gp21 , asm : "ORQ" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 | arg1
{ name : "ORL" , argLength : 2 , reg : gp21 , asm : "ORL" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 | arg1
{ name : "ORQconst" , argLength : 1 , reg : gp11 , asm : "ORQ" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 | auxint
{ name : "ORLconst" , argLength : 1 , reg : gp11 , asm : "ORL" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 | auxint
{ name : "ORQconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "ORQ" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "ORLconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "ORL" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "XORQ" , argLength : 2 , reg : gp21 , asm : "XORQ" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 ^ arg1
{ name : "XORL" , argLength : 2 , reg : gp21 , asm : "XORL" , commutative : true , resultInArg0 : true , clobberFlags : true } , // arg0 ^ arg1
{ name : "XORQconst" , argLength : 1 , reg : gp11 , asm : "XORQ" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 ^ auxint
{ name : "XORLconst" , argLength : 1 , reg : gp11 , asm : "XORL" , aux : "Int32" , resultInArg0 : true , clobberFlags : true } , // arg0 ^ auxint
{ name : "XORQconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "XORQ" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "XORLconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "XORL" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
2016-02-27 08:04:48 -06:00
{ name : "CMPQ" , argLength : 2 , reg : gp2flags , asm : "CMPQ" , typ : "Flags" } , // arg0 compare to arg1
{ name : "CMPL" , argLength : 2 , reg : gp2flags , asm : "CMPL" , typ : "Flags" } , // arg0 compare to arg1
{ name : "CMPW" , argLength : 2 , reg : gp2flags , asm : "CMPW" , typ : "Flags" } , // arg0 compare to arg1
{ name : "CMPB" , argLength : 2 , reg : gp2flags , asm : "CMPB" , typ : "Flags" } , // arg0 compare to arg1
2017-08-28 12:57:52 -07:00
{ name : "CMPQconst" , argLength : 1 , reg : gp1flags , asm : "CMPQ" , typ : "Flags" , aux : "Int32" } , // arg0 compare to auxint
2016-02-27 08:04:48 -06:00
{ name : "CMPLconst" , argLength : 1 , reg : gp1flags , asm : "CMPL" , typ : "Flags" , aux : "Int32" } , // arg0 compare to auxint
{ name : "CMPWconst" , argLength : 1 , reg : gp1flags , asm : "CMPW" , typ : "Flags" , aux : "Int16" } , // arg0 compare to auxint
{ name : "CMPBconst" , argLength : 1 , reg : gp1flags , asm : "CMPB" , typ : "Flags" , aux : "Int8" } , // arg0 compare to auxint
2018-01-03 14:38:55 -08:00
// compare *(arg0+auxint+aux) to arg1 (in that order). arg2=mem.
2018-05-08 09:11:00 -07:00
{ name : "CMPQload" , argLength : 3 , reg : gp1flagsLoad , asm : "CMPQ" , aux : "SymOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
{ name : "CMPLload" , argLength : 3 , reg : gp1flagsLoad , asm : "CMPL" , aux : "SymOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
{ name : "CMPWload" , argLength : 3 , reg : gp1flagsLoad , asm : "CMPW" , aux : "SymOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
{ name : "CMPBload" , argLength : 3 , reg : gp1flagsLoad , asm : "CMPB" , aux : "SymOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
2018-01-03 14:38:55 -08:00
// compare *(arg0+ValAndOff(AuxInt).Off()+aux) to ValAndOff(AuxInt).Val() (in that order). arg1=mem.
2018-05-08 09:11:00 -07:00
{ name : "CMPQconstload" , argLength : 2 , reg : gp0flagsLoad , asm : "CMPQ" , aux : "SymValAndOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
{ name : "CMPLconstload" , argLength : 2 , reg : gp0flagsLoad , asm : "CMPL" , aux : "SymValAndOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
{ name : "CMPWconstload" , argLength : 2 , reg : gp0flagsLoad , asm : "CMPW" , aux : "SymValAndOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
{ name : "CMPBconstload" , argLength : 2 , reg : gp0flagsLoad , asm : "CMPB" , aux : "SymValAndOff" , typ : "Flags" , symEffect : "Read" , faultOnNilArg0 : true } ,
2018-01-03 14:38:55 -08:00
2016-02-27 08:04:48 -06:00
{ name : "UCOMISS" , argLength : 2 , reg : fp2flags , asm : "UCOMISS" , typ : "Flags" } , // arg0 compare to arg1, f32
{ name : "UCOMISD" , argLength : 2 , reg : fp2flags , asm : "UCOMISD" , typ : "Flags" } , // arg0 compare to arg1, f64
2018-09-16 03:05:35 +00:00
{ name : "BTL" , argLength : 2 , reg : gp2flags , asm : "BTL" , typ : "Flags" } , // test whether bit arg0%32 in arg1 is set
{ name : "BTQ" , argLength : 2 , reg : gp2flags , asm : "BTQ" , typ : "Flags" } , // test whether bit arg0%64 in arg1 is set
{ name : "BTCL" , argLength : 2 , reg : gp21 , asm : "BTCL" , resultInArg0 : true , clobberFlags : true } , // complement bit arg1%32 in arg0
{ name : "BTCQ" , argLength : 2 , reg : gp21 , asm : "BTCQ" , resultInArg0 : true , clobberFlags : true } , // complement bit arg1%64 in arg0
{ name : "BTRL" , argLength : 2 , reg : gp21 , asm : "BTRL" , resultInArg0 : true , clobberFlags : true } , // reset bit arg1%32 in arg0
{ name : "BTRQ" , argLength : 2 , reg : gp21 , asm : "BTRQ" , resultInArg0 : true , clobberFlags : true } , // reset bit arg1%64 in arg0
{ name : "BTSL" , argLength : 2 , reg : gp21 , asm : "BTSL" , resultInArg0 : true , clobberFlags : true } , // set bit arg1%32 in arg0
{ name : "BTSQ" , argLength : 2 , reg : gp21 , asm : "BTSQ" , resultInArg0 : true , clobberFlags : true } , // set bit arg1%64 in arg0
cmd/compile: add patterns for bit set/clear/complement on amd64
This patch completes implementation of BT(Q|L), and adds support
for BT(S|R|C)(Q|L).
Example of code changes from time.(*Time).addSec:
if t.wall&hasMonotonic != 0 {
0x1073465 488b08 MOVQ 0(AX), CX
0x1073468 4889ca MOVQ CX, DX
0x107346b 48c1e93f SHRQ $0x3f, CX
0x107346f 48c1e13f SHLQ $0x3f, CX
0x1073473 48f7c1ffffffff TESTQ $-0x1, CX
0x107347a 746b JE 0x10734e7
if t.wall&hasMonotonic != 0 {
0x1073435 488b08 MOVQ 0(AX), CX
0x1073438 480fbae13f BTQ $0x3f, CX
0x107343d 7363 JAE 0x10734a2
Another example:
t.wall = t.wall&nsecMask | uint64(dsec)<<nsecShift | hasMonotonic
0x10734c8 4881e1ffffff3f ANDQ $0x3fffffff, CX
0x10734cf 48c1e61e SHLQ $0x1e, SI
0x10734d3 4809ce ORQ CX, SI
0x10734d6 48b90000000000000080 MOVQ $0x8000000000000000, CX
0x10734e0 4809f1 ORQ SI, CX
0x10734e3 488908 MOVQ CX, 0(AX)
t.wall = t.wall&nsecMask | uint64(dsec)<<nsecShift | hasMonotonic
0x107348b 4881e2ffffff3f ANDQ $0x3fffffff, DX
0x1073492 48c1e61e SHLQ $0x1e, SI
0x1073496 4809f2 ORQ SI, DX
0x1073499 480fbaea3f BTSQ $0x3f, DX
0x107349e 488910 MOVQ DX, 0(AX)
Go1 benchmarks seem unaffected, and I would be surprised
otherwise:
name old time/op new time/op delta
BinaryTree17-4 2.64s ± 4% 2.56s ± 9% -2.92% (p=0.008 n=9+9)
Fannkuch11-4 2.90s ± 1% 2.95s ± 3% +1.76% (p=0.010 n=10+9)
FmtFprintfEmpty-4 35.3ns ± 1% 34.5ns ± 2% -2.34% (p=0.004 n=9+8)
FmtFprintfString-4 57.0ns ± 1% 58.4ns ± 5% +2.52% (p=0.029 n=9+10)
FmtFprintfInt-4 59.8ns ± 3% 59.8ns ± 6% ~ (p=0.565 n=10+10)
FmtFprintfIntInt-4 93.9ns ± 3% 91.2ns ± 5% -2.94% (p=0.014 n=10+9)
FmtFprintfPrefixedInt-4 107ns ± 6% 104ns ± 6% ~ (p=0.099 n=10+10)
FmtFprintfFloat-4 187ns ± 3% 188ns ± 3% ~ (p=0.505 n=10+9)
FmtManyArgs-4 410ns ± 1% 415ns ± 6% ~ (p=0.649 n=8+10)
GobDecode-4 5.30ms ± 3% 5.27ms ± 3% ~ (p=0.436 n=10+10)
GobEncode-4 4.62ms ± 5% 4.47ms ± 2% -3.24% (p=0.001 n=9+10)
Gzip-4 197ms ± 4% 193ms ± 3% ~ (p=0.123 n=10+10)
Gunzip-4 30.4ms ± 3% 30.1ms ± 3% ~ (p=0.481 n=10+10)
HTTPClientServer-4 76.3µs ± 1% 76.0µs ± 1% ~ (p=0.236 n=8+9)
JSONEncode-4 10.5ms ± 9% 10.3ms ± 3% ~ (p=0.280 n=10+10)
JSONDecode-4 42.3ms ±10% 41.3ms ± 2% ~ (p=0.053 n=9+10)
Mandelbrot200-4 3.80ms ± 2% 3.72ms ± 2% -2.15% (p=0.001 n=9+10)
GoParse-4 2.88ms ±10% 2.81ms ± 2% ~ (p=0.247 n=10+10)
RegexpMatchEasy0_32-4 69.5ns ± 4% 68.6ns ± 2% ~ (p=0.171 n=10+10)
RegexpMatchEasy0_1K-4 165ns ± 3% 162ns ± 3% ~ (p=0.137 n=10+10)
RegexpMatchEasy1_32-4 65.7ns ± 6% 64.4ns ± 2% -2.02% (p=0.037 n=10+10)
RegexpMatchEasy1_1K-4 278ns ± 2% 279ns ± 3% ~ (p=0.991 n=8+9)
RegexpMatchMedium_32-4 99.3ns ± 3% 98.5ns ± 4% ~ (p=0.457 n=10+9)
RegexpMatchMedium_1K-4 30.1µs ± 1% 30.4µs ± 2% ~ (p=0.173 n=8+10)
RegexpMatchHard_32-4 1.40µs ± 2% 1.41µs ± 4% ~ (p=0.565 n=10+10)
RegexpMatchHard_1K-4 42.5µs ± 1% 41.5µs ± 3% -2.13% (p=0.002 n=8+9)
Revcomp-4 332ms ± 4% 328ms ± 5% ~ (p=0.720 n=9+10)
Template-4 48.3ms ± 2% 49.6ms ± 3% +2.56% (p=0.002 n=8+10)
TimeParse-4 252ns ± 2% 249ns ± 3% ~ (p=0.116 n=9+10)
TimeFormat-4 262ns ± 4% 252ns ± 3% -4.01% (p=0.000 n=9+10)
name old speed new speed delta
GobDecode-4 145MB/s ± 3% 146MB/s ± 3% ~ (p=0.436 n=10+10)
GobEncode-4 166MB/s ± 5% 172MB/s ± 2% +3.28% (p=0.001 n=9+10)
Gzip-4 98.6MB/s ± 4% 100.4MB/s ± 3% ~ (p=0.123 n=10+10)
Gunzip-4 639MB/s ± 3% 645MB/s ± 3% ~ (p=0.481 n=10+10)
JSONEncode-4 185MB/s ± 8% 189MB/s ± 3% ~ (p=0.280 n=10+10)
JSONDecode-4 46.0MB/s ± 9% 47.0MB/s ± 2% +2.21% (p=0.046 n=9+10)
GoParse-4 20.1MB/s ± 9% 20.6MB/s ± 2% ~ (p=0.239 n=10+10)
RegexpMatchEasy0_32-4 460MB/s ± 4% 467MB/s ± 2% ~ (p=0.165 n=10+10)
RegexpMatchEasy0_1K-4 6.19GB/s ± 3% 6.28GB/s ± 3% ~ (p=0.165 n=10+10)
RegexpMatchEasy1_32-4 487MB/s ± 5% 497MB/s ± 2% +2.00% (p=0.043 n=10+10)
RegexpMatchEasy1_1K-4 3.67GB/s ± 2% 3.67GB/s ± 3% ~ (p=0.963 n=8+9)
RegexpMatchMedium_32-4 10.1MB/s ± 3% 10.1MB/s ± 4% ~ (p=0.435 n=10+9)
RegexpMatchMedium_1K-4 34.0MB/s ± 1% 33.7MB/s ± 2% ~ (p=0.173 n=8+10)
RegexpMatchHard_32-4 22.9MB/s ± 2% 22.7MB/s ± 4% ~ (p=0.565 n=10+10)
RegexpMatchHard_1K-4 24.0MB/s ± 3% 24.7MB/s ± 3% +2.64% (p=0.001 n=9+9)
Revcomp-4 766MB/s ± 4% 775MB/s ± 5% ~ (p=0.720 n=9+10)
Template-4 40.2MB/s ± 2% 39.2MB/s ± 3% -2.47% (p=0.002 n=8+10)
The rules match ~1800 times during all.bash.
Fixes #18943
Change-Id: I64be1ada34e89c486dfd935bf429b35652117ed4
Reviewed-on: https://go-review.googlesource.com/94766
Run-TryBot: Giovanni Bajo <rasky@develer.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2018-02-17 13:54:03 +01:00
{ name : "BTLconst" , argLength : 1 , reg : gp1flags , asm : "BTL" , typ : "Flags" , aux : "Int8" } , // test whether bit auxint in arg0 is set, 0 <= auxint < 32
{ name : "BTQconst" , argLength : 1 , reg : gp1flags , asm : "BTQ" , typ : "Flags" , aux : "Int8" } , // test whether bit auxint in arg0 is set, 0 <= auxint < 64
{ name : "BTCLconst" , argLength : 1 , reg : gp11 , asm : "BTCL" , resultInArg0 : true , clobberFlags : true , aux : "Int8" } , // complement bit auxint in arg0, 0 <= auxint < 32
{ name : "BTCQconst" , argLength : 1 , reg : gp11 , asm : "BTCQ" , resultInArg0 : true , clobberFlags : true , aux : "Int8" } , // complement bit auxint in arg0, 0 <= auxint < 64
{ name : "BTRLconst" , argLength : 1 , reg : gp11 , asm : "BTRL" , resultInArg0 : true , clobberFlags : true , aux : "Int8" } , // reset bit auxint in arg0, 0 <= auxint < 32
{ name : "BTRQconst" , argLength : 1 , reg : gp11 , asm : "BTRQ" , resultInArg0 : true , clobberFlags : true , aux : "Int8" } , // reset bit auxint in arg0, 0 <= auxint < 64
{ name : "BTSLconst" , argLength : 1 , reg : gp11 , asm : "BTSL" , resultInArg0 : true , clobberFlags : true , aux : "Int8" } , // set bit auxint in arg0, 0 <= auxint < 32
{ name : "BTSQconst" , argLength : 1 , reg : gp11 , asm : "BTSQ" , resultInArg0 : true , clobberFlags : true , aux : "Int8" } , // set bit auxint in arg0, 0 <= auxint < 64
2017-02-06 10:55:39 -08:00
2018-09-17 02:05:22 +00:00
// direct bit operation on memory operand
{ name : "BTCQmodify" , argLength : 3 , reg : gpstore , asm : "BTCQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // complement bit arg1 in 64-bit arg0+auxint+aux, arg2=mem
{ name : "BTCLmodify" , argLength : 3 , reg : gpstore , asm : "BTCL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // complement bit arg1 in 32-bit arg0+auxint+aux, arg2=mem
{ name : "BTSQmodify" , argLength : 3 , reg : gpstore , asm : "BTSQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // set bit arg1 in 64-bit arg0+auxint+aux, arg2=mem
{ name : "BTSLmodify" , argLength : 3 , reg : gpstore , asm : "BTSL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // set bit arg1 in 32-bit arg0+auxint+aux, arg2=mem
{ name : "BTRQmodify" , argLength : 3 , reg : gpstore , asm : "BTRQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // reset bit arg1 in 64-bit arg0+auxint+aux, arg2=mem
{ name : "BTRLmodify" , argLength : 3 , reg : gpstore , asm : "BTRL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // reset bit arg1 in 32-bit arg0+auxint+aux, arg2=mem
{ name : "BTCQconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "BTCQ" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // complement bit ValAndOff(AuxInt).Val() in 64-bit arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "BTCLconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "BTCL" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // complement bit ValAndOff(AuxInt).Val() in 32-bit arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "BTSQconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "BTSQ" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // set bit ValAndOff(AuxInt).Val() in 64-bit arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "BTSLconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "BTSL" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // set bit ValAndOff(AuxInt).Val() in 32-bit arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "BTRQconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "BTRQ" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // reset bit ValAndOff(AuxInt).Val() in 64-bit arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
{ name : "BTRLconstmodify" , argLength : 2 , reg : gpstoreconst , asm : "BTRL" , aux : "SymValAndOff" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // reset bit ValAndOff(AuxInt).Val() in 32-bit arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem
2017-03-30 03:30:22 +00:00
{ name : "TESTQ" , argLength : 2 , reg : gp2flags , commutative : true , asm : "TESTQ" , typ : "Flags" } , // (arg0 & arg1) compare to 0
{ name : "TESTL" , argLength : 2 , reg : gp2flags , commutative : true , asm : "TESTL" , typ : "Flags" } , // (arg0 & arg1) compare to 0
{ name : "TESTW" , argLength : 2 , reg : gp2flags , commutative : true , asm : "TESTW" , typ : "Flags" } , // (arg0 & arg1) compare to 0
{ name : "TESTB" , argLength : 2 , reg : gp2flags , commutative : true , asm : "TESTB" , typ : "Flags" } , // (arg0 & arg1) compare to 0
2017-08-28 12:57:52 -07:00
{ name : "TESTQconst" , argLength : 1 , reg : gp1flags , asm : "TESTQ" , typ : "Flags" , aux : "Int32" } , // (arg0 & auxint) compare to 0
2016-02-27 08:04:48 -06:00
{ name : "TESTLconst" , argLength : 1 , reg : gp1flags , asm : "TESTL" , typ : "Flags" , aux : "Int32" } , // (arg0 & auxint) compare to 0
{ name : "TESTWconst" , argLength : 1 , reg : gp1flags , asm : "TESTW" , typ : "Flags" , aux : "Int16" } , // (arg0 & auxint) compare to 0
{ name : "TESTBconst" , argLength : 1 , reg : gp1flags , asm : "TESTB" , typ : "Flags" , aux : "Int8" } , // (arg0 & auxint) compare to 0
2017-03-30 03:30:22 +00:00
{ name : "SHLQ" , argLength : 2 , reg : gp21shift , asm : "SHLQ" , resultInArg0 : true , clobberFlags : true } , // arg0 << arg1, shift amount is mod 64
{ name : "SHLL" , argLength : 2 , reg : gp21shift , asm : "SHLL" , resultInArg0 : true , clobberFlags : true } , // arg0 << arg1, shift amount is mod 32
{ name : "SHLQconst" , argLength : 1 , reg : gp11 , asm : "SHLQ" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // arg0 << auxint, shift amount 0-63
{ name : "SHLLconst" , argLength : 1 , reg : gp11 , asm : "SHLL" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // arg0 << auxint, shift amount 0-31
2015-07-28 16:04:50 -07:00
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
2017-03-30 03:30:22 +00:00
{ name : "SHRQ" , argLength : 2 , reg : gp21shift , asm : "SHRQ" , resultInArg0 : true , clobberFlags : true } , // unsigned arg0 >> arg1, shift amount is mod 64
2018-02-13 12:33:55 -08:00
{ name : "SHRL" , argLength : 2 , reg : gp21shift , asm : "SHRL" , resultInArg0 : true , clobberFlags : true } , // unsigned uint32(arg0) >> arg1, shift amount is mod 32
{ name : "SHRW" , argLength : 2 , reg : gp21shift , asm : "SHRW" , resultInArg0 : true , clobberFlags : true } , // unsigned uint16(arg0) >> arg1, shift amount is mod 32
{ name : "SHRB" , argLength : 2 , reg : gp21shift , asm : "SHRB" , resultInArg0 : true , clobberFlags : true } , // unsigned uint8(arg0) >> arg1, shift amount is mod 32
2017-03-30 03:30:22 +00:00
{ name : "SHRQconst" , argLength : 1 , reg : gp11 , asm : "SHRQ" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // unsigned arg0 >> auxint, shift amount 0-63
2018-02-13 12:33:55 -08:00
{ name : "SHRLconst" , argLength : 1 , reg : gp11 , asm : "SHRL" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // unsigned uint32(arg0) >> auxint, shift amount 0-31
{ name : "SHRWconst" , argLength : 1 , reg : gp11 , asm : "SHRW" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // unsigned uint16(arg0) >> auxint, shift amount 0-15
{ name : "SHRBconst" , argLength : 1 , reg : gp11 , asm : "SHRB" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // unsigned uint8(arg0) >> auxint, shift amount 0-7
2017-03-30 03:30:22 +00:00
{ name : "SARQ" , argLength : 2 , reg : gp21shift , asm : "SARQ" , resultInArg0 : true , clobberFlags : true } , // signed arg0 >> arg1, shift amount is mod 64
2018-02-13 12:33:55 -08:00
{ name : "SARL" , argLength : 2 , reg : gp21shift , asm : "SARL" , resultInArg0 : true , clobberFlags : true } , // signed int32(arg0) >> arg1, shift amount is mod 32
{ name : "SARW" , argLength : 2 , reg : gp21shift , asm : "SARW" , resultInArg0 : true , clobberFlags : true } , // signed int16(arg0) >> arg1, shift amount is mod 32
{ name : "SARB" , argLength : 2 , reg : gp21shift , asm : "SARB" , resultInArg0 : true , clobberFlags : true } , // signed int8(arg0) >> arg1, shift amount is mod 32
2017-03-30 03:30:22 +00:00
{ name : "SARQconst" , argLength : 1 , reg : gp11 , asm : "SARQ" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // signed arg0 >> auxint, shift amount 0-63
2018-02-13 12:33:55 -08:00
{ name : "SARLconst" , argLength : 1 , reg : gp11 , asm : "SARL" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // signed int32(arg0) >> auxint, shift amount 0-31
{ name : "SARWconst" , argLength : 1 , reg : gp11 , asm : "SARW" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // signed int16(arg0) >> auxint, shift amount 0-15
{ name : "SARBconst" , argLength : 1 , reg : gp11 , asm : "SARB" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // signed int8(arg0) >> auxint, shift amount 0-7
2017-03-30 03:30:22 +00:00
2017-03-29 10:04:17 -07:00
{ name : "ROLQ" , argLength : 2 , reg : gp21shift , asm : "ROLQ" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left arg1 bits.
{ name : "ROLL" , argLength : 2 , reg : gp21shift , asm : "ROLL" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left arg1 bits.
{ name : "ROLW" , argLength : 2 , reg : gp21shift , asm : "ROLW" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left arg1 bits.
{ name : "ROLB" , argLength : 2 , reg : gp21shift , asm : "ROLB" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left arg1 bits.
{ name : "RORQ" , argLength : 2 , reg : gp21shift , asm : "RORQ" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate right arg1 bits.
{ name : "RORL" , argLength : 2 , reg : gp21shift , asm : "RORL" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate right arg1 bits.
{ name : "RORW" , argLength : 2 , reg : gp21shift , asm : "RORW" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate right arg1 bits.
{ name : "RORB" , argLength : 2 , reg : gp21shift , asm : "RORB" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate right arg1 bits.
2017-03-30 03:30:22 +00:00
{ name : "ROLQconst" , argLength : 1 , reg : gp11 , asm : "ROLQ" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left auxint, rotate amount 0-63
{ name : "ROLLconst" , argLength : 1 , reg : gp11 , asm : "ROLL" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left auxint, rotate amount 0-31
{ name : "ROLWconst" , argLength : 1 , reg : gp11 , asm : "ROLW" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left auxint, rotate amount 0-15
{ name : "ROLBconst" , argLength : 1 , reg : gp11 , asm : "ROLB" , aux : "Int8" , resultInArg0 : true , clobberFlags : true } , // arg0 rotate left auxint, rotate amount 0-7
2015-08-05 22:11:14 -04:00
2018-05-08 09:11:00 -07:00
{ name : "ADDLload" , argLength : 3 , reg : gp21load , asm : "ADDL" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "ADDQload" , argLength : 3 , reg : gp21load , asm : "ADDQ" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "SUBQload" , argLength : 3 , reg : gp21load , asm : "SUBQ" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "SUBLload" , argLength : 3 , reg : gp21load , asm : "SUBL" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "ANDLload" , argLength : 3 , reg : gp21load , asm : "ANDL" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 & tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "ANDQload" , argLength : 3 , reg : gp21load , asm : "ANDQ" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 & tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "ORQload" , argLength : 3 , reg : gp21load , asm : "ORQ" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 | tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "ORLload" , argLength : 3 , reg : gp21load , asm : "ORL" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 | tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "XORQload" , argLength : 3 , reg : gp21load , asm : "XORQ" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 ^ tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
{ name : "XORLload" , argLength : 3 , reg : gp21load , asm : "XORL" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , symEffect : "Read" } , // arg0 ^ tmp, tmp loaded from arg1+auxint+aux, arg2 = mem
2017-02-10 13:17:20 -06:00
2018-06-29 02:11:53 +00:00
// direct binary-op on memory (read-modify-write)
{ name : "ADDQmodify" , argLength : 3 , reg : gpstore , asm : "ADDQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) += arg1, arg2=mem
{ name : "SUBQmodify" , argLength : 3 , reg : gpstore , asm : "SUBQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) -= arg1, arg2=mem
{ name : "ANDQmodify" , argLength : 3 , reg : gpstore , asm : "ANDQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) &= arg1, arg2=mem
{ name : "ORQmodify" , argLength : 3 , reg : gpstore , asm : "ORQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) |= arg1, arg2=mem
{ name : "XORQmodify" , argLength : 3 , reg : gpstore , asm : "XORQ" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) ^= arg1, arg2=mem
{ name : "ADDLmodify" , argLength : 3 , reg : gpstore , asm : "ADDL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) += arg1, arg2=mem
{ name : "SUBLmodify" , argLength : 3 , reg : gpstore , asm : "SUBL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) -= arg1, arg2=mem
{ name : "ANDLmodify" , argLength : 3 , reg : gpstore , asm : "ANDL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) &= arg1, arg2=mem
{ name : "ORLmodify" , argLength : 3 , reg : gpstore , asm : "ORL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) |= arg1, arg2=mem
{ name : "XORLmodify" , argLength : 3 , reg : gpstore , asm : "XORL" , aux : "SymOff" , typ : "Mem" , clobberFlags : true , faultOnNilArg0 : true , symEffect : "Read,Write" } , // *(arg0+auxint+aux) ^= arg1, arg2=mem
2015-07-28 16:04:50 -07:00
// unary ops
2016-08-04 06:57:34 -04:00
{ name : "NEGQ" , argLength : 1 , reg : gp11 , asm : "NEGQ" , resultInArg0 : true , clobberFlags : true } , // -arg0
{ name : "NEGL" , argLength : 1 , reg : gp11 , asm : "NEGL" , resultInArg0 : true , clobberFlags : true } , // -arg0
2015-06-06 16:03:33 -07:00
2016-08-04 06:57:34 -04:00
{ name : "NOTQ" , argLength : 1 , reg : gp11 , asm : "NOTQ" , resultInArg0 : true , clobberFlags : true } , // ^arg0
{ name : "NOTL" , argLength : 1 , reg : gp11 , asm : "NOTL" , resultInArg0 : true , clobberFlags : true } , // ^arg0
2015-07-29 17:07:09 -07:00
2018-04-25 14:40:17 -07:00
// BS{F,R}Q returns a tuple [result, flags]
2016-08-23 10:43:47 -07:00
// result is undefined if the input is zero.
// flags are set to "equal" if the input is zero, "not equal" otherwise.
2018-04-25 14:40:17 -07:00
// BS{F,R}L returns only the result.
2018-06-07 17:25:28 -07:00
{ name : "BSFQ" , argLength : 1 , reg : gp11flags , asm : "BSFQ" , typ : "(UInt64,Flags)" } , // # of low-order zeroes in 64-bit arg
{ name : "BSFL" , argLength : 1 , reg : gp11 , asm : "BSFL" , typ : "UInt32" , clobberFlags : true } , // # of low-order zeroes in 32-bit arg
{ name : "BSRQ" , argLength : 1 , reg : gp11flags , asm : "BSRQ" , typ : "(UInt64,Flags)" } , // # of high-order zeroes in 64-bit arg
{ name : "BSRL" , argLength : 1 , reg : gp11 , asm : "BSRL" , typ : "UInt32" , clobberFlags : true } , // # of high-order zeroes in 32-bit arg
2016-03-11 00:10:52 -05:00
2018-03-05 20:59:40 +01:00
// CMOV instructions: 64, 32 and 16-bit sizes.
// if arg2 encodes a true result, return arg1, else arg0
{ name : "CMOVQEQ" , argLength : 3 , reg : gp21 , asm : "CMOVQEQ" , resultInArg0 : true } ,
{ name : "CMOVQNE" , argLength : 3 , reg : gp21 , asm : "CMOVQNE" , resultInArg0 : true } ,
{ name : "CMOVQLT" , argLength : 3 , reg : gp21 , asm : "CMOVQLT" , resultInArg0 : true } ,
{ name : "CMOVQGT" , argLength : 3 , reg : gp21 , asm : "CMOVQGT" , resultInArg0 : true } ,
{ name : "CMOVQLE" , argLength : 3 , reg : gp21 , asm : "CMOVQLE" , resultInArg0 : true } ,
{ name : "CMOVQGE" , argLength : 3 , reg : gp21 , asm : "CMOVQGE" , resultInArg0 : true } ,
{ name : "CMOVQLS" , argLength : 3 , reg : gp21 , asm : "CMOVQLS" , resultInArg0 : true } ,
{ name : "CMOVQHI" , argLength : 3 , reg : gp21 , asm : "CMOVQHI" , resultInArg0 : true } ,
{ name : "CMOVQCC" , argLength : 3 , reg : gp21 , asm : "CMOVQCC" , resultInArg0 : true } ,
{ name : "CMOVQCS" , argLength : 3 , reg : gp21 , asm : "CMOVQCS" , resultInArg0 : true } ,
{ name : "CMOVLEQ" , argLength : 3 , reg : gp21 , asm : "CMOVLEQ" , resultInArg0 : true } ,
{ name : "CMOVLNE" , argLength : 3 , reg : gp21 , asm : "CMOVLNE" , resultInArg0 : true } ,
{ name : "CMOVLLT" , argLength : 3 , reg : gp21 , asm : "CMOVLLT" , resultInArg0 : true } ,
{ name : "CMOVLGT" , argLength : 3 , reg : gp21 , asm : "CMOVLGT" , resultInArg0 : true } ,
{ name : "CMOVLLE" , argLength : 3 , reg : gp21 , asm : "CMOVLLE" , resultInArg0 : true } ,
{ name : "CMOVLGE" , argLength : 3 , reg : gp21 , asm : "CMOVLGE" , resultInArg0 : true } ,
{ name : "CMOVLLS" , argLength : 3 , reg : gp21 , asm : "CMOVLLS" , resultInArg0 : true } ,
{ name : "CMOVLHI" , argLength : 3 , reg : gp21 , asm : "CMOVLHI" , resultInArg0 : true } ,
{ name : "CMOVLCC" , argLength : 3 , reg : gp21 , asm : "CMOVLCC" , resultInArg0 : true } ,
{ name : "CMOVLCS" , argLength : 3 , reg : gp21 , asm : "CMOVLCS" , resultInArg0 : true } ,
{ name : "CMOVWEQ" , argLength : 3 , reg : gp21 , asm : "CMOVWEQ" , resultInArg0 : true } ,
{ name : "CMOVWNE" , argLength : 3 , reg : gp21 , asm : "CMOVWNE" , resultInArg0 : true } ,
{ name : "CMOVWLT" , argLength : 3 , reg : gp21 , asm : "CMOVWLT" , resultInArg0 : true } ,
{ name : "CMOVWGT" , argLength : 3 , reg : gp21 , asm : "CMOVWGT" , resultInArg0 : true } ,
{ name : "CMOVWLE" , argLength : 3 , reg : gp21 , asm : "CMOVWLE" , resultInArg0 : true } ,
{ name : "CMOVWGE" , argLength : 3 , reg : gp21 , asm : "CMOVWGE" , resultInArg0 : true } ,
{ name : "CMOVWLS" , argLength : 3 , reg : gp21 , asm : "CMOVWLS" , resultInArg0 : true } ,
{ name : "CMOVWHI" , argLength : 3 , reg : gp21 , asm : "CMOVWHI" , resultInArg0 : true } ,
{ name : "CMOVWCC" , argLength : 3 , reg : gp21 , asm : "CMOVWCC" , resultInArg0 : true } ,
{ name : "CMOVWCS" , argLength : 3 , reg : gp21 , asm : "CMOVWCS" , resultInArg0 : true } ,
// CMOV with floating point instructions. We need separate pseudo-op to handle
// InvertFlags correctly, and to generate special code that handles NaN (unordered flag).
// NOTE: the fact that CMOV*EQF here is marked to generate CMOV*NE is not a bug. See
// code generation in amd64/ssa.go.
{ name : "CMOVQEQF" , argLength : 3 , reg : gp21pax , asm : "CMOVQNE" , resultInArg0 : true } ,
{ name : "CMOVQNEF" , argLength : 3 , reg : gp21 , asm : "CMOVQNE" , resultInArg0 : true } ,
{ name : "CMOVQGTF" , argLength : 3 , reg : gp21 , asm : "CMOVQHI" , resultInArg0 : true } ,
{ name : "CMOVQGEF" , argLength : 3 , reg : gp21 , asm : "CMOVQCC" , resultInArg0 : true } ,
2018-06-27 17:37:38 -05:00
{ name : "CMOVLEQF" , argLength : 3 , reg : gp21pax , asm : "CMOVLNE" , resultInArg0 : true } ,
2018-03-05 20:59:40 +01:00
{ name : "CMOVLNEF" , argLength : 3 , reg : gp21 , asm : "CMOVLNE" , resultInArg0 : true } ,
{ name : "CMOVLGTF" , argLength : 3 , reg : gp21 , asm : "CMOVLHI" , resultInArg0 : true } ,
{ name : "CMOVLGEF" , argLength : 3 , reg : gp21 , asm : "CMOVLCC" , resultInArg0 : true } ,
2018-06-27 17:37:38 -05:00
{ name : "CMOVWEQF" , argLength : 3 , reg : gp21pax , asm : "CMOVWNE" , resultInArg0 : true } ,
2018-03-05 20:59:40 +01:00
{ name : "CMOVWNEF" , argLength : 3 , reg : gp21 , asm : "CMOVWNE" , resultInArg0 : true } ,
{ name : "CMOVWGTF" , argLength : 3 , reg : gp21 , asm : "CMOVWHI" , resultInArg0 : true } ,
{ name : "CMOVWGEF" , argLength : 3 , reg : gp21 , asm : "CMOVWCC" , resultInArg0 : true } ,
2016-03-11 00:10:52 -05:00
2016-08-04 06:57:34 -04:00
{ name : "BSWAPQ" , argLength : 1 , reg : gp11 , asm : "BSWAPQ" , resultInArg0 : true , clobberFlags : true } , // arg0 swap bytes
{ name : "BSWAPL" , argLength : 1 , reg : gp11 , asm : "BSWAPL" , resultInArg0 : true , clobberFlags : true } , // arg0 swap bytes
2016-03-11 00:10:52 -05:00
2017-03-16 21:33:03 -07:00
// POPCNT instructions aren't guaranteed to be on the target platform (they are SSE4).
2018-11-06 17:00:04 +01:00
// Any use must be preceded by a successful check of runtime.x86HasPOPCNT.
2017-03-16 21:33:03 -07:00
{ name : "POPCNTQ" , argLength : 1 , reg : gp11 , asm : "POPCNTQ" , clobberFlags : true } , // count number of set bits in arg0
{ name : "POPCNTL" , argLength : 1 , reg : gp11 , asm : "POPCNTL" , clobberFlags : true } , // count number of set bits in arg0
2016-02-27 08:04:48 -06:00
{ name : "SQRTSD" , argLength : 1 , reg : fp11 , asm : "SQRTSD" } , // sqrt(arg0)
2015-09-12 13:26:57 -07:00
2017-10-05 15:45:46 -05:00
// ROUNDSD instruction isn't guaranteed to be on the target platform (it is SSE4.1)
2018-11-06 17:00:04 +01:00
// Any use must be preceded by a successful check of runtime.x86HasSSE41.
2017-10-05 15:45:46 -05:00
{ name : "ROUNDSD" , argLength : 1 , reg : fp11 , aux : "Int8" , asm : "ROUNDSD" } , // rounds arg0 depending on auxint, 1 means math.Floor, 2 Ceil, 3 Trunc
2018-09-25 03:10:33 -04:00
// VFMADD231SD only exists on platforms with the FMA3 instruction set.
// Any use must be preceded by a successful check of runtime.support_fma.
{ name : "VFMADD231SD" , argLength : 3 , reg : fp31 , resultInArg0 : true , asm : "VFMADD231SD" } ,
2016-02-27 08:04:48 -06:00
{ name : "SBBQcarrymask" , argLength : 1 , reg : flagsgp , asm : "SBBQ" } , // (int64)(-1) if carry is set, 0 if carry is clear.
{ name : "SBBLcarrymask" , argLength : 1 , reg : flagsgp , asm : "SBBL" } , // (int32)(-1) if carry is set, 0 if carry is clear.
2015-07-29 17:07:09 -07:00
// Note: SBBW and SBBB are subsumed by SBBL
2015-06-10 10:39:57 -07:00
2016-02-27 08:04:48 -06:00
{ name : "SETEQ" , argLength : 1 , reg : readflags , asm : "SETEQ" } , // extract == condition from arg0
{ name : "SETNE" , argLength : 1 , reg : readflags , asm : "SETNE" } , // extract != condition from arg0
{ name : "SETL" , argLength : 1 , reg : readflags , asm : "SETLT" } , // extract signed < condition from arg0
{ name : "SETLE" , argLength : 1 , reg : readflags , asm : "SETLE" } , // extract signed <= condition from arg0
{ name : "SETG" , argLength : 1 , reg : readflags , asm : "SETGT" } , // extract signed > condition from arg0
{ name : "SETGE" , argLength : 1 , reg : readflags , asm : "SETGE" } , // extract signed >= condition from arg0
{ name : "SETB" , argLength : 1 , reg : readflags , asm : "SETCS" } , // extract unsigned < condition from arg0
{ name : "SETBE" , argLength : 1 , reg : readflags , asm : "SETLS" } , // extract unsigned <= condition from arg0
{ name : "SETA" , argLength : 1 , reg : readflags , asm : "SETHI" } , // extract unsigned > condition from arg0
{ name : "SETAE" , argLength : 1 , reg : readflags , asm : "SETCC" } , // extract unsigned >= condition from arg0
2018-01-27 11:55:34 +01:00
{ name : "SETO" , argLength : 1 , reg : readflags , asm : "SETOS" } , // extract if overflow flag is set from arg0
2017-10-03 14:12:00 -05:00
// Variants that store result to memory
2018-05-08 09:11:00 -07:00
{ name : "SETEQstore" , argLength : 3 , reg : gpstoreconst , asm : "SETEQ" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract == condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETNEstore" , argLength : 3 , reg : gpstoreconst , asm : "SETNE" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract != condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETLstore" , argLength : 3 , reg : gpstoreconst , asm : "SETLT" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract signed < condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETLEstore" , argLength : 3 , reg : gpstoreconst , asm : "SETLE" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract signed <= condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETGstore" , argLength : 3 , reg : gpstoreconst , asm : "SETGT" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract signed > condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETGEstore" , argLength : 3 , reg : gpstoreconst , asm : "SETGE" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract signed >= condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETBstore" , argLength : 3 , reg : gpstoreconst , asm : "SETCS" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract unsigned < condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETBEstore" , argLength : 3 , reg : gpstoreconst , asm : "SETLS" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract unsigned <= condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETAstore" , argLength : 3 , reg : gpstoreconst , asm : "SETHI" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract unsigned > condition from arg1 to arg0+auxint+aux, arg2=mem
{ name : "SETAEstore" , argLength : 3 , reg : gpstoreconst , asm : "SETCC" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // extract unsigned >= condition from arg1 to arg0+auxint+aux, arg2=mem
2015-08-18 14:39:26 -04:00
// Need different opcodes for floating point conditions because
// any comparison involving a NaN is always FALSE and thus
// the patterns for inverting conditions cannot be used.
2016-08-04 06:57:34 -04:00
{ name : "SETEQF" , argLength : 1 , reg : flagsgpax , asm : "SETEQ" , clobberFlags : true } , // extract == condition from arg0
{ name : "SETNEF" , argLength : 1 , reg : flagsgpax , asm : "SETNE" , clobberFlags : true } , // extract != condition from arg0
{ name : "SETORD" , argLength : 1 , reg : flagsgp , asm : "SETPC" } , // extract "ordered" (No Nan present) condition from arg0
{ name : "SETNAN" , argLength : 1 , reg : flagsgp , asm : "SETPS" } , // extract "unordered" (Nan present) condition from arg0
2015-08-18 14:39:26 -04:00
2016-02-27 08:04:48 -06:00
{ name : "SETGF" , argLength : 1 , reg : flagsgp , asm : "SETHI" } , // extract floating > condition from arg0
{ name : "SETGEF" , argLength : 1 , reg : flagsgp , asm : "SETCC" } , // extract floating >= condition from arg0
2015-06-06 16:03:33 -07:00
2016-08-04 06:57:34 -04:00
{ name : "MOVBQSX" , argLength : 1 , reg : gp11 , asm : "MOVBQSX" } , // sign extend arg0 from int8 to int64
2016-06-02 12:41:42 -07:00
{ name : "MOVBQZX" , argLength : 1 , reg : gp11 , asm : "MOVBLZX" } , // zero extend arg0 from int8 to int64
2016-08-04 06:57:34 -04:00
{ name : "MOVWQSX" , argLength : 1 , reg : gp11 , asm : "MOVWQSX" } , // sign extend arg0 from int16 to int64
2016-06-02 12:41:42 -07:00
{ name : "MOVWQZX" , argLength : 1 , reg : gp11 , asm : "MOVWLZX" } , // zero extend arg0 from int16 to int64
2016-08-04 06:57:34 -04:00
{ name : "MOVLQSX" , argLength : 1 , reg : gp11 , asm : "MOVLQSX" } , // sign extend arg0 from int32 to int64
2016-06-02 12:41:42 -07:00
{ name : "MOVLQZX" , argLength : 1 , reg : gp11 , asm : "MOVL" } , // zero extend arg0 from int32 to int64
2015-06-14 11:38:46 -07:00
2016-01-31 11:39:39 -08:00
{ name : "MOVLconst" , reg : gp01 , asm : "MOVL" , typ : "UInt32" , aux : "Int32" , rematerializeable : true } , // 32 low bits of auxint
{ name : "MOVQconst" , reg : gp01 , asm : "MOVQ" , typ : "UInt64" , aux : "Int64" , rematerializeable : true } , // auxint
2015-07-28 14:19:20 -07:00
2016-02-27 08:04:48 -06:00
{ name : "CVTTSD2SL" , argLength : 1 , reg : fpgp , asm : "CVTTSD2SL" } , // convert float64 to int32
{ name : "CVTTSD2SQ" , argLength : 1 , reg : fpgp , asm : "CVTTSD2SQ" } , // convert float64 to int64
{ name : "CVTTSS2SL" , argLength : 1 , reg : fpgp , asm : "CVTTSS2SL" } , // convert float32 to int32
{ name : "CVTTSS2SQ" , argLength : 1 , reg : fpgp , asm : "CVTTSS2SQ" } , // convert float32 to int64
{ name : "CVTSL2SS" , argLength : 1 , reg : gpfp , asm : "CVTSL2SS" } , // convert int32 to float32
{ name : "CVTSL2SD" , argLength : 1 , reg : gpfp , asm : "CVTSL2SD" } , // convert int32 to float64
{ name : "CVTSQ2SS" , argLength : 1 , reg : gpfp , asm : "CVTSQ2SS" } , // convert int64 to float32
{ name : "CVTSQ2SD" , argLength : 1 , reg : gpfp , asm : "CVTSQ2SD" } , // convert int64 to float64
{ name : "CVTSD2SS" , argLength : 1 , reg : fp11 , asm : "CVTSD2SS" } , // convert float64 to float32
{ name : "CVTSS2SD" , argLength : 1 , reg : fp11 , asm : "CVTSS2SD" } , // convert float32 to float64
cmd/compile,math: improve code generation for math.Abs
Implement int reg <-> fp reg moves on amd64.
If we see a load to int reg followed by an int->fp move, then we can just
load to the fp reg instead. Same for stores.
math.Abs is now:
MOVQ "".x+8(SP), AX
SHLQ $1, AX
SHRQ $1, AX
MOVQ AX, "".~r1+16(SP)
math.Copysign is now:
MOVQ "".x+8(SP), AX
SHLQ $1, AX
SHRQ $1, AX
MOVQ "".y+16(SP), CX
SHRQ $63, CX
SHLQ $63, CX
ORQ CX, AX
MOVQ AX, "".~r2+24(SP)
math.Float64bits is now:
MOVSD "".x+8(SP), X0
MOVSD X0, "".~r1+16(SP)
(it would be nicer to use a non-SSE reg for this, nothing is perfect)
And due to the fix for #21440, the inlined version of these improve as well.
name old time/op new time/op delta
Abs 1.38ns ± 5% 0.89ns ±10% -35.54% (p=0.000 n=10+10)
Copysign 1.56ns ± 7% 1.35ns ± 6% -13.77% (p=0.000 n=9+10)
Fixes #13095
Change-Id: Ibd7f2792412a6668608780b0688a77062e1f1499
Reviewed-on: https://go-review.googlesource.com/58732
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Ilya Tocar <ilya.tocar@intel.com>
2017-08-24 13:19:40 -07:00
// Move values between int and float registers, with no conversion.
// TODO: should we have generic versions of these?
{ name : "MOVQi2f" , argLength : 1 , reg : gpfp , typ : "Float64" } , // move 64 bits from int to float reg
{ name : "MOVQf2i" , argLength : 1 , reg : fpgp , typ : "UInt64" } , // move 64 bits from float to int reg
{ name : "MOVLi2f" , argLength : 1 , reg : gpfp , typ : "Float32" } , // move 32 bits from int to float reg
2018-05-10 10:15:52 -07:00
{ name : "MOVLf2i" , argLength : 1 , reg : fpgp , typ : "UInt32" } , // move 32 bits from float to int reg, zero extend
cmd/compile,math: improve code generation for math.Abs
Implement int reg <-> fp reg moves on amd64.
If we see a load to int reg followed by an int->fp move, then we can just
load to the fp reg instead. Same for stores.
math.Abs is now:
MOVQ "".x+8(SP), AX
SHLQ $1, AX
SHRQ $1, AX
MOVQ AX, "".~r1+16(SP)
math.Copysign is now:
MOVQ "".x+8(SP), AX
SHLQ $1, AX
SHRQ $1, AX
MOVQ "".y+16(SP), CX
SHRQ $63, CX
SHLQ $63, CX
ORQ CX, AX
MOVQ AX, "".~r2+24(SP)
math.Float64bits is now:
MOVSD "".x+8(SP), X0
MOVSD X0, "".~r1+16(SP)
(it would be nicer to use a non-SSE reg for this, nothing is perfect)
And due to the fix for #21440, the inlined version of these improve as well.
name old time/op new time/op delta
Abs 1.38ns ± 5% 0.89ns ±10% -35.54% (p=0.000 n=10+10)
Copysign 1.56ns ± 7% 1.35ns ± 6% -13.77% (p=0.000 n=9+10)
Fixes #13095
Change-Id: Ibd7f2792412a6668608780b0688a77062e1f1499
Reviewed-on: https://go-review.googlesource.com/58732
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Ilya Tocar <ilya.tocar@intel.com>
2017-08-24 13:19:40 -07:00
2016-03-10 13:05:56 -08:00
{ name : "PXOR" , argLength : 2 , reg : fp21 , asm : "PXOR" , commutative : true , resultInArg0 : true } , // exclusive or, applied to X regs for float negation.
2016-02-27 08:04:48 -06:00
2019-03-09 12:41:34 -08:00
{ name : "LEAQ" , argLength : 1 , reg : gp11sb , asm : "LEAQ" , aux : "SymOff" , rematerializeable : true , symEffect : "Addr" } , // arg0 + auxint + offset encoded in aux
{ name : "LEAL" , argLength : 1 , reg : gp11sb , asm : "LEAL" , aux : "SymOff" , rematerializeable : true , symEffect : "Addr" } , // arg0 + auxint + offset encoded in aux
{ name : "LEAW" , argLength : 1 , reg : gp11sb , asm : "LEAW" , aux : "SymOff" , rematerializeable : true , symEffect : "Addr" } , // arg0 + auxint + offset encoded in aux
{ name : "LEAQ1" , argLength : 2 , reg : gp21sb , asm : "LEAQ" , scale : 1 , commutative : true , aux : "SymOff" , symEffect : "Addr" } , // arg0 + arg1 + auxint + aux
{ name : "LEAL1" , argLength : 2 , reg : gp21sb , asm : "LEAL" , scale : 1 , commutative : true , aux : "SymOff" , symEffect : "Addr" } , // arg0 + arg1 + auxint + aux
{ name : "LEAW1" , argLength : 2 , reg : gp21sb , asm : "LEAW" , scale : 1 , commutative : true , aux : "SymOff" , symEffect : "Addr" } , // arg0 + arg1 + auxint + aux
{ name : "LEAQ2" , argLength : 2 , reg : gp21sb , asm : "LEAQ" , scale : 2 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 2*arg1 + auxint + aux
{ name : "LEAL2" , argLength : 2 , reg : gp21sb , asm : "LEAL" , scale : 2 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 2*arg1 + auxint + aux
{ name : "LEAW2" , argLength : 2 , reg : gp21sb , asm : "LEAW" , scale : 2 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 2*arg1 + auxint + aux
{ name : "LEAQ4" , argLength : 2 , reg : gp21sb , asm : "LEAQ" , scale : 4 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 4*arg1 + auxint + aux
{ name : "LEAL4" , argLength : 2 , reg : gp21sb , asm : "LEAL" , scale : 4 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 4*arg1 + auxint + aux
{ name : "LEAW4" , argLength : 2 , reg : gp21sb , asm : "LEAW" , scale : 4 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 4*arg1 + auxint + aux
{ name : "LEAQ8" , argLength : 2 , reg : gp21sb , asm : "LEAQ" , scale : 8 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 8*arg1 + auxint + aux
{ name : "LEAL8" , argLength : 2 , reg : gp21sb , asm : "LEAL" , scale : 8 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 8*arg1 + auxint + aux
{ name : "LEAW8" , argLength : 2 , reg : gp21sb , asm : "LEAW" , scale : 8 , aux : "SymOff" , symEffect : "Addr" } , // arg0 + 8*arg1 + auxint + aux
2018-02-26 07:04:32 -08:00
// Note: LEAx{1,2,4,8} must not have OpSB as either argument.
2016-08-08 11:26:25 -07:00
2015-08-23 21:14:25 -07:00
// auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
2017-03-09 14:46:43 -08:00
{ name : "MOVBload" , argLength : 2 , reg : gpload , asm : "MOVBLZX" , aux : "SymOff" , typ : "UInt8" , faultOnNilArg0 : true , symEffect : "Read" } , // load byte from arg0+auxint+aux. arg1=mem. Zero extend.
{ name : "MOVBQSXload" , argLength : 2 , reg : gpload , asm : "MOVBQSX" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } , // ditto, sign extend to int64
{ name : "MOVWload" , argLength : 2 , reg : gpload , asm : "MOVWLZX" , aux : "SymOff" , typ : "UInt16" , faultOnNilArg0 : true , symEffect : "Read" } , // load 2 bytes from arg0+auxint+aux. arg1=mem. Zero extend.
{ name : "MOVWQSXload" , argLength : 2 , reg : gpload , asm : "MOVWQSX" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } , // ditto, sign extend to int64
{ name : "MOVLload" , argLength : 2 , reg : gpload , asm : "MOVL" , aux : "SymOff" , typ : "UInt32" , faultOnNilArg0 : true , symEffect : "Read" } , // load 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend.
{ name : "MOVLQSXload" , argLength : 2 , reg : gpload , asm : "MOVLQSX" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } , // ditto, sign extend to int64
{ name : "MOVQload" , argLength : 2 , reg : gpload , asm : "MOVQ" , aux : "SymOff" , typ : "UInt64" , faultOnNilArg0 : true , symEffect : "Read" } , // load 8 bytes from arg0+auxint+aux. arg1=mem
{ name : "MOVBstore" , argLength : 3 , reg : gpstore , asm : "MOVB" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store byte in arg1 to arg0+auxint+aux. arg2=mem
{ name : "MOVWstore" , argLength : 3 , reg : gpstore , asm : "MOVW" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
{ name : "MOVLstore" , argLength : 3 , reg : gpstore , asm : "MOVL" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
{ name : "MOVQstore" , argLength : 3 , reg : gpstore , asm : "MOVQ" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
{ name : "MOVOload" , argLength : 2 , reg : fpload , asm : "MOVUPS" , aux : "SymOff" , typ : "Int128" , faultOnNilArg0 : true , symEffect : "Read" } , // load 16 bytes from arg0+auxint+aux. arg1=mem
{ name : "MOVOstore" , argLength : 3 , reg : fpstore , asm : "MOVUPS" , aux : "SymOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
2016-01-31 11:39:39 -08:00
2016-02-02 11:13:50 -08:00
// indexed loads/stores
2019-03-09 12:41:34 -08:00
{ name : "MOVBloadidx1" , argLength : 3 , reg : gploadidx , commutative : true , asm : "MOVBLZX" , scale : 1 , aux : "SymOff" , typ : "UInt8" , symEffect : "Read" } , // load a byte from arg0+arg1+auxint+aux. arg2=mem
{ name : "MOVWloadidx1" , argLength : 3 , reg : gploadidx , commutative : true , asm : "MOVWLZX" , scale : 1 , aux : "SymOff" , typ : "UInt16" , symEffect : "Read" } , // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem
{ name : "MOVWloadidx2" , argLength : 3 , reg : gploadidx , asm : "MOVWLZX" , scale : 2 , aux : "SymOff" , typ : "UInt16" , symEffect : "Read" } , // load 2 bytes from arg0+2*arg1+auxint+aux. arg2=mem
{ name : "MOVLloadidx1" , argLength : 3 , reg : gploadidx , commutative : true , asm : "MOVL" , scale : 1 , aux : "SymOff" , typ : "UInt32" , symEffect : "Read" } , // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem
{ name : "MOVLloadidx4" , argLength : 3 , reg : gploadidx , asm : "MOVL" , scale : 4 , aux : "SymOff" , typ : "UInt32" , symEffect : "Read" } , // load 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem
{ name : "MOVLloadidx8" , argLength : 3 , reg : gploadidx , asm : "MOVL" , scale : 8 , aux : "SymOff" , typ : "UInt32" , symEffect : "Read" } , // load 4 bytes from arg0+8*arg1+auxint+aux. arg2=mem
{ name : "MOVQloadidx1" , argLength : 3 , reg : gploadidx , commutative : true , asm : "MOVQ" , scale : 1 , aux : "SymOff" , typ : "UInt64" , symEffect : "Read" } , // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem
{ name : "MOVQloadidx8" , argLength : 3 , reg : gploadidx , asm : "MOVQ" , scale : 8 , aux : "SymOff" , typ : "UInt64" , symEffect : "Read" } , // load 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem
2016-02-02 11:13:50 -08:00
// TODO: sign-extending indexed loads
2020-01-07 13:41:02 -08:00
{ name : "MOVBstoreidx1" , argLength : 4 , reg : gpstoreidx , commutative : true , asm : "MOVB" , scale : 1 , aux : "SymOff" , symEffect : "Write" } , // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
{ name : "MOVWstoreidx1" , argLength : 4 , reg : gpstoreidx , commutative : true , asm : "MOVW" , scale : 1 , aux : "SymOff" , symEffect : "Write" } , // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
{ name : "MOVWstoreidx2" , argLength : 4 , reg : gpstoreidx , asm : "MOVW" , scale : 2 , aux : "SymOff" , symEffect : "Write" } , // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem
{ name : "MOVLstoreidx1" , argLength : 4 , reg : gpstoreidx , commutative : true , asm : "MOVL" , scale : 1 , aux : "SymOff" , symEffect : "Write" } , // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
{ name : "MOVLstoreidx4" , argLength : 4 , reg : gpstoreidx , asm : "MOVL" , scale : 4 , aux : "SymOff" , symEffect : "Write" } , // store 4 bytes in arg2 to arg0+4*arg1+auxint+aux. arg3=mem
{ name : "MOVLstoreidx8" , argLength : 4 , reg : gpstoreidx , asm : "MOVL" , scale : 8 , aux : "SymOff" , symEffect : "Write" } , // store 4 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem
{ name : "MOVQstoreidx1" , argLength : 4 , reg : gpstoreidx , commutative : true , asm : "MOVQ" , scale : 1 , aux : "SymOff" , symEffect : "Write" } , // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
{ name : "MOVQstoreidx8" , argLength : 4 , reg : gpstoreidx , asm : "MOVQ" , scale : 8 , aux : "SymOff" , symEffect : "Write" } , // store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem
2016-02-02 11:13:50 -08:00
// TODO: add size-mismatched indexed loads, like MOVBstoreidx4.
2015-09-18 18:23:34 -07:00
2015-10-21 13:13:56 -07:00
// For storeconst ops, the AuxInt field encodes both
// the value to store and an address offset of the store.
2016-01-26 15:47:08 -08:00
// Cast AuxInt to a ValAndOff to extract Val and Off fields.
2017-03-09 14:46:43 -08:00
{ name : "MOVBstoreconst" , argLength : 2 , reg : gpstoreconst , asm : "MOVB" , aux : "SymValAndOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux. arg1=mem
{ name : "MOVWstoreconst" , argLength : 2 , reg : gpstoreconst , asm : "MOVW" , aux : "SymValAndOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store low 2 bytes of ...
{ name : "MOVLstoreconst" , argLength : 2 , reg : gpstoreconst , asm : "MOVL" , aux : "SymValAndOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store low 4 bytes of ...
{ name : "MOVQstoreconst" , argLength : 2 , reg : gpstoreconst , asm : "MOVQ" , aux : "SymValAndOff" , typ : "Mem" , faultOnNilArg0 : true , symEffect : "Write" } , // store 8 bytes of ...
2020-01-07 13:41:02 -08:00
{ name : "MOVBstoreconstidx1" , argLength : 3 , reg : gpstoreconstidx , commutative : true , asm : "MOVB" , scale : 1 , aux : "SymValAndOff" , typ : "Mem" , symEffect : "Write" } , // store low byte of ValAndOff(AuxInt).Val() to arg0+1*arg1+ValAndOff(AuxInt).Off()+aux. arg2=mem
{ name : "MOVWstoreconstidx1" , argLength : 3 , reg : gpstoreconstidx , commutative : true , asm : "MOVW" , scale : 1 , aux : "SymValAndOff" , typ : "Mem" , symEffect : "Write" } , // store low 2 bytes of ... arg1 ...
{ name : "MOVWstoreconstidx2" , argLength : 3 , reg : gpstoreconstidx , asm : "MOVW" , scale : 2 , aux : "SymValAndOff" , typ : "Mem" , symEffect : "Write" } , // store low 2 bytes of ... 2*arg1 ...
{ name : "MOVLstoreconstidx1" , argLength : 3 , reg : gpstoreconstidx , commutative : true , asm : "MOVL" , scale : 1 , aux : "SymValAndOff" , typ : "Mem" , symEffect : "Write" } , // store low 4 bytes of ... arg1 ...
{ name : "MOVLstoreconstidx4" , argLength : 3 , reg : gpstoreconstidx , asm : "MOVL" , scale : 4 , aux : "SymValAndOff" , typ : "Mem" , symEffect : "Write" } , // store low 4 bytes of ... 4*arg1 ...
{ name : "MOVQstoreconstidx1" , argLength : 3 , reg : gpstoreconstidx , commutative : true , asm : "MOVQ" , scale : 1 , aux : "SymValAndOff" , typ : "Mem" , symEffect : "Write" } , // store 8 bytes of ... arg1 ...
{ name : "MOVQstoreconstidx8" , argLength : 3 , reg : gpstoreconstidx , asm : "MOVQ" , scale : 8 , aux : "SymValAndOff" , typ : "Mem" , symEffect : "Write" } , // store 8 bytes of ... 8*arg1 ...
2016-02-04 15:53:33 -08:00
2016-07-28 12:22:49 -04:00
// arg0 = pointer to start of memory to zero
2015-09-18 18:23:34 -07:00
// arg1 = value to store (will always be zero)
// arg2 = mem
2016-07-28 12:22:49 -04:00
// auxint = # of bytes to zero
2015-09-18 18:23:34 -07:00
// returns mem
{
2016-02-27 08:04:48 -06:00
name : "DUFFZERO" ,
aux : "Int64" ,
argLength : 3 ,
2015-09-18 18:23:34 -07:00
reg : regInfo {
2015-10-19 13:56:55 -07:00
inputs : [ ] regMask { buildReg ( "DI" ) , buildReg ( "X0" ) } ,
2016-08-04 06:57:34 -04:00
clobbers : buildReg ( "DI" ) ,
2015-09-18 18:23:34 -07:00
} ,
2016-11-21 11:31:39 -05:00
faultOnNilArg0 : true ,
2015-09-18 18:23:34 -07:00
} ,
2016-04-20 11:17:41 -07:00
{ name : "MOVOconst" , reg : regInfo { nil , 0 , [ ] regMask { fp } } , typ : "Int128" , aux : "Int128" , rematerializeable : true } ,
2015-09-18 18:23:34 -07:00
// arg0 = address of memory to zero
// arg1 = # of 8-byte words to zero
// arg2 = value to store (will always be zero)
// arg3 = mem
// returns mem
{
2016-02-27 08:04:48 -06:00
name : "REPSTOSQ" ,
argLength : 4 ,
2015-09-18 18:23:34 -07:00
reg : regInfo {
inputs : [ ] regMask { buildReg ( "DI" ) , buildReg ( "CX" ) , buildReg ( "AX" ) } ,
2016-03-01 15:59:15 -08:00
clobbers : buildReg ( "DI CX" ) ,
2015-09-18 18:23:34 -07:00
} ,
2016-11-21 11:31:39 -05:00
faultOnNilArg0 : true ,
2015-09-18 18:23:34 -07:00
} ,
2016-06-08 22:02:08 -07:00
{ name : "CALLstatic" , argLength : 1 , reg : regInfo { clobbers : callerSave } , aux : "SymOff" , clobberFlags : true , call : true , symEffect : "None" } , // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
2016-09-09 13:11:07 -07:00
{ name : "CALLclosure" , argLength : 3 , reg : regInfo { inputs : [ ] regMask { gpsp , buildReg ( "DX" ) , 0 } , clobbers : callerSave } , aux : "Int64" , clobberFlags : true , call : true } , // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
{ name : "CALLinter" , argLength : 2 , reg : regInfo { inputs : [ ] regMask { gp } , clobbers : callerSave } , aux : "Int64" , clobberFlags : true , call : true } , // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
2015-06-10 15:03:06 -07:00
2015-10-21 17:18:07 -07:00
// arg0 = destination pointer
// arg1 = source pointer
// arg2 = mem
// auxint = offset from duffcopy symbol to call
// returns memory
{
2016-02-27 08:04:48 -06:00
name : "DUFFCOPY" ,
aux : "Int64" ,
argLength : 3 ,
2015-10-21 17:18:07 -07:00
reg : regInfo {
inputs : [ ] regMask { buildReg ( "DI" ) , buildReg ( "SI" ) } ,
2016-08-04 06:57:34 -04:00
clobbers : buildReg ( "DI SI X0" ) , // uses X0 as a temporary
2015-10-21 17:18:07 -07:00
} ,
2016-11-21 11:31:39 -05:00
clobberFlags : true ,
faultOnNilArg0 : true ,
faultOnNilArg1 : true ,
2015-10-21 17:18:07 -07:00
} ,
// arg0 = destination pointer
// arg1 = source pointer
// arg2 = # of 8-byte words to copy
// arg3 = mem
// returns memory
{
2016-02-27 08:04:48 -06:00
name : "REPMOVSQ" ,
argLength : 4 ,
2015-10-21 17:18:07 -07:00
reg : regInfo {
inputs : [ ] regMask { buildReg ( "DI" ) , buildReg ( "SI" ) , buildReg ( "CX" ) } ,
clobbers : buildReg ( "DI SI CX" ) ,
} ,
2016-11-21 11:31:39 -05:00
faultOnNilArg0 : true ,
faultOnNilArg1 : true ,
2015-10-21 17:18:07 -07:00
} ,
2015-06-06 16:03:33 -07:00
// (InvertFlags (CMPQ a b)) == (CMPQ b a)
// So if we want (SETL (CMPQ a b)) but we can't do that because a is a constant,
// then we do (SETL (InvertFlags (CMPQ b a))) instead.
// Rewrites will convert this to (SETG (CMPQ b a)).
// InvertFlags is a pseudo-op which can't appear in assembly output.
2016-02-27 08:04:48 -06:00
{ name : "InvertFlags" , argLength : 1 } , // reverse direction of arg0
2015-08-11 09:47:45 -07:00
2015-08-12 11:22:16 -07:00
// Pseudo-ops
2016-02-27 08:04:48 -06:00
{ name : "LoweredGetG" , argLength : 1 , reg : gp01 } , // arg0=mem
2015-09-11 16:40:05 -04:00
// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
// and sorts it to the very beginning of the block to prevent other
// use of DX (the closure pointer)
2018-02-28 16:30:07 -05:00
{ name : "LoweredGetClosurePtr" , reg : regInfo { outputs : [ ] regMask { buildReg ( "DX" ) } } , zeroWidth : true } ,
2016-10-24 10:25:05 -04:00
// LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
// I.e., if f calls g "calls" getcallerpc,
// the result should be the PC within f that g will return to.
// See runtime/stubs.go for a more detailed discussion.
2017-10-13 11:05:12 -04:00
{ name : "LoweredGetCallerPC" , reg : gp01 , rematerializeable : true } ,
2017-10-09 15:33:29 -04:00
// LoweredGetCallerSP returns the SP of the caller of the current function.
{ name : "LoweredGetCallerSP" , reg : gp01 , rematerializeable : true } ,
2015-10-23 19:12:49 -07:00
//arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
2016-09-27 14:39:27 -07:00
{ name : "LoweredNilCheck" , argLength : 2 , reg : regInfo { inputs : [ ] regMask { gpsp } } , clobberFlags : true , nilCheck : true , faultOnNilArg0 : true } ,
2017-10-26 12:33:04 -04:00
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
// It saves all GP registers if necessary, but may clobber others.
cmd/compile, runtime: use more registers for amd64 write barrier calls
The compiler-inserted write barrier calls use a special ABI
for speed and to minimize the binary size impact.
runtime.gcWriteBarrier takes its args in DI and AX.
This change adds gcWriteBarrier wrapper functions,
varying only in the register used for the second argument.
(Allowing variation in the first argument doesn't offer improvements,
which is convenient, as it avoids quadratic API growth.)
This reduces the number of register copies.
The goals are reduced binary size via reduced register pressure/copies.
One downside to this change is that when the write barrier is on,
we may bounce through several different write barrier wrappers,
which is bad for the instruction cache.
Package runtime write barrier benchmarks for this change:
name old time/op new time/op delta
WriteBarrier-8 16.6ns ± 6% 15.6ns ± 6% -5.73% (p=0.000 n=97+99)
BulkWriteBarrier-8 4.37ns ± 7% 4.22ns ± 8% -3.45% (p=0.000 n=96+99)
However, I don't particularly trust these numbers.
I ran runtime.BenchmarkWriteBarrier multiple times as I rebased
this change, and noticed that the results have high variance
depending on the parent change, perhaps due to aligment.
This change was stress tested with GOGC=1 GODEBUG=gccheckmark=1 go test std.
This change reduces binary sizes:
file before after Δ %
addr2line 4308720 4296688 -12032 -0.279%
api 5965592 5945368 -20224 -0.339%
asm 5148088 5025464 -122624 -2.382%
buildid 2848760 2844904 -3856 -0.135%
cgo 4828968 4812840 -16128 -0.334%
compile 19754720 19529744 -224976 -1.139%
cover 5256840 5236600 -20240 -0.385%
dist 3670312 3658264 -12048 -0.328%
doc 4669608 4657576 -12032 -0.258%
fix 3377976 3365944 -12032 -0.356%
link 6614888 6586472 -28416 -0.430%
nm 4258368 4254528 -3840 -0.090%
objdump 4656336 4644304 -12032 -0.258%
pack 2295176 2295432 +256 +0.011%
pprof 14762356 14709364 -52992 -0.359%
test2json 2824456 2820600 -3856 -0.137%
trace 11684404 11643700 -40704 -0.348%
vet 8284760 8252248 -32512 -0.392%
total 115210328 114580040 -630288 -0.547%
This change improves compiler performance:
name old time/op new time/op delta
Template 208ms ± 3% 207ms ± 3% -0.40% (p=0.030 n=43+44)
Unicode 80.2ms ± 3% 81.3ms ± 3% +1.25% (p=0.000 n=41+44)
GoTypes 699ms ± 3% 694ms ± 2% -0.71% (p=0.016 n=42+37)
Compiler 3.26s ± 2% 3.23s ± 2% -0.86% (p=0.000 n=43+45)
SSA 6.97s ± 1% 6.93s ± 1% -0.63% (p=0.000 n=43+45)
Flate 134ms ± 3% 133ms ± 2% ~ (p=0.139 n=45+42)
GoParser 165ms ± 2% 164ms ± 1% -0.79% (p=0.000 n=45+40)
Reflect 434ms ± 4% 435ms ± 4% ~ (p=0.937 n=44+44)
Tar 181ms ± 2% 181ms ± 2% ~ (p=0.702 n=43+45)
XML 244ms ± 2% 244ms ± 2% ~ (p=0.237 n=45+44)
[Geo mean] 403ms 402ms -0.29%
name old user-time/op new user-time/op delta
Template 271ms ± 2% 268ms ± 1% -1.40% (p=0.000 n=42+42)
Unicode 117ms ± 3% 116ms ± 5% ~ (p=0.066 n=45+45)
GoTypes 948ms ± 2% 936ms ± 2% -1.30% (p=0.000 n=41+40)
Compiler 4.26s ± 1% 4.21s ± 2% -1.25% (p=0.000 n=37+45)
SSA 9.52s ± 2% 9.41s ± 1% -1.18% (p=0.000 n=44+45)
Flate 167ms ± 2% 165ms ± 2% -1.15% (p=0.000 n=44+41)
GoParser 201ms ± 2% 198ms ± 1% -1.40% (p=0.000 n=43+43)
Reflect 563ms ± 8% 560ms ± 7% ~ (p=0.206 n=45+44)
Tar 224ms ± 2% 222ms ± 2% -0.81% (p=0.000 n=45+45)
XML 308ms ± 2% 304ms ± 1% -1.17% (p=0.000 n=42+43)
[Geo mean] 525ms 519ms -1.08%
name old alloc/op new alloc/op delta
Template 36.3MB ± 0% 36.3MB ± 0% ~ (p=0.421 n=5+5)
Unicode 28.4MB ± 0% 28.3MB ± 0% ~ (p=0.056 n=5+5)
GoTypes 121MB ± 0% 121MB ± 0% -0.14% (p=0.008 n=5+5)
Compiler 567MB ± 0% 567MB ± 0% -0.06% (p=0.016 n=4+5)
SSA 1.26GB ± 0% 1.26GB ± 0% -0.07% (p=0.008 n=5+5)
Flate 22.9MB ± 0% 22.8MB ± 0% ~ (p=0.310 n=5+5)
GoParser 28.0MB ± 0% 27.9MB ± 0% -0.09% (p=0.008 n=5+5)
Reflect 78.4MB ± 0% 78.4MB ± 0% -0.03% (p=0.008 n=5+5)
Tar 34.2MB ± 0% 34.2MB ± 0% -0.05% (p=0.008 n=5+5)
XML 44.4MB ± 0% 44.4MB ± 0% -0.04% (p=0.016 n=5+5)
[Geo mean] 76.4MB 76.3MB -0.05%
name old allocs/op new allocs/op delta
Template 356k ± 0% 356k ± 0% -0.13% (p=0.008 n=5+5)
Unicode 326k ± 0% 326k ± 0% -0.07% (p=0.008 n=5+5)
GoTypes 1.24M ± 0% 1.24M ± 0% -0.24% (p=0.008 n=5+5)
Compiler 5.30M ± 0% 5.28M ± 0% -0.34% (p=0.008 n=5+5)
SSA 11.9M ± 0% 11.9M ± 0% -0.16% (p=0.008 n=5+5)
Flate 226k ± 0% 225k ± 0% -0.12% (p=0.008 n=5+5)
GoParser 287k ± 0% 286k ± 0% -0.29% (p=0.008 n=5+5)
Reflect 930k ± 0% 929k ± 0% -0.05% (p=0.008 n=5+5)
Tar 332k ± 0% 331k ± 0% -0.12% (p=0.008 n=5+5)
XML 411k ± 0% 411k ± 0% -0.12% (p=0.008 n=5+5)
[Geo mean] 771k 770k -0.16%
For some packages, this change significantly reduces the size of executable text.
Examples:
file before after Δ %
cmd/internal/obj/arm.s 68658 66855 -1803 -2.626%
cmd/internal/obj/mips.s 57486 56272 -1214 -2.112%
cmd/internal/obj/arm64.s 152107 147163 -4944 -3.250%
cmd/internal/obj/ppc64.s 125544 120456 -5088 -4.053%
cmd/vendor/golang.org/x/tools/go/cfg.s 31699 30742 -957 -3.019%
Full listing:
file before after Δ %
container/ring.s 1890 1870 -20 -1.058%
container/list.s 5366 5390 +24 +0.447%
internal/cpu.s 3298 3295 -3 -0.091%
internal/testlog.s 1507 1501 -6 -0.398%
image/color.s 8281 8248 -33 -0.399%
runtime.s 480970 480075 -895 -0.186%
sync.s 16497 16408 -89 -0.539%
internal/singleflight.s 2591 2577 -14 -0.540%
math/rand.s 10456 10438 -18 -0.172%
cmd/go/internal/par.s 2801 2790 -11 -0.393%
internal/reflectlite.s 28477 28417 -60 -0.211%
errors.s 2750 2736 -14 -0.509%
internal/oserror.s 446 434 -12 -2.691%
sort.s 17061 17046 -15 -0.088%
io.s 17063 16999 -64 -0.375%
vendor/golang.org/x/crypto/hkdf.s 1962 1936 -26 -1.325%
text/tabwriter.s 9617 9574 -43 -0.447%
hash/crc64.s 3414 3408 -6 -0.176%
hash/crc32.s 6657 6651 -6 -0.090%
bytes.s 31932 31863 -69 -0.216%
strconv.s 53158 52799 -359 -0.675%
strings.s 42829 42665 -164 -0.383%
encoding/ascii85.s 4833 4791 -42 -0.869%
vendor/golang.org/x/text/transform.s 16810 16724 -86 -0.512%
path.s 6848 6845 -3 -0.044%
encoding/base32.s 9658 9592 -66 -0.683%
bufio.s 23051 22908 -143 -0.620%
compress/bzip2.s 11773 11764 -9 -0.076%
image.s 37565 37502 -63 -0.168%
syscall.s 82359 82279 -80 -0.097%
regexp/syntax.s 83573 82930 -643 -0.769%
image/jpeg.s 36535 36490 -45 -0.123%
regexp.s 64396 64214 -182 -0.283%
time.s 82724 82622 -102 -0.123%
plugin.s 6539 6536 -3 -0.046%
context.s 10959 10865 -94 -0.858%
internal/poll.s 24286 24270 -16 -0.066%
reflect.s 168304 167927 -377 -0.224%
internal/fmtsort.s 7416 7376 -40 -0.539%
os.s 52465 51787 -678 -1.292%
cmd/go/internal/lockedfile/internal/filelock.s 2326 2317 -9 -0.387%
os/signal.s 4657 4648 -9 -0.193%
runtime/debug.s 6040 5998 -42 -0.695%
encoding/binary.s 30838 30801 -37 -0.120%
vendor/golang.org/x/net/route.s 23694 23491 -203 -0.857%
path/filepath.s 17895 17889 -6 -0.034%
cmd/vendor/golang.org/x/sys/unix.s 78125 78109 -16 -0.020%
io/ioutil.s 6999 6996 -3 -0.043%
encoding/base64.s 12094 12007 -87 -0.719%
crypto/cipher.s 20466 20372 -94 -0.459%
cmd/go/internal/robustio.s 2672 2669 -3 -0.112%
encoding/pem.s 9302 9286 -16 -0.172%
internal/obscuretestdata.s 1719 1695 -24 -1.396%
crypto/aes.s 11014 11002 -12 -0.109%
os/exec.s 29388 29231 -157 -0.534%
cmd/internal/browser.s 2266 2260 -6 -0.265%
internal/goroot.s 4601 4592 -9 -0.196%
vendor/golang.org/x/crypto/chacha20poly1305.s 8945 8942 -3 -0.034%
cmd/vendor/golang.org/x/crypto/ssh/terminal.s 27226 27195 -31 -0.114%
index/suffixarray.s 36431 36411 -20 -0.055%
fmt.s 77017 76709 -308 -0.400%
encoding/hex.s 6241 6154 -87 -1.394%
compress/lzw.s 7133 7069 -64 -0.897%
database/sql/driver.s 18888 18877 -11 -0.058%
net/url.s 29838 29739 -99 -0.332%
debug/plan9obj.s 8329 8279 -50 -0.600%
encoding/csv.s 12986 12902 -84 -0.647%
debug/gosym.s 25403 25330 -73 -0.287%
compress/flate.s 51192 50970 -222 -0.434%
vendor/golang.org/x/net/dns/dnsmessage.s 86769 86208 -561 -0.647%
compress/gzip.s 9791 9758 -33 -0.337%
compress/zlib.s 7310 7277 -33 -0.451%
archive/zip.s 42356 42166 -190 -0.449%
debug/dwarf.s 108259 107730 -529 -0.489%
encoding/json.s 106378 105910 -468 -0.440%
os/user.s 14751 14724 -27 -0.183%
database/sql.s 99011 98404 -607 -0.613%
log.s 9466 9423 -43 -0.454%
debug/pe.s 31272 31182 -90 -0.288%
debug/macho.s 32764 32608 -156 -0.476%
encoding/gob.s 136976 136517 -459 -0.335%
vendor/golang.org/x/text/unicode/bidi.s 27318 27276 -42 -0.154%
archive/tar.s 71416 70975 -441 -0.618%
vendor/golang.org/x/net/http2/hpack.s 23892 23848 -44 -0.184%
vendor/golang.org/x/text/secure/bidirule.s 3354 3351 -3 -0.089%
mime/quotedprintable.s 5960 5925 -35 -0.587%
net/http/internal.s 5874 5853 -21 -0.358%
math/big.s 184147 183692 -455 -0.247%
debug/elf.s 63775 63567 -208 -0.326%
mime.s 39802 39709 -93 -0.234%
encoding/xml.s 111038 110713 -325 -0.293%
crypto/dsa.s 6044 6029 -15 -0.248%
go/token.s 12139 12077 -62 -0.511%
crypto/rand.s 6889 6866 -23 -0.334%
go/scanner.s 19030 19008 -22 -0.116%
flag.s 22320 22236 -84 -0.376%
vendor/golang.org/x/text/unicode/norm.s 66652 66391 -261 -0.392%
crypto/rsa.s 31671 31650 -21 -0.066%
crypto/elliptic.s 51553 51403 -150 -0.291%
internal/xcoff.s 22950 22822 -128 -0.558%
go/constant.s 43750 43689 -61 -0.139%
encoding/asn1.s 57086 57035 -51 -0.089%
runtime/trace.s 2609 2603 -6 -0.230%
crypto/x509/pkix.s 10458 10471 +13 +0.124%
image/gif.s 27544 27385 -159 -0.577%
vendor/golang.org/x/net/idna.s 24558 24502 -56 -0.228%
image/png.s 42775 42685 -90 -0.210%
vendor/golang.org/x/crypto/cryptobyte.s 33616 33493 -123 -0.366%
go/ast.s 80684 80449 -235 -0.291%
net/internal/socktest.s 16571 16535 -36 -0.217%
crypto/ecdsa.s 11948 11936 -12 -0.100%
text/template/parse.s 95138 94002 -1136 -1.194%
runtime/pprof.s 59702 59639 -63 -0.106%
testing.s 68427 68088 -339 -0.495%
internal/testenv.s 5620 5596 -24 -0.427%
testing/internal/testdeps.s 3312 3294 -18 -0.543%
internal/trace.s 78473 78239 -234 -0.298%
testing/iotest.s 4968 4908 -60 -1.208%
os/signal/internal/pty.s 3011 2990 -21 -0.697%
testing/quick.s 12179 12125 -54 -0.443%
cmd/internal/bio.s 9286 9274 -12 -0.129%
cmd/internal/src.s 17684 17663 -21 -0.119%
cmd/internal/goobj2.s 12588 12558 -30 -0.238%
cmd/internal/objabi.s 16408 16390 -18 -0.110%
go/printer.s 77417 77308 -109 -0.141%
go/parser.s 80045 79113 -932 -1.164%
go/format.s 5434 5419 -15 -0.276%
cmd/internal/goobj.s 26146 25954 -192 -0.734%
runtime/pprof/internal/profile.s 102518 102178 -340 -0.332%
text/template.s 95343 94935 -408 -0.428%
cmd/internal/dwarf.s 31718 31572 -146 -0.460%
cmd/vendor/golang.org/x/arch/arm/armasm.s 45240 45151 -89 -0.197%
internal/lazytemplate.s 1470 1457 -13 -0.884%
cmd/vendor/golang.org/x/arch/ppc64/ppc64asm.s 37253 37220 -33 -0.089%
cmd/asm/internal/flags.s 2593 2590 -3 -0.116%
cmd/asm/internal/lex.s 25068 24921 -147 -0.586%
cmd/internal/buildid.s 18536 18263 -273 -1.473%
cmd/vendor/golang.org/x/arch/x86/x86asm.s 80209 80105 -104 -0.130%
go/doc.s 75140 74585 -555 -0.739%
cmd/internal/edit.s 3893 3899 +6 +0.154%
html/template.s 89377 88809 -568 -0.636%
cmd/vendor/golang.org/x/arch/arm64/arm64asm.s 117998 117824 -174 -0.147%
cmd/internal/obj.s 115015 114290 -725 -0.630%
go/build.s 69379 68862 -517 -0.745%
cmd/internal/objfile.s 48106 47982 -124 -0.258%
cmd/cover.s 46239 46113 -126 -0.272%
cmd/addr2line.s 2845 2833 -12 -0.422%
cmd/internal/obj/arm.s 68658 66855 -1803 -2.626%
cmd/internal/obj/mips.s 57486 56272 -1214 -2.112%
cmd/internal/obj/riscv.s 63834 63006 -828 -1.297%
cmd/compile/internal/syntax.s 146582 145456 -1126 -0.768%
cmd/internal/obj/wasm.s 44117 44066 -51 -0.116%
cmd/cgo.s 242645 241653 -992 -0.409%
cmd/internal/obj/arm64.s 152107 147163 -4944 -3.250%
net.s 295972 292010 -3962 -1.339%
go/types.s 321371 319432 -1939 -0.603%
vendor/golang.org/x/net/http/httpproxy.s 9450 9423 -27 -0.286%
net/textproto.s 19455 19406 -49 -0.252%
cmd/internal/obj/ppc64.s 125544 120456 -5088 -4.053%
go/internal/srcimporter.s 6475 6409 -66 -1.019%
log/syslog.s 8017 7929 -88 -1.098%
cmd/compile/internal/logopt.s 10183 10162 -21 -0.206%
net/mail.s 24085 23948 -137 -0.569%
mime/multipart.s 21527 21420 -107 -0.497%
cmd/internal/obj/s390x.s 127610 127757 +147 +0.115%
go/internal/gcimporter.s 34913 34548 -365 -1.045%
vendor/golang.org/x/net/nettest.s 28103 28016 -87 -0.310%
cmd/go/internal/cfg.s 9967 9916 -51 -0.512%
cmd/api.s 39703 39603 -100 -0.252%
go/internal/gccgoimporter.s 56470 56120 -350 -0.620%
go/importer.s 2077 2056 -21 -1.011%
cmd/compile/internal/types.s 48202 47282 -920 -1.909%
cmd/go/internal/str.s 4341 4320 -21 -0.484%
cmd/internal/obj/x86.s 89440 88625 -815 -0.911%
cmd/go/internal/base.s 12667 12580 -87 -0.687%
cmd/go/internal/cache.s 30754 30571 -183 -0.595%
cmd/doc.s 62976 62755 -221 -0.351%
cmd/go/internal/search.s 20114 19993 -121 -0.602%
cmd/vendor/golang.org/x/xerrors.s 17923 17855 -68 -0.379%
cmd/go/internal/lockedfile.s 16451 16415 -36 -0.219%
cmd/vendor/golang.org/x/mod/sumdb/note.s 18200 18150 -50 -0.275%
cmd/vendor/golang.org/x/mod/module.s 17869 17851 -18 -0.101%
cmd/asm/internal/arch.s 37533 37482 -51 -0.136%
cmd/fix.s 87728 87492 -236 -0.269%
cmd/vendor/golang.org/x/mod/sumdb/tlog.s 36394 36367 -27 -0.074%
cmd/vendor/golang.org/x/mod/sumdb/dirhash.s 4990 4963 -27 -0.541%
cmd/go/internal/imports.s 16499 16469 -30 -0.182%
cmd/vendor/golang.org/x/mod/zip.s 18816 18745 -71 -0.377%
cmd/go/internal/cmdflag.s 5126 5123 -3 -0.059%
cmd/internal/test2json.s 9540 9452 -88 -0.922%
cmd/go/internal/tool.s 3629 3623 -6 -0.165%
cmd/go/internal/version.s 11232 11220 -12 -0.107%
cmd/go/internal/mvs.s 25383 25179 -204 -0.804%
cmd/nm.s 5815 5803 -12 -0.206%
cmd/dist.s 210146 209140 -1006 -0.479%
cmd/asm/internal/asm.s 68655 68549 -106 -0.154%
cmd/vendor/golang.org/x/mod/modfile.s 72974 72510 -464 -0.636%
cmd/go/internal/load.s 107548 106861 -687 -0.639%
cmd/link/internal/sym.s 18708 18581 -127 -0.679%
cmd/asm.s 3367 3343 -24 -0.713%
cmd/gofmt.s 30795 30698 -97 -0.315%
cmd/link/internal/objfile.s 21828 21630 -198 -0.907%
cmd/pack.s 14878 14869 -9 -0.060%
cmd/vendor/github.com/google/pprof/internal/elfexec.s 6788 6782 -6 -0.088%
cmd/test2json.s 1647 1641 -6 -0.364%
cmd/link/internal/loader.s 48677 48483 -194 -0.399%
cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags.s 16783 16773 -10 -0.060%
cmd/link/internal/loadelf.s 35464 35126 -338 -0.953%
cmd/link/internal/loadmacho.s 29438 29180 -258 -0.876%
cmd/link/internal/loadpe.s 16440 16371 -69 -0.420%
cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil.s 2106 2100 -6 -0.285%
cmd/link/internal/loadxcoff.s 11711 11615 -96 -0.820%
cmd/vendor/golang.org/x/tools/go/analysis/internal/facts.s 14954 14883 -71 -0.475%
cmd/vendor/golang.org/x/tools/go/ast/inspector.s 5394 5374 -20 -0.371%
cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl.s 37029 36822 -207 -0.559%
cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect.s 340 337 -3 -0.882%
cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall.s 9919 9858 -61 -0.615%
cmd/vendor/golang.org/x/tools/go/analysis/passes/bools.s 6705 6690 -15 -0.224%
cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock.s 9783 9741 -42 -0.429%
cmd/vendor/golang.org/x/tools/go/cfg.s 31699 30742 -957 -3.019%
cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert.s 2768 2762 -6 -0.217%
cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure.s 3031 2998 -33 -1.089%
cmd/vendor/golang.org/x/tools/go/analysis/passes/shift.s 4382 4376 -6 -0.137%
cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods.s 8654 8642 -12 -0.139%
cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv.s 3458 3446 -12 -0.347%
cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag.s 8011 7995 -16 -0.200%
cmd/vendor/golang.org/x/tools/go/analysis/passes/tests.s 6205 6193 -12 -0.193%
cmd/vendor/golang.org/x/tools/go/ast/astutil.s 66183 65861 -322 -0.487%
cmd/vendor/github.com/google/pprof/profile.s 150844 150261 -583 -0.386%
cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable.s 8057 8054 -3 -0.037%
cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult.s 3670 3667 -3 -0.082%
cmd/vendor/github.com/google/pprof/internal/measurement.s 10464 10440 -24 -0.229%
cmd/vendor/golang.org/x/tools/go/types/typeutil.s 12319 12274 -45 -0.365%
cmd/vendor/golang.org/x/tools/go/analysis/unitchecker.s 13503 13342 -161 -1.192%
cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow.s 5261 5218 -43 -0.817%
cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas.s 1462 1459 -3 -0.205%
cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel.s 9594 9582 -12 -0.125%
cmd/vendor/golang.org/x/tools/go/analysis/passes/printf.s 34397 34338 -59 -0.172%
cmd/vendor/github.com/google/pprof/internal/graph.s 53225 52936 -289 -0.543%
cmd/vendor/github.com/ianlancetaylor/demangle.s 177450 175329 -2121 -1.195%
crypto/x509.s 147892 147388 -504 -0.341%
cmd/go/internal/work.s 306465 304950 -1515 -0.494%
cmd/go/internal/run.s 4664 4657 -7 -0.150%
crypto/tls.s 313130 311833 -1297 -0.414%
net/http/httptrace.s 3979 3905 -74 -1.860%
net/smtp.s 14413 14344 -69 -0.479%
cmd/link/internal/ld.s 545343 542279 -3064 -0.562%
cmd/link/internal/mips.s 6218 6215 -3 -0.048%
cmd/link/internal/mips64.s 6108 6103 -5 -0.082%
cmd/link/internal/amd64.s 18154 18112 -42 -0.231%
cmd/link/internal/arm64.s 22527 22494 -33 -0.146%
cmd/link/internal/arm.s 22574 22494 -80 -0.354%
cmd/link/internal/s390x.s 20779 20746 -33 -0.159%
cmd/link/internal/wasm.s 16531 16493 -38 -0.230%
cmd/link/internal/x86.s 18906 18849 -57 -0.301%
cmd/link/internal/ppc64.s 26856 26778 -78 -0.290%
net/http.s 559101 556513 -2588 -0.463%
net/http/cookiejar.s 15912 15885 -27 -0.170%
expvar.s 9531 9525 -6 -0.063%
net/http/httptest.s 16616 16475 -141 -0.849%
net/http/cgi.s 23624 23458 -166 -0.703%
cmd/go/internal/web.s 16546 16489 -57 -0.344%
cmd/vendor/golang.org/x/mod/sumdb.s 33197 33117 -80 -0.241%
net/http/fcgi.s 19266 19169 -97 -0.503%
net/http/httputil.s 39875 39728 -147 -0.369%
cmd/vendor/github.com/google/pprof/internal/symbolz.s 5888 5867 -21 -0.357%
net/rpc.s 34154 34003 -151 -0.442%
cmd/vendor/github.com/google/pprof/internal/transport.s 2746 2716 -30 -1.092%
cmd/vendor/github.com/google/pprof/internal/binutils.s 35999 35875 -124 -0.344%
net/rpc/jsonrpc.s 6637 6598 -39 -0.588%
cmd/vendor/github.com/google/pprof/internal/symbolizer.s 11533 11458 -75 -0.650%
cmd/go/internal/get.s 62921 62803 -118 -0.188%
cmd/vendor/github.com/google/pprof/internal/report.s 80364 80058 -306 -0.381%
cmd/go/internal/modfetch/codehost.s 89680 89066 -614 -0.685%
cmd/trace.s 117171 116701 -470 -0.401%
cmd/vendor/github.com/google/pprof/internal/driver.s 144268 143297 -971 -0.673%
cmd/go/internal/modfetch.s 126299 125860 -439 -0.348%
cmd/vendor/github.com/google/pprof/driver.s 9042 9000 -42 -0.464%
cmd/go/internal/modconv.s 17947 17889 -58 -0.323%
cmd/pprof.s 12399 12326 -73 -0.589%
cmd/go/internal/modload.s 151182 150389 -793 -0.525%
cmd/go/internal/generate.s 11738 11636 -102 -0.869%
cmd/go/internal/help.s 6571 6531 -40 -0.609%
cmd/go/internal/clean.s 11174 11142 -32 -0.286%
cmd/go/internal/vet.s 7897 7867 -30 -0.380%
cmd/go/internal/envcmd.s 22176 22095 -81 -0.365%
cmd/go/internal/list.s 15216 15067 -149 -0.979%
cmd/go/internal/modget.s 38698 38519 -179 -0.463%
cmd/go/internal/modcmd.s 46674 46441 -233 -0.499%
cmd/go/internal/test.s 64664 64456 -208 -0.322%
cmd/go.s 6730 6703 -27 -0.401%
cmd/compile/internal/ssa.s 3592565 3582500 -10065 -0.280%
cmd/compile/internal/gc.s 1549123 1537123 -12000 -0.775%
cmd/compile/internal/riscv64.s 14579 14483 -96 -0.658%
cmd/compile/internal/mips.s 20578 20419 -159 -0.773%
cmd/compile/internal/ppc64.s 25524 25359 -165 -0.646%
cmd/compile/internal/mips64.s 19795 19636 -159 -0.803%
cmd/compile/internal/wasm.s 13329 13290 -39 -0.293%
cmd/compile/internal/s390x.s 28097 27892 -205 -0.730%
cmd/compile/internal/arm.s 31489 31321 -168 -0.534%
cmd/compile/internal/arm64.s 29803 29590 -213 -0.715%
cmd/compile/internal/amd64.s 32961 33221 +260 +0.789%
cmd/compile/internal/x86.s 31029 30878 -151 -0.487%
total 18534966 18440341 -94625 -0.511%
Change-Id: I830d37364f14f0297800adc42c99f60a74c51aca
Reviewed-on: https://go-review.googlesource.com/c/go/+/226367
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2020-03-24 22:14:02 -07:00
{ name : "LoweredWB" , argLength : 3 , reg : regInfo { inputs : [ ] regMask { buildReg ( "DI" ) , buildReg ( "AX CX DX BX BP SI R8 R9" ) } , clobbers : callerSave &^ gp } , clobberFlags : true , aux : "Sym" , symEffect : "None" } ,
2017-10-26 12:33:04 -04:00
2019-02-06 14:12:36 -08:00
// There are three of these functions so that they can have three different register inputs.
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
// default registers to match so we don't need to copy registers around unnecessarily.
{ name : "LoweredPanicBoundsA" , argLength : 3 , aux : "Int64" , reg : regInfo { inputs : [ ] regMask { dx , bx } } , typ : "Mem" } , // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
{ name : "LoweredPanicBoundsB" , argLength : 3 , aux : "Int64" , reg : regInfo { inputs : [ ] regMask { cx , dx } } , typ : "Mem" } , // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
{ name : "LoweredPanicBoundsC" , argLength : 3 , aux : "Int64" , reg : regInfo { inputs : [ ] regMask { ax , cx } } , typ : "Mem" } , // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
2016-03-01 23:21:55 +00:00
// Constant flag values. For any comparison, there are 5 possible
2016-01-05 14:56:26 -08:00
// outcomes: the three from the signed total order (<,==,>) and the
2016-03-01 23:21:55 +00:00
// three from the unsigned total order. The == cases overlap.
2016-01-05 14:56:26 -08:00
// Note: there's a sixth "unordered" outcome for floating-point
// comparisons, but we don't use such a beast yet.
2016-03-01 23:21:55 +00:00
// These ops are for temporary use by rewrite rules. They
2016-01-05 14:56:26 -08:00
// cannot appear in the generated assembly.
{ name : "FlagEQ" } , // equal
{ name : "FlagLT_ULT" } , // signed < and unsigned <
{ name : "FlagLT_UGT" } , // signed < and unsigned >
2017-07-15 12:20:25 -06:00
{ name : "FlagGT_UGT" } , // signed > and unsigned >
{ name : "FlagGT_ULT" } , // signed > and unsigned <
2016-08-23 16:49:28 -07:00
// Atomic loads. These are just normal loads but return <value,memory> tuples
// so they can be properly ordered with other loads.
// load from arg0+auxint+aux. arg1=mem.
2019-03-28 14:58:06 -04:00
{ name : "MOVBatomicload" , argLength : 2 , reg : gpload , asm : "MOVB" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } ,
2017-03-09 14:46:43 -08:00
{ name : "MOVLatomicload" , argLength : 2 , reg : gpload , asm : "MOVL" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } ,
{ name : "MOVQatomicload" , argLength : 2 , reg : gpload , asm : "MOVQ" , aux : "SymOff" , faultOnNilArg0 : true , symEffect : "Read" } ,
2016-08-25 16:02:57 -07:00
// Atomic stores and exchanges. Stores use XCHG to get the right memory ordering semantics.
2016-08-23 16:49:28 -07:00
// store arg0 to arg1+auxint+aux, arg2=mem.
2016-08-25 16:02:57 -07:00
// These ops return a tuple of <old contents of *(arg1+auxint+aux), memory>.
2016-08-23 16:49:28 -07:00
// Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)!
2019-10-23 10:20:49 -04:00
{ name : "XCHGB" , argLength : 3 , reg : gpstorexchg , asm : "XCHGB" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , hasSideEffects : true , symEffect : "RdWr" } ,
2017-03-09 14:46:43 -08:00
{ name : "XCHGL" , argLength : 3 , reg : gpstorexchg , asm : "XCHGL" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , hasSideEffects : true , symEffect : "RdWr" } ,
{ name : "XCHGQ" , argLength : 3 , reg : gpstorexchg , asm : "XCHGQ" , aux : "SymOff" , resultInArg0 : true , faultOnNilArg1 : true , hasSideEffects : true , symEffect : "RdWr" } ,
2016-08-25 16:02:57 -07:00
// Atomic adds.
// *(arg1+auxint+aux) += arg0. arg2=mem.
// Returns a tuple of <old contents of *(arg1+auxint+aux), memory>.
// Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)!
2017-03-09 14:46:43 -08:00
{ name : "XADDLlock" , argLength : 3 , reg : gpstorexchg , asm : "XADDL" , typ : "(UInt32,Mem)" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , hasSideEffects : true , symEffect : "RdWr" } ,
{ name : "XADDQlock" , argLength : 3 , reg : gpstorexchg , asm : "XADDQ" , typ : "(UInt64,Mem)" , aux : "SymOff" , resultInArg0 : true , clobberFlags : true , faultOnNilArg1 : true , hasSideEffects : true , symEffect : "RdWr" } ,
2017-05-15 09:00:55 -07:00
{ name : "AddTupleFirst32" , argLength : 2 } , // arg1=tuple <x,y>. Returns <x+arg0,y>.
{ name : "AddTupleFirst64" , argLength : 2 } , // arg1=tuple <x,y>. Returns <x+arg0,y>.
2016-08-25 16:02:57 -07:00
// Compare and swap.
// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
// if *(arg0+auxint+aux) == arg1 {
// *(arg0+auxint+aux) = arg2
// return (true, memory)
// } else {
// return (false, memory)
// }
// Note that these instructions also return the old value in AX, but we ignore it.
// TODO: have these return flags instead of bool. The current system generates:
// CMPXCHGQ ...
// SETEQ AX
// CMPB AX, $0
// JNE ...
// instead of just
// CMPXCHGQ ...
// JEQ ...
// but we can't do that because memory-using ops can't generate flags yet
// (flagalloc wants to move flag-generating instructions around).
2017-03-09 14:46:43 -08:00
{ name : "CMPXCHGLlock" , argLength : 4 , reg : cmpxchg , asm : "CMPXCHGL" , aux : "SymOff" , clobberFlags : true , faultOnNilArg0 : true , hasSideEffects : true , symEffect : "RdWr" } ,
{ name : "CMPXCHGQlock" , argLength : 4 , reg : cmpxchg , asm : "CMPXCHGQ" , aux : "SymOff" , clobberFlags : true , faultOnNilArg0 : true , hasSideEffects : true , symEffect : "RdWr" } ,
2016-08-25 16:02:57 -07:00
// Atomic memory updates.
2017-03-09 14:46:43 -08:00
{ name : "ANDBlock" , argLength : 3 , reg : gpstore , asm : "ANDB" , aux : "SymOff" , clobberFlags : true , faultOnNilArg0 : true , hasSideEffects : true , symEffect : "RdWr" } , // *(arg0+auxint+aux) &= arg1
{ name : "ORBlock" , argLength : 3 , reg : gpstore , asm : "ORB" , aux : "SymOff" , clobberFlags : true , faultOnNilArg0 : true , hasSideEffects : true , symEffect : "RdWr" } , // *(arg0+auxint+aux) |= arg1
2015-06-06 16:03:33 -07:00
}
var AMD64blocks = [ ] blockData {
2019-08-12 20:19:58 +01:00
{ name : "EQ" , controls : 1 } ,
{ name : "NE" , controls : 1 } ,
{ name : "LT" , controls : 1 } ,
{ name : "LE" , controls : 1 } ,
{ name : "GT" , controls : 1 } ,
{ name : "GE" , controls : 1 } ,
{ name : "OS" , controls : 1 } ,
{ name : "OC" , controls : 1 } ,
{ name : "ULT" , controls : 1 } ,
{ name : "ULE" , controls : 1 } ,
{ name : "UGT" , controls : 1 } ,
{ name : "UGE" , controls : 1 } ,
{ name : "EQF" , controls : 1 } ,
{ name : "NEF" , controls : 1 } ,
{ name : "ORD" , controls : 1 } , // FP, ordered comparison (parity zero)
{ name : "NAN" , controls : 1 } , // FP, unordered comparison (parity one)
2015-06-06 16:03:33 -07:00
}
2016-03-12 14:07:40 -08:00
archs = append ( archs , arch {
2016-05-19 12:33:30 -04:00
name : "AMD64" ,
pkg : "cmd/internal/obj/x86" ,
genfile : "../../amd64/ssa.go" ,
ops : AMD64ops ,
blocks : AMD64blocks ,
regnames : regNamesAMD64 ,
gpregmask : gp ,
fpregmask : fp ,
framepointerreg : int8 ( num [ "BP" ] ) ,
2016-10-06 15:06:45 -04:00
linkreg : - 1 , // not used
2016-03-12 14:07:40 -08:00
} )
2015-06-06 16:03:33 -07:00
}