func trapHandlerPrologue(p *gen.Prog, id trap.ID) {
	in.MOVi.RegImm32(&p.Text, wa.I32, RegTrap, int32(id))
	in.MOV.RegMemDisp(&p.Text, wa.I64, RegScratch, in.BaseText, gen.VectorOffsetTrapHandler)
}
trapHandlerPrologue doesn't update condition flags.
package x86
import (
	"gate.computer/wag/internal/gen"
	"gate.computer/wag/internal/gen/condition"
	"gate.computer/wag/internal/gen/link"
	"gate.computer/wag/internal/gen/operand"
	"gate.computer/wag/internal/gen/reg"
	"gate.computer/wag/internal/gen/rodata"
	"gate.computer/wag/internal/gen/storage"
	"gate.computer/wag/internal/isa/x86/in"
	"gate.computer/wag/internal/isa/x86/nonabi"
	"gate.computer/wag/internal/obj"
	"gate.computer/wag/trap"
	"gate.computer/wag/wa"
	errors "golang.org/x/xerrors"
)
const (
	FuncAlignment = 16
	PadByte = 0xcc  
)
var conditionInsns = [22]in.CCInsn{
	condition.Eq:            in.InsnEq,
	condition.Ne:            in.InsnNe,
	condition.GeS:           in.InsnGeS,
	condition.GtS:           in.InsnGtS,
	condition.GeU:           in.InsnGeU,
	condition.GtU:           in.InsnGtU,
	condition.LeS:           in.InsnLeS,
	condition.LtS:           in.InsnLtS,
	condition.LeU:           in.InsnLeU,
	condition.LtU:           in.InsnLtU,
	condition.OrderedAndEq:  in.InsnEq,
	condition.OrderedAndNe:  in.InsnNe,
	condition.OrderedAndGe:  in.InsnGeU,
	condition.OrderedAndGt:  in.InsnGtU,
	condition.OrderedAndLe:  in.InsnLeU,
	condition.OrderedAndLt:  in.InsnLtU,
	condition.UnorderedOrEq: in.InsnEq,
	condition.UnorderedOrNe: in.InsnNe,
	condition.UnorderedOrGe: in.InsnGeU,
	condition.UnorderedOrGt: in.InsnGtU,
	condition.UnorderedOrLe: in.InsnLeU,
	condition.UnorderedOrLt: in.InsnLtU,
}
var suspendRewindOffsets = [2]int8{
	0: 8,   
	1: 12,  
}
var asm MacroAssembler
type MacroAssembler struct{}
func (MacroAssembler) AlignData(p *gen.Prog, alignment int) {
	pad(p, (alignment-int(p.Text.Addr))&(alignment-1))
}
func (MacroAssembler) AlignFunc(p *gen.Prog) {
	pad(p, (FuncAlignment-int(p.Text.Addr))&(FuncAlignment-1))
}
func (MacroAssembler) PadUntil(p *gen.Prog, addr int32) {
	pad(p, int(addr)-int(p.Text.Addr))
}
func pad(p *gen.Prog, length int) {
	gap := p.Text.Extend(length)
	for i := range gap {
		gap[i] = PadByte
	}
}
func (MacroAssembler) AddToStackPtrUpper32(f *gen.Func, r reg.R) {
	in.SARi.RegImm8(&f.Text, wa.I64, r, 32)  
	in.ADD.RegReg(&f.Text, wa.I64, RegStackPtr, r)
	f.Regs.Free(wa.I64, r)
}
func (MacroAssembler) DropStackValues(p *gen.Prog, n int) {
	in.LEA.RegStackDisp(&p.Text, wa.I64, RegStackPtr, int32(n*obj.Word))
}
func (MacroAssembler) Branch(p *gen.Prog, addr int32) {
	in.JMPcd.Addr32(&p.Text, addr)
}
func (MacroAssembler) BranchStub(p *gen.Prog) int32 {
	return in.JMPcd.Stub32(&p.Text)
}
func (MacroAssembler) BranchIndirect(f *gen.Func, addr reg.R) {
	in.MOV.RegReg(&f.Text, wa.I32, RegScratch, addr)
	f.Regs.Free(wa.I64, addr)
	in.ADD.RegReg(&f.Text, wa.I64, RegScratch, RegTextBase)
	in.JMPcd.Addr32(&f.Text, nonabi.TextAddrRetpoline)
}
func (MacroAssembler) BranchIf(f *gen.Func, x operand.O, labelAddr int32) (sites []int32) {
	sites = asm.BranchIfStub(f, x, true, false)
	if labelAddr != 0 {
		linker.UpdateFarBranches(f.Text.Bytes(), &link.L{Sites: sites, Addr: labelAddr})
	}
	return
}
func (MacroAssembler) BranchIfStub(f *gen.Func, x operand.O, yes, near bool) (sites []int32) {
	var cond condition.C
	if x.Storage == storage.Flags {
		cond = x.FlagsCond()
	} else {
		r, _ := getScratchReg(f, x)
		in.TEST.RegReg(&f.Text, wa.I32, r, r)
		cond = condition.Ne
		f.Regs.Free(wa.I32, r)
	}
	if !yes {
		cond = condition.Inverted[cond]
	}
	var endJumps []int32
	switch {
	case cond >= condition.MinUnorderedOrCondition:
		sites = append(sites, in.JPc.Stub(&f.Text, near))
	case cond >= condition.MinOrderedAndCondition:
		endJumps = append(endJumps, in.JPcb.Stub8(&f.Text))
	}
	sites = append(sites, conditionInsns[cond].JccOpcodeC().Stub(&f.Text, near))
	linker.UpdateNearBranches(f.Text.Bytes(), endJumps)
	return
}
func (MacroAssembler) BranchIfOutOfBounds(p *gen.Prog, indexReg reg.R, upperBound, addr int32) {
	compareBounds(p, indexReg, upperBound)
	in.JLEc.Addr(&p.Text, addr)
}
func (MacroAssembler) BranchIfOutOfBoundsStub(p *gen.Prog, indexReg reg.R, upperBound int32) int32 {
	compareBounds(p, indexReg, upperBound)
	return in.JLEc.AddrStub(&p.Text)
}
func compareBounds(p *gen.Prog, indexReg reg.R, upperBound int32) {
	in.MOVi.RegImm32(&p.Text, wa.I32, RegScratch, upperBound)
	in.TEST.RegReg(&p.Text, wa.I32, indexReg, indexReg)
	in.CMOVL.RegReg(&p.Text, wa.I32, indexReg, RegScratch)  
	in.CMP.RegReg(&p.Text, wa.I32, RegScratch, indexReg)
}
func (MacroAssembler) Call(p *gen.Prog, addr int32) {
	in.CALLcd.Addr32(&p.Text, addr)
}
func (MacroAssembler) CallMissing(p *gen.Prog, atomic bool) {
	in.CALLcd.MissingFunction(&p.Text, atomic)
}
func (MacroAssembler) CallIndirect(f *gen.Func, sigIndex int32, funcIndexReg reg.R) {
	compareBounds(&f.Prog, funcIndexReg, int32(len(f.Module.TableFuncs)))  
	outOfBoundsJump := in.JLEcb.Stub8(&f.Text)
	in.MOV.RegMemIndexDisp(&f.Text, wa.I64, RegResult, in.BaseText, funcIndexReg, in.Scale3, rodata.TableAddr)
	f.Regs.Free(wa.I64, funcIndexReg)
	in.MOV.RegReg(&f.Text, wa.I32, RegScratch, RegResult)  
	in.SHRi.RegImm8(&f.Text, wa.I64, RegResult, 32)        
	in.CMPi.RegImm(&f.Text, wa.I32, RegResult, sigIndex)
	okJump := in.JEcb.Stub8(&f.Text)
	asm.Trap(f, trap.IndirectCallSignatureMismatch)
	linker.UpdateNearBranch(f.Text.Bytes(), outOfBoundsJump)
	asm.Trap(f, trap.IndirectCallIndexOutOfBounds)
	linker.UpdateNearBranch(f.Text.Bytes(), okJump)
	in.ADD.RegReg(&f.Text, wa.I64, RegScratch, RegTextBase)
	in.CALLcd.Addr32(&f.Text, nonabi.TextAddrRetpoline)
}
func (MacroAssembler) ClearIntResultReg(p *gen.Prog) {
	in.XOR.RegReg(&p.Text, wa.I32, RegResult, RegResult)
}
func (MacroAssembler) LoadGlobal(p *gen.Prog, t wa.Type, target reg.R, offset int32) (zeroExtended bool) {
	if t.Category() == wa.Int {
		in.MOV.RegMemDisp(&p.Text, t, target, in.BaseMemory, offset)
	} else {
		in.MOVx.RegMemDisp(&p.Text, t, target, in.BaseMemory, offset)
	}
	return true
}
func (MacroAssembler) StoreGlobal(f *gen.Func, offset int32, x operand.O) {
	var r reg.R
	if x.Storage == storage.Reg {
		r = x.Reg()
		f.Regs.Free(x.Type, r)
	} else {
		r = RegScratch
		asm.Move(f, r, x)
	}
	if x.Type.Category() == wa.Int {
		in.MOVmr.RegMemDisp(&f.Text, x.Type, r, in.BaseMemory, offset)
	} else {
		in.MOVxmr.RegMemDisp(&f.Text, x.Type, r, in.BaseMemory, offset)
	}
}
func initRoutinePrologue(p *gen.Prog) {
	in.MOV.RegMemDisp(&p.Text, wa.I64, RegMemoryBase, in.BaseText, gen.VectorOffsetMemoryAddr)
	in.XOR.RegReg(&p.Text, wa.I32, RegZero, RegZero)
}
func (MacroAssembler) Exit(p *gen.Prog) {
	initRoutinePrologue(p)
	in.MOV.RegMemDisp(&p.Text, wa.I64, RegScratch, in.BaseText, gen.VectorOffsetTrapHandler)
	in.JMPcb.Addr8(&p.Text, nonabi.TextAddrRetpoline)
}
func (MacroAssembler) Resume(p *gen.Prog) {
	initRoutinePrologue(p)
	in.RET.Simple(&p.Text)  
}
func (MacroAssembler) Enter(p *gen.Prog) {
	initRoutinePrologue(p)
	in.POP.Reg(&p.Text, in.OneSize, RegScratch)  
	in.TEST.RegReg(&p.Text, wa.I32, RegScratch, RegScratch)
	skipStart := in.JEcb.Stub8(&p.Text)
	in.ADD.RegReg(&p.Text, wa.I64, RegScratch, RegTextBase)
	in.CALLcd.Addr32(&p.Text, nonabi.TextAddrRetpoline)
	p.Map.PutCallSite(uint32(p.Text.Addr), obj.Word)  
	linker.UpdateNearBranch(p.Text.Bytes(), skipStart)
	in.XOR.RegReg(&p.Text, wa.I32, RegResult, RegResult)  
	in.POP.Reg(&p.Text, in.OneSize, RegScratch)  
	in.TEST.RegReg(&p.Text, wa.I32, RegScratch, RegScratch)
	skipEntry := in.JEcb.Stub8(&p.Text)
	in.ADD.RegReg(&p.Text, wa.I64, RegScratch, RegTextBase)
	in.CALLcd.Addr32(&p.Text, nonabi.TextAddrRetpoline)
	p.Map.PutCallSite(uint32(p.Text.Addr), 0)  
	linker.UpdateNearBranch(p.Text.Bytes(), skipEntry)
	in.JMPcb.Addr8(&p.Text, p.TrapLinks[trap.Exit].Addr)
	asm.AlignFunc(p)
	if p.Text.Addr != nonabi.TextAddrRetpoline {
		panic("x86: hardcoded retpoline address needs to be adjusted")
	}
	in.CALLcd.Addr32(&p.Text, nonabi.TextAddrRetpolineSetup)
	captureSpecAddr := p.Text.Addr
	in.PAUSE.Simple(&p.Text)
	in.JMPcb.Addr8(&p.Text, captureSpecAddr)
	asm.AlignFunc(p)
	if p.Text.Addr != nonabi.TextAddrRetpolineSetup {
		panic("x86: hardcoded retpoline setup address needs to be adjusted")
	}
	asm.StoreStackReg(p, wa.I64, 0, RegScratch)
	in.XOR.RegReg(&p.Text, wa.I32, RegScratch, RegScratch)
	in.RET.Simple(&p.Text)
}
func (MacroAssembler) CallImportVector(f *gen.Func, vecIndex int) {
	numParams := f.NumExtra - 2
	offset := numParams + 1 + f.NumLocals + f.StackDepth  
	in.LEA.RegStackDisp(&f.Text, wa.I64, RegRestartSP, int32(offset*obj.Word))
	in.MOV.RegMemDisp(&f.Text, wa.I64, RegScratch, in.BaseText, int32(vecIndex*8))
	in.CALLcd.Addr32(&f.Text, nonabi.TextAddrRetpoline)
}
func (MacroAssembler) TrapHandler(p *gen.Prog, id trap.ID) {
	trapHandler(p, id)
}
func (MacroAssembler) TrapHandlerRewindNoFunction(p *gen.Prog) {
	in.SUBi.StackImm8(&p.Text, wa.I64, in.CALLcd.Size())
	in.XOR.RegReg(&p.Text, wa.I32, RegTrap, RegTrap)  
	in.INC.Reg(&p.Text, wa.I32, RegTrap)              
	in.MOV.RegMemDisp(&p.Text, wa.I64, RegScratch, in.BaseText, gen.VectorOffsetTrapHandler)
	in.JMPcb.Addr8(&p.Text, nonabi.TextAddrRetpoline)
}
func (MacroAssembler) TrapHandlerRewindCallStackExhausted(p *gen.Prog) {
	in.SUBi.StackImm8(&p.Text, wa.I64, 18)  
	trapHandler(p, trap.CallStackExhausted)
}
func (MacroAssembler) TrapHandlerRewindSuspended(p *gen.Prog, index int) {
	in.SUBi.StackImm8(&p.Text, wa.I64, suspendRewindOffsets[index])
	trapHandler(p, trap.Suspended)
}
func (MacroAssembler) TrapHandlerTruncOverflow(p *gen.Prog, trapIndex int) {
	var (
		floatIntType wa.Type
		fractionSize int8
		exponentMask int32
		goodBits     int32
	)
	switch trapIndex >> 1 {
	case int(wa.Size32 >> 3):
		floatIntType = wa.I32
		fractionSize = 23
		exponentMask = 0xff
		if trapIndex&1 == int(wa.Size32>>3) {
			goodBits = 0x19e  
		} else {  
			goodBits = 0x1be  
		}
	case int(wa.Size64 >> 3):
		floatIntType = wa.I64
		fractionSize = 52
		exponentMask = 0x7ff
		if trapIndex&1 == int(wa.Size32>>3) {
			goodBits = 0xc1e  
		} else {  
			goodBits = 0xc3e  
		}
	default:
		panic(trapIndex)
	}
	in.MOVxmr.RegReg(&p.Text, floatIntType, RegResult, RegScratch)    
	in.RORi.RegImm8(&p.Text, floatIntType, RegScratch, fractionSize)  
	in.CMPi.RegImm32(&p.Text, floatIntType, RegScratch, goodBits)
	jumpIfOutOfRange := in.JNEcb.Stub8(&p.Text)
	in.ANDi.RegImm32(&p.Text, wa.I32, RegScratch, exponentMask)  
	in.CMPi.RegImm32(&p.Text, wa.I32, RegScratch, exponentMask)
	jumpIfInfNan := in.JEcb.Stub8(&p.Text)
	in.RET.Simple(&p.Text)
	linker.UpdateNearBranch(p.Text.Bytes(), jumpIfOutOfRange)
	linker.UpdateNearBranch(p.Text.Bytes(), jumpIfInfNan)
	trapHandler(p, trap.IntegerOverflow)
}
func trapHandler(p *gen.Prog, id trap.ID) {
	trapHandlerPrologue(p, id)
	in.JMPcd.Addr32(&p.Text, nonabi.TextAddrRetpoline)
}