package amd64

import (
	

	
	
	
	
)

func ( *instruction) ( backend.Compiler) ( bool) {
	switch  := .kind;  {
	case nop0, sourceOffsetInfo, defineUninitializedReg, fcvtToSintSequence, fcvtToUintSequence, nopUseReg:
	case ret:
		encodeRet()
	case imm:
		 := regEncodings[.op2.reg().RealReg()]
		 := .u1
		if .b1 { // 64 bit.
			if lower32willSignExtendTo64() {
				// Sign extend mov(imm32).
				encodeRegReg(,
					legacyPrefixesNone,
					0xc7, 1,
					0,
					,
					rexInfo(0).setW(),
				)
				.Emit4Bytes(uint32())
			} else {
				.EmitByte(rexEncodingW | .rexBit())
				.EmitByte(0xb8 | .encoding())
				.Emit8Bytes()
			}
		} else {
			if .rexBit() > 0 {
				.EmitByte(rexEncodingDefault | 0x1)
			}
			.EmitByte(0xb8 | .encoding())
			.Emit4Bytes(uint32())
		}

	case aluRmiR:
		var  rexInfo
		if .b1 {
			 = .setW()
		} else {
			 = .clearW()
		}

		 := regEncodings[.op2.reg().RealReg()]

		 := aluRmiROpcode(.u1)
		if  == aluRmiROpcodeMul {
			 := .op1
			const ,  = 0x0FAF, 2
			switch .kind {
			case operandKindReg:
				 := regEncodings[.reg().RealReg()]
				encodeRegReg(, legacyPrefixesNone, , , , , )
			case operandKindMem:
				 := .op1.addressMode()
				encodeRegMem(, legacyPrefixesNone, , , , , )
			case operandKindImm32:
				 := lower8willSignExtendTo32(.imm32())
				var  uint32
				if  {
					 = 0x6b
				} else {
					 = 0x69
				}
				encodeRegReg(, legacyPrefixesNone, , 1, , , )
				if  {
					.EmitByte(byte(.imm32()))
				} else {
					.Emit4Bytes(.imm32())
				}
			default:
				panic("BUG: invalid operand kind")
			}
		} else {
			const  = 1
			var , ,  uint32
			switch  {
			case aluRmiROpcodeAdd:
				, ,  = 0x01, 0x03, 0x0
			case aluRmiROpcodeSub:
				, ,  = 0x29, 0x2b, 0x5
			case aluRmiROpcodeAnd:
				, ,  = 0x21, 0x23, 0x4
			case aluRmiROpcodeOr:
				, ,  = 0x09, 0x0b, 0x1
			case aluRmiROpcodeXor:
				, ,  = 0x31, 0x33, 0x6
			default:
				panic("BUG: invalid aluRmiROpcode")
			}

			 := .op1
			switch .kind {
			case operandKindReg:
				 := regEncodings[.reg().RealReg()]
				encodeRegReg(, legacyPrefixesNone, , , , , )
			case operandKindMem:
				 := .op1.addressMode()
				encodeRegMem(, legacyPrefixesNone, , , , , )
			case operandKindImm32:
				 := lower8willSignExtendTo32(.imm32())
				var  uint32
				if  {
					 = 0x83
				} else {
					 = 0x81
				}
				encodeRegReg(, legacyPrefixesNone, , , regEnc(), , )
				if  {
					.EmitByte(byte(.imm32()))
				} else {
					.Emit4Bytes(.imm32())
				}
			default:
				panic("BUG: invalid operand kind")
			}
		}

	case movRR:
		 := regEncodings[.op1.reg().RealReg()]
		 := regEncodings[.op2.reg().RealReg()]
		var  rexInfo
		if .b1 {
			 = .setW()
		} else {
			 = .clearW()
		}
		encodeRegReg(, legacyPrefixesNone, 0x89, 1, , , )

	case xmmRmR, blendvpd:
		 := sseOpcode(.u1)
		var  legacyPrefixes
		var  uint32
		var  uint32
		switch  {
		case sseOpcodeAddps:
			, ,  = legacyPrefixesNone, 0x0F58, 2
		case sseOpcodeAddpd:
			, ,  = legacyPrefixes0x66, 0x0F58, 2
		case sseOpcodeAddss:
			, ,  = legacyPrefixes0xF3, 0x0F58, 2
		case sseOpcodeAddsd:
			, ,  = legacyPrefixes0xF2, 0x0F58, 2
		case sseOpcodeAndps:
			, ,  = legacyPrefixesNone, 0x0F54, 2
		case sseOpcodeAndpd:
			, ,  = legacyPrefixes0x66, 0x0F54, 2
		case sseOpcodeAndnps:
			, ,  = legacyPrefixesNone, 0x0F55, 2
		case sseOpcodeAndnpd:
			, ,  = legacyPrefixes0x66, 0x0F55, 2
		case sseOpcodeBlendvps:
			, ,  = legacyPrefixes0x66, 0x0F3814, 3
		case sseOpcodeBlendvpd:
			, ,  = legacyPrefixes0x66, 0x0F3815, 3
		case sseOpcodeDivps:
			, ,  = legacyPrefixesNone, 0x0F5E, 2
		case sseOpcodeDivpd:
			, ,  = legacyPrefixes0x66, 0x0F5E, 2
		case sseOpcodeDivss:
			, ,  = legacyPrefixes0xF3, 0x0F5E, 2
		case sseOpcodeDivsd:
			, ,  = legacyPrefixes0xF2, 0x0F5E, 2
		case sseOpcodeMaxps:
			, ,  = legacyPrefixesNone, 0x0F5F, 2
		case sseOpcodeMaxpd:
			, ,  = legacyPrefixes0x66, 0x0F5F, 2
		case sseOpcodeMaxss:
			, ,  = legacyPrefixes0xF3, 0x0F5F, 2
		case sseOpcodeMaxsd:
			, ,  = legacyPrefixes0xF2, 0x0F5F, 2
		case sseOpcodeMinps:
			, ,  = legacyPrefixesNone, 0x0F5D, 2
		case sseOpcodeMinpd:
			, ,  = legacyPrefixes0x66, 0x0F5D, 2
		case sseOpcodeMinss:
			, ,  = legacyPrefixes0xF3, 0x0F5D, 2
		case sseOpcodeMinsd:
			, ,  = legacyPrefixes0xF2, 0x0F5D, 2
		case sseOpcodeMovlhps:
			, ,  = legacyPrefixesNone, 0x0F16, 2
		case sseOpcodeMovsd:
			, ,  = legacyPrefixes0xF2, 0x0F10, 2
		case sseOpcodeMulps:
			, ,  = legacyPrefixesNone, 0x0F59, 2
		case sseOpcodeMulpd:
			, ,  = legacyPrefixes0x66, 0x0F59, 2
		case sseOpcodeMulss:
			, ,  = legacyPrefixes0xF3, 0x0F59, 2
		case sseOpcodeMulsd:
			, ,  = legacyPrefixes0xF2, 0x0F59, 2
		case sseOpcodeOrpd:
			, ,  = legacyPrefixes0x66, 0x0F56, 2
		case sseOpcodeOrps:
			, ,  = legacyPrefixesNone, 0x0F56, 2
		case sseOpcodePackssdw:
			, ,  = legacyPrefixes0x66, 0x0F6B, 2
		case sseOpcodePacksswb:
			, ,  = legacyPrefixes0x66, 0x0F63, 2
		case sseOpcodePackusdw:
			, ,  = legacyPrefixes0x66, 0x0F382B, 3
		case sseOpcodePackuswb:
			, ,  = legacyPrefixes0x66, 0x0F67, 2
		case sseOpcodePaddb:
			, ,  = legacyPrefixes0x66, 0x0FFC, 2
		case sseOpcodePaddd:
			, ,  = legacyPrefixes0x66, 0x0FFE, 2
		case sseOpcodePaddq:
			, ,  = legacyPrefixes0x66, 0x0FD4, 2
		case sseOpcodePaddw:
			, ,  = legacyPrefixes0x66, 0x0FFD, 2
		case sseOpcodePaddsb:
			, ,  = legacyPrefixes0x66, 0x0FEC, 2
		case sseOpcodePaddsw:
			, ,  = legacyPrefixes0x66, 0x0FED, 2
		case sseOpcodePaddusb:
			, ,  = legacyPrefixes0x66, 0x0FDC, 2
		case sseOpcodePaddusw:
			, ,  = legacyPrefixes0x66, 0x0FDD, 2
		case sseOpcodePand:
			, ,  = legacyPrefixes0x66, 0x0FDB, 2
		case sseOpcodePandn:
			, ,  = legacyPrefixes0x66, 0x0FDF, 2
		case sseOpcodePavgb:
			, ,  = legacyPrefixes0x66, 0x0FE0, 2
		case sseOpcodePavgw:
			, ,  = legacyPrefixes0x66, 0x0FE3, 2
		case sseOpcodePcmpeqb:
			, ,  = legacyPrefixes0x66, 0x0F74, 2
		case sseOpcodePcmpeqw:
			, ,  = legacyPrefixes0x66, 0x0F75, 2
		case sseOpcodePcmpeqd:
			, ,  = legacyPrefixes0x66, 0x0F76, 2
		case sseOpcodePcmpeqq:
			, ,  = legacyPrefixes0x66, 0x0F3829, 3
		case sseOpcodePcmpgtb:
			, ,  = legacyPrefixes0x66, 0x0F64, 2
		case sseOpcodePcmpgtw:
			, ,  = legacyPrefixes0x66, 0x0F65, 2
		case sseOpcodePcmpgtd:
			, ,  = legacyPrefixes0x66, 0x0F66, 2
		case sseOpcodePcmpgtq:
			, ,  = legacyPrefixes0x66, 0x0F3837, 3
		case sseOpcodePmaddwd:
			, ,  = legacyPrefixes0x66, 0x0FF5, 2
		case sseOpcodePmaxsb:
			, ,  = legacyPrefixes0x66, 0x0F383C, 3
		case sseOpcodePmaxsw:
			, ,  = legacyPrefixes0x66, 0x0FEE, 2
		case sseOpcodePmaxsd:
			, ,  = legacyPrefixes0x66, 0x0F383D, 3
		case sseOpcodePmaxub:
			, ,  = legacyPrefixes0x66, 0x0FDE, 2
		case sseOpcodePmaxuw:
			, ,  = legacyPrefixes0x66, 0x0F383E, 3
		case sseOpcodePmaxud:
			, ,  = legacyPrefixes0x66, 0x0F383F, 3
		case sseOpcodePminsb:
			, ,  = legacyPrefixes0x66, 0x0F3838, 3
		case sseOpcodePminsw:
			, ,  = legacyPrefixes0x66, 0x0FEA, 2
		case sseOpcodePminsd:
			, ,  = legacyPrefixes0x66, 0x0F3839, 3
		case sseOpcodePminub:
			, ,  = legacyPrefixes0x66, 0x0FDA, 2
		case sseOpcodePminuw:
			, ,  = legacyPrefixes0x66, 0x0F383A, 3
		case sseOpcodePminud:
			, ,  = legacyPrefixes0x66, 0x0F383B, 3
		case sseOpcodePmulld:
			, ,  = legacyPrefixes0x66, 0x0F3840, 3
		case sseOpcodePmullw:
			, ,  = legacyPrefixes0x66, 0x0FD5, 2
		case sseOpcodePmuludq:
			, ,  = legacyPrefixes0x66, 0x0FF4, 2
		case sseOpcodePor:
			, ,  = legacyPrefixes0x66, 0x0FEB, 2
		case sseOpcodePshufb:
			, ,  = legacyPrefixes0x66, 0x0F3800, 3
		case sseOpcodePsubb:
			, ,  = legacyPrefixes0x66, 0x0FF8, 2
		case sseOpcodePsubd:
			, ,  = legacyPrefixes0x66, 0x0FFA, 2
		case sseOpcodePsubq:
			, ,  = legacyPrefixes0x66, 0x0FFB, 2
		case sseOpcodePsubw:
			, ,  = legacyPrefixes0x66, 0x0FF9, 2
		case sseOpcodePsubsb:
			, ,  = legacyPrefixes0x66, 0x0FE8, 2
		case sseOpcodePsubsw:
			, ,  = legacyPrefixes0x66, 0x0FE9, 2
		case sseOpcodePsubusb:
			, ,  = legacyPrefixes0x66, 0x0FD8, 2
		case sseOpcodePsubusw:
			, ,  = legacyPrefixes0x66, 0x0FD9, 2
		case sseOpcodePunpckhbw:
			, ,  = legacyPrefixes0x66, 0x0F68, 2
		case sseOpcodePunpcklbw:
			, ,  = legacyPrefixes0x66, 0x0F60, 2
		case sseOpcodePxor:
			, ,  = legacyPrefixes0x66, 0x0FEF, 2
		case sseOpcodeSubps:
			, ,  = legacyPrefixesNone, 0x0F5C, 2
		case sseOpcodeSubpd:
			, ,  = legacyPrefixes0x66, 0x0F5C, 2
		case sseOpcodeSubss:
			, ,  = legacyPrefixes0xF3, 0x0F5C, 2
		case sseOpcodeSubsd:
			, ,  = legacyPrefixes0xF2, 0x0F5C, 2
		case sseOpcodeXorps:
			, ,  = legacyPrefixesNone, 0x0F57, 2
		case sseOpcodeXorpd:
			, ,  = legacyPrefixes0x66, 0x0F57, 2
		case sseOpcodePmulhrsw:
			, ,  = legacyPrefixes0x66, 0x0F380B, 3
		case sseOpcodeUnpcklps:
			, ,  = legacyPrefixesNone, 0x0F14, 2
		case sseOpcodePmaddubsw:
			, ,  = legacyPrefixes0x66, 0x0F3804, 3
		default:
			if  == blendvpd {
				, ,  = legacyPrefixes0x66, 0x0F3815, 3
			} else {
				panic(fmt.Sprintf("Unsupported sseOpcode: %s", ))
			}
		}

		 := regEncodings[.op2.reg().RealReg()]

		 := rexInfo(0).clearW()
		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(, , , , , , )
		} else if .op1.kind == operandKindMem {
			 := .op1.addressMode()
			encodeRegMem(, , , , , , )
		} else {
			panic("BUG: invalid operand kind")
		}

	case gprToXmm:
		var  legacyPrefixes
		var  uint32
		const  = 2
		switch sseOpcode(.u1) {
		case sseOpcodeMovd, sseOpcodeMovq:
			,  = legacyPrefixes0x66, 0x0f6e
		case sseOpcodeCvtsi2ss:
			,  = legacyPrefixes0xF3, 0x0f2a
		case sseOpcodeCvtsi2sd:
			,  = legacyPrefixes0xF2, 0x0f2a
		default:
			panic(fmt.Sprintf("Unsupported sseOpcode: %s", sseOpcode(.u1)))
		}

		var  rexInfo
		if .b1 {
			 = .setW()
		} else {
			 = .clearW()
		}
		 := regEncodings[.op2.reg().RealReg()]

		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(, , , , , , )
		} else if .op1.kind == operandKindMem {
			 := .op1.addressMode()
			encodeRegMem(, , , , , , )
		} else {
			panic("BUG: invalid operand kind")
		}

	case xmmUnaryRmR:
		var  legacyPrefixes
		var  uint32
		var  uint32
		 := sseOpcode(.u1)
		switch  {
		case sseOpcodeCvtss2sd:
			, ,  = legacyPrefixes0xF3, 0x0F5A, 2
		case sseOpcodeCvtsd2ss:
			, ,  = legacyPrefixes0xF2, 0x0F5A, 2
		case sseOpcodeMovaps:
			, ,  = legacyPrefixesNone, 0x0F28, 2
		case sseOpcodeMovapd:
			, ,  = legacyPrefixes0x66, 0x0F28, 2
		case sseOpcodeMovdqa:
			, ,  = legacyPrefixes0x66, 0x0F6F, 2
		case sseOpcodeMovdqu:
			, ,  = legacyPrefixes0xF3, 0x0F6F, 2
		case sseOpcodeMovsd:
			, ,  = legacyPrefixes0xF2, 0x0F10, 2
		case sseOpcodeMovss:
			, ,  = legacyPrefixes0xF3, 0x0F10, 2
		case sseOpcodeMovups:
			, ,  = legacyPrefixesNone, 0x0F10, 2
		case sseOpcodeMovupd:
			, ,  = legacyPrefixes0x66, 0x0F10, 2
		case sseOpcodePabsb:
			, ,  = legacyPrefixes0x66, 0x0F381C, 3
		case sseOpcodePabsw:
			, ,  = legacyPrefixes0x66, 0x0F381D, 3
		case sseOpcodePabsd:
			, ,  = legacyPrefixes0x66, 0x0F381E, 3
		case sseOpcodePmovsxbd:
			, ,  = legacyPrefixes0x66, 0x0F3821, 3
		case sseOpcodePmovsxbw:
			, ,  = legacyPrefixes0x66, 0x0F3820, 3
		case sseOpcodePmovsxbq:
			, ,  = legacyPrefixes0x66, 0x0F3822, 3
		case sseOpcodePmovsxwd:
			, ,  = legacyPrefixes0x66, 0x0F3823, 3
		case sseOpcodePmovsxwq:
			, ,  = legacyPrefixes0x66, 0x0F3824, 3
		case sseOpcodePmovsxdq:
			, ,  = legacyPrefixes0x66, 0x0F3825, 3
		case sseOpcodePmovzxbd:
			, ,  = legacyPrefixes0x66, 0x0F3831, 3
		case sseOpcodePmovzxbw:
			, ,  = legacyPrefixes0x66, 0x0F3830, 3
		case sseOpcodePmovzxbq:
			, ,  = legacyPrefixes0x66, 0x0F3832, 3
		case sseOpcodePmovzxwd:
			, ,  = legacyPrefixes0x66, 0x0F3833, 3
		case sseOpcodePmovzxwq:
			, ,  = legacyPrefixes0x66, 0x0F3834, 3
		case sseOpcodePmovzxdq:
			, ,  = legacyPrefixes0x66, 0x0F3835, 3
		case sseOpcodeSqrtps:
			, ,  = legacyPrefixesNone, 0x0F51, 2
		case sseOpcodeSqrtpd:
			, ,  = legacyPrefixes0x66, 0x0F51, 2
		case sseOpcodeSqrtss:
			, ,  = legacyPrefixes0xF3, 0x0F51, 2
		case sseOpcodeSqrtsd:
			, ,  = legacyPrefixes0xF2, 0x0F51, 2
		case sseOpcodeXorps:
			, ,  = legacyPrefixesNone, 0x0F57, 2
		case sseOpcodeXorpd:
			, ,  = legacyPrefixes0x66, 0x0F57, 2
		case sseOpcodeCvtdq2ps:
			, ,  = legacyPrefixesNone, 0x0F5B, 2
		case sseOpcodeCvtdq2pd:
			, ,  = legacyPrefixes0xF3, 0x0FE6, 2
		case sseOpcodeCvtps2pd:
			, ,  = legacyPrefixesNone, 0x0F5A, 2
		case sseOpcodeCvtpd2ps:
			, ,  = legacyPrefixes0x66, 0x0F5A, 2
		case sseOpcodeCvttps2dq:
			, ,  = legacyPrefixes0xF3, 0x0F5B, 2
		case sseOpcodeCvttpd2dq:
			, ,  = legacyPrefixes0x66, 0x0FE6, 2
		default:
			panic(fmt.Sprintf("Unsupported sseOpcode: %s", ))
		}

		 := regEncodings[.op2.reg().RealReg()]

		 := rexInfo(0).clearW()
		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(, , , , , , )
		} else if .op1.kind == operandKindMem {
			 := .op1.addressMode()
			 = encodeRegMem(, , , , , , )
		} else {
			panic("BUG: invalid operand kind")
		}

	case xmmUnaryRmRImm:
		var  legacyPrefixes
		var  uint32
		var  uint32
		 := sseOpcode(.u1)
		switch  {
		case sseOpcodeRoundps:
			, ,  = legacyPrefixes0x66, 0x0f3a08, 3
		case sseOpcodeRoundss:
			, ,  = legacyPrefixes0x66, 0x0f3a0a, 3
		case sseOpcodeRoundpd:
			, ,  = legacyPrefixes0x66, 0x0f3a09, 3
		case sseOpcodeRoundsd:
			, ,  = legacyPrefixes0x66, 0x0f3a0b, 3
		}
		 := rexInfo(0).clearW()
		 := regEncodings[.op2.reg().RealReg()]
		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(, , , , , , )
		} else if .op1.kind == operandKindMem {
			 := .op1.addressMode()
			encodeRegMem(, , , , , , )
		} else {
			panic("BUG: invalid operand kind")
		}

		.EmitByte(byte(.u2))

	case unaryRmR:
		var  legacyPrefixes
		var  uint32
		var  uint32
		 := unaryRmROpcode(.u1)
		// We assume size is either 32 or 64.
		switch  {
		case unaryRmROpcodeBsr:
			, ,  = legacyPrefixesNone, 0x0fbd, 2
		case unaryRmROpcodeBsf:
			, ,  = legacyPrefixesNone, 0x0fbc, 2
		case unaryRmROpcodeLzcnt:
			, ,  = legacyPrefixes0xF3, 0x0fbd, 2
		case unaryRmROpcodeTzcnt:
			, ,  = legacyPrefixes0xF3, 0x0fbc, 2
		case unaryRmROpcodePopcnt:
			, ,  = legacyPrefixes0xF3, 0x0fb8, 2
		default:
			panic(fmt.Sprintf("Unsupported unaryRmROpcode: %s", ))
		}

		 := regEncodings[.op2.reg().RealReg()]

		 := rexInfo(0)
		if .b1 { // 64 bit.
			 = rexInfo(0).setW()
		} else {
			 = rexInfo(0).clearW()
		}
		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(, , , , , , )
		} else if .op1.kind == operandKindMem {
			 := .op1.addressMode()
			encodeRegMem(, , , , , , )
		} else {
			panic("BUG: invalid operand kind")
		}

	case not:
		var  legacyPrefixes
		 := regEncodings[.op1.reg().RealReg()]
		 := rexInfo(0)
		if .b1 { // 64 bit.
			 = rexInfo(0).setW()
		} else {
			 = rexInfo(0).clearW()
		}
		 := uint8(2)
		encodeEncEnc(, , 0xf7, 1, , uint8(), )

	case neg:
		var  legacyPrefixes
		 := regEncodings[.op1.reg().RealReg()]
		 := rexInfo(0)
		if .b1 { // 64 bit.
			 = rexInfo(0).setW()
		} else {
			 = rexInfo(0).clearW()
		}
		 := uint8(3)
		encodeEncEnc(, , 0xf7, 1, , uint8(), )

	case div:
		 := rexInfo(0)
		if .b1 { // 64 bit.
			 = rexInfo(0).setW()
		} else {
			 = rexInfo(0).clearW()
		}
		var  uint8
		if .u1 != 0 { // Signed.
			 = 7
		} else {
			 = 6
		}

		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			encodeEncEnc(, legacyPrefixesNone, 0xf7, 1, , uint8(), )
		} else if .kind == operandKindMem {
			 := .addressMode()
			encodeEncMem(, legacyPrefixesNone, 0xf7, 1, , , )
		} else {
			panic("BUG: invalid operand kind")
		}

	case mulHi:
		var  legacyPrefixes
		 := rexInfo(0)
		if .b1 { // 64 bit.
			 = rexInfo(0).setW()
		} else {
			 = rexInfo(0).clearW()
		}

		 := .u1 != 0
		var  uint8
		if  {
			 = 5
		} else {
			 = 4
		}

		// src1 is implicitly rax,
		// dst_lo is implicitly rax,
		// dst_hi is implicitly rdx.
		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			encodeEncEnc(, , 0xf7, 1, , uint8(), )
		} else if .kind == operandKindMem {
			 := .addressMode()
			encodeEncMem(, , 0xf7, 1, , , )
		} else {
			panic("BUG: invalid operand kind")
		}

	case signExtendData:
		if .b1 { // 64 bit.
			.EmitByte(0x48)
			.EmitByte(0x99)
		} else {
			.EmitByte(0x99)
		}
	case movzxRmR, movsxRmR:
		 := .kind == movsxRmR

		 := extMode(.u1)
		var  uint32
		var  uint32
		var  rexInfo
		switch  {
		case extModeBL:
			if  {
				, ,  = 0x0fbe, 2, .clearW()
			} else {
				, ,  = 0x0fb6, 2, .clearW()
			}
		case extModeBQ:
			if  {
				, ,  = 0x0fbe, 2, .setW()
			} else {
				, ,  = 0x0fb6, 2, .setW()
			}
		case extModeWL:
			if  {
				, ,  = 0x0fbf, 2, .clearW()
			} else {
				, ,  = 0x0fb7, 2, .clearW()
			}
		case extModeWQ:
			if  {
				, ,  = 0x0fbf, 2, .setW()
			} else {
				, ,  = 0x0fb7, 2, .setW()
			}
		case extModeLQ:
			if  {
				, ,  = 0x63, 1, .setW()
			} else {
				, ,  = 0x8b, 1, .clearW()
			}
		default:
			panic("BUG: invalid extMode")
		}

		 := .op1
		 := regEncodings[.op2.reg().RealReg()]
		switch .kind {
		case operandKindReg:
			 := regEncodings[.reg().RealReg()]
			if  == extModeBL ||  == extModeBQ {
				// Some destinations must be encoded with REX.R = 1.
				if  := .encoding();  >= 4 &&  <= 7 {
					 = .always()
				}
			}
			encodeRegReg(, legacyPrefixesNone, , , , , )
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(, legacyPrefixesNone, , , , , )
		default:
			panic("BUG: invalid operand kind")
		}

	case mov64MR:
		 := .op1.addressMode()
		encodeLoad64(, , .op2.reg().RealReg())

	case lea:
		 = true
		 := regEncodings[.op2.reg().RealReg()]
		 := rexInfo(0).setW()
		const ,  = 0x8d, 1
		switch .op1.kind {
		case operandKindMem:
			 := .op1.addressMode()
			encodeRegMem(, legacyPrefixesNone, , , , , )
		case operandKindLabel:
			.encode(, regRexBit(byte()), 0)
			.EmitByte(byte(() & 0xff))

			// Indicate "LEAQ [RIP + 32bit displacement].
			// https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing
			.EmitByte(encodeModRM(0b00, .encoding(), 0b101))

			// This will be resolved later, so we just emit a placeholder (0xffffffff for testing).
			.Emit4Bytes(0xffffffff)
		default:
			panic("BUG: invalid operand kind")
		}

	case movRM:
		 := .op2.addressMode()
		 := regEncodings[.op1.reg().RealReg()]

		var  rexInfo
		switch .u1 {
		case 1:
			if  := .encoding();  >= 4 &&  <= 7 {
				 = .always()
			}
			encodeRegMem(, legacyPrefixesNone, 0x88, 1, , , .clearW())
		case 2:
			encodeRegMem(, legacyPrefixes0x66, 0x89, 1, , , .clearW())
		case 4:
			encodeRegMem(, legacyPrefixesNone, 0x89, 1, , , .clearW())
		case 8:
			encodeRegMem(, legacyPrefixesNone, 0x89, 1, , , .setW())
		default:
			panic(fmt.Sprintf("BUG: invalid size %d: %s", .u1, .String()))
		}

	case shiftR:
		 := regEncodings[.op2.reg().RealReg()]
		 := .op1

		var  uint32
		var  legacyPrefixes
		 := rexInfo(0)
		if .b1 { // 64 bit.
			 = rexInfo(0).setW()
		} else {
			 = rexInfo(0).clearW()
		}

		switch .kind {
		case operandKindReg:
			if .reg() != rcxVReg {
				panic("BUG: invalid reg operand: must be rcx")
			}
			,  = 0xd3, legacyPrefixesNone
			encodeEncEnc(, , , 1, uint8(.u1), uint8(), )
		case operandKindImm32:
			,  = 0xc1, legacyPrefixesNone
			encodeEncEnc(, , , 1, uint8(.u1), uint8(), )
			.EmitByte(byte(.imm32()))
		default:
			panic("BUG: invalid operand kind")
		}
	case xmmRmiReg:
		const  = legacyPrefixes0x66
		 := rexInfo(0).clearW()
		 := regEncodings[.op2.reg().RealReg()]

		var  uint32
		var  uint8

		 := sseOpcode(.u1)
		 := .op1
		if .op1.kind == operandKindImm32 {
			switch  {
			case sseOpcodePsllw:
				,  = 0x0f71, 6
			case sseOpcodePslld:
				,  = 0x0f72, 6
			case sseOpcodePsllq:
				,  = 0x0f73, 6
			case sseOpcodePsraw:
				,  = 0x0f71, 4
			case sseOpcodePsrad:
				,  = 0x0f72, 4
			case sseOpcodePsrlw:
				,  = 0x0f71, 2
			case sseOpcodePsrld:
				,  = 0x0f72, 2
			case sseOpcodePsrlq:
				,  = 0x0f73, 2
			default:
				panic("invalid opcode")
			}

			encodeEncEnc(, , , 2, , uint8(), )
			 := .imm32()
			if  > 0xff& {
				panic("immediate value does not fit 1 byte")
			}
			.EmitByte(uint8())
		} else {
			switch  {
			case sseOpcodePsllw:
				 = 0x0ff1
			case sseOpcodePslld:
				 = 0x0ff2
			case sseOpcodePsllq:
				 = 0x0ff3
			case sseOpcodePsraw:
				 = 0x0fe1
			case sseOpcodePsrad:
				 = 0x0fe2
			case sseOpcodePsrlw:
				 = 0x0fd1
			case sseOpcodePsrld:
				 = 0x0fd2
			case sseOpcodePsrlq:
				 = 0x0fd3
			default:
				panic("invalid opcode")
			}

			if .kind == operandKindReg {
				 := regEncodings[.reg().RealReg()]
				encodeRegReg(, , , 2, , , )
			} else if .kind == operandKindMem {
				 := .addressMode()
				encodeRegMem(, , , 2, , , )
			} else {
				panic("BUG: invalid operand kind")
			}
		}

	case cmpRmiR:
		var  uint32
		 := .u1 != 0
		 := rexInfo(0)
		 := .b1
		if  { // 64 bit.
			 = .setW()
		} else {
			 = .clearW()
		}
		 := regEncodings[.op2.reg().RealReg()]
		 := .op1
		switch .kind {
		case operandKindReg:
			 := regEncodings[.reg().RealReg()]
			if  {
				 = 0x39
			} else {
				 = 0x85
			}
			// Here we swap the encoding of the operands for CMP to be consistent with the output of LLVM/GCC.
			encodeRegReg(, legacyPrefixesNone, , 1, , , )

		case operandKindMem:
			if  {
				 = 0x3b
			} else {
				 = 0x85
			}
			 := .addressMode()
			encodeRegMem(, legacyPrefixesNone, , 1, , , )

		case operandKindImm32:
			 := .imm32()
			 :=  && lower8willSignExtendTo32()
			var  uint8

			switch {
			case  && :
				,  = 0x83, 7
			case  && !:
				,  = 0x81, 7
			default:
				,  = 0xf7, 0
			}
			encodeEncEnc(, legacyPrefixesNone, , 1, , uint8(), )
			if  {
				.EmitByte(uint8())
			} else {
				.Emit4Bytes()
			}

		default:
			panic("BUG: invalid operand kind")
		}
	case setcc:
		 := cond(.u1)
		 := regEncodings[.op2.reg().RealReg()]
		 := rexInfo(0).clearW().always()
		 := uint32(0x0f90) + uint32()
		encodeEncEnc(, legacyPrefixesNone, , 2, 0, uint8(), )
	case cmove:
		 := cond(.u1)
		 := regEncodings[.op2.reg().RealReg()]
		 := rexInfo(0)
		if .b1 { // 64 bit.
			 = .setW()
		} else {
			 = .clearW()
		}
		 := uint32(0x0f40) + uint32()
		 := .op1
		switch .kind {
		case operandKindReg:
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(, legacyPrefixesNone, , 2, , , )
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(, legacyPrefixesNone, , 2, , , )
		default:
			panic("BUG: invalid operand kind")
		}
	case push64:
		 := .op1

		switch .kind {
		case operandKindReg:
			 := regEncodings[.reg().RealReg()]
			if .rexBit() > 0 {
				.EmitByte(rexEncodingDefault | 0x1)
			}
			.EmitByte(0x50 | .encoding())
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(
				, legacyPrefixesNone, 0xff, 1, regEnc(6), , rexInfo(0).clearW(),
			)
		case operandKindImm32:
			.EmitByte(0x68)
			.Emit4Bytes(.imm32())
		default:
			panic("BUG: invalid operand kind")
		}

	case pop64:
		 := regEncodings[.op1.reg().RealReg()]
		if .rexBit() > 0 {
			.EmitByte(rexEncodingDefault | 0x1)
		}
		.EmitByte(0x58 | .encoding())

	case xmmMovRM:
		var  legacyPrefixes
		var  uint32
		const  = 2
		switch sseOpcode(.u1) {
		case sseOpcodeMovaps:
			,  = legacyPrefixesNone, 0x0f29
		case sseOpcodeMovapd:
			,  = legacyPrefixes0x66, 0x0f29
		case sseOpcodeMovdqa:
			,  = legacyPrefixes0x66, 0x0f7f
		case sseOpcodeMovdqu:
			,  = legacyPrefixes0xF3, 0x0f7f
		case sseOpcodeMovss:
			,  = legacyPrefixes0xF3, 0x0f11
		case sseOpcodeMovsd:
			,  = legacyPrefixes0xF2, 0x0f11
		case sseOpcodeMovups:
			,  = legacyPrefixesNone, 0x0f11
		case sseOpcodeMovupd:
			,  = legacyPrefixes0x66, 0x0f11
		default:
			panic(fmt.Sprintf("Unsupported sseOpcode: %s", sseOpcode(.u1)))
		}

		 := regEncodings[.op1.reg().RealReg()]
		encodeRegMem(, , , , , .op2.addressMode(), rexInfo(0).clearW())
	case xmmLoadConst:
		panic("TODO")
	case xmmToGpr:
		var  legacyPrefixes
		var  uint32
		var  bool
		const  = 2
		switch sseOpcode(.u1) {
		case sseOpcodeMovd, sseOpcodeMovq:
			, ,  = legacyPrefixes0x66, 0x0f7e, false
		case sseOpcodeMovmskps:
			, ,  = legacyPrefixesNone, 0x0f50, true
		case sseOpcodeMovmskpd:
			, ,  = legacyPrefixes0x66, 0x0f50, true
		case sseOpcodePmovmskb:
			, ,  = legacyPrefixes0x66, 0x0fd7, true
		case sseOpcodeCvttss2si:
			, ,  = legacyPrefixes0xF3, 0x0f2c, true
		case sseOpcodeCvttsd2si:
			, ,  = legacyPrefixes0xF2, 0x0f2c, true
		default:
			panic(fmt.Sprintf("Unsupported sseOpcode: %s", sseOpcode(.u1)))
		}

		var  rexInfo
		if .b1 {
			 = .setW()
		} else {
			 = .clearW()
		}
		 := regEncodings[.op1.reg().RealReg()]
		 := regEncodings[.op2.reg().RealReg()]
		if  {
			,  = , 
		}
		encodeRegReg(, , , , , , )

	case cvtUint64ToFloatSeq:
		panic("TODO")
	case cvtFloatToSintSeq:
		panic("TODO")
	case cvtFloatToUintSeq:
		panic("TODO")
	case xmmMinMaxSeq:
		panic("TODO")
	case xmmCmpRmR:
		var  legacyPrefixes
		var  uint32
		var  uint32
		 := rexInfo(0)
		 := .b1
		if  { // 64 bit.
			 = .setW()
		} else {
			 = .clearW()
		}

		 := sseOpcode(.u1)
		switch  {
		case sseOpcodePtest:
			, ,  = legacyPrefixes0x66, 0x0f3817, 3
		case sseOpcodeUcomisd:
			, ,  = legacyPrefixes0x66, 0x0f2e, 2
		case sseOpcodeUcomiss:
			, ,  = legacyPrefixesNone, 0x0f2e, 2
		default:
			panic(fmt.Sprintf("Unsupported sseOpcode: %s", ))
		}

		 := regEncodings[.op2.reg().RealReg()]
		 := .op1
		switch .kind {
		case operandKindReg:
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(, , , , , , )

		case operandKindMem:
			 := .addressMode()
			encodeRegMem(, , , , , , )

		default:
			panic("BUG: invalid operand kind")
		}
	case xmmRmRImm:
		 := sseOpcode(.u1)
		var  legacyPrefixes
		var  uint32
		var  uint32
		var  bool
		switch  {
		case sseOpcodeCmpps:
			, ,  = legacyPrefixesNone, 0x0FC2, 2
		case sseOpcodeCmppd:
			, ,  = legacyPrefixes0x66, 0x0FC2, 2
		case sseOpcodeCmpss:
			, ,  = legacyPrefixes0xF3, 0x0FC2, 2
		case sseOpcodeCmpsd:
			, ,  = legacyPrefixes0xF2, 0x0FC2, 2
		case sseOpcodeInsertps:
			, ,  = legacyPrefixes0x66, 0x0F3A21, 3
		case sseOpcodePalignr:
			, ,  = legacyPrefixes0x66, 0x0F3A0F, 3
		case sseOpcodePinsrb:
			, ,  = legacyPrefixes0x66, 0x0F3A20, 3
		case sseOpcodePinsrw:
			, ,  = legacyPrefixes0x66, 0x0FC4, 2
		case sseOpcodePinsrd, sseOpcodePinsrq:
			, ,  = legacyPrefixes0x66, 0x0F3A22, 3
		case sseOpcodePextrb:
			 = true
			, ,  = legacyPrefixes0x66, 0x0F3A14, 3
		case sseOpcodePextrw:
			, ,  = legacyPrefixes0x66, 0x0FC5, 2
		case sseOpcodePextrd, sseOpcodePextrq:
			 = true
			, ,  = legacyPrefixes0x66, 0x0F3A16, 3
		case sseOpcodePshufd:
			, ,  = legacyPrefixes0x66, 0x0F70, 2
		case sseOpcodeRoundps:
			, ,  = legacyPrefixes0x66, 0x0F3A08, 3
		case sseOpcodeRoundpd:
			, ,  = legacyPrefixes0x66, 0x0F3A09, 3
		case sseOpcodeShufps:
			, ,  = legacyPrefixesNone, 0x0FC6, 2
		default:
			panic(fmt.Sprintf("Unsupported sseOpcode: %s", ))
		}

		 := regEncodings[.op2.reg().RealReg()]

		var  rexInfo
		if  == sseOpcodePextrq ||  == sseOpcodePinsrq {
			 = rexInfo(0).setW()
		} else {
			 = rexInfo(0).clearW()
		}
		 := .op1
		if .kind == operandKindReg {
			 := regEncodings[.reg().RealReg()]
			if  {
				,  = , 
			}
			encodeRegReg(, , , , , , )
		} else if .op1.kind == operandKindMem {
			if  {
				panic("BUG: this is not possible to encode")
			}
			 := .op1.addressMode()
			encodeRegMem(, , , , , , )
		} else {
			panic("BUG: invalid operand kind")
		}

		.EmitByte(byte(.u2))

	case jmp:
		const (
			    = 0xff
			 = 1
			 = 4
		)
		 := .op1
		switch .kind {
		case operandKindLabel:
			 = true
			fallthrough
		case operandKindImm32:
			.EmitByte(0xe9)
			.Emit4Bytes(.imm32())
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(,
				legacyPrefixesNone,
				, ,
				, , rexInfo(0).clearW(),
			)
		case operandKindReg:
			 := .reg().RealReg()
			encodeRegReg(
				,
				legacyPrefixesNone,
				, ,
				,
				regEncodings[], rexInfo(0).clearW(),
			)
		default:
			panic("BUG: invalid operand kind")
		}

	case jmpIf:
		 := .op1
		switch .kind {
		case operandKindLabel:
			 = true
			fallthrough
		case operandKindImm32:
			.EmitByte(0x0f)
			.EmitByte(0x80 | cond(.u1).encoding())
			.Emit4Bytes(.imm32())
		default:
			panic("BUG: invalid operand kind")
		}

	case jmpTableIsland:
		 = true
		for  := uint64(0);  < .u2; ++ {
			.Emit8Bytes(0)
		}

	case exitSequence:
		 := .op1.reg()
		 := .op2.addressMode()

		// Restore the RBP, RSP, and return to the Go code:
		* = amode{
			kindWithShift: uint32(amodeImmReg), base: ,
			imm32: wazevoapi.ExecutionContextOffsetOriginalFramePointer.U32(),
		}
		encodeLoad64(, , rbp)
		.imm32 = wazevoapi.ExecutionContextOffsetOriginalStackPointer.U32()
		encodeLoad64(, , rsp)
		encodeRet()

	case ud2:
		.EmitByte(0x0f)
		.EmitByte(0x0b)

	case call:
		.EmitByte(0xe8)
		// Meaning that the call target is a function value, and requires relocation.
		.AddRelocationInfo(ssa.FuncRef(.u1))
		// Note that this is zero as a placeholder for the call target if it's a function value.
		.Emit4Bytes(uint32(.u2))

	case callIndirect:
		 := .op1

		const  = 1
		const  = 0xff
		 := rexInfo(0).clearW()
		switch .kind {
		case operandKindReg:
			 := regEncodings[.reg().RealReg()]
			encodeRegReg(,
				legacyPrefixesNone,
				, ,
				regEnc(2),
				,
				,
			)
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(,
				legacyPrefixesNone,
				, ,
				regEnc(2),
				,
				,
			)
		default:
			panic("BUG: invalid operand kind")
		}

	case xchg:
		,  := regEncodings[.op1.reg().RealReg()], .op2
		 := .u1

		var  rexInfo
		var  uint32
		 := legacyPrefixesNone
		switch  {
		case 8:
			 = 0x87
			 = rexInfo(0).setW()
		case 4:
			 = 0x87
			 = rexInfo(0).clearW()
		case 2:
			 = legacyPrefixes0x66
			 = 0x87
			 = rexInfo(0).clearW()
		case 1:
			 = 0x86
			if .op2.kind == operandKindReg {
				panic("TODO?: xchg on two 1-byte registers")
			}
			// Some destinations must be encoded with REX.R = 1.
			if  := .encoding();  >= 4 &&  <= 7 {
				 = rexInfo(0).always()
			}
		default:
			panic(fmt.Sprintf("BUG: invalid size %d: %s", , .String()))
		}

		switch .kind {
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(, , , 1, , , )
		case operandKindReg:
			 := .reg().RealReg()
			encodeRegReg(, , , 1, , regEncodings[], )
		default:
			panic("BUG: invalid operand kind")
		}

	case lockcmpxchg:
		,  := regEncodings[.op1.reg().RealReg()], .op2
		 := .u1

		var  rexInfo
		var  uint32
		 := legacyPrefixes0xF0 // Lock prefix.
		switch  {
		case 8:
			 = 0x0FB1
			 = rexInfo(0).setW()
		case 4:
			 = 0x0FB1
			 = rexInfo(0).clearW()
		case 2:
			 = legacyPrefixes0x660xF0 // Legacy prefix + Lock prefix.
			 = 0x0FB1
			 = rexInfo(0).clearW()
		case 1:
			 = 0x0FB0
			// Some destinations must be encoded with REX.R = 1.
			if  := .encoding();  >= 4 &&  <= 7 {
				 = rexInfo(0).always()
			}
		default:
			panic(fmt.Sprintf("BUG: invalid size %d: %s", , .String()))
		}

		switch .kind {
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(, , , 2, , , )
		default:
			panic("BUG: invalid operand kind")
		}

	case lockxadd:
		,  := regEncodings[.op1.reg().RealReg()], .op2
		 := .u1

		var  rexInfo
		var  uint32
		 := legacyPrefixes0xF0 // Lock prefix.
		switch  {
		case 8:
			 = 0x0FC1
			 = rexInfo(0).setW()
		case 4:
			 = 0x0FC1
			 = rexInfo(0).clearW()
		case 2:
			 = legacyPrefixes0x660xF0 // Legacy prefix + Lock prefix.
			 = 0x0FC1
			 = rexInfo(0).clearW()
		case 1:
			 = 0x0FC0
			// Some destinations must be encoded with REX.R = 1.
			if  := .encoding();  >= 4 &&  <= 7 {
				 = rexInfo(0).always()
			}
		default:
			panic(fmt.Sprintf("BUG: invalid size %d: %s", , .String()))
		}

		switch .kind {
		case operandKindMem:
			 := .addressMode()
			encodeRegMem(, , , 2, , , )
		default:
			panic("BUG: invalid operand kind")
		}

	case zeros:
		 := .op2.reg()
		if .RegType() == regalloc.RegTypeInt {
			.asAluRmiR(aluRmiROpcodeXor, newOperandReg(), , true)
		} else {
			.asXmmRmR(sseOpcodePxor, newOperandReg(), )
		}
		.()

	case mfence:
		// https://www.felixcloutier.com/x86/mfence
		.EmitByte(0x0f)
		.EmitByte(0xae)
		.EmitByte(0xf0)

	default:
		panic(fmt.Sprintf("TODO: %v", .kind))
	}
	return
}

func encodeLoad64( backend.Compiler,  *amode,  regalloc.RealReg) {
	 := regEncodings[]
	encodeRegMem(, legacyPrefixesNone, 0x8b, 1, , , rexInfo(0).setW())
}

func encodeRet( backend.Compiler) {
	.EmitByte(0xc3)
}

func encodeEncEnc(
	 backend.Compiler,
	 legacyPrefixes,
	 uint32,
	 uint32,
	 uint8,
	 uint8,
	 rexInfo,
) {
	.encode()
	.encode(, >>3, >>3)

	for  > 0 {
		--
		.EmitByte(byte(( >> ( << 3)) & 0xff))
	}
	.EmitByte(encodeModRM(3, &7, &7))
}

func encodeRegReg(
	 backend.Compiler,
	 legacyPrefixes,
	 uint32,
	 uint32,
	 regEnc,
	 regEnc,
	 rexInfo,
) {
	encodeEncEnc(, , , , uint8(), uint8(), )
}

func encodeModRM( byte,  byte,  byte) byte {
	return <<6 | <<3 | 
}

func encodeSIB( byte,  byte,  byte) byte {
	return <<6 | <<3 | 
}

func encodeRegMem(
	 backend.Compiler,  legacyPrefixes,  uint32,  uint32,  regEnc,  *amode,  rexInfo,
) ( bool) {
	 = encodeEncMem(, , , , uint8(), , )
	return
}

func encodeEncMem(
	 backend.Compiler,  legacyPrefixes,  uint32,  uint32,  uint8,  *amode,  rexInfo,
) ( bool) {
	.encode()

	const (
		    = 0b00
		 = 0b01
		  = 0b10

		 = 4 // the encoding of rsp or r12 register.
	)

	switch .kind() {
	case amodeImmReg, amodeImmRBP:
		 := .base.RealReg()
		 := regEncodings[]

		.encode(, regRexBit(), .rexBit())

		for  > 0 {
			--
			.EmitByte(byte(( >> ( << 3)) & 0xff))
		}

		// SIB byte is the last byte of the memory encoding before the displacement
		const  = 0x24 // == encodeSIB(0, 4, 4)

		, ,  := .imm32 == 0,  == rbp,  == r13
		 := lower8willSignExtendTo32(.imm32)
		 :=  == rsp ||  == r12

		if  && ! && ! { // rbp or r13 can't be used as base for without displacement encoding.
			.EmitByte(encodeModRM(, regEncoding(), .encoding()))
			if  {
				.EmitByte()
			}
		} else if  { // Note: this includes the case where m.imm32 == 0 && base == rbp || base == r13.
			.EmitByte(encodeModRM(, regEncoding(), .encoding()))
			if  {
				.EmitByte()
			}
			.EmitByte(byte(.imm32))
		} else {
			.EmitByte(encodeModRM(, regEncoding(), .encoding()))
			if  {
				.EmitByte()
			}
			.Emit4Bytes(.imm32)
		}

	case amodeRegRegShift:
		 := .base.RealReg()
		 := regEncodings[]
		 := .index.RealReg()
		 := regEncodings[]

		if  == rsp {
			panic("BUG: rsp can't be used as index of addressing mode")
		}

		.encodeForIndex(, regEnc(), , )

		for  > 0 {
			--
			.EmitByte(byte(( >> ( << 3)) & 0xff))
		}

		, ,  := .imm32 == 0,  == rbp,  == r13
		if  && ! && ! { // rbp or r13 can't be used as base for without displacement encoding. (curious why? because it's interpreted as RIP relative addressing).
			.EmitByte(encodeModRM(, regEncoding(), ))
			.EmitByte(encodeSIB(.shift(), .encoding(), .encoding()))
		} else if lower8willSignExtendTo32(.imm32) {
			.EmitByte(encodeModRM(, regEncoding(), ))
			.EmitByte(encodeSIB(.shift(), .encoding(), .encoding()))
			.EmitByte(byte(.imm32))
		} else {
			.EmitByte(encodeModRM(, regEncoding(), ))
			.EmitByte(encodeSIB(.shift(), .encoding(), .encoding()))
			.Emit4Bytes(.imm32)
		}

	case amodeRipRel:
		.encode(, regRexBit(), 0)
		for  > 0 {
			--
			.EmitByte(byte(( >> ( << 3)) & 0xff))
		}

		// Indicate "LEAQ [RIP + 32bit displacement].
		// https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing
		.EmitByte(encodeModRM(0b00, regEncoding(), 0b101))

		// This will be resolved later, so we just emit a placeholder.
		 = true
		.Emit4Bytes(0)

	default:
		panic("BUG: invalid addressing mode")
	}
	return
}

const (
	rexEncodingDefault byte = 0x40
	rexEncodingW            = rexEncodingDefault | 0x08
)

// rexInfo is a bit set to indicate:
//
//	0x01: W bit must be cleared.
//	0x02: REX prefix must be emitted.
type rexInfo byte

func ( rexInfo) () rexInfo {
	return  | 0x01
}

func ( rexInfo) () rexInfo {
	return  & 0x02
}

func ( rexInfo) () rexInfo {
	return  | 0x02
}

func ( rexInfo) () rexInfo { //nolint
	return  & 0x01
}

func ( rexInfo) ( backend.Compiler,  uint8,  uint8) {
	var  byte = 0
	if &0x01 != 0 {
		 = 0x01
	}
	 := rexEncodingDefault | <<3 | <<2 | 
	if  != rexEncodingDefault || &0x02 != 0 {
		.EmitByte()
	}
}

func ( rexInfo) ( backend.Compiler,  regEnc,  regEnc,  regEnc) {
	var  byte = 0
	if &0x01 != 0 {
		 = 0x01
	}
	 := .rexBit()
	 := .rexBit()
	 := .rexBit()
	 := byte(0x40) | <<3 | <<2 | <<1 | 
	if  != 0x40 || &0x02 != 0 {
		.EmitByte()
	}
}

type regEnc byte

func ( regEnc) () byte {
	return regRexBit(byte())
}

func ( regEnc) () byte {
	return regEncoding(byte())
}

func regRexBit( byte) byte {
	return  >> 3
}

func regEncoding( byte) byte {
	return  & 0x07
}

var regEncodings = [...]regEnc{
	rax:   0b000,
	rcx:   0b001,
	rdx:   0b010,
	rbx:   0b011,
	rsp:   0b100,
	rbp:   0b101,
	rsi:   0b110,
	rdi:   0b111,
	r8:    0b1000,
	r9:    0b1001,
	r10:   0b1010,
	r11:   0b1011,
	r12:   0b1100,
	r13:   0b1101,
	r14:   0b1110,
	r15:   0b1111,
	xmm0:  0b000,
	xmm1:  0b001,
	xmm2:  0b010,
	xmm3:  0b011,
	xmm4:  0b100,
	xmm5:  0b101,
	xmm6:  0b110,
	xmm7:  0b111,
	xmm8:  0b1000,
	xmm9:  0b1001,
	xmm10: 0b1010,
	xmm11: 0b1011,
	xmm12: 0b1100,
	xmm13: 0b1101,
	xmm14: 0b1110,
	xmm15: 0b1111,
}

type legacyPrefixes byte

const (
	legacyPrefixesNone legacyPrefixes = iota
	legacyPrefixes0x66
	legacyPrefixes0xF0
	legacyPrefixes0x660xF0
	legacyPrefixes0xF2
	legacyPrefixes0xF3
)

func ( legacyPrefixes) ( backend.Compiler) {
	switch  {
	case legacyPrefixesNone:
	case legacyPrefixes0x66:
		.EmitByte(0x66)
	case legacyPrefixes0xF0:
		.EmitByte(0xf0)
	case legacyPrefixes0x660xF0:
		.EmitByte(0x66)
		.EmitByte(0xf0)
	case legacyPrefixes0xF2:
		.EmitByte(0xf2)
	case legacyPrefixes0xF3:
		.EmitByte(0xf3)
	default:
		panic("BUG: invalid legacy prefix")
	}
}

func lower32willSignExtendTo64( uint64) bool {
	 := int64()
	return  == int64(uint64(int32()))
}

func lower8willSignExtendTo32( uint32) bool {
	 := int32()
	return  == (( << 24) >> 24)
}