src/cmd/compile/internal/amd64/ssa.go GO 2,697 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,697.
1// Copyright 2016 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package amd6467import (8	"fmt"9	"math"1011	"cmd/compile/internal/base"12	"cmd/compile/internal/ir"13	"cmd/compile/internal/logopt"14	"cmd/compile/internal/objw"15	"cmd/compile/internal/ssa"16	"cmd/compile/internal/ssa/block"17	"cmd/compile/internal/ssa/ssaop"18	"cmd/compile/internal/ssagen"19	"cmd/compile/internal/types"20	"cmd/internal/obj"21	"cmd/internal/obj/x86"22	"internal/abi"23	"internal/buildcfg"24)2526// ssaMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.27func ssaMarkMoves(s *ssagen.State, b *ssa.Block) {28	flive := b.FlagsLiveAtEnd29	for _, c := range b.ControlValues() {30		flive = c.Type.IsFlags() || flive31	}32	for i := len(b.Values) - 1; i >= 0; i-- {33		v := b.Values[i]34		if flive && (v.Op == ssaop.OpAMD64MOVLconst || v.Op == ssaop.OpAMD64MOVQconst) {35			// The "mark" is any non-nil Aux value.36			v.Aux = ssa.AuxMark37		}38		if v.Type.IsFlags() {39			flive = false40		}41		for _, a := range v.Args {42			if a.Type.IsFlags() {43				flive = true44			}45		}46	}47}4849func isGPReg(r int16) bool {50	return x86.REG_AL <= r && r <= x86.REG_R1551}5253func isFPReg(r int16) bool {54	return x86.REG_X0 <= r && r <= x86.REG_Z3155}5657func isKReg(r int16) bool {58	return x86.REG_K0 <= r && r <= x86.REG_K759}6061func isLowFPReg(r int16) bool {62	return x86.REG_X0 <= r && r <= x86.REG_X1563}6465func isHighFPReg(r int16) bool {66	return x86.REG_X16 <= r && r <= x86.REG_X31 || x86.REG_Y16 <= r && r <= x86.REG_Y31 || x86.REG_Z16 <= r && r <= x86.REG_Z3167}6869// loadByRegWidth returns the load instruction of the given register of a given width.70func loadByRegWidth(r int16, width int64) obj.As {71	// Avoid partial register write for GPR72	if !isFPReg(r) && !isKReg(r) {73		switch width {74		case 1:75			return x86.AMOVBLZX76		case 2:77			return x86.AMOVWLZX78		}79	}80	// Otherwise, there's no difference between load and store opcodes.81	return storeByRegWidth(r, width)82}8384// storeByRegWidth returns the store instruction of the given register of a given width.85// It's also used for loading const to a reg.86func storeByRegWidth(r int16, width int64) obj.As {87	if isHighFPReg(r) {88		// High registers require AVX512 instruction89		return x86.AVMOVDQU6490	}91	if isFPReg(r) {92		switch width {93		case 4:94			return x86.AMOVSS95		case 8:96			return x86.AMOVSD97		case 16:98			// int128s are in SSE registers99			return x86.AMOVUPS100		case 32:101			return x86.AVMOVDQU102		case 64:103			return x86.AVMOVDQU64104		}105	}106	if isKReg(r) {107		return x86.AKMOVQ108	}109	// gp110	switch width {111	case 1:112		return x86.AMOVB113	case 2:114		return x86.AMOVW115	case 4:116		return x86.AMOVL117	case 8:118		return x86.AMOVQ119	}120	panic(fmt.Sprintf("bad store reg=%v, width=%d", r, width))121}122123// moveByRegsWidth returns the reg->reg move instruction of the given dest/src registers of a given width.124func moveByRegsWidth(dest, src int16, width int64) obj.As {125	// fp -> fp126	if isFPReg(dest) && isFPReg(src) {127		if isHighFPReg(src) || isHighFPReg(dest) {128			// High registers require AVX512 instruction129			return x86.AVMOVDQU64130		}131		// Moving the whole sse2 register is faster132		// than moving just the correct low portion of it.133		// There is no xmm->xmm move with 1 byte opcode,134		// so use movups, which has 2 byte opcode.135		if width <= 16 {136			return x86.AMOVUPS137		}138		if width <= 32 {139			return x86.AVMOVDQU140		}141		return x86.AVMOVDQU64142	}143	// k -> gp, gp -> k, k -> k144	if isKReg(dest) || isKReg(src) {145		if isFPReg(dest) || isFPReg(src) {146			panic(fmt.Sprintf("bad move, src=%v, dest=%v, width=%d", src, dest, width))147		}148		return x86.AKMOVQ149	}150	// gp -> fp, fp -> gp, gp -> gp151	switch width {152	case 1:153		// Avoids partial register write154		return x86.AMOVL155	case 2:156		return x86.AMOVL157	case 4:158		return x86.AMOVL159	case 8:160		return x86.AMOVQ161	case 16:162		// int128s are in SSE registers163		return x86.AMOVUPS164	case 32:165		return x86.AVMOVDQU166	case 64:167		return x86.AVMOVDQU64168	}169	panic(fmt.Sprintf("bad move, src=%v, dest=%v, width=%d", src, dest, width))170}171172// opregreg emits instructions for173//174//	dest := dest(To) op src(From)175//176// and also returns the created obj.Prog so it177// may be further adjusted (offset, scale, etc).178func opregreg(s *ssagen.State, op obj.As, dest, src int16) *obj.Prog {179	p := s.Prog(op)180	p.From.Type = obj.TYPE_REG181	p.To.Type = obj.TYPE_REG182	p.To.Reg = dest183	p.From.Reg = src184	return p185}186187// memIdx fills out a as an indexed memory reference for v.188// It assumes that the base register and the index register189// are v.Args[0].Reg() and v.Args[1].Reg(), respectively.190// The caller must still use gc.AddAux/gc.AddAux2 to handle v.Aux as necessary.191func memIdx(a *obj.Addr, v *ssa.Value) {192	r, i := v.Args[0].Reg(), v.Args[1].Reg()193	a.Type = obj.TYPE_MEM194	a.Scale = v.Op.Scale()195	if a.Scale == 1 && i == x86.REG_SP {196		r, i = i, r197	}198	a.Reg = r199	a.Index = i200}201202func getgFromTLS(s *ssagen.State, r int16) {203	// See the comments in cmd/internal/obj/x86/obj6.go204	// near CanUse1InsnTLS for a detailed explanation of these instructions.205	if x86.CanUse1InsnTLS(base.Ctxt) {206		// MOVQ (TLS), r207		p := s.Prog(x86.AMOVQ)208		p.From.Type = obj.TYPE_MEM209		p.From.Reg = x86.REG_TLS210		p.To.Type = obj.TYPE_REG211		p.To.Reg = r212	} else {213		// MOVQ TLS, r214		// MOVQ (r)(TLS*1), r215		p := s.Prog(x86.AMOVQ)216		p.From.Type = obj.TYPE_REG217		p.From.Reg = x86.REG_TLS218		p.To.Type = obj.TYPE_REG219		p.To.Reg = r220		q := s.Prog(x86.AMOVQ)221		q.From.Type = obj.TYPE_MEM222		q.From.Reg = r223		q.From.Index = x86.REG_TLS224		q.From.Scale = 1225		q.To.Type = obj.TYPE_REG226		q.To.Reg = r227	}228}229230func ssaGenValue(s *ssagen.State, v *ssa.Value) {231	switch v.Op {232	case ssaop.OpAMD64VFMADD231SD, ssaop.OpAMD64VFMADD231SS, ssaop.OpAMD64VFMSUB231SD, ssaop.OpAMD64VFMSUB231SS, ssaop.OpAMD64VFNMADD231SD, ssaop.OpAMD64VFNMADD231SS:233		p := s.Prog(v.Op.Asm())234		p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[2].Reg()}235		p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}236		p.AddRestSourceReg(v.Args[1].Reg())237	case ssaop.OpAMD64ADDQ, ssaop.OpAMD64ADDL:238		r := v.Reg()239		r1 := v.Args[0].Reg()240		r2 := v.Args[1].Reg()241		switch {242		case r == r1:243			p := s.Prog(v.Op.Asm())244			p.From.Type = obj.TYPE_REG245			p.From.Reg = r2246			p.To.Type = obj.TYPE_REG247			p.To.Reg = r248		case r == r2:249			p := s.Prog(v.Op.Asm())250			p.From.Type = obj.TYPE_REG251			p.From.Reg = r1252			p.To.Type = obj.TYPE_REG253			p.To.Reg = r254		default:255			var asm obj.As256			if v.Op == ssaop.OpAMD64ADDQ {257				asm = x86.ALEAQ258			} else {259				asm = x86.ALEAL260			}261			p := s.Prog(asm)262			p.From.Type = obj.TYPE_MEM263			p.From.Reg = r1264			p.From.Scale = 1265			p.From.Index = r2266			p.To.Type = obj.TYPE_REG267			p.To.Reg = r268		}269	// 2-address opcode arithmetic270	case ssaop.OpAMD64SUBQ, ssaop.OpAMD64SUBL,271		ssaop.OpAMD64MULQ, ssaop.OpAMD64MULL,272		ssaop.OpAMD64ANDQ, ssaop.OpAMD64ANDL,273		ssaop.OpAMD64ORQ, ssaop.OpAMD64ORL,274		ssaop.OpAMD64XORQ, ssaop.OpAMD64XORL,275		ssaop.OpAMD64SHLQ, ssaop.OpAMD64SHLL,276		ssaop.OpAMD64SHRQ, ssaop.OpAMD64SHRL, ssaop.OpAMD64SHRW, ssaop.OpAMD64SHRB,277		ssaop.OpAMD64SARQ, ssaop.OpAMD64SARL, ssaop.OpAMD64SARW, ssaop.OpAMD64SARB,278		ssaop.OpAMD64ROLQ, ssaop.OpAMD64ROLL, ssaop.OpAMD64ROLW, ssaop.OpAMD64ROLB,279		ssaop.OpAMD64RORQ, ssaop.OpAMD64RORL, ssaop.OpAMD64RORW, ssaop.OpAMD64RORB,280		ssaop.OpAMD64ADDSS, ssaop.OpAMD64ADDSD, ssaop.OpAMD64SUBSS, ssaop.OpAMD64SUBSD,281		ssaop.OpAMD64MULSS, ssaop.OpAMD64MULSD, ssaop.OpAMD64DIVSS, ssaop.OpAMD64DIVSD,282		ssaop.OpAMD64MINSS, ssaop.OpAMD64MINSD,283		ssaop.OpAMD64MAXSS, ssaop.OpAMD64MAXSD,284		ssaop.OpAMD64POR, ssaop.OpAMD64PXOR,285		ssaop.OpAMD64BTSL, ssaop.OpAMD64BTSQ,286		ssaop.OpAMD64BTCL, ssaop.OpAMD64BTCQ,287		ssaop.OpAMD64BTRL, ssaop.OpAMD64BTRQ,288		ssaop.OpAMD64PCMPEQB, ssaop.OpAMD64PSIGNB,289		ssaop.OpAMD64PUNPCKLBW:290		opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())291292	case ssaop.OpAMD64PSHUFLW:293		p := s.Prog(v.Op.Asm())294		imm := v.AuxInt295		if imm < 0 || imm > 255 {296			v.Fatalf("Invalid source selection immediate")297		}298		p.From.Offset = imm299		p.From.Type = obj.TYPE_CONST300		p.AddRestSourceReg(v.Args[0].Reg())301		p.To.Type = obj.TYPE_REG302		p.To.Reg = v.Reg()303304	case ssaop.OpAMD64PSHUFBbroadcast:305		// PSHUFB with a control mask of zero copies byte 0 to all306		// bytes in the register.307		//308		// X15 is always zero with ABIInternal.309		if s.ABI != obj.ABIInternal {310			// zero X15 manually311			opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)312		}313314		p := s.Prog(v.Op.Asm())315		p.From.Type = obj.TYPE_REG316		p.To.Type = obj.TYPE_REG317		p.To.Reg = v.Reg()318		p.From.Reg = x86.REG_X15319320	case ssaop.OpAMD64BLSIQ, ssaop.OpAMD64BLSIL,321		ssaop.OpAMD64BLSMSKQ, ssaop.OpAMD64BLSMSKL,322		ssaop.OpAMD64BLSRQ, ssaop.OpAMD64BLSRL:323		p := s.Prog(v.Op.Asm())324		p.From.Type = obj.TYPE_REG325		p.From.Reg = v.Args[0].Reg()326		p.To.Type = obj.TYPE_REG327		switch v.Op {328		case ssaop.OpAMD64BLSRQ, ssaop.OpAMD64BLSRL:329			p.To.Reg = v.Reg0()330		default:331			p.To.Reg = v.Reg()332		}333334	case ssaop.OpAMD64ANDNQ, ssaop.OpAMD64ANDNL:335		p := s.Prog(v.Op.Asm())336		p.From.Type = obj.TYPE_REG337		p.From.Reg = v.Args[0].Reg()338		p.To.Type = obj.TYPE_REG339		p.To.Reg = v.Reg()340		p.AddRestSourceReg(v.Args[1].Reg())341342	case ssaop.OpAMD64SARXL, ssaop.OpAMD64SARXQ,343		ssaop.OpAMD64SHLXL, ssaop.OpAMD64SHLXQ,344		ssaop.OpAMD64SHRXL, ssaop.OpAMD64SHRXQ:345		p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())346		p.AddRestSourceReg(v.Args[0].Reg())347348	case ssaop.OpAMD64SHLXLload, ssaop.OpAMD64SHLXQload,349		ssaop.OpAMD64SHRXLload, ssaop.OpAMD64SHRXQload,350		ssaop.OpAMD64SARXLload, ssaop.OpAMD64SARXQload:351		p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())352		m := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()}353		ssagen.AddAux(&m, v)354		p.AddRestSource(m)355356	case ssaop.OpAMD64SHLXLloadidx1, ssaop.OpAMD64SHLXLloadidx4, ssaop.OpAMD64SHLXLloadidx8,357		ssaop.OpAMD64SHRXLloadidx1, ssaop.OpAMD64SHRXLloadidx4, ssaop.OpAMD64SHRXLloadidx8,358		ssaop.OpAMD64SARXLloadidx1, ssaop.OpAMD64SARXLloadidx4, ssaop.OpAMD64SARXLloadidx8,359		ssaop.OpAMD64SHLXQloadidx1, ssaop.OpAMD64SHLXQloadidx8,360		ssaop.OpAMD64SHRXQloadidx1, ssaop.OpAMD64SHRXQloadidx8,361		ssaop.OpAMD64SARXQloadidx1, ssaop.OpAMD64SARXQloadidx8:362		p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[2].Reg())363		m := obj.Addr{Type: obj.TYPE_MEM}364		memIdx(&m, v)365		ssagen.AddAux(&m, v)366		p.AddRestSource(m)367368	case ssaop.OpAMD64DIVQU, ssaop.OpAMD64DIVLU, ssaop.OpAMD64DIVWU:369		// Arg[0] (the dividend) is in AX.370		// Arg[1] (the divisor) can be in any other register.371		// Result[0] (the quotient) is in AX.372		// Result[1] (the remainder) is in DX.373		r := v.Args[1].Reg()374375		// Zero extend dividend.376		opregreg(s, x86.AXORL, x86.REG_DX, x86.REG_DX)377378		// Issue divide.379		p := s.Prog(v.Op.Asm())380		p.From.Type = obj.TYPE_REG381		p.From.Reg = r382383	case ssaop.OpAMD64DIVQ, ssaop.OpAMD64DIVL, ssaop.OpAMD64DIVW:384		// Arg[0] (the dividend) is in AX.385		// Arg[1] (the divisor) can be in any other register.386		// Result[0] (the quotient) is in AX.387		// Result[1] (the remainder) is in DX.388		r := v.Args[1].Reg()389390		var opCMP, opNEG, opSXD obj.As391		switch v.Op {392		case ssaop.OpAMD64DIVQ:393			opCMP, opNEG, opSXD = x86.ACMPQ, x86.ANEGQ, x86.ACQO394		case ssaop.OpAMD64DIVL:395			opCMP, opNEG, opSXD = x86.ACMPL, x86.ANEGL, x86.ACDQ396		case ssaop.OpAMD64DIVW:397			opCMP, opNEG, opSXD = x86.ACMPW, x86.ANEGW, x86.ACWD398		}399400		// CPU faults upon signed overflow, which occurs when the most401		// negative int is divided by -1. Handle divide by -1 as a special case.402		var j1, j2 *obj.Prog403		if ssa.DivisionNeedsFixUp(v) {404			c := s.Prog(opCMP)405			c.From.Type = obj.TYPE_REG406			c.From.Reg = r407			c.To.Type = obj.TYPE_CONST408			c.To.Offset = -1409410			// Divisor is not -1, proceed with normal division.411			j1 = s.Prog(x86.AJNE)412			j1.To.Type = obj.TYPE_BRANCH413414			// Divisor is -1, manually compute quotient and remainder via fixup code.415			// n / -1 = -n416			n1 := s.Prog(opNEG)417			n1.To.Type = obj.TYPE_REG418			n1.To.Reg = x86.REG_AX419420			// n % -1 == 0421			opregreg(s, x86.AXORL, x86.REG_DX, x86.REG_DX)422423			// TODO(khr): issue only the -1 fixup code we need.424			// For instance, if only the quotient is used, no point in zeroing the remainder.425426			// Skip over normal division.427			j2 = s.Prog(obj.AJMP)428			j2.To.Type = obj.TYPE_BRANCH429		}430431		// Sign extend dividend and perform division.432		p := s.Prog(opSXD)433		if j1 != nil {434			j1.To.SetTarget(p)435		}436		p = s.Prog(v.Op.Asm())437		p.From.Type = obj.TYPE_REG438		p.From.Reg = r439440		if j2 != nil {441			j2.To.SetTarget(s.Pc())442		}443444	case ssaop.OpAMD64HMULQ, ssaop.OpAMD64HMULL, ssaop.OpAMD64HMULQU, ssaop.OpAMD64HMULLU:445		// the frontend rewrites constant division by 8/16/32 bit integers into446		// HMUL by a constant447		// SSA rewrites generate the 64 bit versions448449		// Arg[0] is already in AX as it's the only register we allow450		// and DX is the only output we care about (the high bits)451		p := s.Prog(v.Op.Asm())452		p.From.Type = obj.TYPE_REG453		p.From.Reg = v.Args[1].Reg()454455		// IMULB puts the high portion in AH instead of DL,456		// so move it to DL for consistency457		if v.Type.Size() == 1 {458			m := s.Prog(x86.AMOVB)459			m.From.Type = obj.TYPE_REG460			m.From.Reg = x86.REG_AH461			m.To.Type = obj.TYPE_REG462			m.To.Reg = x86.REG_DX463		}464465	case ssaop.OpAMD64MULQU, ssaop.OpAMD64MULLU:466		// Arg[0] is already in AX as it's the only register we allow467		// results lo in AX468		p := s.Prog(v.Op.Asm())469		p.From.Type = obj.TYPE_REG470		p.From.Reg = v.Args[1].Reg()471472	case ssaop.OpAMD64MULQU2:473		// Arg[0] is already in AX as it's the only register we allow474		// results hi in DX, lo in AX475		p := s.Prog(v.Op.Asm())476		p.From.Type = obj.TYPE_REG477		p.From.Reg = v.Args[1].Reg()478479	case ssaop.OpAMD64MULXQ:480		// Arg[0] is already in DX (the implicit operand); Arg[1] is any GP/mem.481		// SSA outputs are (hi, lo) -> Reg0()=hi, Reg1()=lo.482		// Go assembler syntax: MULXQ src, lo, hi (encodes vvvv=lo, reg=hi).483		p := s.Prog(v.Op.Asm())484		p.From.Type = obj.TYPE_REG485		p.From.Reg = v.Args[1].Reg()486		p.AddRestSourceReg(v.Reg1())487		p.To.Type = obj.TYPE_REG488		p.To.Reg = v.Reg0()489490	case ssaop.OpAMD64DIVQU2:491		// Arg[0], Arg[1] are already in Dx, AX, as they're the only registers we allow492		// results q in AX, r in DX493		p := s.Prog(v.Op.Asm())494		p.From.Type = obj.TYPE_REG495		p.From.Reg = v.Args[2].Reg()496497	case ssaop.OpAMD64AVGQU:498		// compute (x+y)/2 unsigned.499		// Do a 64-bit add, the overflow goes into the carry.500		// Shift right once and pull the carry back into the 63rd bit.501		p := s.Prog(x86.AADDQ)502		p.From.Type = obj.TYPE_REG503		p.To.Type = obj.TYPE_REG504		p.To.Reg = v.Reg()505		p.From.Reg = v.Args[1].Reg()506		p = s.Prog(x86.ARCRQ)507		p.From.Type = obj.TYPE_CONST508		p.From.Offset = 1509		p.To.Type = obj.TYPE_REG510		p.To.Reg = v.Reg()511512	case ssaop.OpAMD64ADDQcarry, ssaop.OpAMD64ADCQ:513		r := v.Reg0()514		r0 := v.Args[0].Reg()515		r1 := v.Args[1].Reg()516		switch r {517		case r0:518			p := s.Prog(v.Op.Asm())519			p.From.Type = obj.TYPE_REG520			p.From.Reg = r1521			p.To.Type = obj.TYPE_REG522			p.To.Reg = r523		case r1:524			p := s.Prog(v.Op.Asm())525			p.From.Type = obj.TYPE_REG526			p.From.Reg = r0527			p.To.Type = obj.TYPE_REG528			p.To.Reg = r529		default:530			v.Fatalf("output not in same register as an input %s", v.LongString())531		}532533	case ssaop.OpAMD64SUBQborrow, ssaop.OpAMD64SBBQ:534		p := s.Prog(v.Op.Asm())535		p.From.Type = obj.TYPE_REG536		p.From.Reg = v.Args[1].Reg()537		p.To.Type = obj.TYPE_REG538		p.To.Reg = v.Reg0()539540	case ssaop.OpAMD64ADDQconstcarry, ssaop.OpAMD64ADCQconst, ssaop.OpAMD64SUBQconstborrow, ssaop.OpAMD64SBBQconst:541		p := s.Prog(v.Op.Asm())542		p.From.Type = obj.TYPE_CONST543		p.From.Offset = v.AuxInt544		p.To.Type = obj.TYPE_REG545		p.To.Reg = v.Reg0()546547	case ssaop.OpAMD64ADDQconst, ssaop.OpAMD64ADDLconst:548		r := v.Reg()549		a := v.Args[0].Reg()550		if r == a {551			switch v.AuxInt {552			case 1:553				var asm obj.As554				// Software optimization manual recommends add $1,reg.555				// But inc/dec is 1 byte smaller. ICC always uses inc556				// Clang/GCC choose depending on flags, but prefer add.557				// Experiments show that inc/dec is both a little faster558				// and make a binary a little smaller.559				if v.Op == ssaop.OpAMD64ADDQconst {560					asm = x86.AINCQ561				} else {562					asm = x86.AINCL563				}564				p := s.Prog(asm)565				p.To.Type = obj.TYPE_REG566				p.To.Reg = r567				return568			case -1:569				var asm obj.As570				if v.Op == ssaop.OpAMD64ADDQconst {571					asm = x86.ADECQ572				} else {573					asm = x86.ADECL574				}575				p := s.Prog(asm)576				p.To.Type = obj.TYPE_REG577				p.To.Reg = r578				return579			case 0x80:580				// 'SUBQ $-0x80, r' is shorter to encode than581				// and functionally equivalent to 'ADDQ $0x80, r'.582				asm := x86.ASUBL583				if v.Op == ssaop.OpAMD64ADDQconst {584					asm = x86.ASUBQ585				}586				p := s.Prog(asm)587				p.From.Type = obj.TYPE_CONST588				p.From.Offset = -0x80589				p.To.Type = obj.TYPE_REG590				p.To.Reg = r591				return592593			}594			p := s.Prog(v.Op.Asm())595			p.From.Type = obj.TYPE_CONST596			p.From.Offset = v.AuxInt597			p.To.Type = obj.TYPE_REG598			p.To.Reg = r599			return600		}601		var asm obj.As602		if v.Op == ssaop.OpAMD64ADDQconst {603			asm = x86.ALEAQ604		} else {605			asm = x86.ALEAL606		}607		p := s.Prog(asm)608		p.From.Type = obj.TYPE_MEM609		p.From.Reg = a610		p.From.Offset = v.AuxInt611		p.To.Type = obj.TYPE_REG612		p.To.Reg = r613614	case ssaop.OpAMD64CMOVQEQ, ssaop.OpAMD64CMOVLEQ, ssaop.OpAMD64CMOVWEQ,615		ssaop.OpAMD64CMOVQLT, ssaop.OpAMD64CMOVLLT, ssaop.OpAMD64CMOVWLT,616		ssaop.OpAMD64CMOVQNE, ssaop.OpAMD64CMOVLNE, ssaop.OpAMD64CMOVWNE,617		ssaop.OpAMD64CMOVQGT, ssaop.OpAMD64CMOVLGT, ssaop.OpAMD64CMOVWGT,618		ssaop.OpAMD64CMOVQLE, ssaop.OpAMD64CMOVLLE, ssaop.OpAMD64CMOVWLE,619		ssaop.OpAMD64CMOVQGE, ssaop.OpAMD64CMOVLGE, ssaop.OpAMD64CMOVWGE,620		ssaop.OpAMD64CMOVQHI, ssaop.OpAMD64CMOVLHI, ssaop.OpAMD64CMOVWHI,621		ssaop.OpAMD64CMOVQLS, ssaop.OpAMD64CMOVLLS, ssaop.OpAMD64CMOVWLS,622		ssaop.OpAMD64CMOVQCC, ssaop.OpAMD64CMOVLCC, ssaop.OpAMD64CMOVWCC,623		ssaop.OpAMD64CMOVQCS, ssaop.OpAMD64CMOVLCS, ssaop.OpAMD64CMOVWCS,624		ssaop.OpAMD64CMOVQGTF, ssaop.OpAMD64CMOVLGTF, ssaop.OpAMD64CMOVWGTF,625		ssaop.OpAMD64CMOVQGEF, ssaop.OpAMD64CMOVLGEF, ssaop.OpAMD64CMOVWGEF:626		p := s.Prog(v.Op.Asm())627		p.From.Type = obj.TYPE_REG628		p.From.Reg = v.Args[1].Reg()629		p.To.Type = obj.TYPE_REG630		p.To.Reg = v.Reg()631632	case ssaop.OpAMD64CMOVQNEF, ssaop.OpAMD64CMOVLNEF, ssaop.OpAMD64CMOVWNEF:633		// Flag condition: ^ZERO || PARITY634		// Generate:635		//   CMOV*NE  SRC,DST636		//   CMOV*PS  SRC,DST637		p := s.Prog(v.Op.Asm())638		p.From.Type = obj.TYPE_REG639		p.From.Reg = v.Args[1].Reg()640		p.To.Type = obj.TYPE_REG641		p.To.Reg = v.Reg()642		var q *obj.Prog643		if v.Op == ssaop.OpAMD64CMOVQNEF {644			q = s.Prog(x86.ACMOVQPS)645		} else if v.Op == ssaop.OpAMD64CMOVLNEF {646			q = s.Prog(x86.ACMOVLPS)647		} else {648			q = s.Prog(x86.ACMOVWPS)649		}650		q.From.Type = obj.TYPE_REG651		q.From.Reg = v.Args[1].Reg()652		q.To.Type = obj.TYPE_REG653		q.To.Reg = v.Reg()654655	case ssaop.OpAMD64CMOVQEQF, ssaop.OpAMD64CMOVLEQF, ssaop.OpAMD64CMOVWEQF:656		// Flag condition: ZERO && !PARITY657		// Generate:658		//   MOV      SRC,TMP659		//   CMOV*NE  DST,TMP660		//   CMOV*PC  TMP,DST661		//662		// TODO(rasky): we could generate:663		//   CMOV*NE  DST,SRC664		//   CMOV*PC  SRC,DST665		// But this requires a way for regalloc to know that SRC might be666		// clobbered by this instruction.667		t := v.RegTmp()668		opregreg(s, moveByRegsWidth(t, v.Args[1].Reg(), v.Type.Size()), t, v.Args[1].Reg())669670		p := s.Prog(v.Op.Asm())671		p.From.Type = obj.TYPE_REG672		p.From.Reg = v.Reg()673		p.To.Type = obj.TYPE_REG674		p.To.Reg = t675		var q *obj.Prog676		if v.Op == ssaop.OpAMD64CMOVQEQF {677			q = s.Prog(x86.ACMOVQPC)678		} else if v.Op == ssaop.OpAMD64CMOVLEQF {679			q = s.Prog(x86.ACMOVLPC)680		} else {681			q = s.Prog(x86.ACMOVWPC)682		}683		q.From.Type = obj.TYPE_REG684		q.From.Reg = t685		q.To.Type = obj.TYPE_REG686		q.To.Reg = v.Reg()687688	case ssaop.OpAMD64MULQconst, ssaop.OpAMD64MULLconst:689		r := v.Reg()690		p := s.Prog(v.Op.Asm())691		p.From.Type = obj.TYPE_CONST692		p.From.Offset = v.AuxInt693		p.To.Type = obj.TYPE_REG694		p.To.Reg = r695		p.AddRestSourceReg(v.Args[0].Reg())696697	case ssaop.OpAMD64ANDQconst:698		asm := v.Op.Asm()699		// If the constant is positive and fits into 32 bits, use ANDL.700		// This saves a few bytes of encoding.701		if 0 <= v.AuxInt && v.AuxInt <= (1<<32-1) {702			asm = x86.AANDL703		}704		p := s.Prog(asm)705		p.From.Type = obj.TYPE_CONST706		p.From.Offset = v.AuxInt707		p.To.Type = obj.TYPE_REG708		p.To.Reg = v.Reg()709710	case ssaop.OpAMD64SUBQconst, ssaop.OpAMD64SUBLconst,711		ssaop.OpAMD64ANDLconst,712		ssaop.OpAMD64ORQconst, ssaop.OpAMD64ORLconst,713		ssaop.OpAMD64XORQconst, ssaop.OpAMD64XORLconst:714		p := s.Prog(v.Op.Asm())715		p.From.Type = obj.TYPE_CONST716		p.From.Offset = v.AuxInt717		p.To.Type = obj.TYPE_REG718		p.To.Reg = v.Reg()719720	case ssaop.OpAMD64SHLQconst, ssaop.OpAMD64SHLLconst,721		ssaop.OpAMD64SHRQconst, ssaop.OpAMD64SHRLconst, ssaop.OpAMD64SHRWconst, ssaop.OpAMD64SHRBconst,722		ssaop.OpAMD64SARQconst, ssaop.OpAMD64SARLconst, ssaop.OpAMD64SARWconst, ssaop.OpAMD64SARBconst,723		ssaop.OpAMD64ROLQconst, ssaop.OpAMD64ROLLconst, ssaop.OpAMD64ROLWconst, ssaop.OpAMD64ROLBconst:724		var maxShift int64725		switch v.Op {726		case ssaop.OpAMD64SHLQconst, ssaop.OpAMD64SHRQconst, ssaop.OpAMD64SARQconst, ssaop.OpAMD64ROLQconst:727			maxShift = 63728		case ssaop.OpAMD64SHLLconst, ssaop.OpAMD64SHRLconst, ssaop.OpAMD64SARLconst, ssaop.OpAMD64ROLLconst:729			maxShift = 31730		case ssaop.OpAMD64SHRWconst, ssaop.OpAMD64SARWconst, ssaop.OpAMD64ROLWconst:731			maxShift = 15732		case ssaop.OpAMD64SHRBconst, ssaop.OpAMD64SARBconst, ssaop.OpAMD64ROLBconst:733			maxShift = 7734		default:735			panic("unreachable")736		}737		if v.AuxInt < 0 || v.AuxInt > maxShift {738			v.Fatalf("shift amount out of range [0,%d]: %d", maxShift, v.AuxInt)739		}740		p := s.Prog(v.Op.Asm())741		p.From.Type = obj.TYPE_CONST742		p.From.Offset = v.AuxInt743		p.To.Type = obj.TYPE_REG744		p.To.Reg = v.Reg()745	case ssaop.OpAMD64SBBQcarrymask, ssaop.OpAMD64SBBLcarrymask:746		r := v.Reg()747		p := s.Prog(v.Op.Asm())748		p.From.Type = obj.TYPE_REG749		p.From.Reg = r750		p.To.Type = obj.TYPE_REG751		p.To.Reg = r752	case ssaop.OpAMD64LEAQ1, ssaop.OpAMD64LEAQ2, ssaop.OpAMD64LEAQ4, ssaop.OpAMD64LEAQ8,753		ssaop.OpAMD64LEAL1, ssaop.OpAMD64LEAL2, ssaop.OpAMD64LEAL4, ssaop.OpAMD64LEAL8,754		ssaop.OpAMD64LEAW1, ssaop.OpAMD64LEAW2, ssaop.OpAMD64LEAW4, ssaop.OpAMD64LEAW8:755		p := s.Prog(v.Op.Asm())756		memIdx(&p.From, v)757		ssagen.AddAux(&p.From, v)758		p.To.Type = obj.TYPE_REG759		p.To.Reg = v.Reg()760	case ssaop.OpAMD64LEAQ, ssaop.OpAMD64LEAL, ssaop.OpAMD64LEAW:761		p := s.Prog(v.Op.Asm())762		p.From.Type = obj.TYPE_MEM763		p.From.Reg = v.Args[0].Reg()764		ssagen.AddAux(&p.From, v)765		p.To.Type = obj.TYPE_REG766		p.To.Reg = v.Reg()767	case ssaop.OpAMD64CMPQ, ssaop.OpAMD64CMPL, ssaop.OpAMD64CMPW, ssaop.OpAMD64CMPB,768		ssaop.OpAMD64TESTQ, ssaop.OpAMD64TESTL, ssaop.OpAMD64TESTW, ssaop.OpAMD64TESTB,769		ssaop.OpAMD64BTL, ssaop.OpAMD64BTQ:770		opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())771	case ssaop.OpAMD64UCOMISS, ssaop.OpAMD64UCOMISD:772		// Go assembler has swapped operands for UCOMISx relative to CMP,773		// must account for that right here.774		opregreg(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg())775	case ssaop.OpAMD64CMPQconst, ssaop.OpAMD64CMPLconst, ssaop.OpAMD64CMPWconst, ssaop.OpAMD64CMPBconst:776		p := s.Prog(v.Op.Asm())777		p.From.Type = obj.TYPE_REG778		p.From.Reg = v.Args[0].Reg()779		p.To.Type = obj.TYPE_CONST780		p.To.Offset = v.AuxInt781	case ssaop.OpAMD64BTLconst, ssaop.OpAMD64BTQconst,782		ssaop.OpAMD64TESTQconst, ssaop.OpAMD64TESTLconst, ssaop.OpAMD64TESTWconst, ssaop.OpAMD64TESTBconst,783		ssaop.OpAMD64BTSQconst,784		ssaop.OpAMD64BTCQconst,785		ssaop.OpAMD64BTRQconst:786		op := v.Op787		if op == ssaop.OpAMD64BTQconst && v.AuxInt < 32 {788			// Emit 32-bit version because it's shorter789			op = ssaop.OpAMD64BTLconst790		}791		p := s.Prog(op.Asm())792		p.From.Type = obj.TYPE_CONST793		p.From.Offset = v.AuxInt794		p.To.Type = obj.TYPE_REG795		p.To.Reg = v.Args[0].Reg()796	case ssaop.OpAMD64CMPQload, ssaop.OpAMD64CMPLload, ssaop.OpAMD64CMPWload, ssaop.OpAMD64CMPBload:797		p := s.Prog(v.Op.Asm())798		p.From.Type = obj.TYPE_MEM799		p.From.Reg = v.Args[0].Reg()800		ssagen.AddAux(&p.From, v)801		p.To.Type = obj.TYPE_REG802		p.To.Reg = v.Args[1].Reg()803	case ssaop.OpAMD64CMPQconstload, ssaop.OpAMD64CMPLconstload, ssaop.OpAMD64CMPWconstload, ssaop.OpAMD64CMPBconstload:804		sc := v.AuxValAndOff()805		p := s.Prog(v.Op.Asm())806		p.From.Type = obj.TYPE_MEM807		p.From.Reg = v.Args[0].Reg()808		ssagen.AddAux2(&p.From, v, sc.Off64())809		p.To.Type = obj.TYPE_CONST810		p.To.Offset = sc.Val64()811	case ssaop.OpAMD64CMPQloadidx8, ssaop.OpAMD64CMPQloadidx1, ssaop.OpAMD64CMPLloadidx4, ssaop.OpAMD64CMPLloadidx1, ssaop.OpAMD64CMPWloadidx2, ssaop.OpAMD64CMPWloadidx1, ssaop.OpAMD64CMPBloadidx1:812		p := s.Prog(v.Op.Asm())813		memIdx(&p.From, v)814		ssagen.AddAux(&p.From, v)815		p.To.Type = obj.TYPE_REG816		p.To.Reg = v.Args[2].Reg()817	case ssaop.OpAMD64CMPQconstloadidx8, ssaop.OpAMD64CMPQconstloadidx1, ssaop.OpAMD64CMPLconstloadidx4, ssaop.OpAMD64CMPLconstloadidx1, ssaop.OpAMD64CMPWconstloadidx2, ssaop.OpAMD64CMPWconstloadidx1, ssaop.OpAMD64CMPBconstloadidx1:818		sc := v.AuxValAndOff()819		p := s.Prog(v.Op.Asm())820		memIdx(&p.From, v)821		ssagen.AddAux2(&p.From, v, sc.Off64())822		p.To.Type = obj.TYPE_CONST823		p.To.Offset = sc.Val64()824	case ssaop.OpAMD64MOVLconst, ssaop.OpAMD64MOVQconst:825		x := v.Reg()826827		// If flags aren't live (indicated by v.Aux == nil),828		// then we can rewrite MOV $0, AX into XOR AX, AX.829		if v.AuxInt == 0 && v.Aux == nil {830			opregreg(s, x86.AXORL, x, x)831			break832		}833834		asm := v.Op.Asm()835		// Use MOVL to move a small constant into a register836		// when the constant is positive and fits into 32 bits.837		if 0 <= v.AuxInt && v.AuxInt <= (1<<32-1) {838			// The upper 32bit are zeroed automatically when using MOVL.839			asm = x86.AMOVL840		}841		p := s.Prog(asm)842		p.From.Type = obj.TYPE_CONST843		p.From.Offset = v.AuxInt844		p.To.Type = obj.TYPE_REG845		p.To.Reg = x846847	case ssaop.OpAMD64MOVSSconst, ssaop.OpAMD64MOVSDconst:848		x := v.Reg()849		if !isFPReg(x) && v.AuxInt == 0 && v.Aux == nil {850			opregreg(s, x86.AXORL, x, x)851			break852		}853		p := s.Prog(storeByRegWidth(x, v.Type.Size()))854		p.From.Type = obj.TYPE_FCONST855		p.From.Val = math.Float64frombits(uint64(v.AuxInt))856		p.To.Type = obj.TYPE_REG857		p.To.Reg = x858	case ssaop.OpAMD64MOVQload, ssaop.OpAMD64MOVLload, ssaop.OpAMD64MOVWload, ssaop.OpAMD64MOVBload, ssaop.OpAMD64MOVOload,859		ssaop.OpAMD64MOVSSload, ssaop.OpAMD64MOVSDload, ssaop.OpAMD64MOVBQSXload, ssaop.OpAMD64MOVWQSXload, ssaop.OpAMD64MOVLQSXload,860		ssaop.OpAMD64MOVBEQload, ssaop.OpAMD64MOVBELload:861		p := s.Prog(v.Op.Asm())862		p.From.Type = obj.TYPE_MEM863		p.From.Reg = v.Args[0].Reg()864		ssagen.AddAux(&p.From, v)865		p.To.Type = obj.TYPE_REG866		p.To.Reg = v.Reg()867	case ssaop.OpAMD64MOVBloadidx1, ssaop.OpAMD64MOVWloadidx1, ssaop.OpAMD64MOVLloadidx1, ssaop.OpAMD64MOVQloadidx1, ssaop.OpAMD64MOVSSloadidx1, ssaop.OpAMD64MOVSDloadidx1,868		ssaop.OpAMD64MOVQloadidx8, ssaop.OpAMD64MOVSDloadidx8, ssaop.OpAMD64MOVLloadidx8, ssaop.OpAMD64MOVLloadidx4, ssaop.OpAMD64MOVSSloadidx4, ssaop.OpAMD64MOVWloadidx2,869		ssaop.OpAMD64MOVBELloadidx1, ssaop.OpAMD64MOVBELloadidx4, ssaop.OpAMD64MOVBELloadidx8, ssaop.OpAMD64MOVBEQloadidx1, ssaop.OpAMD64MOVBEQloadidx8:870		p := s.Prog(v.Op.Asm())871		memIdx(&p.From, v)872		ssagen.AddAux(&p.From, v)873		p.To.Type = obj.TYPE_REG874		p.To.Reg = v.Reg()875	case ssaop.OpAMD64MOVQstore, ssaop.OpAMD64MOVSSstore, ssaop.OpAMD64MOVSDstore, ssaop.OpAMD64MOVLstore, ssaop.OpAMD64MOVWstore, ssaop.OpAMD64MOVBstore, ssaop.OpAMD64MOVOstore,876		ssaop.OpAMD64ADDQmodify, ssaop.OpAMD64SUBQmodify, ssaop.OpAMD64ANDQmodify, ssaop.OpAMD64ORQmodify, ssaop.OpAMD64XORQmodify,877		ssaop.OpAMD64ADDLmodify, ssaop.OpAMD64SUBLmodify, ssaop.OpAMD64ANDLmodify, ssaop.OpAMD64ORLmodify, ssaop.OpAMD64XORLmodify,878		ssaop.OpAMD64MOVBEQstore, ssaop.OpAMD64MOVBELstore, ssaop.OpAMD64MOVBEWstore:879		p := s.Prog(v.Op.Asm())880		p.From.Type = obj.TYPE_REG881		p.From.Reg = v.Args[1].Reg()882		p.To.Type = obj.TYPE_MEM883		p.To.Reg = v.Args[0].Reg()884		ssagen.AddAux(&p.To, v)885	case ssaop.OpAMD64MOVBstoreidx1, ssaop.OpAMD64MOVWstoreidx1, ssaop.OpAMD64MOVLstoreidx1, ssaop.OpAMD64MOVQstoreidx1, ssaop.OpAMD64MOVSSstoreidx1, ssaop.OpAMD64MOVSDstoreidx1,886		ssaop.OpAMD64MOVQstoreidx8, ssaop.OpAMD64MOVSDstoreidx8, ssaop.OpAMD64MOVLstoreidx8, ssaop.OpAMD64MOVSSstoreidx4, ssaop.OpAMD64MOVLstoreidx4, ssaop.OpAMD64MOVWstoreidx2,887		ssaop.OpAMD64ADDLmodifyidx1, ssaop.OpAMD64ADDLmodifyidx4, ssaop.OpAMD64ADDLmodifyidx8, ssaop.OpAMD64ADDQmodifyidx1, ssaop.OpAMD64ADDQmodifyidx8,888		ssaop.OpAMD64SUBLmodifyidx1, ssaop.OpAMD64SUBLmodifyidx4, ssaop.OpAMD64SUBLmodifyidx8, ssaop.OpAMD64SUBQmodifyidx1, ssaop.OpAMD64SUBQmodifyidx8,889		ssaop.OpAMD64ANDLmodifyidx1, ssaop.OpAMD64ANDLmodifyidx4, ssaop.OpAMD64ANDLmodifyidx8, ssaop.OpAMD64ANDQmodifyidx1, ssaop.OpAMD64ANDQmodifyidx8,890		ssaop.OpAMD64ORLmodifyidx1, ssaop.OpAMD64ORLmodifyidx4, ssaop.OpAMD64ORLmodifyidx8, ssaop.OpAMD64ORQmodifyidx1, ssaop.OpAMD64ORQmodifyidx8,891		ssaop.OpAMD64XORLmodifyidx1, ssaop.OpAMD64XORLmodifyidx4, ssaop.OpAMD64XORLmodifyidx8, ssaop.OpAMD64XORQmodifyidx1, ssaop.OpAMD64XORQmodifyidx8,892		ssaop.OpAMD64MOVBEWstoreidx1, ssaop.OpAMD64MOVBEWstoreidx2, ssaop.OpAMD64MOVBELstoreidx1, ssaop.OpAMD64MOVBELstoreidx4, ssaop.OpAMD64MOVBELstoreidx8, ssaop.OpAMD64MOVBEQstoreidx1, ssaop.OpAMD64MOVBEQstoreidx8:893		p := s.Prog(v.Op.Asm())894		p.From.Type = obj.TYPE_REG895		p.From.Reg = v.Args[2].Reg()896		memIdx(&p.To, v)897		ssagen.AddAux(&p.To, v)898	case ssaop.OpAMD64ADDQconstmodify, ssaop.OpAMD64ADDLconstmodify,899		ssaop.OpAMD64ADDWconstmodify, ssaop.OpAMD64ADDBconstmodify:900		sc := v.AuxValAndOff()901		off := sc.Off64()902		val := sc.Val()903		if val == 1 || val == -1 {904			var asm obj.As905			switch v.Op {906			case ssaop.OpAMD64ADDQconstmodify:907				asm = x86.AINCQ908				if val == -1 {909					asm = x86.ADECQ910				}911			case ssaop.OpAMD64ADDLconstmodify:912				asm = x86.AINCL913				if val == -1 {914					asm = x86.ADECL915				}916			case ssaop.OpAMD64ADDWconstmodify:917				asm = x86.AINCW918				if val == -1 {919					asm = x86.ADECW920				}921			default:922				asm = x86.AINCB923				if val == -1 {924					asm = x86.ADECB925				}926			}927			p := s.Prog(asm)928			p.To.Type = obj.TYPE_MEM929			p.To.Reg = v.Args[0].Reg()930			ssagen.AddAux2(&p.To, v, off)931			break932		}933		fallthrough934	case ssaop.OpAMD64ANDQconstmodify, ssaop.OpAMD64ANDLconstmodify, ssaop.OpAMD64ORQconstmodify, ssaop.OpAMD64ORLconstmodify,935		ssaop.OpAMD64XORQconstmodify, ssaop.OpAMD64XORLconstmodify,936		ssaop.OpAMD64ANDWconstmodify, ssaop.OpAMD64ANDBconstmodify, ssaop.OpAMD64ORWconstmodify, ssaop.OpAMD64ORBconstmodify,937		ssaop.OpAMD64XORWconstmodify, ssaop.OpAMD64XORBconstmodify,938		ssaop.OpAMD64BTSQconstmodify, ssaop.OpAMD64BTRQconstmodify, ssaop.OpAMD64BTCQconstmodify:939		sc := v.AuxValAndOff()940		off := sc.Off64()941		val := sc.Val64()942		p := s.Prog(v.Op.Asm())943		p.From.Type = obj.TYPE_CONST944		p.From.Offset = val945		p.To.Type = obj.TYPE_MEM946		p.To.Reg = v.Args[0].Reg()947		ssagen.AddAux2(&p.To, v, off)948949	case ssaop.OpAMD64MOVQstoreconst, ssaop.OpAMD64MOVLstoreconst, ssaop.OpAMD64MOVWstoreconst, ssaop.OpAMD64MOVBstoreconst:950		sc := v.AuxValAndOff()951		p := s.Prog(v.Op.Asm())952		if sc.Val() == 0 && s.ABI == obj.ABIInternal && buildcfg.GOOS != "plan9" && (v.Op == ssaop.OpAMD64MOVQstoreconst || v.Op == ssaop.OpAMD64MOVLstoreconst) {953			p.From.Type = obj.TYPE_REG954			p.From.Reg = x86.REG_X15955		} else {956			p.From.Type = obj.TYPE_CONST957			p.From.Offset = sc.Val64()958		}959		p.To.Type = obj.TYPE_MEM960		p.To.Reg = v.Args[0].Reg()961		ssagen.AddAux2(&p.To, v, sc.Off64())962	case ssaop.OpAMD64MOVOstoreconst:963		sc := v.AuxValAndOff()964		if sc.Val() != 0 {965			v.Fatalf("MOVO for non zero constants not implemented: %s", v.LongString())966		}967968		if s.ABI != obj.ABIInternal {969			// zero X15 manually970			opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)971		}972		p := s.Prog(v.Op.Asm())973		p.From.Type = obj.TYPE_REG974		p.From.Reg = x86.REG_X15975		p.To.Type = obj.TYPE_MEM976		p.To.Reg = v.Args[0].Reg()977		ssagen.AddAux2(&p.To, v, sc.Off64())978979	case ssaop.OpAMD64MOVQstoreconstidx1, ssaop.OpAMD64MOVQstoreconstidx8, ssaop.OpAMD64MOVLstoreconstidx1, ssaop.OpAMD64MOVLstoreconstidx4, ssaop.OpAMD64MOVWstoreconstidx1, ssaop.OpAMD64MOVWstoreconstidx2, ssaop.OpAMD64MOVBstoreconstidx1,980		ssaop.OpAMD64ADDLconstmodifyidx1, ssaop.OpAMD64ADDLconstmodifyidx4, ssaop.OpAMD64ADDLconstmodifyidx8, ssaop.OpAMD64ADDQconstmodifyidx1, ssaop.OpAMD64ADDQconstmodifyidx8,981		ssaop.OpAMD64ANDLconstmodifyidx1, ssaop.OpAMD64ANDLconstmodifyidx4, ssaop.OpAMD64ANDLconstmodifyidx8, ssaop.OpAMD64ANDQconstmodifyidx1, ssaop.OpAMD64ANDQconstmodifyidx8,982		ssaop.OpAMD64ORLconstmodifyidx1, ssaop.OpAMD64ORLconstmodifyidx4, ssaop.OpAMD64ORLconstmodifyidx8, ssaop.OpAMD64ORQconstmodifyidx1, ssaop.OpAMD64ORQconstmodifyidx8,983		ssaop.OpAMD64XORLconstmodifyidx1, ssaop.OpAMD64XORLconstmodifyidx4, ssaop.OpAMD64XORLconstmodifyidx8, ssaop.OpAMD64XORQconstmodifyidx1, ssaop.OpAMD64XORQconstmodifyidx8,984		ssaop.OpAMD64ADDWconstmodifyidx1, ssaop.OpAMD64ADDWconstmodifyidx2, ssaop.OpAMD64ADDBconstmodifyidx1,985		ssaop.OpAMD64ANDWconstmodifyidx1, ssaop.OpAMD64ANDWconstmodifyidx2, ssaop.OpAMD64ANDBconstmodifyidx1,986		ssaop.OpAMD64ORWconstmodifyidx1, ssaop.OpAMD64ORWconstmodifyidx2, ssaop.OpAMD64ORBconstmodifyidx1,987		ssaop.OpAMD64XORWconstmodifyidx1, ssaop.OpAMD64XORWconstmodifyidx2, ssaop.OpAMD64XORBconstmodifyidx1:988		p := s.Prog(v.Op.Asm())989		p.From.Type = obj.TYPE_CONST990		sc := v.AuxValAndOff()991		p.From.Offset = sc.Val64()992		if sc.Val() == 0 && s.ABI == obj.ABIInternal && buildcfg.GOOS != "plan9" {993			switch v.Op {994			case ssaop.OpAMD64MOVQstoreconstidx1, ssaop.OpAMD64MOVQstoreconstidx8,995				ssaop.OpAMD64MOVLstoreconstidx1, ssaop.OpAMD64MOVLstoreconstidx4:996				p.From.Type = obj.TYPE_REG997				p.From.Reg = x86.REG_X15998			}999		}1000		switch {1001		case p.As == x86.AADDQ && p.From.Offset == 1:1002			p.As = x86.AINCQ1003			p.From.Type = obj.TYPE_NONE1004		case p.As == x86.AADDQ && p.From.Offset == -1:1005			p.As = x86.ADECQ1006			p.From.Type = obj.TYPE_NONE1007		case p.As == x86.AADDL && p.From.Offset == 1:1008			p.As = x86.AINCL1009			p.From.Type = obj.TYPE_NONE1010		case p.As == x86.AADDL && p.From.Offset == -1:1011			p.As = x86.ADECL1012			p.From.Type = obj.TYPE_NONE1013		case p.As == x86.AADDW && p.From.Offset == 1:1014			p.As = x86.AINCW1015			p.From.Type = obj.TYPE_NONE1016		case p.As == x86.AADDW && p.From.Offset == -1:1017			p.As = x86.ADECW1018			p.From.Type = obj.TYPE_NONE1019		case p.As == x86.AADDB && p.From.Offset == 1:1020			p.As = x86.AINCB1021			p.From.Type = obj.TYPE_NONE1022		case p.As == x86.AADDB && p.From.Offset == -1:1023			p.As = x86.ADECB1024			p.From.Type = obj.TYPE_NONE1025		}1026		memIdx(&p.To, v)1027		ssagen.AddAux2(&p.To, v, sc.Off64())1028	case ssaop.OpAMD64MOVLQSX, ssaop.OpAMD64MOVWQSX, ssaop.OpAMD64MOVBQSX, ssaop.OpAMD64MOVLQZX, ssaop.OpAMD64MOVWQZX, ssaop.OpAMD64MOVBQZX,1029		ssaop.OpAMD64CVTTSS2SL, ssaop.OpAMD64CVTTSD2SL, ssaop.OpAMD64CVTTSS2SQ, ssaop.OpAMD64CVTTSD2SQ,1030		ssaop.OpAMD64CVTSS2SD, ssaop.OpAMD64CVTSD2SS, ssaop.OpAMD64VPBROADCASTB, ssaop.OpAMD64PMOVMSKB:1031		opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())1032	case ssaop.OpAMD64CVTSL2SD, ssaop.OpAMD64CVTSQ2SD, ssaop.OpAMD64CVTSQ2SS, ssaop.OpAMD64CVTSL2SS:1033		r := v.Reg()1034		// Break false dependency on destination register.1035		opregreg(s, x86.AXORPS, r, r)1036		opregreg(s, v.Op.Asm(), r, v.Args[0].Reg())1037	case ssaop.OpAMD64MOVQi2f, ssaop.OpAMD64MOVQf2i, ssaop.OpAMD64MOVLi2f, ssaop.OpAMD64MOVLf2i:1038		var p *obj.Prog1039		switch v.Op {1040		case ssaop.OpAMD64MOVQi2f, ssaop.OpAMD64MOVQf2i:1041			p = s.Prog(x86.AMOVQ)1042		case ssaop.OpAMD64MOVLi2f, ssaop.OpAMD64MOVLf2i:1043			p = s.Prog(x86.AMOVL)1044		}1045		p.From.Type = obj.TYPE_REG1046		p.From.Reg = v.Args[0].Reg()1047		p.To.Type = obj.TYPE_REG1048		p.To.Reg = v.Reg()1049	case ssaop.OpAMD64ADDQload, ssaop.OpAMD64ADDLload, ssaop.OpAMD64SUBQload, ssaop.OpAMD64SUBLload,1050		ssaop.OpAMD64ANDQload, ssaop.OpAMD64ANDLload, ssaop.OpAMD64ORQload, ssaop.OpAMD64ORLload,1051		ssaop.OpAMD64XORQload, ssaop.OpAMD64XORLload, ssaop.OpAMD64ADDSDload, ssaop.OpAMD64ADDSSload,1052		ssaop.OpAMD64SUBSDload, ssaop.OpAMD64SUBSSload, ssaop.OpAMD64MULSDload, ssaop.OpAMD64MULSSload,1053		ssaop.OpAMD64DIVSDload, ssaop.OpAMD64DIVSSload:1054		p := s.Prog(v.Op.Asm())1055		p.From.Type = obj.TYPE_MEM1056		p.From.Reg = v.Args[1].Reg()1057		ssagen.AddAux(&p.From, v)1058		p.To.Type = obj.TYPE_REG1059		p.To.Reg = v.Reg()1060	case ssaop.OpAMD64ADDLloadidx1, ssaop.OpAMD64ADDLloadidx4, ssaop.OpAMD64ADDLloadidx8, ssaop.OpAMD64ADDQloadidx1, ssaop.OpAMD64ADDQloadidx8,1061		ssaop.OpAMD64SUBLloadidx1, ssaop.OpAMD64SUBLloadidx4, ssaop.OpAMD64SUBLloadidx8, ssaop.OpAMD64SUBQloadidx1, ssaop.OpAMD64SUBQloadidx8,1062		ssaop.OpAMD64ANDLloadidx1, ssaop.OpAMD64ANDLloadidx4, ssaop.OpAMD64ANDLloadidx8, ssaop.OpAMD64ANDQloadidx1, ssaop.OpAMD64ANDQloadidx8,1063		ssaop.OpAMD64ORLloadidx1, ssaop.OpAMD64ORLloadidx4, ssaop.OpAMD64ORLloadidx8, ssaop.OpAMD64ORQloadidx1, ssaop.OpAMD64ORQloadidx8,1064		ssaop.OpAMD64XORLloadidx1, ssaop.OpAMD64XORLloadidx4, ssaop.OpAMD64XORLloadidx8, ssaop.OpAMD64XORQloadidx1, ssaop.OpAMD64XORQloadidx8,1065		ssaop.OpAMD64ADDSSloadidx1, ssaop.OpAMD64ADDSSloadidx4, ssaop.OpAMD64ADDSDloadidx1, ssaop.OpAMD64ADDSDloadidx8,1066		ssaop.OpAMD64SUBSSloadidx1, ssaop.OpAMD64SUBSSloadidx4, ssaop.OpAMD64SUBSDloadidx1, ssaop.OpAMD64SUBSDloadidx8,1067		ssaop.OpAMD64MULSSloadidx1, ssaop.OpAMD64MULSSloadidx4, ssaop.OpAMD64MULSDloadidx1, ssaop.OpAMD64MULSDloadidx8,1068		ssaop.OpAMD64DIVSSloadidx1, ssaop.OpAMD64DIVSSloadidx4, ssaop.OpAMD64DIVSDloadidx1, ssaop.OpAMD64DIVSDloadidx8:1069		p := s.Prog(v.Op.Asm())10701071		r, i := v.Args[1].Reg(), v.Args[2].Reg()1072		p.From.Type = obj.TYPE_MEM1073		p.From.Scale = v.Op.Scale()1074		if p.From.Scale == 1 && i == x86.REG_SP {1075			r, i = i, r1076		}1077		p.From.Reg = r1078		p.From.Index = i10791080		ssagen.AddAux(&p.From, v)1081		p.To.Type = obj.TYPE_REG1082		p.To.Reg = v.Reg()10831084	case ssaop.OpAMD64LoweredZero:1085		if s.ABI != obj.ABIInternal {1086			// zero X15 manually1087			opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)1088		}1089		ptrReg := v.Args[0].Reg()1090		n := v.AuxInt1091		if n < 16 {1092			v.Fatalf("Zero too small %d", n)1093		}1094		zero16 := func(off int64) {1095			zero16(s, ptrReg, off)1096		}10971098		// Generate zeroing instructions.1099		var off int641100		for n >= 16 {1101			zero16(off)1102			off += 161103			n -= 161104		}1105		if n != 0 {1106			// use partially overlapped write.1107			// TODO: n <= 8, use smaller write?1108			zero16(off + n - 16)1109		}11101111	case ssaop.OpAMD64LoweredZeroLoop:1112		if s.ABI != obj.ABIInternal {1113			// zero X15 manually1114			opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)1115		}1116		ptrReg := v.Args[0].Reg()1117		countReg := v.RegTmp()1118		n := v.AuxInt1119		loopSize := int64(64)1120		if n < 3*loopSize {1121			// - a loop count of 0 won't work.1122			// - a loop count of 1 is useless.1123			// - a loop count of 2 is a code size ~tie1124			//     4 instructions to implement the loop1125			//     4 instructions in the loop body1126			//   vs1127			//     8 instructions in the straightline code1128			//   Might as well use straightline code.1129			v.Fatalf("ZeroLoop size too small %d", n)1130		}1131		zero16 := func(off int64) {1132			zero16(s, ptrReg, off)1133		}11341135		// Put iteration count in a register.1136		//   MOVL    $n, countReg1137		p := s.Prog(x86.AMOVL)1138		p.From.Type = obj.TYPE_CONST1139		p.From.Offset = n / loopSize1140		p.To.Type = obj.TYPE_REG1141		p.To.Reg = countReg1142		cntInit := p11431144		// Zero loopSize bytes starting at ptrReg.1145		for i := range loopSize / 16 {1146			zero16(i * 16)1147		}1148		//   ADDQ    $loopSize, ptrReg1149		p = s.Prog(x86.AADDQ)1150		p.From.Type = obj.TYPE_CONST1151		p.From.Offset = loopSize1152		p.To.Type = obj.TYPE_REG1153		p.To.Reg = ptrReg1154		//   DECL    countReg1155		p = s.Prog(x86.ADECL)1156		p.To.Type = obj.TYPE_REG1157		p.To.Reg = countReg1158		// Jump to first instruction in loop if we're not done yet.1159		//   JNE     head1160		p = s.Prog(x86.AJNE)1161		p.To.Type = obj.TYPE_BRANCH1162		p.To.SetTarget(cntInit.Link)11631164		// Multiples of the loop size are now done.1165		n %= loopSize11661167		// Write any fractional portion.1168		var off int641169		for n >= 16 {1170			zero16(off)1171			off += 161172			n -= 161173		}1174		if n != 0 {1175			// Use partially-overlapping write.1176			// TODO: n <= 8, use smaller write?1177			zero16(off + n - 16)1178		}11791180	case ssaop.OpAMD64LoweredMove:1181		dstReg := v.Args[0].Reg()1182		srcReg := v.Args[1].Reg()1183		if dstReg == srcReg {1184			break1185		}1186		tmpReg := int16(x86.REG_X14)1187		n := v.AuxInt1188		if n < 16 {1189			v.Fatalf("Move too small %d", n)1190		}1191		// move 16 bytes from srcReg+off to dstReg+off.1192		move16 := func(off int64) {1193			move16(s, srcReg, dstReg, tmpReg, off)1194		}11951196		// Generate copying instructions.1197		var off int641198		for n >= 16 {1199			move16(off)1200			off += 161201			n -= 161202		}1203		if n != 0 {1204			// use partially overlapped read/write.1205			// TODO: use smaller operations when we can?1206			move16(off + n - 16)1207		}12081209	case ssaop.OpAMD64LoweredMoveLoop:1210		dstReg := v.Args[0].Reg()1211		srcReg := v.Args[1].Reg()1212		if dstReg == srcReg {1213			break1214		}1215		countReg := v.RegTmp()1216		tmpReg := int16(x86.REG_X14)1217		n := v.AuxInt1218		loopSize := int64(64)1219		if n < 3*loopSize {1220			// - a loop count of 0 won't work.1221			// - a loop count of 1 is useless.1222			// - a loop count of 2 is a code size ~tie1223			//     4 instructions to implement the loop1224			//     4 instructions in the loop body1225			//   vs1226			//     8 instructions in the straightline code1227			//   Might as well use straightline code.1228			v.Fatalf("ZeroLoop size too small %d", n)1229		}1230		// move 16 bytes from srcReg+off to dstReg+off.1231		move16 := func(off int64) {1232			move16(s, srcReg, dstReg, tmpReg, off)1233		}12341235		// Put iteration count in a register.1236		//   MOVL    $n, countReg1237		p := s.Prog(x86.AMOVL)1238		p.From.Type = obj.TYPE_CONST1239		p.From.Offset = n / loopSize1240		p.To.Type = obj.TYPE_REG1241		p.To.Reg = countReg1242		cntInit := p12431244		// Copy loopSize bytes starting at srcReg to dstReg.1245		for i := range loopSize / 16 {1246			move16(i * 16)1247		}1248		//   ADDQ    $loopSize, srcReg1249		p = s.Prog(x86.AADDQ)1250		p.From.Type = obj.TYPE_CONST1251		p.From.Offset = loopSize1252		p.To.Type = obj.TYPE_REG1253		p.To.Reg = srcReg1254		//   ADDQ    $loopSize, dstReg1255		p = s.Prog(x86.AADDQ)1256		p.From.Type = obj.TYPE_CONST1257		p.From.Offset = loopSize1258		p.To.Type = obj.TYPE_REG1259		p.To.Reg = dstReg1260		//   DECL    countReg1261		p = s.Prog(x86.ADECL)1262		p.To.Type = obj.TYPE_REG1263		p.To.Reg = countReg1264		// Jump to loop header if we're not done yet.1265		//   JNE     head1266		p = s.Prog(x86.AJNE)1267		p.To.Type = obj.TYPE_BRANCH1268		p.To.SetTarget(cntInit.Link)12691270		// Multiples of the loop size are now done.1271		n %= loopSize12721273		// Copy any fractional portion.1274		var off int641275		for n >= 16 {1276			move16(off)1277			off += 161278			n -= 161279		}1280		if n != 0 {1281			// Use partially-overlapping copy.1282			move16(off + n - 16)1283		}12841285	case ssaop.OpCopy: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?1286		if v.Type.IsMemory() {1287			return1288		}1289		arg := v.Args[0]1290		x := arg.Reg()1291		y := v.Reg()1292		if v.Type.IsSIMD() {1293			x = simdOrMaskReg(arg)1294			y = simdOrMaskReg(v)1295		}1296		if x != y {1297			width := v.Type.Size()1298			if width == 8 && isGPReg(y) && ssa.ZeroUpper32Bits(arg) {1299				// The source was naturally zext-ed from 32 to 64 bits,1300				// but we are asked to do a full 64-bit copy.1301				// Save the REX prefix byte in I-CACHE by using a 32-bit move,1302				// since it zeroes the upper 32 bits anyway.1303				width = 41304			}1305			opregreg(s, moveByRegsWidth(y, x, width), y, x)1306		}1307	case ssaop.OpLoadReg:1308		if v.Type.IsFlags() {1309			v.Fatalf("load flags not implemented: %v", v.LongString())1310			return1311		}1312		r := v.Reg()1313		p := s.Prog(loadByRegWidth(r, v.Type.Size()))1314		ssagen.AddrAuto(&p.From, v.Args[0])1315		p.To.Type = obj.TYPE_REG1316		if v.Type.IsSIMD() {1317			r = simdOrMaskReg(v)1318		}1319		p.To.Reg = r13201321	case ssaop.OpStoreReg:1322		if v.Type.IsFlags() {1323			v.Fatalf("store flags not implemented: %v", v.LongString())1324			return1325		}1326		r := v.Args[0].Reg()1327		if v.Type.IsSIMD() {1328			r = simdOrMaskReg(v.Args[0])1329		}1330		p := s.Prog(storeByRegWidth(r, v.Type.Size()))1331		p.From.Type = obj.TYPE_REG1332		p.From.Reg = r1333		ssagen.AddrAuto(&p.To, v)1334	case ssaop.OpAMD64LoweredHasCPUFeature:1335		// If this load changes width, update zeroUpperBits in AMD64Ops.go.1336		p := s.Prog(x86.AMOVBLZX)1337		p.From.Type = obj.TYPE_MEM1338		ssagen.AddAux(&p.From, v)1339		p.To.Type = obj.TYPE_REG1340		p.To.Reg = v.Reg()1341	case ssaop.OpArgIntReg, ssaop.OpArgFloatReg:1342		// The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill1343		// The loop only runs once.1344		for _, ap := range v.Block.Func.RegArgs {1345			// Pass the spill/unspill information along to the assembler, offset by size of return PC pushed on stack.1346			addr := ssagen.SpillSlotAddr(ap, x86.REG_SP, v.Block.Func.Config.PtrSize)1347			reg := ap.Reg1348			t := ap.Type1349			sz := t.Size()1350			if t.IsSIMD() {1351				reg = simdRegBySize(reg, sz)1352			}1353			s.FuncInfo().AddSpill(1354				obj.RegSpill{Reg: reg, Addr: addr, Unspill: loadByRegWidth(reg, sz), Spill: storeByRegWidth(reg, sz)})1355		}1356		v.Block.Func.RegArgs = nil1357		ssagen.CheckArgReg(v)1358	case ssaop.OpAMD64LoweredGetClosurePtr:1359		// Closure pointer is DX.1360		ssagen.CheckLoweredGetClosurePtr(v)1361	case ssaop.OpAMD64LoweredGetG:1362		if s.ABI == obj.ABIInternal {1363			v.Fatalf("LoweredGetG should not appear in ABIInternal")1364		}1365		r := v.Reg()1366		getgFromTLS(s, r)1367	case ssaop.OpAMD64CALLstatic, ssaop.OpAMD64CALLtail, ssaop.OpAMD64CALLtailinter:1368		if s.ABI == obj.ABI0 && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABIInternal {1369			// zeroing X15 when entering ABIInternal from ABI01370			zeroX15(s)1371			// set G register from TLS1372			getgFromTLS(s, x86.REG_R14)1373		}1374		if v.Op == ssaop.OpAMD64CALLtail || v.Op == ssaop.OpAMD64CALLtailinter {1375			s.TailCall(v)1376			break1377		}1378		s.Call(v)1379		if s.ABI == obj.ABIInternal && v.Aux.(*ssa.AuxCall).Fn.ABI() == obj.ABI0 {1380			// zeroing X15 when entering ABIInternal from ABI01381			zeroX15(s)1382			// set G register from TLS1383			getgFromTLS(s, x86.REG_R14)1384		}1385	case ssaop.OpAMD64CALLclosure, ssaop.OpAMD64CALLinter:1386		s.Call(v)13871388	case ssaop.OpAMD64LoweredGetCallerPC:1389		p := s.Prog(x86.AMOVQ)1390		p.From.Type = obj.TYPE_MEM1391		p.From.Offset = -8 // PC is stored 8 bytes below first parameter.1392		p.From.Name = obj.NAME_PARAM1393		p.To.Type = obj.TYPE_REG1394		p.To.Reg = v.Reg()13951396	case ssaop.OpAMD64LoweredGetCallerSP:1397		// caller's SP is the address of the first arg1398		mov := x86.AMOVQ1399		if types.PtrSize == 4 {1400			mov = x86.AMOVL1401		}1402		p := s.Prog(mov)1403		p.From.Type = obj.TYPE_ADDR1404		p.From.Offset = -base.Ctxt.Arch.FixedFrameSize // 0 on amd64, just to be consistent with other architectures1405		p.From.Name = obj.NAME_PARAM1406		p.To.Type = obj.TYPE_REG1407		p.To.Reg = v.Reg()14081409	case ssaop.OpAMD64LoweredWB:1410		p := s.Prog(obj.ACALL)1411		p.To.Type = obj.TYPE_MEM1412		p.To.Name = obj.NAME_EXTERN1413		// AuxInt encodes how many buffer entries we need.1414		p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]14151416	case ssaop.OpAMD64LoweredPanicBoundsRR, ssaop.OpAMD64LoweredPanicBoundsRC, ssaop.OpAMD64LoweredPanicBoundsCR, ssaop.OpAMD64LoweredPanicBoundsCC:1417		// Compute the constant we put in the PCData entry for this call.1418		code, signed := ssa.BoundsKind(v.AuxInt).Code()1419		xIsReg := false1420		yIsReg := false1421		xVal := 01422		yVal := 01423		switch v.Op {1424		case ssaop.OpAMD64LoweredPanicBoundsRR:1425			xIsReg = true1426			xVal = int(v.Args[0].Reg() - x86.REG_AX)1427			yIsReg = true1428			yVal = int(v.Args[1].Reg() - x86.REG_AX)1429		case ssaop.OpAMD64LoweredPanicBoundsRC:1430			xIsReg = true1431			xVal = int(v.Args[0].Reg() - x86.REG_AX)1432			c := v.Aux.(ssa.PanicBoundsC).C1433			if c >= 0 && c <= abi.BoundsMaxConst {1434				yVal = int(c)1435			} else {1436				// Move constant to a register1437				yIsReg = true1438				if yVal == xVal {1439					yVal = 11440				}1441				p := s.Prog(x86.AMOVQ)1442				p.From.Type = obj.TYPE_CONST1443				p.From.Offset = c1444				p.To.Type = obj.TYPE_REG1445				p.To.Reg = x86.REG_AX + int16(yVal)1446			}1447		case ssaop.OpAMD64LoweredPanicBoundsCR:1448			yIsReg = true1449			yVal = int(v.Args[0].Reg() - x86.REG_AX)1450			c := v.Aux.(ssa.PanicBoundsC).C1451			if c >= 0 && c <= abi.BoundsMaxConst {1452				xVal = int(c)1453			} else {1454				// Move constant to a register1455				xIsReg = true1456				if xVal == yVal {1457					xVal = 11458				}1459				p := s.Prog(x86.AMOVQ)1460				p.From.Type = obj.TYPE_CONST1461				p.From.Offset = c1462				p.To.Type = obj.TYPE_REG1463				p.To.Reg = x86.REG_AX + int16(xVal)1464			}1465		case ssaop.OpAMD64LoweredPanicBoundsCC:1466			c := v.Aux.(ssa.PanicBoundsCC).Cx1467			if c >= 0 && c <= abi.BoundsMaxConst {1468				xVal = int(c)1469			} else {1470				// Move constant to a register1471				xIsReg = true1472				p := s.Prog(x86.AMOVQ)1473				p.From.Type = obj.TYPE_CONST1474				p.From.Offset = c1475				p.To.Type = obj.TYPE_REG1476				p.To.Reg = x86.REG_AX + int16(xVal)1477			}1478			c = v.Aux.(ssa.PanicBoundsCC).Cy1479			if c >= 0 && c <= abi.BoundsMaxConst {1480				yVal = int(c)1481			} else {1482				// Move constant to a register1483				yIsReg = true1484				yVal = 11485				p := s.Prog(x86.AMOVQ)1486				p.From.Type = obj.TYPE_CONST1487				p.From.Offset = c1488				p.To.Type = obj.TYPE_REG1489				p.To.Reg = x86.REG_AX + int16(yVal)1490			}1491		}1492		c := abi.BoundsEncode(code, signed, xIsReg, yIsReg, xVal, yVal)14931494		p := s.Prog(obj.APCDATA)1495		p.From.SetConst(abi.PCDATA_PanicBounds)1496		p.To.SetConst(int64(c))1497		p = s.Prog(obj.ACALL)1498		p.To.Type = obj.TYPE_MEM1499		p.To.Name = obj.NAME_EXTERN1500		p.To.Sym = ir.Syms.PanicBounds15011502	case ssaop.OpAMD64NEGQ, ssaop.OpAMD64NEGL,1503		ssaop.OpAMD64BSWAPQ, ssaop.OpAMD64BSWAPL,1504		ssaop.OpAMD64NOTQ, ssaop.OpAMD64NOTL:1505		p := s.Prog(v.Op.Asm())1506		p.To.Type = obj.TYPE_REG1507		p.To.Reg = v.Reg()15081509	case ssaop.OpAMD64NEGLflags:1510		p := s.Prog(v.Op.Asm())1511		p.To.Type = obj.TYPE_REG1512		p.To.Reg = v.Reg0()15131514	case ssaop.OpAMD64ADDQconstflags, ssaop.OpAMD64ADDLconstflags:1515		p := s.Prog(v.Op.Asm())1516		p.From.Type = obj.TYPE_CONST1517		p.From.Offset = v.AuxInt1518		// Note: the inc/dec instructions do not modify1519		// the carry flag like add$1 / sub$1 do.1520		// We currently never use the CF/OF flags from1521		// these instructions, so that is ok.1522		switch {1523		case p.As == x86.AADDQ && p.From.Offset == 1:1524			p.As = x86.AINCQ1525			p.From.Type = obj.TYPE_NONE1526		case p.As == x86.AADDQ && p.From.Offset == -1:1527			p.As = x86.ADECQ1528			p.From.Type = obj.TYPE_NONE1529		case p.As == x86.AADDL && p.From.Offset == 1:1530			p.As = x86.AINCL1531			p.From.Type = obj.TYPE_NONE1532		case p.As == x86.AADDL && p.From.Offset == -1:1533			p.As = x86.ADECL1534			p.From.Type = obj.TYPE_NONE1535		}1536		p.To.Type = obj.TYPE_REG1537		p.To.Reg = v.Reg0()15381539	case ssaop.OpAMD64BSFQ, ssaop.OpAMD64BSRQ, ssaop.OpAMD64BSFL, ssaop.OpAMD64BSRL, ssaop.OpAMD64SQRTSD, ssaop.OpAMD64SQRTSS:1540		p := s.Prog(v.Op.Asm())1541		p.From.Type = obj.TYPE_REG1542		p.From.Reg = v.Args[0].Reg()1543		p.To.Type = obj.TYPE_REG1544		switch v.Op {1545		case ssaop.OpAMD64BSFQ, ssaop.OpAMD64BSRQ:1546			p.To.Reg = v.Reg0()1547		case ssaop.OpAMD64BSFL, ssaop.OpAMD64BSRL, ssaop.OpAMD64SQRTSD, ssaop.OpAMD64SQRTSS:1548			p.To.Reg = v.Reg()1549		}1550	case ssaop.OpAMD64LoweredRound32F, ssaop.OpAMD64LoweredRound64F:1551		// input is already rounded1552	case ssaop.OpAMD64ROUNDSD, ssaop.OpAMD64ROUNDSS:1553		p := s.Prog(v.Op.Asm())1554		val := v.AuxInt1555		// 0 means math.RoundToEven, 1 Floor, 2 Ceil, 3 Trunc1556		if val < 0 || val > 3 {1557			v.Fatalf("Invalid rounding mode")1558		}1559		p.From.Offset = val1560		p.From.Type = obj.TYPE_CONST1561		p.AddRestSourceReg(v.Args[0].Reg())1562		p.To.Type = obj.TYPE_REG1563		p.To.Reg = v.Reg()1564	case ssaop.OpAMD64POPCNTQ, ssaop.OpAMD64POPCNTL,1565		ssaop.OpAMD64TZCNTQ, ssaop.OpAMD64TZCNTL,1566		ssaop.OpAMD64LZCNTQ, ssaop.OpAMD64LZCNTL:1567		if v.Args[0].Reg() != v.Reg() {1568			// POPCNT/TZCNT/LZCNT have a false dependency on the destination register on Intel cpus.1569			// TZCNT/LZCNT problem affects pre-Skylake models. See discussion at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62011#c7.1570			// Xor register with itself to break the dependency.1571			opregreg(s, x86.AXORL, v.Reg(), v.Reg())1572		}1573		p := s.Prog(v.Op.Asm())1574		p.From.Type = obj.TYPE_REG1575		p.From.Reg = v.Args[0].Reg()1576		p.To.Type = obj.TYPE_REG1577		p.To.Reg = v.Reg()15781579	case ssaop.OpAMD64SETEQ, ssaop.OpAMD64SETNE,1580		ssaop.OpAMD64SETL, ssaop.OpAMD64SETLE,1581		ssaop.OpAMD64SETG, ssaop.OpAMD64SETGE,1582		ssaop.OpAMD64SETGF, ssaop.OpAMD64SETGEF,1583		ssaop.OpAMD64SETB, ssaop.OpAMD64SETBE,1584		ssaop.OpAMD64SETORD, ssaop.OpAMD64SETNAN,1585		ssaop.OpAMD64SETA, ssaop.OpAMD64SETAE,1586		ssaop.OpAMD64SETO:1587		p := s.Prog(v.Op.Asm())1588		p.To.Type = obj.TYPE_REG1589		p.To.Reg = v.Reg()15901591	case ssaop.OpAMD64SETEQstore, ssaop.OpAMD64SETNEstore,1592		ssaop.OpAMD64SETLstore, ssaop.OpAMD64SETLEstore,1593		ssaop.OpAMD64SETGstore, ssaop.OpAMD64SETGEstore,1594		ssaop.OpAMD64SETBstore, ssaop.OpAMD64SETBEstore,1595		ssaop.OpAMD64SETAstore, ssaop.OpAMD64SETAEstore:1596		p := s.Prog(v.Op.Asm())1597		p.To.Type = obj.TYPE_MEM1598		p.To.Reg = v.Args[0].Reg()1599		ssagen.AddAux(&p.To, v)16001601	case ssaop.OpAMD64SETEQstoreidx1, ssaop.OpAMD64SETNEstoreidx1,1602		ssaop.OpAMD64SETLstoreidx1, ssaop.OpAMD64SETLEstoreidx1,1603		ssaop.OpAMD64SETGstoreidx1, ssaop.OpAMD64SETGEstoreidx1,1604		ssaop.OpAMD64SETBstoreidx1, ssaop.OpAMD64SETBEstoreidx1,1605		ssaop.OpAMD64SETAstoreidx1, ssaop.OpAMD64SETAEstoreidx1:1606		p := s.Prog(v.Op.Asm())1607		memIdx(&p.To, v)1608		ssagen.AddAux(&p.To, v)16091610	case ssaop.OpAMD64SETNEF:1611		t := v.RegTmp()1612		p := s.Prog(v.Op.Asm())1613		p.To.Type = obj.TYPE_REG1614		p.To.Reg = v.Reg()1615		q := s.Prog(x86.ASETPS)1616		q.To.Type = obj.TYPE_REG1617		q.To.Reg = t1618		// ORL avoids partial register write and is smaller than ORQ, used by old compiler1619		opregreg(s, x86.AORL, v.Reg(), t)16201621	case ssaop.OpAMD64SETEQF:1622		t := v.RegTmp()1623		p := s.Prog(v.Op.Asm())1624		p.To.Type = obj.TYPE_REG1625		p.To.Reg = v.Reg()1626		q := s.Prog(x86.ASETPC)1627		q.To.Type = obj.TYPE_REG1628		q.To.Reg = t1629		// ANDL avoids partial register write and is smaller than ANDQ, used by old compiler1630		opregreg(s, x86.AANDL, v.Reg(), t)16311632	case ssaop.OpAMD64InvertFlags:1633		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())1634	case ssaop.OpAMD64FlagEQ, ssaop.OpAMD64FlagLT_ULT, ssaop.OpAMD64FlagLT_UGT, ssaop.OpAMD64FlagGT_ULT, ssaop.OpAMD64FlagGT_UGT:1635		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())1636	case ssaop.OpAMD64AddTupleFirst32, ssaop.OpAMD64AddTupleFirst64:1637		v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString())1638	case ssaop.OpAMD64REPSTOSQ:1639		s.Prog(x86.AREP)1640		s.Prog(x86.ASTOSQ)1641	case ssaop.OpAMD64REPMOVSQ:1642		s.Prog(x86.AREP)1643		s.Prog(x86.AMOVSQ)1644	case ssaop.OpAMD64LoweredNilCheck:1645		// Issue a load which will fault if the input is nil.1646		// TODO: We currently use the 2-byte instruction TESTB AX, (reg).1647		// Should we use the 3-byte TESTB $0, (reg) instead? It is larger1648		// but it doesn't have false dependency on AX.1649		// Or maybe allocate an output register and use MOVL (reg),reg2 ?1650		// That trades clobbering flags for clobbering a register.1651		p := s.Prog(x86.ATESTB)1652		p.From.Type = obj.TYPE_REG1653		p.From.Reg = x86.REG_AX1654		p.To.Type = obj.TYPE_MEM1655		p.To.Reg = v.Args[0].Reg()1656		if logopt.Enabled() {1657			logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)1658		}1659		if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers1660			base.WarnfAt(v.Pos, "generated nil check")1661		}1662	case ssaop.OpAMD64MOVBatomicload, ssaop.OpAMD64MOVLatomicload, ssaop.OpAMD64MOVQatomicload:1663		p := s.Prog(v.Op.Asm())1664		p.From.Type = obj.TYPE_MEM1665		p.From.Reg = v.Args[0].Reg()1666		ssagen.AddAux(&p.From, v)1667		p.To.Type = obj.TYPE_REG1668		p.To.Reg = v.Reg0()1669	case ssaop.OpAMD64XCHGB, ssaop.OpAMD64XCHGL, ssaop.OpAMD64XCHGQ:1670		p := s.Prog(v.Op.Asm())1671		p.From.Type = obj.TYPE_REG1672		p.From.Reg = v.Reg0()1673		p.To.Type = obj.TYPE_MEM1674		p.To.Reg = v.Args[1].Reg()1675		ssagen.AddAux(&p.To, v)1676	case ssaop.OpAMD64XADDLlock, ssaop.OpAMD64XADDQlock:1677		s.Prog(x86.ALOCK)1678		p := s.Prog(v.Op.Asm())1679		p.From.Type = obj.TYPE_REG1680		p.From.Reg = v.Reg0()1681		p.To.Type = obj.TYPE_MEM1682		p.To.Reg = v.Args[1].Reg()1683		ssagen.AddAux(&p.To, v)1684	case ssaop.OpAMD64CMPXCHGLlock, ssaop.OpAMD64CMPXCHGQlock:1685		if v.Args[1].Reg() != x86.REG_AX {1686			v.Fatalf("input[1] not in AX %s", v.LongString())1687		}1688		s.Prog(x86.ALOCK)1689		p := s.Prog(v.Op.Asm())1690		p.From.Type = obj.TYPE_REG1691		p.From.Reg = v.Args[2].Reg()1692		p.To.Type = obj.TYPE_MEM1693		p.To.Reg = v.Args[0].Reg()1694		ssagen.AddAux(&p.To, v)1695		p = s.Prog(x86.ASETEQ)1696		p.To.Type = obj.TYPE_REG1697		p.To.Reg = v.Reg0()1698	case ssaop.OpAMD64ANDBlock, ssaop.OpAMD64ANDLlock, ssaop.OpAMD64ANDQlock,1699		ssaop.OpAMD64ORBlock, ssaop.OpAMD64ORLlock, ssaop.OpAMD64ORQlock,1700		ssaop.OpAMD64ADDLlock, ssaop.OpAMD64ADDQlock,1701		ssaop.OpAMD64SUBLlock, ssaop.OpAMD64SUBQlock:1702		// Atomic memory operations that don't need to return the old value.1703		s.Prog(x86.ALOCK)1704		p := s.Prog(v.Op.Asm())1705		p.From.Type = obj.TYPE_REG1706		p.From.Reg = v.Args[1].Reg()1707		p.To.Type = obj.TYPE_MEM1708		p.To.Reg = v.Args[0].Reg()1709		ssagen.AddAux(&p.To, v)1710	case ssaop.OpAMD64INCLlock, ssaop.OpAMD64INCQlock,1711		ssaop.OpAMD64DECLlock, ssaop.OpAMD64DECQlock:1712		// Unary atomic memory operations that don't need to return the old value.1713		s.Prog(x86.ALOCK)1714		p := s.Prog(v.Op.Asm())1715		p.To.Type = obj.TYPE_MEM1716		p.To.Reg = v.Args[0].Reg()1717		ssagen.AddAux(&p.To, v)1718	case ssaop.OpAMD64LoweredAtomicAnd64, ssaop.OpAMD64LoweredAtomicOr64, ssaop.OpAMD64LoweredAtomicAnd32, ssaop.OpAMD64LoweredAtomicOr32:1719		// Atomic memory operations that need to return the old value.1720		// We need to do these with compare-and-exchange to get access to the old value.1721		// loop:1722		// MOVQ mask, tmp1723		// MOVQ (addr), AX1724		// ANDQ AX, tmp1725		// LOCK CMPXCHGQ tmp, (addr) : note that AX is implicit old value to compare against1726		// JNE loop1727		// : result in AX1728		//1729		// If the width written to AX changes, update zeroUpperBits in AMD64Ops.go.1730		mov := x86.AMOVQ1731		op := x86.AANDQ1732		cmpxchg := x86.ACMPXCHGQ1733		switch v.Op {1734		case ssaop.OpAMD64LoweredAtomicOr64:1735			op = x86.AORQ1736		case ssaop.OpAMD64LoweredAtomicAnd32:1737			mov = x86.AMOVL1738			op = x86.AANDL1739			cmpxchg = x86.ACMPXCHGL1740		case ssaop.OpAMD64LoweredAtomicOr32:1741			mov = x86.AMOVL1742			op = x86.AORL1743			cmpxchg = x86.ACMPXCHGL1744		}1745		addr := v.Args[0].Reg()1746		mask := v.Args[1].Reg()1747		tmp := v.RegTmp()1748		p1 := s.Prog(mov)1749		p1.From.Type = obj.TYPE_REG1750		p1.From.Reg = mask1751		p1.To.Type = obj.TYPE_REG1752		p1.To.Reg = tmp1753		p2 := s.Prog(mov)1754		p2.From.Type = obj.TYPE_MEM1755		p2.From.Reg = addr1756		ssagen.AddAux(&p2.From, v)1757		p2.To.Type = obj.TYPE_REG1758		p2.To.Reg = x86.REG_AX1759		p3 := s.Prog(op)1760		p3.From.Type = obj.TYPE_REG1761		p3.From.Reg = x86.REG_AX1762		p3.To.Type = obj.TYPE_REG1763		p3.To.Reg = tmp1764		s.Prog(x86.ALOCK)1765		p5 := s.Prog(cmpxchg)1766		p5.From.Type = obj.TYPE_REG1767		p5.From.Reg = tmp1768		p5.To.Type = obj.TYPE_MEM1769		p5.To.Reg = addr1770		ssagen.AddAux(&p5.To, v)1771		p6 := s.Prog(x86.AJNE)1772		p6.To.Type = obj.TYPE_BRANCH1773		p6.To.SetTarget(p1)1774	case ssaop.OpAMD64PrefetchT0, ssaop.OpAMD64PrefetchNTA:1775		p := s.Prog(v.Op.Asm())1776		p.From.Type = obj.TYPE_MEM1777		p.From.Reg = v.Args[0].Reg()1778	case ssaop.OpClobber:1779		p := s.Prog(x86.AMOVL)1780		p.From.Type = obj.TYPE_CONST1781		p.From.Offset = 0xdeaddead1782		p.To.Type = obj.TYPE_MEM1783		p.To.Reg = x86.REG_SP1784		ssagen.AddAux(&p.To, v)1785		p = s.Prog(x86.AMOVL)1786		p.From.Type = obj.TYPE_CONST1787		p.From.Offset = 0xdeaddead1788		p.To.Type = obj.TYPE_MEM1789		p.To.Reg = x86.REG_SP1790		ssagen.AddAux(&p.To, v)1791		p.To.Offset += 41792	case ssaop.OpClobberReg:1793		x := uint64(0xdeaddeaddeaddead)1794		p := s.Prog(x86.AMOVQ)1795		p.From.Type = obj.TYPE_CONST1796		p.From.Offset = int64(x)1797		p.To.Type = obj.TYPE_REG1798		p.To.Reg = v.Reg()17991800	// SIMD ops1801	case ssaop.OpAMD64VZEROUPPER, ssaop.OpAMD64VZEROALL:1802		s.Prog(v.Op.Asm())18031804	case ssaop.OpAMD64Zero128, ssaop.OpAMD64Zero256, ssaop.OpAMD64Zero512: // no code emitted18051806	case ssaop.OpAMD64VMOVSSf2v, ssaop.OpAMD64VMOVSDf2v:1807		// These are for initializing the least 32/64 bits of a SIMD register from a "float".1808		p := s.Prog(v.Op.Asm())1809		p.From.Type = obj.TYPE_REG1810		p.From.Reg = v.Args[0].Reg()1811		p.AddRestSourceReg(x86.REG_X15)1812		p.To.Type = obj.TYPE_REG1813		p.To.Reg = simdReg(v)18141815	case ssaop.OpAMD64VMOVQload, ssaop.OpAMD64VMOVDload,1816		ssaop.OpAMD64VMOVSSload, ssaop.OpAMD64VMOVSDload:1817		p := s.Prog(v.Op.Asm())1818		p.From.Type = obj.TYPE_MEM1819		p.From.Reg = v.Args[0].Reg()1820		ssagen.AddAux(&p.From, v)1821		p.To.Type = obj.TYPE_REG1822		p.To.Reg = simdReg(v)18231824	case ssaop.OpAMD64VMOVSSconst, ssaop.OpAMD64VMOVSDconst:1825		// for loading constants directly into SIMD registers1826		x := simdReg(v)1827		p := s.Prog(v.Op.Asm())1828		p.From.Type = obj.TYPE_FCONST1829		p.From.Val = math.Float64frombits(uint64(v.AuxInt))1830		p.To.Type = obj.TYPE_REG1831		p.To.Reg = x18321833	case ssaop.OpAMD64VMOVD, ssaop.OpAMD64VMOVQ:1834		// These are for initializing the least 32/64 bits of a SIMD register from an "int".1835		p := s.Prog(v.Op.Asm())1836		p.From.Type = obj.TYPE_REG1837		p.From.Reg = v.Args[0].Reg()1838		p.To.Type = obj.TYPE_REG1839		p.To.Reg = simdReg(v)18401841	case ssaop.OpAMD64VMOVDQUload128, ssaop.OpAMD64VMOVDQUload256, ssaop.OpAMD64VMOVDQUload512,1842		ssaop.OpAMD64KMOVBload, ssaop.OpAMD64KMOVWload, ssaop.OpAMD64KMOVDload, ssaop.OpAMD64KMOVQload:1843		p := s.Prog(v.Op.Asm())1844		p.From.Type = obj.TYPE_MEM1845		p.From.Reg = v.Args[0].Reg()1846		ssagen.AddAux(&p.From, v)1847		p.To.Type = obj.TYPE_REG1848		p.To.Reg = simdOrMaskReg(v)1849	case ssaop.OpAMD64VMOVDQUstore128, ssaop.OpAMD64VMOVDQUstore256, ssaop.OpAMD64VMOVDQUstore512,1850		ssaop.OpAMD64KMOVBstore, ssaop.OpAMD64KMOVWstore, ssaop.OpAMD64KMOVDstore, ssaop.OpAMD64KMOVQstore:1851		p := s.Prog(v.Op.Asm())1852		p.From.Type = obj.TYPE_REG1853		p.From.Reg = simdOrMaskReg(v.Args[1])1854		p.To.Type = obj.TYPE_MEM1855		p.To.Reg = v.Args[0].Reg()1856		ssagen.AddAux(&p.To, v)18571858	case ssaop.OpAMD64VPMASK32load128, ssaop.OpAMD64VPMASK64load128, ssaop.OpAMD64VPMASK32load256, ssaop.OpAMD64VPMASK64load256:1859		p := s.Prog(v.Op.Asm())1860		p.From.Type = obj.TYPE_MEM1861		p.From.Reg = v.Args[0].Reg()1862		ssagen.AddAux(&p.From, v)1863		p.To.Type = obj.TYPE_REG1864		p.To.Reg = simdReg(v)1865		p.AddRestSourceReg(simdReg(v.Args[1])) // masking simd reg18661867	case ssaop.OpAMD64VPMASK32store128, ssaop.OpAMD64VPMASK64store128, ssaop.OpAMD64VPMASK32store256, ssaop.OpAMD64VPMASK64store256:1868		p := s.Prog(v.Op.Asm())1869		p.From.Type = obj.TYPE_REG1870		p.From.Reg = simdReg(v.Args[2])1871		p.To.Type = obj.TYPE_MEM1872		p.To.Reg = v.Args[0].Reg()1873		ssagen.AddAux(&p.To, v)1874		p.AddRestSourceReg(simdReg(v.Args[1])) // masking simd reg18751876	case ssaop.OpAMD64VPMASK64load512, ssaop.OpAMD64VPMASK32load512, ssaop.OpAMD64VPMASK16load512, ssaop.OpAMD64VPMASK8load512:1877		p := s.Prog(v.Op.Asm())1878		p.From.Type = obj.TYPE_MEM1879		p.From.Reg = v.Args[0].Reg()1880		ssagen.AddAux(&p.From, v)1881		p.To.Type = obj.TYPE_REG1882		p.To.Reg = simdReg(v)1883		p.AddRestSourceReg(v.Args[1].Reg()) // simd mask reg1884		x86.ParseSuffix(p, "Z")             // must be zero if not in mask18851886	case ssaop.OpAMD64KANDB, ssaop.OpAMD64KANDW, ssaop.OpAMD64KANDD, ssaop.OpAMD64KANDQ,1887		ssaop.OpAMD64KORB, ssaop.OpAMD64KORW, ssaop.OpAMD64KORD, ssaop.OpAMD64KORQ,1888		ssaop.OpAMD64KXORB, ssaop.OpAMD64KXORW, ssaop.OpAMD64KXORD, ssaop.OpAMD64KXORQ,1889		ssaop.OpAMD64KXNORB, ssaop.OpAMD64KXNORW, ssaop.OpAMD64KXNORD, ssaop.OpAMD64KXNORQ: // XNOR == EQ1890		p := s.Prog(v.Op.Asm())1891		p.From.Type = obj.TYPE_REG1892		p.From.Reg = v.Args[0].Reg()1893		p.To.Type = obj.TYPE_REG1894		p.To.Reg = v.Reg()1895		p.AddRestSourceReg(v.Args[1].Reg()) // masking simd reg18961897	case ssaop.OpAMD64VPMASK64store512, ssaop.OpAMD64VPMASK32store512, ssaop.OpAMD64VPMASK16store512, ssaop.OpAMD64VPMASK8store512:1898		p := s.Prog(v.Op.Asm())1899		p.From.Type = obj.TYPE_REG1900		p.From.Reg = simdReg(v.Args[2])1901		p.To.Type = obj.TYPE_MEM1902		p.To.Reg = v.Args[0].Reg()1903		ssagen.AddAux(&p.To, v)1904		p.AddRestSourceReg(v.Args[1].Reg()) // simd mask reg19051906	case ssaop.OpAMD64VPMOVMToVec8x16,1907		ssaop.OpAMD64VPMOVMToVec8x32,1908		ssaop.OpAMD64VPMOVMToVec8x64,1909		ssaop.OpAMD64VPMOVMToVec16x8,1910		ssaop.OpAMD64VPMOVMToVec16x16,1911		ssaop.OpAMD64VPMOVMToVec16x32,1912		ssaop.OpAMD64VPMOVMToVec32x4,1913		ssaop.OpAMD64VPMOVMToVec32x8,1914		ssaop.OpAMD64VPMOVMToVec32x16,1915		ssaop.OpAMD64VPMOVMToVec64x2,1916		ssaop.OpAMD64VPMOVMToVec64x4,1917		ssaop.OpAMD64VPMOVMToVec64x8:1918		p := s.Prog(v.Op.Asm())1919		p.From.Type = obj.TYPE_REG1920		p.From.Reg = v.Args[0].Reg()1921		p.To.Type = obj.TYPE_REG1922		p.To.Reg = simdReg(v)19231924	case ssaop.OpAMD64VPMOVVec8x16ToM,1925		ssaop.OpAMD64VPMOVVec8x32ToM,1926		ssaop.OpAMD64VPMOVVec8x64ToM,1927		ssaop.OpAMD64VPMOVVec16x8ToM,1928		ssaop.OpAMD64VPMOVVec16x16ToM,1929		ssaop.OpAMD64VPMOVVec16x32ToM,1930		ssaop.OpAMD64VPMOVVec32x4ToM,1931		ssaop.OpAMD64VPMOVVec32x8ToM,1932		ssaop.OpAMD64VPMOVVec32x16ToM,1933		ssaop.OpAMD64VPMOVVec64x2ToM,1934		ssaop.OpAMD64VPMOVVec64x4ToM,1935		ssaop.OpAMD64VPMOVVec64x8ToM,1936		ssaop.OpAMD64VPMOVMSKB128,1937		ssaop.OpAMD64VPMOVMSKB256,1938		ssaop.OpAMD64VMOVMSKPS128,1939		ssaop.OpAMD64VMOVMSKPS256,1940		ssaop.OpAMD64VMOVMSKPD128,1941		ssaop.OpAMD64VMOVMSKPD256:1942		p := s.Prog(v.Op.Asm())1943		p.From.Type = obj.TYPE_REG1944		p.From.Reg = simdReg(v.Args[0])1945		p.To.Type = obj.TYPE_REG1946		p.To.Reg = v.Reg()19471948	case ssaop.OpAMD64KMOVQk, ssaop.OpAMD64KMOVDk, ssaop.OpAMD64KMOVWk, ssaop.OpAMD64KMOVBk,1949		ssaop.OpAMD64KMOVQi, ssaop.OpAMD64KMOVDi, ssaop.OpAMD64KMOVWi, ssaop.OpAMD64KMOVBi:1950		// See also ssa.OpAMD64KMOVQload1951		p := s.Prog(v.Op.Asm())1952		p.From.Type = obj.TYPE_REG1953		p.From.Reg = v.Args[0].Reg()1954		p.To.Type = obj.TYPE_REG1955		p.To.Reg = v.Reg()1956	case ssaop.OpAMD64VPTEST:1957		// Some instructions setting flags put their second operand into the destination reg.1958		// See also CMP[BWDQ].1959		p := s.Prog(v.Op.Asm())1960		p.From.Type = obj.TYPE_REG1961		p.From.Reg = simdReg(v.Args[0])1962		p.To.Type = obj.TYPE_REG1963		p.To.Reg = simdReg(v.Args[1])19641965	default:1966		if !ssaGenSIMDValue(s, v) {1967			v.Fatalf("genValue not implemented: %s", v.LongString())1968		}1969	}1970}19711972// zeroX15 zeroes the X15 register.1973func zeroX15(s *ssagen.State) {1974	vxorps := func(s *ssagen.State) {1975		p := s.Prog(x86.AVXORPS)1976		p.From.Type = obj.TYPE_REG1977		p.From.Reg = x86.REG_X151978		p.AddRestSourceReg(x86.REG_X15)1979		p.To.Type = obj.TYPE_REG1980		p.To.Reg = x86.REG_X151981	}1982	if buildcfg.GOAMD64 >= 3 {1983		vxorps(s)1984		return1985	}1986	opregreg(s, x86.AXORPS, x86.REG_X15, x86.REG_X15)1987	// AVX may not be available, check before zeroing the high bits.1988	p := s.Prog(x86.ACMPB)1989	p.From.Type = obj.TYPE_MEM1990	p.From.Name = obj.NAME_EXTERN1991	p.From.Sym = ir.Syms.X86HasAVX1992	p.To.Type = obj.TYPE_CONST1993	p.To.Offset = 11994	jmp := s.Prog(x86.AJNE)1995	jmp.To.Type = obj.TYPE_BRANCH1996	vxorps(s)1997	end := s.Prog(obj.ANOP)1998	jmp.To.SetTarget(end)1999}

Code quality findings 1

Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
s.JumpTables = append(s.JumpTables, b)

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.