text: // Inferno utils/6l/span.c
  // http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
  //
  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
  //	Portions Copyright © 1997-1999 Vita Nuova Limited
  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
  //	Portions Copyright © 2004,2006 Bruce Ellis
  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  //
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  
  // Instruction layout.
  
  #include <u.h>
  #include <libc.h>
  #include <bio.h>
  #include <link.h>
  #include "../cmd/6l/6.out.h"
  #include "../runtime/stack.h"
  
  enum
  {
  	MaxAlign = 32,	// max data alignment
  	
  	// Loop alignment constants:
  	// want to align loop entry to LoopAlign-byte boundary,
  	// and willing to insert at most MaxLoopPad bytes of NOP to do so.
  	// We define a loop entry as the target of a backward jump.
  	//
  	// gcc uses MaxLoopPad = 10 for its 'generic x86-64' config,
  	// and it aligns all jump targets, not just backward jump targets.
  	//
  	// As of 6/1/2012, the effect of setting MaxLoopPad = 10 here
  	// is very slight but negative, so the alignment is disabled by
  	// setting MaxLoopPad = 0. The code is here for reference and
  	// for future experiments.
  	// 
  	LoopAlign = 16,
  	MaxLoopPad = 0,
  
  	FuncAlign = 16
  };
  
  typedef	struct	Optab	Optab;
  typedef	struct	Movtab	Movtab;
  
  struct	Optab
  {
  	short	as;
  	uchar*	ytab;
  	uchar	prefix;
  	uchar	op[23];
  };
  struct	Movtab
  {
  	short	as;
  	uchar	ft;
  	uchar	tt;
  	uchar	code;
  	uchar	op[4];
  };
  
  enum
  {
  	Yxxx		= 0,
  	Ynone,
  	Yi0,
  	Yi1,
  	Yi8,
  	Ys32,
  	Yi32,
  	Yi64,
  	Yiauto,
  	Yal,
  	Ycl,
  	Yax,
  	Ycx,
  	Yrb,
  	Yrl,
  	Yrf,
  	Yf0,
  	Yrx,
  	Ymb,
  	Yml,
  	Ym,
  	Ybr,
  	Ycol,
  
  	Ycs,	Yss,	Yds,	Yes,	Yfs,	Ygs,
  	Ygdtr,	Yidtr,	Yldtr,	Ymsw,	Ytask,
  	Ycr0,	Ycr1,	Ycr2,	Ycr3,	Ycr4,	Ycr5,	Ycr6,	Ycr7,	Ycr8,
  	Ydr0,	Ydr1,	Ydr2,	Ydr3,	Ydr4,	Ydr5,	Ydr6,	Ydr7,
  	Ytr0,	Ytr1,	Ytr2,	Ytr3,	Ytr4,	Ytr5,	Ytr6,	Ytr7,	Yrl32,	Yrl64,
  	Ymr, Ymm,
  	Yxr, Yxm,
  	Ytls,
  	Ymax,
  
  	Zxxx		= 0,
  
  	Zlit,
  	Zlitm_r,
  	Z_rp,
  	Zbr,
  	Zcall,
  	Zcallindreg,
  	Zib_,
  	Zib_rp,
  	Zibo_m,
  	Zibo_m_xm,
  	Zil_,
  	Zil_rp,
  	Ziq_rp,
  	Zilo_m,
  	Ziqo_m,
  	Zjmp,
  	Zloop,
  	Zo_iw,
  	Zm_o,
  	Zm_r,
  	Zm2_r,
  	Zm_r_xm,
  	Zm_r_i_xm,
  	Zm_r_3d,
  	Zm_r_xm_nr,
  	Zr_m_xm_nr,
  	Zibm_r,	/* mmx1,mmx2/mem64,imm8 */
  	Zmb_r,
  	Zaut_r,
  	Zo_m,
  	Zo_m64,
  	Zpseudo,
  	Zr_m,
  	Zr_m_xm,
  	Zr_m_i_xm,
  	Zrp_,
  	Z_ib,
  	Z_il,
  	Zm_ibo,
  	Zm_ilo,
  	Zib_rr,
  	Zil_rr,
  	Zclr,
  	Zbyte,
  	Zmax,
  
  	Px		= 0,
  	P32		= 0x32,	/* 32-bit only */
  	Pe		= 0x66,	/* operand escape */
  	Pm		= 0x0f,	/* 2byte opcode escape */
  	Pq		= 0xff,	/* both escapes: 66 0f */
  	Pb		= 0xfe,	/* byte operands */
  	Pf2		= 0xf2,	/* xmm escape 1: f2 0f */
  	Pf3		= 0xf3,	/* xmm escape 2: f3 0f */
  	Pq3		= 0x67, /* xmm escape 3: 66 48 0f */
  	Pw		= 0x48,	/* Rex.w */
  	Py		= 0x80,	/* defaults to 64-bit mode */
  
  	Rxf		= 1<<9,	/* internal flag for Rxr on from */
  	Rxt		= 1<<8,	/* internal flag for Rxr on to */
  	Rxw		= 1<<3,	/* =1, 64-bit operand size */
  	Rxr		= 1<<2,	/* extend modrm reg */
  	Rxx		= 1<<1,	/* extend sib index */
  	Rxb		= 1<<0,	/* extend modrm r/m, sib base, or opcode reg */
  
  	Maxand	= 10,		/* in -a output width of the byte codes */
  };
  
  static uchar ycover[Ymax*Ymax];
  static	int	reg[D_NONE];
  static	int	regrex[D_NONE+1];
  static	void	asmins(Link *ctxt, Prog *p);
  
  static uchar	ynone[] =
  {
  	Ynone,	Ynone,	Zlit,	1,
  	0
  };
  static uchar	ytext[] =
  {
  	Ymb,	Yi64,	Zpseudo,1,
  	0
  };
  static uchar	ynop[] =
  {
  	Ynone,	Ynone,	Zpseudo,0,
  	Ynone,	Yiauto,	Zpseudo,0,
  	Ynone,	Yml,	Zpseudo,0,
  	Ynone,	Yrf,	Zpseudo,0,
  	Ynone,	Yxr,	Zpseudo,0,
  	Yiauto,	Ynone,	Zpseudo,0,
  	Yml,	Ynone,	Zpseudo,0,
  	Yrf,	Ynone,	Zpseudo,0,
  	Yxr,	Ynone,	Zpseudo,1,
  	0
  };
  static uchar	yfuncdata[] =
  {
  	Yi32,	Ym,	Zpseudo,	0,
  	0
  };
  static uchar	ypcdata[] = 
  {
  	Yi32,	Yi32,	Zpseudo,	0,
  	0
  };
  static uchar	yxorb[] =
  {
  	Yi32,	Yal,	Zib_,	1,
  	Yi32,	Ymb,	Zibo_m,	2,
  	Yrb,	Ymb,	Zr_m,	1,
  	Ymb,	Yrb,	Zm_r,	1,
  	0
  };
  static uchar	yxorl[] =
  {
  	Yi8,	Yml,	Zibo_m,	2,
  	Yi32,	Yax,	Zil_,	1,
  	Yi32,	Yml,	Zilo_m,	2,
  	Yrl,	Yml,	Zr_m,	1,
  	Yml,	Yrl,	Zm_r,	1,
  	0
  };
  static uchar	yaddl[] =
  {
  	Yi8,	Yml,	Zibo_m,	2,
  	Yi32,	Yax,	Zil_,	1,
  	Yi32,	Yml,	Zilo_m,	2,
  	Yrl,	Yml,	Zr_m,	1,
  	Yml,	Yrl,	Zm_r,	1,
  	0
  };
  static uchar	yincb[] =
  {
  	Ynone,	Ymb,	Zo_m,	2,
  	0
  };
  static uchar	yincw[] =
  {
  	Ynone,	Yml,	Zo_m,	2,
  	0
  };
  static uchar	yincl[] =
  {
  	Ynone,	Yml,	Zo_m,	2,
  	0
  };
  static uchar	ycmpb[] =
  {
  	Yal,	Yi32,	Z_ib,	1,
  	Ymb,	Yi32,	Zm_ibo,	2,
  	Ymb,	Yrb,	Zm_r,	1,
  	Yrb,	Ymb,	Zr_m,	1,
  	0
  };
  static uchar	ycmpl[] =
  {
  	Yml,	Yi8,	Zm_ibo,	2,
  	Yax,	Yi32,	Z_il,	1,
  	Yml,	Yi32,	Zm_ilo,	2,
  	Yml,	Yrl,	Zm_r,	1,
  	Yrl,	Yml,	Zr_m,	1,
  	0
  };
  static uchar	yshb[] =
  {
  	Yi1,	Ymb,	Zo_m,	2,
  	Yi32,	Ymb,	Zibo_m,	2,
  	Ycx,	Ymb,	Zo_m,	2,
  	0
  };
  static uchar	yshl[] =
  {
  	Yi1,	Yml,	Zo_m,	2,
  	Yi32,	Yml,	Zibo_m,	2,
  	Ycl,	Yml,	Zo_m,	2,
  	Ycx,	Yml,	Zo_m,	2,
  	0
  };
  static uchar	ytestb[] =
  {
  	Yi32,	Yal,	Zib_,	1,
  	Yi32,	Ymb,	Zibo_m,	2,
  	Yrb,	Ymb,	Zr_m,	1,
  	Ymb,	Yrb,	Zm_r,	1,
  	0
  };
  static uchar	ytestl[] =
  {
  	Yi32,	Yax,	Zil_,	1,
  	Yi32,	Yml,	Zilo_m,	2,
  	Yrl,	Yml,	Zr_m,	1,
  	Yml,	Yrl,	Zm_r,	1,
  	0
  };
  static uchar	ymovb[] =
  {
  	Yrb,	Ymb,	Zr_m,	1,
  	Ymb,	Yrb,	Zm_r,	1,
  	Yi32,	Yrb,	Zib_rp,	1,
  	Yi32,	Ymb,	Zibo_m,	2,
  	0
  };
  static uchar	ymbs[] =
  {
  	Ymb,	Ynone,	Zm_o,	2,
  	0
  };
  static uchar	ybtl[] =
  {
  	Yi8,	Yml,	Zibo_m,	2,
  	Yrl,	Yml,	Zr_m,	1,
  	0
  };
  static uchar	ymovw[] =
  {
  	Yrl,	Yml,	Zr_m,	1,
  	Yml,	Yrl,	Zm_r,	1,
  	Yi0,	Yrl,	Zclr,	1,
  	Yi32,	Yrl,	Zil_rp,	1,
  	Yi32,	Yml,	Zilo_m,	2,
  	Yiauto,	Yrl,	Zaut_r,	2,
  	0
  };
  static uchar	ymovl[] =
  {
  	Yrl,	Yml,	Zr_m,	1,
  	Yml,	Yrl,	Zm_r,	1,
  	Yi0,	Yrl,	Zclr,	1,
  	Yi32,	Yrl,	Zil_rp,	1,
  	Yi32,	Yml,	Zilo_m,	2,
  	Yml,	Ymr,	Zm_r_xm,	1,	// MMX MOVD
  	Ymr,	Yml,	Zr_m_xm,	1,	// MMX MOVD
  	Yml,	Yxr,	Zm_r_xm,	2,	// XMM MOVD (32 bit)
  	Yxr,	Yml,	Zr_m_xm,	2,	// XMM MOVD (32 bit)
  	Yiauto,	Yrl,	Zaut_r,	2,
  	0
  };
  static uchar	yret[] =
  {
  	Ynone,	Ynone,	Zo_iw,	1,
  	Yi32,	Ynone,	Zo_iw,	1,
  	0
  };
  static uchar	ymovq[] =
  {
  	Yrl,	Yml,	Zr_m,	1,	// 0x89
  	Yml,	Yrl,	Zm_r,	1,	// 0x8b
  	Yi0,	Yrl,	Zclr,	1,	// 0x31
  	Ys32,	Yrl,	Zilo_m,	2,	// 32 bit signed 0xc7,(0)
  	Yi64,	Yrl,	Ziq_rp,	1,	// 0xb8 -- 32/64 bit immediate
  	Yi32,	Yml,	Zilo_m,	2,	// 0xc7,(0)
  	Ym,	Ymr,	Zm_r_xm_nr,	1,	// MMX MOVQ (shorter encoding)
  	Ymr,	Ym,	Zr_m_xm_nr,	1,	// MMX MOVQ
  	Ymm,	Ymr,	Zm_r_xm,	1,	// MMX MOVD
  	Ymr,	Ymm,	Zr_m_xm,	1,	// MMX MOVD
  	Yxr,	Ymr,	Zm_r_xm_nr,	2,	// MOVDQ2Q
  	Yxm,	Yxr,	Zm_r_xm_nr,	2, // MOVQ xmm1/m64 -> xmm2
  	Yxr,	Yxm,	Zr_m_xm_nr,	2, // MOVQ xmm1 -> xmm2/m64
  	Yml,	Yxr,	Zm_r_xm,	2,	// MOVD xmm load
  	Yxr,	Yml,	Zr_m_xm,	2,	// MOVD xmm store
  	Yiauto,	Yrl,	Zaut_r,	2,	// built-in LEAQ
  	0
  };
  static uchar	ym_rl[] =
  {
  	Ym,	Yrl,	Zm_r,	1,
  	0
  };
  static uchar	yrl_m[] =
  {
  	Yrl,	Ym,	Zr_m,	1,
  	0
  };
  static uchar	ymb_rl[] =
  {
  	Ymb,	Yrl,	Zmb_r,	1,
  	0
  };
  static uchar	yml_rl[] =
  {
  	Yml,	Yrl,	Zm_r,	1,
  	0
  };
  static uchar	yrl_ml[] =
  {
  	Yrl,	Yml,	Zr_m,	1,
  	0
  };
  static uchar	yml_mb[] =
  {
  	Yrb,	Ymb,	Zr_m,	1,
  	Ymb,	Yrb,	Zm_r,	1,
  	0
  };
  static uchar	yrb_mb[] =
  {
  	Yrb,	Ymb,	Zr_m,	1,
  	0
  };
  static uchar	yxchg[] =
  {
  	Yax,	Yrl,	Z_rp,	1,
  	Yrl,	Yax,	Zrp_,	1,
  	Yrl,	Yml,	Zr_m,	1,
  	Yml,	Yrl,	Zm_r,	1,
  	0
  };
  static uchar	ydivl[] =
  {
  	Yml,	Ynone,	Zm_o,	2,
  	0
  };
  static uchar	ydivb[] =
  {
  	Ymb,	Ynone,	Zm_o,	2,
  	0
  };
  static uchar	yimul[] =
  {
  	Yml,	Ynone,	Zm_o,	2,
  	Yi8,	Yrl,	Zib_rr,	1,
  	Yi32,	Yrl,	Zil_rr,	1,
  	Yml,	Yrl,	Zm_r,	2,
  	0
  };
  static uchar	yimul3[] =
  {
  	Yml,	Yrl,	Zibm_r,	2,
  	0
  };
  static uchar	ybyte[] =
  {
  	Yi64,	Ynone,	Zbyte,	1,
  	0
  };
  static uchar	yin[] =
  {
  	Yi32,	Ynone,	Zib_,	1,
  	Ynone,	Ynone,	Zlit,	1,
  	0
  };
  static uchar	yint[] =
  {
  	Yi32,	Ynone,	Zib_,	1,
  	0
  };
  static uchar	ypushl[] =
  {
  	Yrl,	Ynone,	Zrp_,	1,
  	Ym,	Ynone,	Zm_o,	2,
  	Yi8,	Ynone,	Zib_,	1,
  	Yi32,	Ynone,	Zil_,	1,
  	0
  };
  static uchar	ypopl[] =
  {
  	Ynone,	Yrl,	Z_rp,	1,
  	Ynone,	Ym,	Zo_m,	2,
  	0
  };
  static uchar	ybswap[] =
  {
  	Ynone,	Yrl,	Z_rp,	2,
  	0,
  };
  static uchar	yscond[] =
  {
  	Ynone,	Ymb,	Zo_m,	2,
  	0
  };
  static uchar	yjcond[] =
  {
  	Ynone,	Ybr,	Zbr,	0,
  	Yi0,	Ybr,	Zbr,	0,
  	Yi1,	Ybr,	Zbr,	1,
  	0
  };
  static uchar	yloop[] =
  {
  	Ynone,	Ybr,	Zloop,	1,
  	0
  };
  static uchar	ycall[] =
  {
  	Ynone,	Yml,	Zcallindreg,	0,
  	Yrx,	Yrx,	Zcallindreg,	2,
  	Ynone,	Ybr,	Zcall,	1,
  	0
  };
  static uchar	yduff[] =
  {
  	Ynone,	Yi32,	Zcall,	1,
  	0
  };
  static uchar	yjmp[] =
  {
  	Ynone,	Yml,	Zo_m64,	2,
  	Ynone,	Ybr,	Zjmp,	1,
  	0
  };
  
  static uchar	yfmvd[] =
  {
  	Ym,	Yf0,	Zm_o,	2,
  	Yf0,	Ym,	Zo_m,	2,
  	Yrf,	Yf0,	Zm_o,	2,
  	Yf0,	Yrf,	Zo_m,	2,
  	0
  };
  static uchar	yfmvdp[] =
  {
  	Yf0,	Ym,	Zo_m,	2,
  	Yf0,	Yrf,	Zo_m,	2,
  	0
  };
  static uchar	yfmvf[] =
  {
  	Ym,	Yf0,	Zm_o,	2,
  	Yf0,	Ym,	Zo_m,	2,
  	0
  };
  static uchar	yfmvx[] =
  {
  	Ym,	Yf0,	Zm_o,	2,
  	0
  };
  static uchar	yfmvp[] =
  {
  	Yf0,	Ym,	Zo_m,	2,
  	0
  };
  static uchar	yfadd[] =
  {
  	Ym,	Yf0,	Zm_o,	2,
  	Yrf,	Yf0,	Zm_o,	2,
  	Yf0,	Yrf,	Zo_m,	2,
  	0
  };
  static uchar	yfaddp[] =
  {
  	Yf0,	Yrf,	Zo_m,	2,
  	0
  };
  static uchar	yfxch[] =
  {
  	Yf0,	Yrf,	Zo_m,	2,
  	Yrf,	Yf0,	Zm_o,	2,
  	0
  };
  static uchar	ycompp[] =
  {
  	Yf0,	Yrf,	Zo_m,	2,	/* botch is really f0,f1 */
  	0
  };
  static uchar	ystsw[] =
  {
  	Ynone,	Ym,	Zo_m,	2,
  	Ynone,	Yax,	Zlit,	1,
  	0
  };
  static uchar	ystcw[] =
  {
  	Ynone,	Ym,	Zo_m,	2,
  	Ym,	Ynone,	Zm_o,	2,
  	0
  };
  static uchar	ysvrs[] =
  {
  	Ynone,	Ym,	Zo_m,	2,
  	Ym,	Ynone,	Zm_o,	2,
  	0
  };
  static uchar	ymm[] = 
  {
  	Ymm,	Ymr,	Zm_r_xm,	1,
  	Yxm,	Yxr,	Zm_r_xm,	2,
  	0
  };
  static uchar	yxm[] = 
  {
  	Yxm,	Yxr,	Zm_r_xm,	1,
  	0
  };
  static uchar	yxcvm1[] = 
  {
  	Yxm,	Yxr,	Zm_r_xm,	2,
  	Yxm,	Ymr,	Zm_r_xm,	2,
  	0
  };
  static uchar	yxcvm2[] =
  {
  	Yxm,	Yxr,	Zm_r_xm,	2,
  	Ymm,	Yxr,	Zm_r_xm,	2,
  	0
  };
  /*
  static uchar	yxmq[] = 
  {
  	Yxm,	Yxr,	Zm_r_xm,	2,
  	0
  };
  */
  static uchar	yxr[] = 
  {
  	Yxr,	Yxr,	Zm_r_xm,	1,
  	0
  };
  static uchar	yxr_ml[] =
  {
  	Yxr,	Yml,	Zr_m_xm,	1,
  	0
  };
  static uchar	ymr[] =
  {
  	Ymr,	Ymr,	Zm_r,	1,
  	0
  };
  static uchar	ymr_ml[] =
  {
  	Ymr,	Yml,	Zr_m_xm,	1,
  	0
  };
  static uchar	yxcmp[] =
  {
  	Yxm,	Yxr, Zm_r_xm,	1,
  	0
  };
  static uchar	yxcmpi[] =
  {
  	Yxm,	Yxr, Zm_r_i_xm,	2,
  	0
  };
  static uchar	yxmov[] =
  {
  	Yxm,	Yxr,	Zm_r_xm,	1,
  	Yxr,	Yxm,	Zr_m_xm,	1,
  	0
  };
  static uchar	yxcvfl[] = 
  {
  	Yxm,	Yrl,	Zm_r_xm,	1,
  	0
  };
  static uchar	yxcvlf[] =
  {
  	Yml,	Yxr,	Zm_r_xm,	1,
  	0
  };
  static uchar	yxcvfq[] = 
  {
  	Yxm,	Yrl,	Zm_r_xm,	2,
  	0
  };
  static uchar	yxcvqf[] =
  {
  	Yml,	Yxr,	Zm_r_xm,	2,
  	0
  };
  static uchar	yps[] = 
  {
  	Ymm,	Ymr,	Zm_r_xm,	1,
  	Yi8,	Ymr,	Zibo_m_xm,	2,
  	Yxm,	Yxr,	Zm_r_xm,	2,
  	Yi8,	Yxr,	Zibo_m_xm,	3,
  	0
  };
  static uchar	yxrrl[] =
  {
  	Yxr,	Yrl,	Zm_r,	1,
  	0
  };
  static uchar	ymfp[] =
  {
  	Ymm,	Ymr,	Zm_r_3d,	1,
  	0,
  };
  static uchar	ymrxr[] =
  {
  	Ymr,	Yxr,	Zm_r,	1,
  	Yxm,	Yxr,	Zm_r_xm,	1,
  	0
  };
  static uchar	ymshuf[] =
  {
  	Ymm,	Ymr,	Zibm_r,	2,
  	0
  };
  static uchar	ymshufb[] =
  {
  	Yxm,	Yxr,	Zm2_r,	2,
  	0
  };
  static uchar	yxshuf[] =
  {
  	Yxm,	Yxr,	Zibm_r,	2,
  	0
  };
  static uchar	yextrw[] =
  {
  	Yxr,	Yrl,	Zibm_r,	2,
  	0
  };
  static uchar	yinsrw[] =
  {
  	Yml,	Yxr,	Zibm_r,	2,
  	0
  };
  static uchar	yinsr[] =
  {
  	Ymm,	Yxr,	Zibm_r,	3,
  	0
  };
  static uchar	ypsdq[] =
  {
  	Yi8,	Yxr,	Zibo_m,	2,
  	0
  };
  static uchar	ymskb[] =
  {
  	Yxr,	Yrl,	Zm_r_xm,	2,
  	Ymr,	Yrl,	Zm_r_xm,	1,
  	0
  };
  static uchar	ycrc32l[] =
  {
  	Yml,	Yrl,	Zlitm_r,	0,
  };
  static uchar	yprefetch[] =
  {
  	Ym,	Ynone,	Zm_o,	2,
  	0,
  };
  static uchar	yaes[] =
  {
  	Yxm,	Yxr,	Zlitm_r,	2,
  	0
  };
  static uchar	yaes2[] =
  {
  	Yxm,	Yxr,	Zibm_r,	2,
  	0
  };
  
  /*
   * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
   * and p->from and p->to as operands (Addr*).  The linker scans optab to find
   * the entry with the given p->as and then looks through the ytable for that
   * instruction (the second field in the optab struct) for a line whose first
   * two values match the Ytypes of the p->from and p->to operands.  The function
   * oclass in span.c computes the specific Ytype of an operand and then the set
   * of more general Ytypes that it satisfies is implied by the ycover table, set
   * up in instinit.  For example, oclass distinguishes the constants 0 and 1
   * from the more general 8-bit constants, but instinit says
   *
   *        ycover[Yi0*Ymax + Ys32] = 1;
   *        ycover[Yi1*Ymax + Ys32] = 1;
   *        ycover[Yi8*Ymax + Ys32] = 1;
   *
   * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
   * if that's what an instruction can handle.
   *
   * In parallel with the scan through the ytable for the appropriate line, there
   * is a z pointer that starts out pointing at the strange magic byte list in
   * the Optab struct.  With each step past a non-matching ytable line, z
   * advances by the 4th entry in the line.  When a matching line is found, that
   * z pointer has the extra data to use in laying down the instruction bytes.
   * The actual bytes laid down are a function of the 3rd entry in the line (that
   * is, the Ztype) and the z bytes.
   *
   * For example, let's look at AADDL.  The optab line says:
   *        { AADDL,        yaddl,  Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
   *
   * and yaddl says
   *        uchar   yaddl[] =
   *        {
   *                Yi8,    Yml,    Zibo_m, 2,
   *                Yi32,   Yax,    Zil_,   1,
   *                Yi32,   Yml,    Zilo_m, 2,
   *                Yrl,    Yml,    Zr_m,   1,
   *                Yml,    Yrl,    Zm_r,   1,
   *                0
   *        };
   *
   * so there are 5 possible types of ADDL instruction that can be laid down, and
   * possible states used to lay them down (Ztype and z pointer, assuming z
   * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
   *
   *        Yi8, Yml -> Zibo_m, z (0x83, 00)
   *        Yi32, Yax -> Zil_, z+2 (0x05)
   *        Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
   *        Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
   *        Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
   *
   * The Pconstant in the optab line controls the prefix bytes to emit.  That's
   * relatively straightforward as this program goes.
   *
   * The switch on t[2] in doasm implements the various Z cases.  Zibo_m, for
   * example, is an opcode byte (z[0]) then an asmando (which is some kind of
   * encoded addressing mode for the Yml arg), and then a single immediate byte.
   * Zilo_m is the same but a long (32-bit) immediate.
   */
  static Optab optab[] =
  /*	as, ytab, andproto, opcode */
  {
  	{ AXXX },
  	{ AAAA,		ynone,	P32, {0x37} },
  	{ AAAD,		ynone,	P32, {0xd5,0x0a} },
  	{ AAAM,		ynone,	P32, {0xd4,0x0a} },
  	{ AAAS,		ynone,	P32, {0x3f} },
  	{ AADCB,	yxorb,	Pb, {0x14,0x80,(02),0x10,0x10} },
  	{ AADCL,	yxorl,	Px, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
  	{ AADCQ,	yxorl,	Pw, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
  	{ AADCW,	yxorl,	Pe, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
  	{ AADDB,	yxorb,	Pb, {0x04,0x80,(00),0x00,0x02} },
  	{ AADDL,	yaddl,	Px, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
  	{ AADDPD,	yxm,	Pq, {0x58} },
  	{ AADDPS,	yxm,	Pm, {0x58} },
  	{ AADDQ,	yaddl,	Pw, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
  	{ AADDSD,	yxm,	Pf2, {0x58} },
  	{ AADDSS,	yxm,	Pf3, {0x58} },
  	{ AADDW,	yaddl,	Pe, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
  	{ AADJSP },
  	{ AANDB,	yxorb,	Pb, {0x24,0x80,(04),0x20,0x22} },
  	{ AANDL,	yxorl,	Px, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
  	{ AANDNPD,	yxm,	Pq, {0x55} },
  	{ AANDNPS,	yxm,	Pm, {0x55} },
  	{ AANDPD,	yxm,	Pq, {0x54} },
  	{ AANDPS,	yxm,	Pq, {0x54} },
  	{ AANDQ,	yxorl,	Pw, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
  	{ AANDW,	yxorl,	Pe, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
  	{ AARPL,	yrl_ml,	P32, {0x63} },
  	{ ABOUNDL,	yrl_m,	P32, {0x62} },
  	{ ABOUNDW,	yrl_m,	Pe, {0x62} },
  	{ ABSFL,	yml_rl,	Pm, {0xbc} },
  	{ ABSFQ,	yml_rl,	Pw, {0x0f,0xbc} },
  	{ ABSFW,	yml_rl,	Pq, {0xbc} },
  	{ ABSRL,	yml_rl,	Pm, {0xbd} },
  	{ ABSRQ,	yml_rl,	Pw, {0x0f,0xbd} },
  	{ ABSRW,	yml_rl,	Pq, {0xbd} },
  	{ ABSWAPL,	ybswap,	Px, {0x0f,0xc8} },
  	{ ABSWAPQ,	ybswap,	Pw, {0x0f,0xc8} },
  	{ ABTCL,	ybtl,	Pm, {0xba,(07),0xbb} },
  	{ ABTCQ,	ybtl,	Pw, {0x0f,0xba,(07),0x0f,0xbb} },
  	{ ABTCW,	ybtl,	Pq, {0xba,(07),0xbb} },
  	{ ABTL,		ybtl,	Pm, {0xba,(04),0xa3} },
  	{ ABTQ,		ybtl,	Pw, {0x0f,0xba,(04),0x0f,0xa3}},
  	{ ABTRL,	ybtl,	Pm, {0xba,(06),0xb3} },
  	{ ABTRQ,	ybtl,	Pw, {0x0f,0xba,(06),0x0f,0xb3} },
  	{ ABTRW,	ybtl,	Pq, {0xba,(06),0xb3} },
  	{ ABTSL,	ybtl,	Pm, {0xba,(05),0xab } },
  	{ ABTSQ,	ybtl,	Pw, {0x0f,0xba,(05),0x0f,0xab} },
  	{ ABTSW,	ybtl,	Pq, {0xba,(05),0xab } },
  	{ ABTW,		ybtl,	Pq, {0xba,(04),0xa3} },
  	{ ABYTE,	ybyte,	Px, {1} },
  	{ ACALL,	ycall,	Px, {0xff,(02),0xe8} },
  	{ ACDQ,		ynone,	Px, {0x99} },
  	{ ACLC,		ynone,	Px, {0xf8} },
  	{ ACLD,		ynone,	Px, {0xfc} },
  	{ ACLI,		ynone,	Px, {0xfa} },
  	{ ACLTS,	ynone,	Pm, {0x06} },
  	{ ACMC,		ynone,	Px, {0xf5} },
  	{ ACMOVLCC,	yml_rl,	Pm, {0x43} },
  	{ ACMOVLCS,	yml_rl,	Pm, {0x42} },
  	{ ACMOVLEQ,	yml_rl,	Pm, {0x44} },
  	{ ACMOVLGE,	yml_rl,	Pm, {0x4d} },
  	{ ACMOVLGT,	yml_rl,	Pm, {0x4f} },
  	{ ACMOVLHI,	yml_rl,	Pm, {0x47} },
  	{ ACMOVLLE,	yml_rl,	Pm, {0x4e} },
  	{ ACMOVLLS,	yml_rl,	Pm, {0x46} },
  	{ ACMOVLLT,	yml_rl,	Pm, {0x4c} },
  	{ ACMOVLMI,	yml_rl,	Pm, {0x48} },
  	{ ACMOVLNE,	yml_rl,	Pm, {0x45} },
  	{ ACMOVLOC,	yml_rl,	Pm, {0x41} },
  	{ ACMOVLOS,	yml_rl,	Pm, {0x40} },
  	{ ACMOVLPC,	yml_rl,	Pm, {0x4b} },
  	{ ACMOVLPL,	yml_rl,	Pm, {0x49} },
  	{ ACMOVLPS,	yml_rl,	Pm, {0x4a} },
  	{ ACMOVQCC,	yml_rl,	Pw, {0x0f,0x43} },
  	{ ACMOVQCS,	yml_rl,	Pw, {0x0f,0x42} },
  	{ ACMOVQEQ,	yml_rl,	Pw, {0x0f,0x44} },
  	{ ACMOVQGE,	yml_rl,	Pw, {0x0f,0x4d} },
  	{ ACMOVQGT,	yml_rl,	Pw, {0x0f,0x4f} },
  	{ ACMOVQHI,	yml_rl,	Pw, {0x0f,0x47} },
  	{ ACMOVQLE,	yml_rl,	Pw, {0x0f,0x4e} },
  	{ ACMOVQLS,	yml_rl,	Pw, {0x0f,0x46} },
  	{ ACMOVQLT,	yml_rl,	Pw, {0x0f,0x4c} },
  	{ ACMOVQMI,	yml_rl,	Pw, {0x0f,0x48} },
  	{ ACMOVQNE,	yml_rl,	Pw, {0x0f,0x45} },
  	{ ACMOVQOC,	yml_rl,	Pw, {0x0f,0x41} },
  	{ ACMOVQOS,	yml_rl,	Pw, {0x0f,0x40} },
  	{ ACMOVQPC,	yml_rl,	Pw, {0x0f,0x4b} },
  	{ ACMOVQPL,	yml_rl,	Pw, {0x0f,0x49} },
  	{ ACMOVQPS,	yml_rl,	Pw, {0x0f,0x4a} },
  	{ ACMOVWCC,	yml_rl,	Pq, {0x43} },
  	{ ACMOVWCS,	yml_rl,	Pq, {0x42} },
  	{ ACMOVWEQ,	yml_rl,	Pq, {0x44} },
  	{ ACMOVWGE,	yml_rl,	Pq, {0x4d} },
  	{ ACMOVWGT,	yml_rl,	Pq, {0x4f} },
  	{ ACMOVWHI,	yml_rl,	Pq, {0x47} },
  	{ ACMOVWLE,	yml_rl,	Pq, {0x4e} },
  	{ ACMOVWLS,	yml_rl,	Pq, {0x46} },
  	{ ACMOVWLT,	yml_rl,	Pq, {0x4c} },
  	{ ACMOVWMI,	yml_rl,	Pq, {0x48} },
  	{ ACMOVWNE,	yml_rl,	Pq, {0x45} },
  	{ ACMOVWOC,	yml_rl,	Pq, {0x41} },
  	{ ACMOVWOS,	yml_rl,	Pq, {0x40} },
  	{ ACMOVWPC,	yml_rl,	Pq, {0x4b} },
  	{ ACMOVWPL,	yml_rl,	Pq, {0x49} },
  	{ ACMOVWPS,	yml_rl,	Pq, {0x4a} },
  	{ ACMPB,	ycmpb,	Pb, {0x3c,0x80,(07),0x38,0x3a} },
  	{ ACMPL,	ycmpl,	Px, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
  	{ ACMPPD,	yxcmpi,	Px, {Pe,0xc2} },
  	{ ACMPPS,	yxcmpi,	Pm, {0xc2,0} },
  	{ ACMPQ,	ycmpl,	Pw, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
  	{ ACMPSB,	ynone,	Pb, {0xa6} },
  	{ ACMPSD,	yxcmpi,	Px, {Pf2,0xc2} },
  	{ ACMPSL,	ynone,	Px, {0xa7} },
  	{ ACMPSQ,	ynone,	Pw, {0xa7} },
  	{ ACMPSS,	yxcmpi,	Px, {Pf3,0xc2} },
  	{ ACMPSW,	ynone,	Pe, {0xa7} },
  	{ ACMPW,	ycmpl,	Pe, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
  	{ ACOMISD,	yxcmp,	Pe, {0x2f} },
  	{ ACOMISS,	yxcmp,	Pm, {0x2f} },
  	{ ACPUID,	ynone,	Pm, {0xa2} },
  	{ ACVTPL2PD,	yxcvm2,	Px, {Pf3,0xe6,Pe,0x2a} },
  	{ ACVTPL2PS,	yxcvm2,	Pm, {0x5b,0,0x2a,0,} },
  	{ ACVTPD2PL,	yxcvm1,	Px, {Pf2,0xe6,Pe,0x2d} },
  	{ ACVTPD2PS,	yxm,	Pe, {0x5a} },
  	{ ACVTPS2PL,	yxcvm1, Px, {Pe,0x5b,Pm,0x2d} },
  	{ ACVTPS2PD,	yxm,	Pm, {0x5a} },
  	{ API2FW,	ymfp,	Px, {0x0c} },
  	{ ACVTSD2SL,	yxcvfl, Pf2, {0x2d} },
  	{ ACVTSD2SQ,	yxcvfq, Pw, {Pf2,0x2d} },
  	{ ACVTSD2SS,	yxm,	Pf2, {0x5a} },
  	{ ACVTSL2SD,	yxcvlf, Pf2, {0x2a} },
  	{ ACVTSQ2SD,	yxcvqf, Pw, {Pf2,0x2a} },
  	{ ACVTSL2SS,	yxcvlf, Pf3, {0x2a} },
  	{ ACVTSQ2SS,	yxcvqf, Pw, {Pf3,0x2a} },
  	{ ACVTSS2SD,	yxm,	Pf3, {0x5a} },
  	{ ACVTSS2SL,	yxcvfl, Pf3, {0x2d} },
  	{ ACVTSS2SQ,	yxcvfq, Pw, {Pf3,0x2d} },
  	{ ACVTTPD2PL,	yxcvm1,	Px, {Pe,0xe6,Pe,0x2c} },
  	{ ACVTTPS2PL,	yxcvm1,	Px, {Pf3,0x5b,Pm,0x2c} },
  	{ ACVTTSD2SL,	yxcvfl, Pf2, {0x2c} },
  	{ ACVTTSD2SQ,	yxcvfq, Pw, {Pf2,0x2c} },
  	{ ACVTTSS2SL,	yxcvfl,	Pf3, {0x2c} },
  	{ ACVTTSS2SQ,	yxcvfq, Pw, {Pf3,0x2c} },
  	{ ACWD,		ynone,	Pe, {0x99} },
  	{ ACQO,		ynone,	Pw, {0x99} },
  	{ ADAA,		ynone,	P32, {0x27} },
  	{ ADAS,		ynone,	P32, {0x2f} },
  	{ ADATA },
  	{ ADECB,	yincb,	Pb, {0xfe,(01)} },
  	{ ADECL,	yincl,	Px, {0xff,(01)} },
  	{ ADECQ,	yincl,	Pw, {0xff,(01)} },
  	{ ADECW,	yincw,	Pe, {0xff,(01)} },
  	{ ADIVB,	ydivb,	Pb, {0xf6,(06)} },
  	{ ADIVL,	ydivl,	Px, {0xf7,(06)} },
  	{ ADIVPD,	yxm,	Pe, {0x5e} },
  	{ ADIVPS,	yxm,	Pm, {0x5e} },
  	{ ADIVQ,	ydivl,	Pw, {0xf7,(06)} },
  	{ ADIVSD,	yxm,	Pf2, {0x5e} },
  	{ ADIVSS,	yxm,	Pf3, {0x5e} },
  	{ ADIVW,	ydivl,	Pe, {0xf7,(06)} },
  	{ AEMMS,	ynone,	Pm, {0x77} },
  	{ AENTER },				/* botch */
  	{ AFXRSTOR,	ysvrs,	Pm, {0xae,(01),0xae,(01)} },
  	{ AFXSAVE,	ysvrs,	Pm, {0xae,(00),0xae,(00)} },
  	{ AFXRSTOR64,	ysvrs,	Pw, {0x0f,0xae,(01),0x0f,0xae,(01)} },
  	{ AFXSAVE64,	ysvrs,	Pw, {0x0f,0xae,(00),0x0f,0xae,(00)} },
  	{ AGLOBL },
  	{ AGOK },
  	{ AHISTORY },
  	{ AHLT,		ynone,	Px, {0xf4} },
  	{ AIDIVB,	ydivb,	Pb, {0xf6,(07)} },
  	{ AIDIVL,	ydivl,	Px, {0xf7,(07)} },
  	{ AIDIVQ,	ydivl,	Pw, {0xf7,(07)} },
  	{ AIDIVW,	ydivl,	Pe, {0xf7,(07)} },
  	{ AIMULB,	ydivb,	Pb, {0xf6,(05)} },
  	{ AIMULL,	yimul,	Px, {0xf7,(05),0x6b,0x69,Pm,0xaf} },
  	{ AIMULQ,	yimul,	Pw, {0xf7,(05),0x6b,0x69,Pm,0xaf} },
  	{ AIMULW,	yimul,	Pe, {0xf7,(05),0x6b,0x69,Pm,0xaf} },
  	{ AIMUL3Q,	yimul3,	Pw, {0x6b,(00)} },
  	{ AINB,		yin,	Pb, {0xe4,0xec} },
  	{ AINCB,	yincb,	Pb, {0xfe,(00)} },
  	{ AINCL,	yincl,	Px, {0xff,(00)} },
  	{ AINCQ,	yincl,	Pw, {0xff,(00)} },
  	{ AINCW,	yincw,	Pe, {0xff,(00)} },
  	{ AINL,		yin,	Px, {0xe5,0xed} },
  	{ AINSB,	ynone,	Pb, {0x6c} },
  	{ AINSL,	ynone,	Px, {0x6d} },
  	{ AINSW,	ynone,	Pe, {0x6d} },
  	{ AINT,		yint,	Px, {0xcd} },
  	{ AINTO,	ynone,	P32, {0xce} },
  	{ AINW,		yin,	Pe, {0xe5,0xed} },
  	{ AIRETL,	ynone,	Px, {0xcf} },
  	{ AIRETQ,	ynone,	Pw, {0xcf} },
  	{ AIRETW,	ynone,	Pe, {0xcf} },
  	{ AJCC,		yjcond,	Px, {0x73,0x83,(00)} },
  	{ AJCS,		yjcond,	Px, {0x72,0x82} },
  	{ AJCXZL,	yloop,	Px, {0xe3} },
  	{ AJCXZQ,	yloop,	Px, {0xe3} },
  	{ AJEQ,		yjcond,	Px, {0x74,0x84} },
  	{ AJGE,		yjcond,	Px, {0x7d,0x8d} },
  	{ AJGT,		yjcond,	Px, {0x7f,0x8f} },
  	{ AJHI,		yjcond,	Px, {0x77,0x87} },
  	{ AJLE,		yjcond,	Px, {0x7e,0x8e} },
  	{ AJLS,		yjcond,	Px, {0x76,0x86} },
  	{ AJLT,		yjcond,	Px, {0x7c,0x8c} },
  	{ AJMI,		yjcond,	Px, {0x78,0x88} },
  	{ AJMP,		yjmp,	Px, {0xff,(04),0xeb,0xe9} },
  	{ AJNE,		yjcond,	Px, {0x75,0x85} },
  	{ AJOC,		yjcond,	Px, {0x71,0x81,(00)} },
  	{ AJOS,		yjcond,	Px, {0x70,0x80,(00)} },
  	{ AJPC,		yjcond,	Px, {0x7b,0x8b} },
  	{ AJPL,		yjcond,	Px, {0x79,0x89} },
  	{ AJPS,		yjcond,	Px, {0x7a,0x8a} },
  	{ ALAHF,	ynone,	Px, {0x9f} },
  	{ ALARL,	yml_rl,	Pm, {0x02} },
  	{ ALARW,	yml_rl,	Pq, {0x02} },
  	{ ALDMXCSR,	ysvrs,	Pm, {0xae,(02),0xae,(02)} },
  	{ ALEAL,	ym_rl,	Px, {0x8d} },
  	{ ALEAQ,	ym_rl,	Pw, {0x8d} },
  	{ ALEAVEL,	ynone,	P32, {0xc9} },
  	{ ALEAVEQ,	ynone,	Py, {0xc9} },
  	{ ALEAVEW,	ynone,	Pe, {0xc9} },
  	{ ALEAW,	ym_rl,	Pe, {0x8d} },
  	{ ALOCK,	ynone,	Px, {0xf0} },
  	{ ALODSB,	ynone,	Pb, {0xac} },
  	{ ALODSL,	ynone,	Px, {0xad} },
  	{ ALODSQ,	ynone,	Pw, {0xad} },
  	{ ALODSW,	ynone,	Pe, {0xad} },
  	{ ALONG,	ybyte,	Px, {4} },
  	{ ALOOP,	yloop,	Px, {0xe2} },
  	{ ALOOPEQ,	yloop,	Px, {0xe1} },
  	{ ALOOPNE,	yloop,	Px, {0xe0} },
  	{ ALSLL,	yml_rl,	Pm, {0x03 } },
  	{ ALSLW,	yml_rl,	Pq, {0x03 } },
  	{ AMASKMOVOU,	yxr,	Pe, {0xf7} },
  	{ AMASKMOVQ,	ymr,	Pm, {0xf7} },
  	{ AMAXPD,	yxm,	Pe, {0x5f} },
  	{ AMAXPS,	yxm,	Pm, {0x5f} },
  	{ AMAXSD,	yxm,	Pf2, {0x5f} },
  	{ AMAXSS,	yxm,	Pf3, {0x5f} },
  	{ AMINPD,	yxm,	Pe, {0x5d} },
  	{ AMINPS,	yxm,	Pm, {0x5d} },
  	{ AMINSD,	yxm,	Pf2, {0x5d} },
  	{ AMINSS,	yxm,	Pf3, {0x5d} },
  	{ AMOVAPD,	yxmov,	Pe, {0x28,0x29} },
  	{ AMOVAPS,	yxmov,	Pm, {0x28,0x29} },
  	{ AMOVB,	ymovb,	Pb, {0x88,0x8a,0xb0,0xc6,(00)} },
  	{ AMOVBLSX,	ymb_rl,	Pm, {0xbe} },
  	{ AMOVBLZX,	ymb_rl,	Pm, {0xb6} },
  	{ AMOVBQSX,	ymb_rl,	Pw, {0x0f,0xbe} },
  	{ AMOVBQZX,	ymb_rl,	Pm, {0xb6} },
  	{ AMOVBWSX,	ymb_rl,	Pq, {0xbe} },
  	{ AMOVBWZX,	ymb_rl,	Pq, {0xb6} },
  	{ AMOVO,	yxmov,	Pe, {0x6f,0x7f} },
  	{ AMOVOU,	yxmov,	Pf3, {0x6f,0x7f} },
  	{ AMOVHLPS,	yxr,	Pm, {0x12} },
  	{ AMOVHPD,	yxmov,	Pe, {0x16,0x17} },
  	{ AMOVHPS,	yxmov,	Pm, {0x16,0x17} },
  	{ AMOVL,	ymovl,	Px, {0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0} },
  	{ AMOVLHPS,	yxr,	Pm, {0x16} },
  	{ AMOVLPD,	yxmov,	Pe, {0x12,0x13} },
  	{ AMOVLPS,	yxmov,	Pm, {0x12,0x13} },
  	{ AMOVLQSX,	yml_rl,	Pw, {0x63} },
  	{ AMOVLQZX,	yml_rl,	Px, {0x8b} },
  	{ AMOVMSKPD,	yxrrl,	Pq, {0x50} },
  	{ AMOVMSKPS,	yxrrl,	Pm, {0x50} },
  	{ AMOVNTO,	yxr_ml,	Pe, {0xe7} },
  	{ AMOVNTPD,	yxr_ml,	Pe, {0x2b} },
  	{ AMOVNTPS,	yxr_ml,	Pm, {0x2b} },
  	{ AMOVNTQ,	ymr_ml,	Pm, {0xe7} },
  	{ AMOVQ,	ymovq,	Pw, {0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0} },
  	{ AMOVQOZX,	ymrxr,	Pf3, {0xd6,0x7e} },
  	{ AMOVSB,	ynone,	Pb, {0xa4} },
  	{ AMOVSD,	yxmov,	Pf2, {0x10,0x11} },
  	{ AMOVSL,	ynone,	Px, {0xa5} },
  	{ AMOVSQ,	ynone,	Pw, {0xa5} },
  	{ AMOVSS,	yxmov,	Pf3, {0x10,0x11} },
  	{ AMOVSW,	ynone,	Pe, {0xa5} },
  	{ AMOVUPD,	yxmov,	Pe, {0x10,0x11} },
  	{ AMOVUPS,	yxmov,	Pm, {0x10,0x11} },
  	{ AMOVW,	ymovw,	Pe, {0x89,0x8b,0x31,0xb8,0xc7,(00),0} },
  	{ AMOVWLSX,	yml_rl,	Pm, {0xbf} },
  	{ AMOVWLZX,	yml_rl,	Pm, {0xb7} },
  	{ AMOVWQSX,	yml_rl,	Pw, {0x0f,0xbf} },
  	{ AMOVWQZX,	yml_rl,	Pw, {0x0f,0xb7} },
  	{ AMULB,	ydivb,	Pb, {0xf6,(04)} },
  	{ AMULL,	ydivl,	Px, {0xf7,(04)} },
  	{ AMULPD,	yxm,	Pe, {0x59} },
  	{ AMULPS,	yxm,	Ym, {0x59} },
  	{ AMULQ,	ydivl,	Pw, {0xf7,(04)} },
  	{ AMULSD,	yxm,	Pf2, {0x59} },
  	{ AMULSS,	yxm,	Pf3, {0x59} },
  	{ AMULW,	ydivl,	Pe, {0xf7,(04)} },
  	{ ANAME },
  	{ ANEGB,	yscond,	Pb, {0xf6,(03)} },
  	{ ANEGL,	yscond,	Px, {0xf7,(03)} },
  	{ ANEGQ,	yscond,	Pw, {0xf7,(03)} },
  	{ ANEGW,	yscond,	Pe, {0xf7,(03)} },
  	{ ANOP,		ynop,	Px, {0,0} },
  	{ ANOTB,	yscond,	Pb, {0xf6,(02)} },
  	{ ANOTL,	yscond,	Px, {0xf7,(02)} },
  	{ ANOTQ,	yscond,	Pw, {0xf7,(02)} },
  	{ ANOTW,	yscond,	Pe, {0xf7,(02)} },
  	{ AORB,		yxorb,	Pb, {0x0c,0x80,(01),0x08,0x0a} },
  	{ AORL,		yxorl,	Px, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
  	{ AORPD,	yxm,	Pq, {0x56} },
  	{ AORPS,	yxm,	Pm, {0x56} },
  	{ AORQ,		yxorl,	Pw, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
  	{ AORW,		yxorl,	Pe, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
  	{ AOUTB,	yin,	Pb, {0xe6,0xee} },
  	{ AOUTL,	yin,	Px, {0xe7,0xef} },
  	{ AOUTSB,	ynone,	Pb, {0x6e} },
  	{ AOUTSL,	ynone,	Px, {0x6f} },
  	{ AOUTSW,	ynone,	Pe, {0x6f} },
  	{ AOUTW,	yin,	Pe, {0xe7,0xef} },
  	{ APACKSSLW,	ymm,	Py, {0x6b,Pe,0x6b} },
  	{ APACKSSWB,	ymm,	Py, {0x63,Pe,0x63} },
  	{ APACKUSWB,	ymm,	Py, {0x67,Pe,0x67} },
  	{ APADDB,	ymm,	Py, {0xfc,Pe,0xfc} },
  	{ APADDL,	ymm,	Py, {0xfe,Pe,0xfe} },
  	{ APADDQ,	yxm,	Pe, {0xd4} },
  	{ APADDSB,	ymm,	Py, {0xec,Pe,0xec} },
  	{ APADDSW,	ymm,	Py, {0xed,Pe,0xed} },
  	{ APADDUSB,	ymm,	Py, {0xdc,Pe,0xdc} },
  	{ APADDUSW,	ymm,	Py, {0xdd,Pe,0xdd} },
  	{ APADDW,	ymm,	Py, {0xfd,Pe,0xfd} },
  	{ APAND,	ymm,	Py, {0xdb,Pe,0xdb} },
  	{ APANDN,	ymm,	Py, {0xdf,Pe,0xdf} },
  	{ APAUSE,	ynone,	Px, {0xf3,0x90} },
  	{ APAVGB,	ymm,	Py, {0xe0,Pe,0xe0} },
  	{ APAVGW,	ymm,	Py, {0xe3,Pe,0xe3} },
  	{ APCMPEQB,	ymm,	Py, {0x74,Pe,0x74} },
  	{ APCMPEQL,	ymm,	Py, {0x76,Pe,0x76} },
  	{ APCMPEQW,	ymm,	Py, {0x75,Pe,0x75} },
  	{ APCMPGTB,	ymm,	Py, {0x64,Pe,0x64} },
  	{ APCMPGTL,	ymm,	Py, {0x66,Pe,0x66} },
  	{ APCMPGTW,	ymm,	Py, {0x65,Pe,0x65} },
  	{ APEXTRW,	yextrw,	Pq, {0xc5,(00)} },
  	{ APF2IL,	ymfp,	Px, {0x1d} },
  	{ APF2IW,	ymfp,	Px, {0x1c} },
  	{ API2FL,	ymfp,	Px, {0x0d} },
  	{ APFACC,	ymfp,	Px, {0xae} },
  	{ APFADD,	ymfp,	Px, {0x9e} },
  	{ APFCMPEQ,	ymfp,	Px, {0xb0} },
  	{ APFCMPGE,	ymfp,	Px, {0x90} },
  	{ APFCMPGT,	ymfp,	Px, {0xa0} },
  	{ APFMAX,	ymfp,	Px, {0xa4} },
  	{ APFMIN,	ymfp,	Px, {0x94} },
  	{ APFMUL,	ymfp,	Px, {0xb4} },
  	{ APFNACC,	ymfp,	Px, {0x8a} },
  	{ APFPNACC,	ymfp,	Px, {0x8e} },
  	{ APFRCP,	ymfp,	Px, {0x96} },
  	{ APFRCPIT1,	ymfp,	Px, {0xa6} },
  	{ APFRCPI2T,	ymfp,	Px, {0xb6} },
  	{ APFRSQIT1,	ymfp,	Px, {0xa7} },
  	{ APFRSQRT,	ymfp,	Px, {0x97} },
  	{ APFSUB,	ymfp,	Px, {0x9a} },
  	{ APFSUBR,	ymfp,	Px, {0xaa} },
  	{ APINSRW,	yinsrw,	Pq, {0xc4,(00)} },
  	{ APINSRD,	yinsr,	Pq, {0x3a, 0x22, (00)} },
  	{ APINSRQ,	yinsr,	Pq3, {0x3a, 0x22, (00)} },
  	{ APMADDWL,	ymm,	Py, {0xf5,Pe,0xf5} },
  	{ APMAXSW,	yxm,	Pe, {0xee} },
  	{ APMAXUB,	yxm,	Pe, {0xde} },
  	{ APMINSW,	yxm,	Pe, {0xea} },
  	{ APMINUB,	yxm,	Pe, {0xda} },
  	{ APMOVMSKB,	ymskb,	Px, {Pe,0xd7,0xd7} },
  	{ APMULHRW,	ymfp,	Px, {0xb7} },
  	{ APMULHUW,	ymm,	Py, {0xe4,Pe,0xe4} },
  	{ APMULHW,	ymm,	Py, {0xe5,Pe,0xe5} },
  	{ APMULLW,	ymm,	Py, {0xd5,Pe,0xd5} },
  	{ APMULULQ,	ymm,	Py, {0xf4,Pe,0xf4} },
  	{ APOPAL,	ynone,	P32, {0x61} },
  	{ APOPAW,	ynone,	Pe, {0x61} },
  	{ APOPFL,	ynone,	P32, {0x9d} },
  	{ APOPFQ,	ynone,	Py, {0x9d} },
  	{ APOPFW,	ynone,	Pe, {0x9d} },
  	{ APOPL,	ypopl,	P32, {0x58,0x8f,(00)} },
  	{ APOPQ,	ypopl,	Py, {0x58,0x8f,(00)} },
  	{ APOPW,	ypopl,	Pe, {0x58,0x8f,(00)} },
  	{ APOR,		ymm,	Py, {0xeb,Pe,0xeb} },
  	{ APSADBW,	yxm,	Pq, {0xf6} },
  	{ APSHUFHW,	yxshuf,	Pf3, {0x70,(00)} },
  	{ APSHUFL,	yxshuf,	Pq, {0x70,(00)} },
  	{ APSHUFLW,	yxshuf,	Pf2, {0x70,(00)} },
  	{ APSHUFW,	ymshuf,	Pm, {0x70,(00)} },
  	{ APSHUFB,	ymshufb,Pq, {0x38, 0x00} },
  	{ APSLLO,	ypsdq,	Pq, {0x73,(07)} },
  	{ APSLLL,	yps,	Py, {0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06)} },
  	{ APSLLQ,	yps,	Py, {0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06)} },
  	{ APSLLW,	yps,	Py, {0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06)} },
  	{ APSRAL,	yps,	Py, {0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04)} },
  	{ APSRAW,	yps,	Py, {0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04)} },
  	{ APSRLO,	ypsdq,	Pq, {0x73,(03)} },
  	{ APSRLL,	yps,	Py, {0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02)} },
  	{ APSRLQ,	yps,	Py, {0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02)} },
  	{ APSRLW,	yps,	Py, {0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02)} },
  	{ APSUBB,	yxm,	Pe, {0xf8} },
  	{ APSUBL,	yxm,	Pe, {0xfa} },
  	{ APSUBQ,	yxm,	Pe, {0xfb} },
  	{ APSUBSB,	yxm,	Pe, {0xe8} },
  	{ APSUBSW,	yxm,	Pe, {0xe9} },
  	{ APSUBUSB,	yxm,	Pe, {0xd8} },
  	{ APSUBUSW,	yxm,	Pe, {0xd9} },
  	{ APSUBW,	yxm,	Pe, {0xf9} },
  	{ APSWAPL,	ymfp,	Px, {0xbb} },
  	{ APUNPCKHBW,	ymm,	Py, {0x68,Pe,0x68} },
  	{ APUNPCKHLQ,	ymm,	Py, {0x6a,Pe,0x6a} },
  	{ APUNPCKHQDQ,	yxm,	Pe, {0x6d} },
  	{ APUNPCKHWL,	ymm,	Py, {0x69,Pe,0x69} },
  	{ APUNPCKLBW,	ymm,	Py, {0x60,Pe,0x60} },
  	{ APUNPCKLLQ,	ymm,	Py, {0x62,Pe,0x62} },
  	{ APUNPCKLQDQ,	yxm,	Pe, {0x6c} },
  	{ APUNPCKLWL,	ymm,	Py, {0x61,Pe,0x61} },
  	{ APUSHAL,	ynone,	P32, {0x60} },
  	{ APUSHAW,	ynone,	Pe, {0x60} },
  	{ APUSHFL,	ynone,	P32, {0x9c} },
  	{ APUSHFQ,	ynone,	Py, {0x9c} },
  	{ APUSHFW,	ynone,	Pe, {0x9c} },
  	{ APUSHL,	ypushl,	P32, {0x50,0xff,(06),0x6a,0x68} },
  	{ APUSHQ,	ypushl,	Py, {0x50,0xff,(06),0x6a,0x68} },
  	{ APUSHW,	ypushl,	Pe, {0x50,0xff,(06),0x6a,0x68} },
  	{ APXOR,	ymm,	Py, {0xef,Pe,0xef} },
  	{ AQUAD,	ybyte,	Px, {8} },
  	{ ARCLB,	yshb,	Pb, {0xd0,(02),0xc0,(02),0xd2,(02)} },
  	{ ARCLL,	yshl,	Px, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
  	{ ARCLQ,	yshl,	Pw, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
  	{ ARCLW,	yshl,	Pe, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
  	{ ARCPPS,	yxm,	Pm, {0x53} },
  	{ ARCPSS,	yxm,	Pf3, {0x53} },
  	{ ARCRB,	yshb,	Pb, {0xd0,(03),0xc0,(03),0xd2,(03)} },
  	{ ARCRL,	yshl,	Px, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
  	{ ARCRQ,	yshl,	Pw, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
  	{ ARCRW,	yshl,	Pe, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
  	{ AREP,		ynone,	Px, {0xf3} },
  	{ AREPN,	ynone,	Px, {0xf2} },
  	{ ARET,		ynone,	Px, {0xc3} },
  	{ ARETFW,	yret,	Pe, {0xcb,0xca} },
  	{ ARETFL,	yret,	Px, {0xcb,0xca} },
  	{ ARETFQ,	yret,	Pw, {0xcb,0xca} },
  	{ AROLB,	yshb,	Pb, {0xd0,(00),0xc0,(00),0xd2,(00)} },
  	{ AROLL,	yshl,	Px, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
  	{ AROLQ,	yshl,	Pw, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
  	{ AROLW,	yshl,	Pe, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
  	{ ARORB,	yshb,	Pb, {0xd0,(01),0xc0,(01),0xd2,(01)} },
  	{ ARORL,	yshl,	Px, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
  	{ ARORQ,	yshl,	Pw, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
  	{ ARORW,	yshl,	Pe, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
  	{ ARSQRTPS,	yxm,	Pm, {0x52} },
  	{ ARSQRTSS,	yxm,	Pf3, {0x52} },
  	{ ASAHF,	ynone,	Px, {0x86,0xe0,0x50,0x9d} },	/* XCHGB AH,AL; PUSH AX; POPFL */
  	{ ASALB,	yshb,	Pb, {0xd0,(04),0xc0,(04),0xd2,(04)} },
  	{ ASALL,	yshl,	Px, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
  	{ ASALQ,	yshl,	Pw, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
  	{ ASALW,	yshl,	Pe, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
  	{ ASARB,	yshb,	Pb, {0xd0,(07),0xc0,(07),0xd2,(07)} },
  	{ ASARL,	yshl,	Px, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
  	{ ASARQ,	yshl,	Pw, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
  	{ ASARW,	yshl,	Pe, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
  	{ ASBBB,	yxorb,	Pb, {0x1c,0x80,(03),0x18,0x1a} },
  	{ ASBBL,	yxorl,	Px, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
  	{ ASBBQ,	yxorl,	Pw, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
  	{ ASBBW,	yxorl,	Pe, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
  	{ ASCASB,	ynone,	Pb, {0xae} },
  	{ ASCASL,	ynone,	Px, {0xaf} },
  	{ ASCASQ,	ynone,	Pw, {0xaf} },
  	{ ASCASW,	ynone,	Pe, {0xaf} },
  	{ ASETCC,	yscond,	Pm, {0x93,(00)} },
  	{ ASETCS,	yscond,	Pm, {0x92,(00)} },
  	{ ASETEQ,	yscond,	Pm, {0x94,(00)} },
  	{ ASETGE,	yscond,	Pm, {0x9d,(00)} },
  	{ ASETGT,	yscond,	Pm, {0x9f,(00)} },
  	{ ASETHI,	yscond,	Pm, {0x97,(00)} },
  	{ ASETLE,	yscond,	Pm, {0x9e,(00)} },
  	{ ASETLS,	yscond,	Pm, {0x96,(00)} },
  	{ ASETLT,	yscond,	Pm, {0x9c,(00)} },
  	{ ASETMI,	yscond,	Pm, {0x98,(00)} },
  	{ ASETNE,	yscond,	Pm, {0x95,(00)} },
  	{ ASETOC,	yscond,	Pm, {0x91,(00)} },
  	{ ASETOS,	yscond,	Pm, {0x90,(00)} },
  	{ ASETPC,	yscond,	Pm, {0x9b,(00)} },
  	{ ASETPL,	yscond,	Pm, {0x99,(00)} },
  	{ ASETPS,	yscond,	Pm, {0x9a,(00)} },
  	{ ASHLB,	yshb,	Pb, {0xd0,(04),0xc0,(04),0xd2,(04)} },
  	{ ASHLL,	yshl,	Px, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
  	{ ASHLQ,	yshl,	Pw, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
  	{ ASHLW,	yshl,	Pe, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
  	{ ASHRB,	yshb,	Pb, {0xd0,(05),0xc0,(05),0xd2,(05)} },
  	{ ASHRL,	yshl,	Px, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
  	{ ASHRQ,	yshl,	Pw, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
  	{ ASHRW,	yshl,	Pe, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
  	{ ASHUFPD,	yxshuf,	Pq, {0xc6,(00)} },
  	{ ASHUFPS,	yxshuf,	Pm, {0xc6,(00)} },
  	{ ASQRTPD,	yxm,	Pe, {0x51} },
  	{ ASQRTPS,	yxm,	Pm, {0x51} },
  	{ ASQRTSD,	yxm,	Pf2, {0x51} },
  	{ ASQRTSS,	yxm,	Pf3, {0x51} },
  	{ ASTC,		ynone,	Px, {0xf9} },
  	{ ASTD,		ynone,	Px, {0xfd} },
  	{ ASTI,		ynone,	Px, {0xfb} },
  	{ ASTMXCSR,	ysvrs,	Pm, {0xae,(03),0xae,(03)} },
  	{ ASTOSB,	ynone,	Pb, {0xaa} },
  	{ ASTOSL,	ynone,	Px, {0xab} },
  	{ ASTOSQ,	ynone,	Pw, {0xab} },
  	{ ASTOSW,	ynone,	Pe, {0xab} },
  	{ ASUBB,	yxorb,	Pb, {0x2c,0x80,(05),0x28,0x2a} },
  	{ ASUBL,	yaddl,	Px, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
  	{ ASUBPD,	yxm,	Pe, {0x5c} },
  	{ ASUBPS,	yxm,	Pm, {0x5c} },
  	{ ASUBQ,	yaddl,	Pw, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
  	{ ASUBSD,	yxm,	Pf2, {0x5c} },
  	{ ASUBSS,	yxm,	Pf3, {0x5c} },
  	{ ASUBW,	yaddl,	Pe, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
  	{ ASWAPGS,	ynone,	Pm, {0x01,0xf8} },
  	{ ASYSCALL,	ynone,	Px, {0x0f,0x05} },	/* fast syscall */
  	{ ATESTB,	ytestb,	Pb, {0xa8,0xf6,(00),0x84,0x84} },
  	{ ATESTL,	ytestl,	Px, {0xa9,0xf7,(00),0x85,0x85} },
  	{ ATESTQ,	ytestl,	Pw, {0xa9,0xf7,(00),0x85,0x85} },
  	{ ATESTW,	ytestl,	Pe, {0xa9,0xf7,(00),0x85,0x85} },
  	{ ATEXT,	ytext,	Px },
  	{ AUCOMISD,	yxcmp,	Pe, {0x2e} },
  	{ AUCOMISS,	yxcmp,	Pm, {0x2e} },
  	{ AUNPCKHPD,	yxm,	Pe, {0x15} },
  	{ AUNPCKHPS,	yxm,	Pm, {0x15} },
  	{ AUNPCKLPD,	yxm,	Pe, {0x14} },
  	{ AUNPCKLPS,	yxm,	Pm, {0x14} },
  	{ AVERR,	ydivl,	Pm, {0x00,(04)} },
  	{ AVERW,	ydivl,	Pm, {0x00,(05)} },
  	{ AWAIT,	ynone,	Px, {0x9b} },
  	{ AWORD,	ybyte,	Px, {2} },
  	{ AXCHGB,	yml_mb,	Pb, {0x86,0x86} },
  	{ AXCHGL,	yxchg,	Px, {0x90,0x90,0x87,0x87} },
  	{ AXCHGQ,	yxchg,	Pw, {0x90,0x90,0x87,0x87} },
  	{ AXCHGW,	yxchg,	Pe, {0x90,0x90,0x87,0x87} },
  	{ AXLAT,	ynone,	Px, {0xd7} },
  	{ AXORB,	yxorb,	Pb, {0x34,0x80,(06),0x30,0x32} },
  	{ AXORL,	yxorl,	Px, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
  	{ AXORPD,	yxm,	Pe, {0x57} },
  	{ AXORPS,	yxm,	Pm, {0x57} },
  	{ AXORQ,	yxorl,	Pw, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
  	{ AXORW,	yxorl,	Pe, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
  
  	{ AFMOVB,	yfmvx,	Px, {0xdf,(04)} },
  	{ AFMOVBP,	yfmvp,	Px, {0xdf,(06)} },
  	{ AFMOVD,	yfmvd,	Px, {0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02)} },
  	{ AFMOVDP,	yfmvdp,	Px, {0xdd,(03),0xdd,(03)} },
  	{ AFMOVF,	yfmvf,	Px, {0xd9,(00),0xd9,(02)} },
  	{ AFMOVFP,	yfmvp,	Px, {0xd9,(03)} },
  	{ AFMOVL,	yfmvf,	Px, {0xdb,(00),0xdb,(02)} },
  	{ AFMOVLP,	yfmvp,	Px, {0xdb,(03)} },
  	{ AFMOVV,	yfmvx,	Px, {0xdf,(05)} },
  	{ AFMOVVP,	yfmvp,	Px, {0xdf,(07)} },
  	{ AFMOVW,	yfmvf,	Px, {0xdf,(00),0xdf,(02)} },
  	{ AFMOVWP,	yfmvp,	Px, {0xdf,(03)} },
  	{ AFMOVX,	yfmvx,	Px, {0xdb,(05)} },
  	{ AFMOVXP,	yfmvp,	Px, {0xdb,(07)} },
  
  	{ AFCOMB },
  	{ AFCOMBP },
  	{ AFCOMD,	yfadd,	Px, {0xdc,(02),0xd8,(02),0xdc,(02)} },	/* botch */
  	{ AFCOMDP,	yfadd,	Px, {0xdc,(03),0xd8,(03),0xdc,(03)} },	/* botch */
  	{ AFCOMDPP,	ycompp,	Px, {0xde,(03)} },
  	{ AFCOMF,	yfmvx,	Px, {0xd8,(02)} },
  	{ AFCOMFP,	yfmvx,	Px, {0xd8,(03)} },
  	{ AFCOML,	yfmvx,	Px, {0xda,(02)} },
  	{ AFCOMLP,	yfmvx,	Px, {0xda,(03)} },
  	{ AFCOMW,	yfmvx,	Px, {0xde,(02)} },
  	{ AFCOMWP,	yfmvx,	Px, {0xde,(03)} },
  
  	{ AFUCOM,	ycompp,	Px, {0xdd,(04)} },
  	{ AFUCOMP,	ycompp, Px, {0xdd,(05)} },
  	{ AFUCOMPP,	ycompp,	Px, {0xda,(13)} },
  
  	{ AFADDDP,	yfaddp,	Px, {0xde,(00)} },
  	{ AFADDW,	yfmvx,	Px, {0xde,(00)} },
  	{ AFADDL,	yfmvx,	Px, {0xda,(00)} },
  	{ AFADDF,	yfmvx,	Px, {0xd8,(00)} },
  	{ AFADDD,	yfadd,	Px, {0xdc,(00),0xd8,(00),0xdc,(00)} },
  
  	{ AFMULDP,	yfaddp,	Px, {0xde,(01)} },
  	{ AFMULW,	yfmvx,	Px, {0xde,(01)} },
  	{ AFMULL,	yfmvx,	Px, {0xda,(01)} },
  	{ AFMULF,	yfmvx,	Px, {0xd8,(01)} },
  	{ AFMULD,	yfadd,	Px, {0xdc,(01),0xd8,(01),0xdc,(01)} },
  
  	{ AFSUBDP,	yfaddp,	Px, {0xde,(05)} },
  	{ AFSUBW,	yfmvx,	Px, {0xde,(04)} },
  	{ AFSUBL,	yfmvx,	Px, {0xda,(04)} },
  	{ AFSUBF,	yfmvx,	Px, {0xd8,(04)} },
  	{ AFSUBD,	yfadd,	Px, {0xdc,(04),0xd8,(04),0xdc,(05)} },
  
  	{ AFSUBRDP,	yfaddp,	Px, {0xde,(04)} },
  	{ AFSUBRW,	yfmvx,	Px, {0xde,(05)} },
  	{ AFSUBRL,	yfmvx,	Px, {0xda,(05)} },
  	{ AFSUBRF,	yfmvx,	Px, {0xd8,(05)} },
  	{ AFSUBRD,	yfadd,	Px, {0xdc,(05),0xd8,(05),0xdc,(04)} },
  
  	{ AFDIVDP,	yfaddp,	Px, {0xde,(07)} },
  	{ AFDIVW,	yfmvx,	Px, {0xde,(06)} },
  	{ AFDIVL,	yfmvx,	Px, {0xda,(06)} },
  	{ AFDIVF,	yfmvx,	Px, {0xd8,(06)} },
  	{ AFDIVD,	yfadd,	Px, {0xdc,(06),0xd8,(06),0xdc,(07)} },
  
  	{ AFDIVRDP,	yfaddp,	Px, {0xde,(06)} },
  	{ AFDIVRW,	yfmvx,	Px, {0xde,(07)} },
  	{ AFDIVRL,	yfmvx,	Px, {0xda,(07)} },
  	{ AFDIVRF,	yfmvx,	Px, {0xd8,(07)} },
  	{ AFDIVRD,	yfadd,	Px, {0xdc,(07),0xd8,(07),0xdc,(06)} },
  
  	{ AFXCHD,	yfxch,	Px, {0xd9,(01),0xd9,(01)} },
  	{ AFFREE },
  	{ AFLDCW,	ystcw,	Px, {0xd9,(05),0xd9,(05)} },
  	{ AFLDENV,	ystcw,	Px, {0xd9,(04),0xd9,(04)} },
  	{ AFRSTOR,	ysvrs,	Px, {0xdd,(04),0xdd,(04)} },
  	{ AFSAVE,	ysvrs,	Px, {0xdd,(06),0xdd,(06)} },
  	{ AFSTCW,	ystcw,	Px, {0xd9,(07),0xd9,(07)} },
  	{ AFSTENV,	ystcw,	Px, {0xd9,(06),0xd9,(06)} },
  	{ AFSTSW,	ystsw,	Px, {0xdd,(07),0xdf,0xe0} },
  	{ AF2XM1,	ynone,	Px, {0xd9, 0xf0} },
  	{ AFABS,	ynone,	Px, {0xd9, 0xe1} },
  	{ AFCHS,	ynone,	Px, {0xd9, 0xe0} },
  	{ AFCLEX,	ynone,	Px, {0xdb, 0xe2} },
  	{ AFCOS,	ynone,	Px, {0xd9, 0xff} },
  	{ AFDECSTP,	ynone,	Px, {0xd9, 0xf6} },
  	{ AFINCSTP,	ynone,	Px, {0xd9, 0xf7} },
  	{ AFINIT,	ynone,	Px, {0xdb, 0xe3} },
  	{ AFLD1,	ynone,	Px, {0xd9, 0xe8} },
  	{ AFLDL2E,	ynone,	Px, {0xd9, 0xea} },
  	{ AFLDL2T,	ynone,	Px, {0xd9, 0xe9} },
  	{ AFLDLG2,	ynone,	Px, {0xd9, 0xec} },
  	{ AFLDLN2,	ynone,	Px, {0xd9, 0xed} },
  	{ AFLDPI,	ynone,	Px, {0xd9, 0xeb} },
  	{ AFLDZ,	ynone,	Px, {0xd9, 0xee} },
  	{ AFNOP,	ynone,	Px, {0xd9, 0xd0} },
  	{ AFPATAN,	ynone,	Px, {0xd9, 0xf3} },
  	{ AFPREM,	ynone,	Px, {0xd9, 0xf8} },
  	{ AFPREM1,	ynone,	Px, {0xd9, 0xf5} },
  	{ AFPTAN,	ynone,	Px, {0xd9, 0xf2} },
  	{ AFRNDINT,	ynone,	Px, {0xd9, 0xfc} },
  	{ AFSCALE,	ynone,	Px, {0xd9, 0xfd} },
  	{ AFSIN,	ynone,	Px, {0xd9, 0xfe} },
  	{ AFSINCOS,	ynone,	Px, {0xd9, 0xfb} },
  	{ AFSQRT,	ynone,	Px, {0xd9, 0xfa} },
  	{ AFTST,	ynone,	Px, {0xd9, 0xe4} },
  	{ AFXAM,	ynone,	Px, {0xd9, 0xe5} },
  	{ AFXTRACT,	ynone,	Px, {0xd9, 0xf4} },
  	{ AFYL2X,	ynone,	Px, {0xd9, 0xf1} },
  	{ AFYL2XP1,	ynone,	Px, {0xd9, 0xf9} },
  
  	{ ACMPXCHGB,	yrb_mb,	Pb, {0x0f,0xb0} },
  	{ ACMPXCHGL,	yrl_ml,	Px, {0x0f,0xb1} },
  	{ ACMPXCHGW,	yrl_ml,	Pe, {0x0f,0xb1} },
  	{ ACMPXCHGQ,	yrl_ml,	Pw, {0x0f,0xb1} },
  	{ ACMPXCHG8B,	yscond,	Pm, {0xc7,(01)} },
  	{ AINVD,	ynone,	Pm, {0x08} },
  	{ AINVLPG,	ymbs,	Pm, {0x01,(07)} },
  	{ ALFENCE,	ynone,	Pm, {0xae,0xe8} },
  	{ AMFENCE,	ynone,	Pm, {0xae,0xf0} },
  	{ AMOVNTIL,	yrl_ml,	Pm, {0xc3} },
  	{ AMOVNTIQ,	yrl_ml, Pw, {0x0f,0xc3} },
  	{ ARDMSR,	ynone,	Pm, {0x32} },
  	{ ARDPMC,	ynone,	Pm, {0x33} },
  	{ ARDTSC,	ynone,	Pm, {0x31} },
  	{ ARSM,		ynone,	Pm, {0xaa} },
  	{ ASFENCE,	ynone,	Pm, {0xae,0xf8} },
  	{ ASYSRET,	ynone,	Pm, {0x07} },
  	{ AWBINVD,	ynone,	Pm, {0x09} },
  	{ AWRMSR,	ynone,	Pm, {0x30} },
  
  	{ AXADDB,	yrb_mb,	Pb, {0x0f,0xc0} },
  	{ AXADDL,	yrl_ml,	Px, {0x0f,0xc1} },
  	{ AXADDQ,	yrl_ml,	Pw, {0x0f,0xc1} },
  	{ AXADDW,	yrl_ml,	Pe, {0x0f,0xc1} },
  
  	{ ACRC32B,       ycrc32l,Px, {0xf2,0x0f,0x38,0xf0,0} },
  	{ ACRC32Q,       ycrc32l,Pw, {0xf2,0x0f,0x38,0xf1,0} },
  	
  	{ APREFETCHT0,	yprefetch,	Pm,	{0x18,(01)} },
  	{ APREFETCHT1,	yprefetch,	Pm,	{0x18,(02)} },
  	{ APREFETCHT2,	yprefetch,	Pm,	{0x18,(03)} },
  	{ APREFETCHNTA,	yprefetch,	Pm,	{0x18,(00)} },
  	
  	{ AMOVQL,	yrl_ml,	Px, {0x89} },
  
  	{ AUNDEF,		ynone,	Px, {0x0f, 0x0b} },
  
  	{ AAESENC,	yaes,	Pq, {0x38,0xdc,(0)} },
  	{ AAESENCLAST,	yaes,	Pq, {0x38,0xdd,(0)} },
  	{ AAESDEC,	yaes,	Pq, {0x38,0xde,(0)} },
  	{ AAESDECLAST,	yaes,	Pq, {0x38,0xdf,(0)} },
  	{ AAESIMC,	yaes,	Pq, {0x38,0xdb,(0)} },
  	{ AAESKEYGENASSIST,	yaes2,	Pq, {0x3a,0xdf,(0)} },
  
  	{ APSHUFD,	yaes2,	Pq,	{0x70,(0)} },
  	{ APCLMULQDQ,	yxshuf,	Pq, {0x3a,0x44,0} },
  
  	{ AUSEFIELD,	ynop,	Px, {0,0} },
  	{ ATYPE },
  	{ AFUNCDATA,	yfuncdata,	Px, {0,0} },
  	{ APCDATA,	ypcdata,	Px, {0,0} },
  	{ ACHECKNIL },
  	{ AVARDEF },
  	{ AVARKILL },
  	{ ADUFFCOPY,	yduff,	Px, {0xe8} },
  	{ ADUFFZERO,	yduff,	Px, {0xe8} },
  
  	{ AEND },
  	{0}
  };
  
  static Optab*	opindex[ALAST+1];
  static vlong	vaddr(Link*, Addr*, Reloc*);
  
  // isextern reports whether s describes an external symbol that must avoid pc-relative addressing.
  // This happens on systems like Solaris that call .so functions instead of system calls.
  // It does not seem to be necessary for any other systems. This is probably working
  // around a Solaris-specific bug that should be fixed differently, but we don't know
  // what that bug is. And this does fix it.
  static int
  isextern(LSym *s)
  {
  	// All the Solaris dynamic imports from libc.so begin with "libc·", which
  	// the compiler rewrites to "libc." by the time liblink gets it.
  	// Haiku also uses this for dynamic imports but from libroot instead.
  #if defined(__HAIKU__)
  	return strncmp(s->name, "libroot.", 9) == 0;
  #else
  	return strncmp(s->name, "libc.", 5) == 0;
  #endif
  }
  
  // single-instruction no-ops of various lengths.
  // constructed by hand and disassembled with gdb to verify.
  // see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion.
  static uchar nop[][16] = {
  	{0x90},
  	{0x66, 0x90},
  	{0x0F, 0x1F, 0x00},
  	{0x0F, 0x1F, 0x40, 0x00},
  	{0x0F, 0x1F, 0x44, 0x00, 0x00},
  	{0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
  	{0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
  	{0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
  	{0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
  	// Native Client rejects the repeated 0x66 prefix.
  	// {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
  };
  
  static void
  fillnop(uchar *p, int n)
  {
  	int m;
  
  	while(n > 0) {
  		m = n;
  		if(m > nelem(nop))
  			m = nelem(nop);
  		memmove(p, nop[m-1], m);
  		p += m;
  		n -= m;
  	}
  }
  
  static void instinit(void);
  
  static int32
  naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
  {
  	symgrow(ctxt, s, c+pad);
  	fillnop(s->p+c, pad);
  	return c+pad;
  }
  
  static int
  spadjop(Link *ctxt, Prog *p, int l, int q)
  {
  	if(p->mode != 64 || ctxt->arch->ptrsize == 4)
  		return l;
  	return q;
  }
  
  void
  span6(Link *ctxt, LSym *s)
  {
  	Prog *p, *q;
  	int32 c, v, loop;
  	uchar *bp;
  	int n, m, i;
  
  	ctxt->cursym = s;
  	
  	if(s->p != nil)
  		return;
  	
  	if(ycover[0] == 0)
  		instinit();
  	
  	for(p = ctxt->cursym->text; p != nil; p = p->link) {
  		n = 0;
  		if(p->to.type == D_BRANCH)
  			if(p->pcond == nil)
  				p->pcond = p;
  		if((q = p->pcond) != nil)
  			if(q->back != 2)
  				n = 1;
  		p->back = n;
  		if(p->as == AADJSP) {
  			p->to.type = D_SP;
  			v = -p->from.offset;
  			p->from.offset = v;
  			p->as = spadjop(ctxt, p, AADDL, AADDQ);
  			if(v < 0) {
  				p->as = spadjop(ctxt, p, ASUBL, ASUBQ);
  				v = -v;
  				p->from.offset = v;
  			}
  			if(v == 0)
  				p->as = ANOP;
  		}
  	}
  
  	for(p = s->text; p != nil; p = p->link) {
  		p->back = 2;	// use short branches first time through
  		if((q = p->pcond) != nil && (q->back & 2)) {
  			p->back |= 1;	// backward jump
  			q->back |= 4;   // loop head
  		}
  
  		if(p->as == AADJSP) {
  			p->to.type = D_SP;
  			v = -p->from.offset;
  			p->from.offset = v;
  			p->as = spadjop(ctxt, p, AADDL, AADDQ);
  			if(v < 0) {
  				p->as = spadjop(ctxt, p, ASUBL, ASUBQ);
  				v = -v;
  				p->from.offset = v;
  			}
  			if(v == 0)
  				p->as = ANOP;
  		}
  	}
  	
  	n = 0;
  	do {
  		loop = 0;
  		memset(s->r, 0, s->nr*sizeof s->r[0]);
  		s->nr = 0;
  		s->np = 0;
  		c = 0;
  		for(p = s->text; p != nil; p = p->link) {
  			if(ctxt->headtype == Hnacl && p->isize > 0) {
  				static LSym *deferreturn;
  				
  				if(deferreturn == nil)
  					deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
  
  				// pad everything to avoid crossing 32-byte boundary
  				if((c>>5) != ((c+p->isize-1)>>5))
  					c = naclpad(ctxt, s, c, -c&31);
  				// pad call deferreturn to start at 32-byte boundary
  				// so that subtracting 5 in jmpdefer will jump back
  				// to that boundary and rerun the call.
  				if(p->as == ACALL && p->to.sym == deferreturn)
  					c = naclpad(ctxt, s, c, -c&31);
  				// pad call to end at 32-byte boundary
  				if(p->as == ACALL)
  					c = naclpad(ctxt, s, c, -(c+p->isize)&31);
  				
  				// the linker treats REP and STOSQ as different instructions
  				// but in fact the REP is a prefix on the STOSQ.
  				// make sure REP has room for 2 more bytes, so that
  				// padding will not be inserted before the next instruction.
  				if((p->as == AREP || p->as == AREPN) && (c>>5) != ((c+3-1)>>5))
  					c = naclpad(ctxt, s, c, -c&31);
  				
  				// same for LOCK.
  				// various instructions follow; the longest is 4 bytes.
  				// give ourselves 8 bytes so as to avoid surprises.
  				if(p->as == ALOCK && (c>>5) != ((c+8-1)>>5))
  					c = naclpad(ctxt, s, c, -c&31);
  			}
  
  			if((p->back & 4) && (c&(LoopAlign-1)) != 0) {
  				// pad with NOPs
  				v = -c&(LoopAlign-1);
  				if(v <= MaxLoopPad) {
  					symgrow(ctxt, s, c+v);
  					fillnop(s->p+c, v);
  					c += v;
  				}
  			}
  
  			p->pc = c;
  
  			// process forward jumps to p
  			for(q = p->comefrom; q != nil; q = q->forwd) {
  				v = p->pc - (q->pc + q->mark);
  				if(q->back & 2)	{	// short
  					if(v > 127) {
  						loop++;
  						q->back ^= 2;
  					}
  					if(q->as == AJCXZL)
  						s->p[q->pc+2] = v;
  					else
  						s->p[q->pc+1] = v;
  				} else {
  					bp = s->p + q->pc + q->mark - 4;
  					*bp++ = v;
  					*bp++ = v>>8;
  					*bp++ = v>>16;
  					*bp = v>>24;
  				}	
  			}
  			p->comefrom = nil;
  
  			p->pc = c;
  			asmins(ctxt, p);
  			m = ctxt->andptr-ctxt->and;
  			if(p->isize != m) {
  				p->isize = m;
  				loop++;
  			}
  			symgrow(ctxt, s, p->pc+m);
  			memmove(s->p+p->pc, ctxt->and, m);
  			p->mark = m;
  			c += m;
  		}
  		if(++n > 20) {
  			ctxt->diag("span must be looping");
  			sysfatal("loop");
  		}
  	} while(loop);
  	
  	if(ctxt->headtype == Hnacl)
  		c = naclpad(ctxt, s, c, -c&31);
  	
  	c += -c&(FuncAlign-1);
  	s->size = c;
  
  	if(0 /* debug['a'] > 1 */) {
  		print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
  		for(i=0; i<s->np; i++) {
  			print(" %.2ux", s->p[i]);
  			if(i%16 == 15)
  				print("\n  %.6ux", i+1);
  		}
  		if(i%16)
  			print("\n");
  	
  		for(i=0; i<s->nr; i++) {
  			Reloc *r;
  			
  			r = &s->r[i];
  			print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
  		}
  	}
  }
  
  static void
  instinit(void)
  {
  	int c, i;
  
  	for(i=1; optab[i].as; i++) {
  		c = optab[i].as;
  		if(opindex[c] != nil)
  			sysfatal("phase error in optab: %d (%A)", i, c);
  		opindex[c] = &optab[i];
  	}
  
  	for(i=0; i<Ymax; i++)
  		ycover[i*Ymax + i] = 1;
  
  	ycover[Yi0*Ymax + Yi8] = 1;
  	ycover[Yi1*Ymax + Yi8] = 1;
  
  	ycover[Yi0*Ymax + Ys32] = 1;
  	ycover[Yi1*Ymax + Ys32] = 1;
  	ycover[Yi8*Ymax + Ys32] = 1;
  
  	ycover[Yi0*Ymax + Yi32] = 1;
  	ycover[Yi1*Ymax + Yi32] = 1;
  	ycover[Yi8*Ymax + Yi32] = 1;
  	ycover[Ys32*Ymax + Yi32] = 1;
  
  	ycover[Yi0*Ymax + Yi64] = 1;
  	ycover[Yi1*Ymax + Yi64] = 1;
  	ycover[Yi8*Ymax + Yi64] = 1;
  	ycover[Ys32*Ymax + Yi64] = 1;
  	ycover[Yi32*Ymax + Yi64] = 1;
  
  	ycover[Yal*Ymax + Yrb] = 1;
  	ycover[Ycl*Ymax + Yrb] = 1;
  	ycover[Yax*Ymax + Yrb] = 1;
  	ycover[Ycx*Ymax + Yrb] = 1;
  	ycover[Yrx*Ymax + Yrb] = 1;
  	ycover[Yrl*Ymax + Yrb] = 1;
  
  	ycover[Ycl*Ymax + Ycx] = 1;
  
  	ycover[Yax*Ymax + Yrx] = 1;
  	ycover[Ycx*Ymax + Yrx] = 1;
  
  	ycover[Yax*Ymax + Yrl] = 1;
  	ycover[Ycx*Ymax + Yrl] = 1;
  	ycover[Yrx*Ymax + Yrl] = 1;
  
  	ycover[Yf0*Ymax + Yrf] = 1;
  
  	ycover[Yal*Ymax + Ymb] = 1;
  	ycover[Ycl*Ymax + Ymb] = 1;
  	ycover[Yax*Ymax + Ymb] = 1;
  	ycover[Ycx*Ymax + Ymb] = 1;
  	ycover[Yrx*Ymax + Ymb] = 1;
  	ycover[Yrb*Ymax + Ymb] = 1;
  	ycover[Yrl*Ymax + Ymb] = 1;
  	ycover[Ym*Ymax + Ymb] = 1;
  
  	ycover[Yax*Ymax + Yml] = 1;
  	ycover[Ycx*Ymax + Yml] = 1;
  	ycover[Yrx*Ymax + Yml] = 1;
  	ycover[Yrl*Ymax + Yml] = 1;
  	ycover[Ym*Ymax + Yml] = 1;
  
  	ycover[Yax*Ymax + Ymm] = 1;
  	ycover[Ycx*Ymax + Ymm] = 1;
  	ycover[Yrx*Ymax + Ymm] = 1;
  	ycover[Yrl*Ymax + Ymm] = 1;
  	ycover[Ym*Ymax + Ymm] = 1;
  	ycover[Ymr*Ymax + Ymm] = 1;
  
  	ycover[Ym*Ymax + Yxm] = 1;
  	ycover[Yxr*Ymax + Yxm] = 1;
  
  	for(i=0; i<D_NONE; i++) {
  		reg[i] = -1;
  		if(i >= D_AL && i <= D_R15B) {
  			reg[i] = (i-D_AL) & 7;
  			if(i >= D_SPB && i <= D_DIB)
  				regrex[i] = 0x40;
  			if(i >= D_R8B && i <= D_R15B)
  				regrex[i] = Rxr | Rxx | Rxb;
  		}
  		if(i >= D_AH && i<= D_BH)
  			reg[i] = 4 + ((i-D_AH) & 7);
  		if(i >= D_AX && i <= D_R15) {
  			reg[i] = (i-D_AX) & 7;
  			if(i >= D_R8)
  				regrex[i] = Rxr | Rxx | Rxb;
  		}
  		if(i >= D_F0 && i <= D_F0+7)
  			reg[i] = (i-D_F0) & 7;
  		if(i >= D_M0 && i <= D_M0+7)
  			reg[i] = (i-D_M0) & 7;
  		if(i >= D_X0 && i <= D_X0+15) {
  			reg[i] = (i-D_X0) & 7;
  			if(i >= D_X0+8)
  				regrex[i] = Rxr | Rxx | Rxb;
  		}
  		if(i >= D_CR+8 && i <= D_CR+15)
  			regrex[i] = Rxr;
  	}
  }
  
  static int
  prefixof(Link *ctxt, Addr *a)
  {
  	switch(a->type) {
  	case D_INDIR+D_CS:
  		return 0x2e;
  	case D_INDIR+D_DS:
  		return 0x3e;
  	case D_INDIR+D_ES:
  		return 0x26;
  	case D_INDIR+D_FS:
  		return 0x64;
  	case D_INDIR+D_GS:
  		return 0x65;
  	case D_INDIR+D_TLS:
  		// NOTE: Systems listed here should be only systems that
  		// support direct TLS references like 8(TLS) implemented as
  		// direct references from FS or GS. Systems that require
  		// the initial-exec model, where you load the TLS base into
  		// a register and then index from that register, do not reach
  		// this code and should not be listed.
  		switch(ctxt->headtype) {
  		default:
  			sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
  		case Hdragonfly:
  		case Hfreebsd:
  		case Hlinux:
  		case Hnetbsd:
  		case Hopenbsd:
  		case Hsolaris:
  			return 0x64; // FS
  		case Hdarwin:
  			return 0x65; // GS
  		}
  	}
  	switch(a->index) {
  	case D_CS:
  		return 0x2e;
  	case D_DS:
  		return 0x3e;
  	case D_ES:
  		return 0x26;
  	case D_FS:
  		return 0x64;
  	case D_GS:
  		return 0x65;
  	}
  	return 0;
  }
  
  static int
  oclass(Link *ctxt, Addr *a)
  {
  	vlong v;
  	int32 l;
  
  	if(a->type >= D_INDIR || a->index != D_NONE) {
  		if(a->index != D_NONE && a->scale == 0) {
  			if(a->type == D_ADDR) {
  				switch(a->index) {
  				case D_EXTERN:
  				case D_STATIC:
  					if(a->sym != nil && isextern(a->sym))
  						return Yi32;
  					return Yiauto; // use pc-relative addressing
  				case D_AUTO:
  				case D_PARAM:
  					return Yiauto;
  				}
  				return Yxxx;
  			}
  			return Ycol;
  		}
  		return Ym;
  	}
  	switch(a->type)
  	{
  	case D_AL:
  		return Yal;
  
  	case D_AX:
  		return Yax;
  
  /*
  	case D_SPB:
  */
  	case D_BPB:
  	case D_SIB:
  	case D_DIB:
  	case D_R8B:
  	case D_R9B:
  	case D_R10B:
  	case D_R11B:
  	case D_R12B:
  	case D_R13B:
  	case D_R14B:
  	case D_R15B:
  		if(ctxt->asmode != 64)
  			return Yxxx;
  	case D_DL:
  	case D_BL:
  	case D_AH:
  	case D_CH:
  	case D_DH:
  	case D_BH:
  		return Yrb;
  
  	case D_CL:
  		return Ycl;
  
  	case D_CX:
  		return Ycx;
  
  	case D_DX:
  	case D_BX:
  		return Yrx;
  
  	case D_R8:	/* not really Yrl */
  	case D_R9:
  	case D_R10:
  	case D_R11:
  	case D_R12:
  	case D_R13:
  	case D_R14:
  	case D_R15:
  		if(ctxt->asmode != 64)
  			return Yxxx;
  	case D_SP:
  	case D_BP:
  	case D_SI:
  	case D_DI:
  		return Yrl;
  
  	case D_F0+0:
  		return	Yf0;
  
  	case D_F0+1:
  	case D_F0+2:
  	case D_F0+3:
  	case D_F0+4:
  	case D_F0+5:
  	case D_F0+6:
  	case D_F0+7:
  		return	Yrf;
  
  	case D_M0+0:
  	case D_M0+1:
  	case D_M0+2:
  	case D_M0+3:
  	case D_M0+4:
  	case D_M0+5:
  	case D_M0+6:
  	case D_M0+7:
  		return	Ymr;
  
  	case D_X0+0:
  	case D_X0+1:
  	case D_X0+2:
  	case D_X0+3:
  	case D_X0+4:
  	case D_X0+5:
  	case D_X0+6:
  	case D_X0+7:
  	case D_X0+8:
  	case D_X0+9:
  	case D_X0+10:
  	case D_X0+11:
  	case D_X0+12:
  	case D_X0+13:
  	case D_X0+14:
  	case D_X0+15:
  		return	Yxr;
  
  	case D_NONE:
  		return Ynone;
  
  	case D_CS:	return	Ycs;
  	case D_SS:	return	Yss;
  	case D_DS:	return	Yds;
  	case D_ES:	return	Yes;
  	case D_FS:	return	Yfs;
  	case D_GS:	return	Ygs;
  	case D_TLS:	return	Ytls;
  
  	case D_GDTR:	return	Ygdtr;
  	case D_IDTR:	return	Yidtr;
  	case D_LDTR:	return	Yldtr;
  	case D_MSW:	return	Ymsw;
  	case D_TASK:	return	Ytask;
  
  	case D_CR+0:	return	Ycr0;
  	case D_CR+1:	return	Ycr1;
  	case D_CR+2:	return	Ycr2;
  	case D_CR+3:	return	Ycr3;
  	case D_CR+4:	return	Ycr4;
  	case D_CR+5:	return	Ycr5;
  	case D_CR+6:	return	Ycr6;
  	case D_CR+7:	return	Ycr7;
  	case D_CR+8:	return	Ycr8;
  
  	case D_DR+0:	return	Ydr0;
  	case D_DR+1:	return	Ydr1;
  	case D_DR+2:	return	Ydr2;
  	case D_DR+3:	return	Ydr3;
  	case D_DR+4:	return	Ydr4;
  	case D_DR+5:	return	Ydr5;
  	case D_DR+6:	return	Ydr6;
  	case D_DR+7:	return	Ydr7;
  
  	case D_TR+0:	return	Ytr0;
  	case D_TR+1:	return	Ytr1;
  	case D_TR+2:	return	Ytr2;
  	case D_TR+3:	return	Ytr3;
  	case D_TR+4:	return	Ytr4;
  	case D_TR+5:	return	Ytr5;
  	case D_TR+6:	return	Ytr6;
  	case D_TR+7:	return	Ytr7;
  
  	case D_EXTERN:
  	case D_STATIC:
  	case D_AUTO:
  	case D_PARAM:
  		return Ym;
  
  	case D_CONST:
  	case D_ADDR:
  		if(a->sym == nil) {
  			v = a->offset;
  			if(v == 0)
  				return Yi0;
  			if(v == 1)
  				return Yi1;
  			if(v >= -128 && v <= 127)
  				return Yi8;
  			l = v;
  			if((vlong)l == v)
  				return Ys32;	/* can sign extend */
  			if((v>>32) == 0)
  				return Yi32;	/* unsigned */
  			return Yi64;
  		}
  		return Yi32;
  
  	case D_BRANCH:
  		return Ybr;
  	}
  	return Yxxx;
  }
  
  static void
  asmidx(Link *ctxt, int scale, int index, int base)
  {
  	int i;
  
  	switch(index) {
  	default:
  		goto bad;
  
  	case D_NONE:
  		i = 4 << 3;
  		goto bas;
  
  	case D_R8:
  	case D_R9:
  	case D_R10:
  	case D_R11:
  	case D_R12:
  	case D_R13:
  	case D_R14:
  	case D_R15:
  		if(ctxt->asmode != 64)
  			goto bad;
  	case D_AX:
  	case D_CX:
  	case D_DX:
  	case D_BX:
  	case D_BP:
  	case D_SI:
  	case D_DI:
  		i = reg[index] << 3;
  		break;
  	}
  	switch(scale) {
  	default:
  		goto bad;
  	case 1:
  		break;
  	case 2:
  		i |= (1<<6);
  		break;
  	case 4:
  		i |= (2<<6);
  		break;
  	case 8:
  		i |= (3<<6);
  		break;
  	}
  bas:
  	switch(base) {
  	default:
  		goto bad;
  	case D_NONE:	/* must be mod=00 */
  		i |= 5;
  		break;
  	case D_R8:
  	case D_R9:
  	case D_R10:
  	case D_R11:
  	case D_R12:
  	case D_R13:
  	case D_R14:
  	case D_R15:
  		if(ctxt->asmode != 64)
  			goto bad;
  	case D_AX:
  	case D_CX:
  	case D_DX:
  	case D_BX:
  	case D_SP:
  	case D_BP:
  	case D_SI:
  	case D_DI:
  		i |= reg[base];
  		break;
  	}
  	*ctxt->andptr++ = i;
  	return;
  bad:
  	ctxt->diag("asmidx: bad address %d/%d/%d", scale, index, base);
  	*ctxt->andptr++ = 0;
  	return;
  }
  
  static void
  put4(Link *ctxt, int32 v)
  {
  	ctxt->andptr[0] = v;
  	ctxt->andptr[1] = v>>8;
  	ctxt->andptr[2] = v>>16;
  	ctxt->andptr[3] = v>>24;
  	ctxt->andptr += 4;
  }
  
  static void
  relput4(Link *ctxt, Prog *p, Addr *a)
  {
  	vlong v;
  	Reloc rel, *r;
  	
  	v = vaddr(ctxt, a, &rel);
  	if(rel.siz != 0) {
  		if(rel.siz != 4)
  			ctxt->diag("bad reloc");
  		r = addrel(ctxt->cursym);
  		*r = rel;
  		r->off = p->pc + ctxt->andptr - ctxt->and;
  	}
  	put4(ctxt, v);
  }
  
  static void
  put8(Link *ctxt, vlong v)
  {
  	ctxt->andptr[0] = v;
  	ctxt->andptr[1] = v>>8;
  	ctxt->andptr[2] = v>>16;
  	ctxt->andptr[3] = v>>24;
  	ctxt->andptr[4] = v>>32;
  	ctxt->andptr[5] = v>>40;
  	ctxt->andptr[6] = v>>48;
  	ctxt->andptr[7] = v>>56;
  	ctxt->andptr += 8;
  }
  
  /*
  static void
  relput8(Prog *p, Addr *a)
  {
  	vlong v;
  	Reloc rel, *r;
  	
  	v = vaddr(ctxt, a, &rel);
  	if(rel.siz != 0) {
  		r = addrel(ctxt->cursym);
  		*r = rel;
  		r->siz = 8;
  		r->off = p->pc + ctxt->andptr - ctxt->and;
  	}
  	put8(ctxt, v);
  }
  */
  
  static vlong
  vaddr(Link *ctxt, Addr *a, Reloc *r)
  {
  	int t;
  	vlong v;
  	LSym *s;
  	
  	if(r != nil)
  		memset(r, 0, sizeof *r);
  
  	t = a->type;
  	v = a->offset;
  	if(t == D_ADDR)
  		t = a->index;
  	switch(t) {
  	case D_STATIC:
  	case D_EXTERN:
  		s = a->sym;
  		if(r == nil) {
  			ctxt->diag("need reloc for %D", a);
  			sysfatal("reloc");
  		}
  		if(isextern(s)) {
  			r->siz = 4;
  			r->type = R_ADDR;
  		} else {
  			r->siz = 4;
  			r->type = R_PCREL;
  		}
  		r->off = -1;	// caller must fill in
  		r->sym = s;
  		r->add = v;
  		v = 0;
  		if(s->type == STLSBSS) {
  			r->xadd = r->add - r->siz;
  			r->type = R_TLS;
  			r->xsym = s;
  		}
  		break;
  	
  	case D_INDIR+D_TLS:
  		if(r == nil) {
  			ctxt->diag("need reloc for %D", a);
  			sysfatal("reloc");
  		}
  		r->type = R_TLS_LE;
  		r->siz = 4;
  		r->off = -1;	// caller must fill in
  		r->add = v;
  		v = 0;
  		break;
  	}
  	return v;
  }
  
  static void
  asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64)
  {
  	int32 v;
  	int t, scale;
  	Reloc rel;
  
  	USED(m64);
  	rex &= (0x40 | Rxr);
  	v = a->offset;
  	t = a->type;
  	rel.siz = 0;
  	if(a->index != D_NONE && a->index != D_TLS) {
  		if(t < D_INDIR) { 
  			switch(t) {
  			default:
  				goto bad;
  			case D_EXTERN:
  			case D_STATIC:
  				if(!isextern(a->sym))
  					goto bad;
  				t = D_NONE;
  				v = vaddr(ctxt, a, &rel);
  				break;
  			case D_AUTO:
  			case D_PARAM:
  				t = D_SP;
  				break;
  			}
  		} else
  			t -= D_INDIR;
  		ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
  		if(t == D_NONE) {
  			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
  			asmidx(ctxt, a->scale, a->index, t);
  			goto putrelv;
  		}
  		if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
  			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
  			asmidx(ctxt, a->scale, a->index, t);
  			return;
  		}
  		if(v >= -128 && v < 128 && rel.siz == 0) {
  			*ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
  			asmidx(ctxt, a->scale, a->index, t);
  			*ctxt->andptr++ = v;
  			return;
  		}
  		*ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
  		asmidx(ctxt, a->scale, a->index, t);
  		goto putrelv;
  	}
  	if(t >= D_AL && t <= D_X0+15) {
  		if(v)
  			goto bad;
  		*ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
  		ctxt->rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
  		return;
  	}
  	
  	scale = a->scale;
  	if(t < D_INDIR) {
  		switch(a->type) {
  		default:
  			goto bad;
  		case D_STATIC:
  		case D_EXTERN:
  			t = D_NONE;
  			v = vaddr(ctxt, a, &rel);
  			break;
  		case D_AUTO:
  		case D_PARAM:
  			t = D_SP;
  			break;
  		}
  		scale = 1;
  	} else
  		t -= D_INDIR;
  	if(t == D_TLS)
  		v = vaddr(ctxt, a, &rel);
  
  	ctxt->rexflag |= (regrex[t] & Rxb) | rex;
  	if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
  		if((a->sym == nil || !isextern(a->sym)) && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) {
  			*ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
  			goto putrelv;
  		}
  		/* temporary */
  		*ctxt->andptr++ = (0 <<  6) | (4 << 0) | (r << 3);	/* sib present */
  		*ctxt->andptr++ = (0 << 6) | (4 << 3) | (5 << 0);	/* DS:d32 */
  		goto putrelv;
  	}
  	if(t == D_SP || t == D_R12) {
  		if(v == 0) {
  			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
  			asmidx(ctxt, scale, D_NONE, t);
  			return;
  		}
  		if(v >= -128 && v < 128) {
  			*ctxt->andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
  			asmidx(ctxt, scale, D_NONE, t);
  			*ctxt->andptr++ = v;
  			return;
  		}
  		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
  		asmidx(ctxt, scale, D_NONE, t);
  		goto putrelv;
  	}
  	if(t >= D_AX && t <= D_R15) {
  		if(a->index == D_TLS) {
  			memset(&rel, 0, sizeof rel);
  			rel.type = R_TLS_IE;
  			rel.siz = 4;
  			rel.sym = nil;
  			rel.add = v;
  			v = 0;
  		}
  		if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
  			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
  			return;
  		}
  		if(v >= -128 && v < 128 && rel.siz == 0) {
  			ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
  			ctxt->andptr[1] = v;
  			ctxt->andptr += 2;
  			return;
  		}
  		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
  		goto putrelv;
  	}
  	goto bad;
  	
  putrelv:
  	if(rel.siz != 0) {
  		Reloc *r;
  
  		if(rel.siz != 4) {
  			ctxt->diag("bad rel");
  			goto bad;
  		}
  		r = addrel(ctxt->cursym);
  		*r = rel;
  		r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
  	}
  		
  	put4(ctxt, v);
  	return;
  
  bad:
  	ctxt->diag("asmand: bad address %D", a);
  	return;
  }
  
  static void
  asmand(Link *ctxt, Addr *a, Addr *ra)
  {
  	asmandsz(ctxt, a, reg[ra->type], regrex[ra->type], 0);
  }
  
  static void
  asmando(Link *ctxt, Addr *a, int o)
  {
  	asmandsz(ctxt, a, o, 0, 0);
  }
  
  static void
  bytereg(Addr *a, uint8 *t)
  {
  	if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
  		a->type = D_AL + (a->type-D_AX);
  		*t = 0;
  	}
  }
  
  enum {
  	E = 0xff,
  };
  static Movtab	ymovtab[] =
  {
  /* push */
  	{APUSHL,	Ycs,	Ynone,	0,	{0x0e,E,0,0}},
  	{APUSHL,	Yss,	Ynone,	0,	{0x16,E,0,0}},
  	{APUSHL,	Yds,	Ynone,	0,	{0x1e,E,0,0}},
  	{APUSHL,	Yes,	Ynone,	0,	{0x06,E,0,0}},
  	{APUSHL,	Yfs,	Ynone,	0,	{0x0f,0xa0,E,0}},
  	{APUSHL,	Ygs,	Ynone,	0,	{0x0f,0xa8,E,0}},
  	{APUSHQ,	Yfs,	Ynone,	0,	{0x0f,0xa0,E,0}},
  	{APUSHQ,	Ygs,	Ynone,	0,	{0x0f,0xa8,E,0}},
  
  	{APUSHW,	Ycs,	Ynone,	0,	{Pe,0x0e,E,0}},
  	{APUSHW,	Yss,	Ynone,	0,	{Pe,0x16,E,0}},
  	{APUSHW,	Yds,	Ynone,	0,	{Pe,0x1e,E,0}},
  	{APUSHW,	Yes,	Ynone,	0,	{Pe,0x06,E,0}},
  	{APUSHW,	Yfs,	Ynone,	0,	{Pe,0x0f,0xa0,E}},
  	{APUSHW,	Ygs,	Ynone,	0,	{Pe,0x0f,0xa8,E}},
  
  /* pop */
  	{APOPL,	Ynone,	Yds,	0,	{0x1f,E,0,0}},
  	{APOPL,	Ynone,	Yes,	0,	{0x07,E,0,0}},
  	{APOPL,	Ynone,	Yss,	0,	{0x17,E,0,0}},
  	{APOPL,	Ynone,	Yfs,	0,	{0x0f,0xa1,E,0}},
  	{APOPL,	Ynone,	Ygs,	0,	{0x0f,0xa9,E,0}},
  	{APOPQ,	Ynone,	Yfs,	0,	{0x0f,0xa1,E,0}},
  	{APOPQ,	Ynone,	Ygs,	0,	{0x0f,0xa9,E,0}},
  
  	{APOPW,	Ynone,	Yds,	0,	{Pe,0x1f,E,0}},
  	{APOPW,	Ynone,	Yes,	0,	{Pe,0x07,E,0}},
  	{APOPW,	Ynone,	Yss,	0,	{Pe,0x17,E,0}},
  	{APOPW,	Ynone,	Yfs,	0,	{Pe,0x0f,0xa1,E}},
  	{APOPW,	Ynone,	Ygs,	0,	{Pe,0x0f,0xa9,E}},
  
  /* mov seg */
  	{AMOVW,	Yes,	Yml,	1,	{0x8c,0,0,0}},
  	{AMOVW,	Ycs,	Yml,	1,	{0x8c,1,0,0}},
  	{AMOVW,	Yss,	Yml,	1,	{0x8c,2,0,0}},
  	{AMOVW,	Yds,	Yml,	1,	{0x8c,3,0,0}},
  	{AMOVW,	Yfs,	Yml,	1,	{0x8c,4,0,0}},
  	{AMOVW,	Ygs,	Yml,	1,	{0x8c,5,0,0}},
  
  	{AMOVW,	Yml,	Yes,	2,	{0x8e,0,0,0}},
  	{AMOVW,	Yml,	Ycs,	2,	{0x8e,1,0,0}},
  	{AMOVW,	Yml,	Yss,	2,	{0x8e,2,0,0}},
  	{AMOVW,	Yml,	Yds,	2,	{0x8e,3,0,0}},
  	{AMOVW,	Yml,	Yfs,	2,	{0x8e,4,0,0}},
  	{AMOVW,	Yml,	Ygs,	2,	{0x8e,5,0,0}},
  
  /* mov cr */
  	{AMOVL,	Ycr0,	Yml,	3,	{0x0f,0x20,0,0}},
  	{AMOVL,	Ycr2,	Yml,	3,	{0x0f,0x20,2,0}},
  	{AMOVL,	Ycr3,	Yml,	3,	{0x0f,0x20,3,0}},
  	{AMOVL,	Ycr4,	Yml,	3,	{0x0f,0x20,4,0}},
  	{AMOVL,	Ycr8,	Yml,	3,	{0x0f,0x20,8,0}},
  	{AMOVQ,	Ycr0,	Yml,	3,	{0x0f,0x20,0,0}},
  	{AMOVQ,	Ycr2,	Yml,	3,	{0x0f,0x20,2,0}},
  	{AMOVQ,	Ycr3,	Yml,	3,	{0x0f,0x20,3,0}},
  	{AMOVQ,	Ycr4,	Yml,	3,	{0x0f,0x20,4,0}},
  	{AMOVQ,	Ycr8,	Yml,	3,	{0x0f,0x20,8,0}},
  
  	{AMOVL,	Yml,	Ycr0,	4,	{0x0f,0x22,0,0}},
  	{AMOVL,	Yml,	Ycr2,	4,	{0x0f,0x22,2,0}},
  	{AMOVL,	Yml,	Ycr3,	4,	{0x0f,0x22,3,0}},
  	{AMOVL,	Yml,	Ycr4,	4,	{0x0f,0x22,4,0}},
  	{AMOVL,	Yml,	Ycr8,	4,	{0x0f,0x22,8,0}},
  	{AMOVQ,	Yml,	Ycr0,	4,	{0x0f,0x22,0,0}},
  	{AMOVQ,	Yml,	Ycr2,	4,	{0x0f,0x22,2,0}},
  	{AMOVQ,	Yml,	Ycr3,	4,	{0x0f,0x22,3,0}},
  	{AMOVQ,	Yml,	Ycr4,	4,	{0x0f,0x22,4,0}},
  	{AMOVQ,	Yml,	Ycr8,	4,	{0x0f,0x22,8,0}},
  
  /* mov dr */
  	{AMOVL,	Ydr0,	Yml,	3,	{0x0f,0x21,0,0}},
  	{AMOVL,	Ydr6,	Yml,	3,	{0x0f,0x21,6,0}},
  	{AMOVL,	Ydr7,	Yml,	3,	{0x0f,0x21,7,0}},
  	{AMOVQ,	Ydr0,	Yml,	3,	{0x0f,0x21,0,0}},
  	{AMOVQ,	Ydr6,	Yml,	3,	{0x0f,0x21,6,0}},
  	{AMOVQ,	Ydr7,	Yml,	3,	{0x0f,0x21,7,0}},
  
  	{AMOVL,	Yml,	Ydr0,	4,	{0x0f,0x23,0,0}},
  	{AMOVL,	Yml,	Ydr6,	4,	{0x0f,0x23,6,0}},
  	{AMOVL,	Yml,	Ydr7,	4,	{0x0f,0x23,7,0}},
  	{AMOVQ,	Yml,	Ydr0,	4,	{0x0f,0x23,0,0}},
  	{AMOVQ,	Yml,	Ydr6,	4,	{0x0f,0x23,6,0}},
  	{AMOVQ,	Yml,	Ydr7,	4,	{0x0f,0x23,7,0}},
  
  /* mov tr */
  	{AMOVL,	Ytr6,	Yml,	3,	{0x0f,0x24,6,0}},
  	{AMOVL,	Ytr7,	Yml,	3,	{0x0f,0x24,7,0}},
  
  	{AMOVL,	Yml,	Ytr6,	4,	{0x0f,0x26,6,E}},
  	{AMOVL,	Yml,	Ytr7,	4,	{0x0f,0x26,7,E}},
  
  /* lgdt, sgdt, lidt, sidt */
  	{AMOVL,	Ym,	Ygdtr,	4,	{0x0f,0x01,2,0}},
  	{AMOVL,	Ygdtr,	Ym,	3,	{0x0f,0x01,0,0}},
  	{AMOVL,	Ym,	Yidtr,	4,	{0x0f,0x01,3,0}},
  	{AMOVL,	Yidtr,	Ym,	3,	{0x0f,0x01,1,0}},
  	{AMOVQ,	Ym,	Ygdtr,	4,	{0x0f,0x01,2,0}},
  	{AMOVQ,	Ygdtr,	Ym,	3,	{0x0f,0x01,0,0}},
  	{AMOVQ,	Ym,	Yidtr,	4,	{0x0f,0x01,3,0}},
  	{AMOVQ,	Yidtr,	Ym,	3,	{0x0f,0x01,1,0}},
  
  /* lldt, sldt */
  	{AMOVW,	Yml,	Yldtr,	4,	{0x0f,0x00,2,0}},
  	{AMOVW,	Yldtr,	Yml,	3,	{0x0f,0x00,0,0}},
  
  /* lmsw, smsw */
  	{AMOVW,	Yml,	Ymsw,	4,	{0x0f,0x01,6,0}},
  	{AMOVW,	Ymsw,	Yml,	3,	{0x0f,0x01,4,0}},
  
  /* ltr, str */
  	{AMOVW,	Yml,	Ytask,	4,	{0x0f,0x00,3,0}},
  	{AMOVW,	Ytask,	Yml,	3,	{0x0f,0x00,1,0}},
  
  /* load full pointer */
  	{AMOVL,	Yml,	Ycol,	5,	{0,0,0,0}},
  	{AMOVW,	Yml,	Ycol,	5,	{Pe,0,0,0}},
  
  /* double shift */
  	{ASHLL,	Ycol,	Yml,	6,	{0xa4,0xa5,0,0}},
  	{ASHRL,	Ycol,	Yml,	6,	{0xac,0xad,0,0}},
  	{ASHLQ,	Ycol,	Yml,	6,	{Pw,0xa4,0xa5,0}},
  	{ASHRQ,	Ycol,	Yml,	6,	{Pw,0xac,0xad,0}},
  	{ASHLW,	Ycol,	Yml,	6,	{Pe,0xa4,0xa5,0}},
  	{ASHRW,	Ycol,	Yml,	6,	{Pe,0xac,0xad,0}},
  
  /* load TLS base */
  	{AMOVQ,	Ytls,	Yrl,	7,	{0,0,0,0}},
  
  	{0}
  };
  
  static int
  isax(Addr *a)
  {
  
  	switch(a->type) {
  	case D_AX:
  	case D_AL:
  	case D_AH:
  	case D_INDIR+D_AX:
  		return 1;
  	}
  	if(a->index == D_AX)
  		return 1;
  	return 0;
  }
  
  static void
  subreg(Prog *p, int from, int to)
  {
  
  	if(0 /*debug['Q']*/)
  		print("\n%P	s/%R/%R/\n", p, from, to);
  
  	if(p->from.type == from)
  		p->from.type = to;
  	if(p->to.type == from)
  		p->to.type = to;
  
  	if(p->from.index == from)
  		p->from.index = to;
  	if(p->to.index == from)
  		p->to.index = to;
  
  	from += D_INDIR;
  	if(p->from.type == from)
  		p->from.type = to+D_INDIR;
  	if(p->to.type == from)
  		p->to.type = to+D_INDIR;
  
  	if(0 /*debug['Q']*/)
  		print("%P\n", p);
  }
  
  static int
  mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
  {
  	switch(op){
  	case Pm:
  	case Pe:
  	case Pf2:
  	case Pf3:
  		if(osize != 1){
  			if(op != Pm)
  				*ctxt->andptr++ = op;
  			*ctxt->andptr++ = Pm;
  			op = o->op[++z];
  			break;
  		}
  	default:
  		if(ctxt->andptr == ctxt->and || ctxt->and[ctxt->andptr - ctxt->and - 1] != Pm)
  			*ctxt->andptr++ = Pm;
  		break;
  	}
  	*ctxt->andptr++ = op;
  	return z;
  }
  
  static void
  doasm(Link *ctxt, Prog *p)
  {
  	Optab *o;
  	Prog *q, pp;
  	uchar *t;
  	Movtab *mo;
  	int z, op, ft, tt, xo, l, pre;
  	vlong v;
  	Reloc rel, *r;
  	Addr *a;
  	
  	ctxt->curp = p;	// TODO
  
  	o = opindex[p->as];
  	if(o == nil) {
  		ctxt->diag("asmins: missing op %P", p);
  		return;
  	}
  	
  	pre = prefixof(ctxt, &p->from);
  	if(pre)
  		*ctxt->andptr++ = pre;
  	pre = prefixof(ctxt, &p->to);
  	if(pre)
  		*ctxt->andptr++ = pre;
  
  	if(p->ft == 0)
  		p->ft = oclass(ctxt, &p->from);
  	if(p->tt == 0)
  		p->tt = oclass(ctxt, &p->to);
  
  	ft = p->ft * Ymax;
  	tt = p->tt * Ymax;
  
  	t = o->ytab;
  	if(t == 0) {
  		ctxt->diag("asmins: noproto %P", p);
  		return;
  	}
  	xo = o->op[0] == 0x0f;
  	for(z=0; *t; z+=t[3]+xo,t+=4)
  		if(ycover[ft+t[0]])
  		if(ycover[tt+t[1]])
  			goto found;
  	goto domov;
  
  found:
  	switch(o->prefix) {
  	case Pq:	/* 16 bit escape and opcode escape */
  		*ctxt->andptr++ = Pe;
  		*ctxt->andptr++ = Pm;
  		break;
  	case Pq3:	/* 16 bit escape, Rex.w, and opcode escape */
  		*ctxt->andptr++ = Pe;
  		*ctxt->andptr++ = Pw;
  		*ctxt->andptr++ = Pm;
  		break;
  
  	case Pf2:	/* xmm opcode escape */
  	case Pf3:
  		*ctxt->andptr++ = o->prefix;
  		*ctxt->andptr++ = Pm;
  		break;
  
  	case Pm:	/* opcode escape */
  		*ctxt->andptr++ = Pm;
  		break;
  
  	case Pe:	/* 16 bit escape */
  		*ctxt->andptr++ = Pe;
  		break;
  
  	case Pw:	/* 64-bit escape */
  		if(p->mode != 64)
  			ctxt->diag("asmins: illegal 64: %P", p);
  		ctxt->rexflag |= Pw;
  		break;
  
  	case Pb:	/* botch */
  		bytereg(&p->from, &p->ft);
  		bytereg(&p->to, &p->tt);
  		break;
  
  	case P32:	/* 32 bit but illegal if 64-bit mode */
  		if(p->mode == 64)
  			ctxt->diag("asmins: illegal in 64-bit mode: %P", p);
  		break;
  
  	case Py:	/* 64-bit only, no prefix */
  		if(p->mode != 64)
  			ctxt->diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
  		break;
  	}
  
  	if(z >= nelem(o->op))
  		sysfatal("asmins bad table %P", p);
  	op = o->op[z];
  	if(op == 0x0f) {
  		*ctxt->andptr++ = op;
  		op = o->op[++z];
  	}
  	switch(t[2]) {
  	default:
  		ctxt->diag("asmins: unknown z %d %P", t[2], p);
  		return;
  
  	case Zpseudo:
  		break;
  
  	case Zlit:
  		for(; op = o->op[z]; z++)
  			*ctxt->andptr++ = op;
  		break;
  
  	case Zlitm_r:
  		for(; op = o->op[z]; z++)
  			*ctxt->andptr++ = op;
  		asmand(ctxt, &p->from, &p->to);
  		break;
  
  	case Zmb_r:
  		bytereg(&p->from, &p->ft);
  		/* fall through */
  	case Zm_r:
  		*ctxt->andptr++ = op;
  		asmand(ctxt, &p->from, &p->to);
  		break;
  	case Zm2_r:
  		*ctxt->andptr++ = op;
  		*ctxt->andptr++ = o->op[z+1];
  		asmand(ctxt, &p->from, &p->to);
  		break;
  
  	case Zm_r_xm:
  		mediaop(ctxt, o, op, t[3], z);
  		asmand(ctxt, &p->from, &p->to);
  		break;
  
  	case Zm_r_xm_nr:
  		ctxt->rexflag = 0;
  		mediaop(ctxt, o, op, t[3], z);
  		asmand(ctxt, &p->from, &p->to);
  		break;
  
  	case Zm_r_i_xm:
  		mediaop(ctxt, o, op, t[3], z);
  		asmand(ctxt, &p->from, &p->to);
  		*ctxt->andptr++ = p->to.offset;
  		break;
  
  	case Zm_r_3d:
  		*ctxt->andptr++ = 0x0f;
  		*ctxt->andptr++ = 0x0f;
  		asmand(ctxt, &p->from, &p->to);
  		*ctxt->andptr++ = op;
  		break;
  
  	case Zibm_r:
  		while ((op = o->op[z++]) != 0)
  			*ctxt->andptr++ = op;
  		asmand(ctxt, &p->from, &p->to);
  		*ctxt->andptr++ = p->to.offset;
  		break;
  
  	case Zaut_r:
  		*ctxt->andptr++ = 0x8d;	/* leal */
  		if(p->from.type != D_ADDR)
  			ctxt->diag("asmins: Zaut sb type ADDR");
  		p->from.type = p->from.index;
  		p->from.index = D_NONE;
  		asmand(ctxt, &p->from, &p->to);
  		p->from.index = p->from.type;
  		p->from.type = D_ADDR;
  		break;
  
  	case Zm_o:
  		*ctxt->andptr++ = op;
  		asmando(ctxt, &p->from, o->op[z+1]);
  		break;
  
  	case Zr_m:
  		*ctxt->andptr++ = op;
  		asmand(ctxt, &p->to, &p->from);
  		break;
  
  	case Zr_m_xm:
  		mediaop(ctxt, o, op, t[3], z);
  		asmand(ctxt, &p->to, &p->from);
  		break;
  
  	case Zr_m_xm_nr:
  		ctxt->rexflag = 0;
  		mediaop(ctxt, o, op, t[3], z);
  		asmand(ctxt, &p->to, &p->from);
  		break;
  
  	case Zr_m_i_xm:
  		mediaop(ctxt, o, op, t[3], z);
  		asmand(ctxt, &p->to, &p->from);
  		*ctxt->andptr++ = p->from.offset;
  		break;
  
  	case Zo_m:
  		*ctxt->andptr++ = op;
  		asmando(ctxt, &p->to, o->op[z+1]);
  		break;
  
  	case Zcallindreg:
  		r = addrel(ctxt->cursym);
  		r->off = p->pc;
  		r->type = R_CALLIND;
  		r->siz = 0;
  		// fallthrough
  	case Zo_m64:
  		*ctxt->andptr++ = op;
  		asmandsz(ctxt, &p->to, o->op[z+1], 0, 1);
  		break;
  
  	case Zm_ibo:
  		*ctxt->andptr++ = op;
  		asmando(ctxt, &p->from, o->op[z+1]);
  		*ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
  		break;
  
  	case Zibo_m:
  		*ctxt->andptr++ = op;
  		asmando(ctxt, &p->to, o->op[z+1]);
  		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
  		break;
  
  	case Zibo_m_xm:
  		z = mediaop(ctxt, o, op, t[3], z);
  		asmando(ctxt, &p->to, o->op[z+1]);
  		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
  		break;
  
  	case Z_ib:
  	case Zib_:
  		if(t[2] == Zib_)
  			a = &p->from;
  		else
  			a = &p->to;
  		*ctxt->andptr++ = op;
  		*ctxt->andptr++ = vaddr(ctxt, a, nil);
  		break;
  
  	case Zib_rp:
  		ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
  		*ctxt->andptr++ = op + reg[p->to.type];
  		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
  		break;
  
  	case Zil_rp:
  		ctxt->rexflag |= regrex[p->to.type] & Rxb;
  		*ctxt->andptr++ = op + reg[p->to.type];
  		if(o->prefix == Pe) {
  			v = vaddr(ctxt, &p->from, nil);
  			*ctxt->andptr++ = v;
  			*ctxt->andptr++ = v>>8;
  		}
  		else
  			relput4(ctxt, p, &p->from);
  		break;
  
  	case Zo_iw:
  		*ctxt->andptr++ = op;
  		if(p->from.type != D_NONE){
  			v = vaddr(ctxt, &p->from, nil);
  			*ctxt->andptr++ = v;
  			*ctxt->andptr++ = v>>8;
  		}
  		break;
  
  	case Ziq_rp:
  		v = vaddr(ctxt, &p->from, &rel);
  		l = v>>32;
  		if(l == 0 && rel.siz != 8){
  			//p->mark |= 0100;
  			//print("zero: %llux %P\n", v, p);
  			ctxt->rexflag &= ~(0x40|Rxw);
  			ctxt->rexflag |= regrex[p->to.type] & Rxb;
  			*ctxt->andptr++ = 0xb8 + reg[p->to.type];
  			if(rel.type != 0) {
  				r = addrel(ctxt->cursym);
  				*r = rel;
  				r->off = p->pc + ctxt->andptr - ctxt->and;
  			}
  			put4(ctxt, v);
  		}else if(l == -1 && (v&((uvlong)1<<31))!=0){	/* sign extend */
  			//p->mark |= 0100;
  			//print("sign: %llux %P\n", v, p);
  			*ctxt->andptr ++ = 0xc7;
  			asmando(ctxt, &p->to, 0);
  			put4(ctxt, v);
  		}else{	/* need all 8 */
  			//print("all: %llux %P\n", v, p);
  			ctxt->rexflag |= regrex[p->to.type] & Rxb;
  			*ctxt->andptr++ = op + reg[p->to.type];
  			if(rel.type != 0) {
  				r = addrel(ctxt->cursym);
  				*r = rel;
  				r->off = p->pc + ctxt->andptr - ctxt->and;
  			}
  			put8(ctxt, v);
  		}
  		break;
  
  	case Zib_rr:
  		*ctxt->andptr++ = op;
  		asmand(ctxt, &p->to, &p->to);
  		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
  		break;
  
  	case Z_il:
  	case Zil_:
  		if(t[2] == Zil_)
  			a = &p->from;
  		else
  			a = &p->to;
  		*ctxt->andptr++ = op;
  		if(o->prefix == Pe) {
  			v = vaddr(ctxt, a, nil);
  			*ctxt->andptr++ = v;
  			*ctxt->andptr++ = v>>8;
  		}
  		else
  			relput4(ctxt, p, a);
  		break;
  
  	case Zm_ilo:
  	case Zilo_m:
  		*ctxt->andptr++ = op;
  		if(t[2] == Zilo_m) {
  			a = &p->from;
  			asmando(ctxt, &p->to, o->op[z+1]);
  		} else {
  			a = &p->to;
  			asmando(ctxt, &p->from, o->op[z+1]);
  		}
  		if(o->prefix == Pe) {
  			v = vaddr(ctxt, a, nil);
  			*ctxt->andptr++ = v;
  			*ctxt->andptr++ = v>>8;
  		}
  		else
  			relput4(ctxt, p, a);
  		break;
  
  	case Zil_rr:
  		*ctxt->andptr++ = op;
  		asmand(ctxt, &p->to, &p->to);
  		if(o->prefix == Pe) {
  			v = vaddr(ctxt, &p->from, nil);
  			*ctxt->andptr++ = v;
  			*ctxt->andptr++ = v>>8;
  		}
  		else
  			relput4(ctxt, p, &p->from);
  		break;
  
  	case Z_rp:
  		ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
  		*ctxt->andptr++ = op + reg[p->to.type];
  		break;
  
  	case Zrp_:
  		ctxt->rexflag |= regrex[p->from.type] & (Rxb|0x40);
  		*ctxt->andptr++ = op + reg[p->from.type];
  		break;
  
  	case Zclr:
  		ctxt->rexflag &= ~Pw;
  		*ctxt->andptr++ = op;
  		asmand(ctxt, &p->to, &p->to);
  		break;
  
  	case Zcall:
  		if(p->to.sym == nil) {
  			ctxt->diag("call without target");
  			sysfatal("bad code");
  		}
  		*ctxt->andptr++ = op;
  		r = addrel(ctxt->cursym);
  		r->off = p->pc + ctxt->andptr - ctxt->and;
  		r->sym = p->to.sym;
  		r->add = p->to.offset;
  		r->type = R_CALL;
  		r->siz = 4;
  		put4(ctxt, 0);
  		break;
  
  	case Zbr:
  	case Zjmp:
  	case Zloop:
  		// TODO: jump across functions needs reloc
  		if(p->to.sym != nil) {
  			if(t[2] != Zjmp) {
  				ctxt->diag("branch to ATEXT");
  				sysfatal("bad code");
  			}
  			*ctxt->andptr++ = o->op[z+1];
  			r = addrel(ctxt->cursym);
  			r->off = p->pc + ctxt->andptr - ctxt->and;
  			r->sym = p->to.sym;
  			r->type = R_PCREL;
  			r->siz = 4;
  			put4(ctxt, 0);
  			break;
  		}
  		// Assumes q is in this function.
  		// TODO: Check in input, preserve in brchain.
  
  		// Fill in backward jump now.
  		q = p->pcond;
  		if(q == nil) {
  			ctxt->diag("jmp/branch/loop without target");
  			sysfatal("bad code");
  		}
  		if(p->back & 1) {
  			v = q->pc - (p->pc + 2);
  			if(v >= -128) {
  				if(p->as == AJCXZL)
  					*ctxt->andptr++ = 0x67;
  				*ctxt->andptr++ = op;
  				*ctxt->andptr++ = v;
  			} else if(t[2] == Zloop) {
  				ctxt->diag("loop too far: %P", p);
  			} else {
  				v -= 5-2;
  				if(t[2] == Zbr) {
  					*ctxt->andptr++ = 0x0f;
  					v--;
  				}
  				*ctxt->andptr++ = o->op[z+1];
  				*ctxt->andptr++ = v;
  				*ctxt->andptr++ = v>>8;
  				*ctxt->andptr++ = v>>16;
  				*ctxt->andptr++ = v>>24;
  			}
  			break;
  		}
  		
  		// Annotate target; will fill in later.
  		p->forwd = q->comefrom;
  		q->comefrom = p;
  		if(p->back & 2)	{ // short
  			if(p->as == AJCXZL)
  				*ctxt->andptr++ = 0x67;
  			*ctxt->andptr++ = op;
  			*ctxt->andptr++ = 0;
  		} else if(t[2] == Zloop) {
  			ctxt->diag("loop too far: %P", p);
  		} else {
  			if(t[2] == Zbr)
  				*ctxt->andptr++ = 0x0f;
  			*ctxt->andptr++ = o->op[z+1];
  			*ctxt->andptr++ = 0;
  			*ctxt->andptr++ = 0;
  			*ctxt->andptr++ = 0;
  			*ctxt->andptr++ = 0;
  		}
  		break;
  				
  /*
  		v = q->pc - p->pc - 2;
  		if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
  			*ctxt->andptr++ = op;
  			*ctxt->andptr++ = v;
  		} else {
  			v -= 5-2;
  			if(t[2] == Zbr) {
  				*ctxt->andptr++ = 0x0f;
  				v--;
  			}
  			*ctxt->andptr++ = o->op[z+1];
  			*ctxt->andptr++ = v;
  			*ctxt->andptr++ = v>>8;
  			*ctxt->andptr++ = v>>16;
  			*ctxt->andptr++ = v>>24;
  		}
  */
  		break;
  
  	case Zbyte:
  		v = vaddr(ctxt, &p->from, &rel);
  		if(rel.siz != 0) {
  			rel.siz = op;
  			r = addrel(ctxt->cursym);
  			*r = rel;
  			r->off = p->pc + ctxt->andptr - ctxt->and;
  		}
  		*ctxt->andptr++ = v;
  		if(op > 1) {
  			*ctxt->andptr++ = v>>8;
  			if(op > 2) {
  				*ctxt->andptr++ = v>>16;
  				*ctxt->andptr++ = v>>24;
  				if(op > 4) {
  					*ctxt->andptr++ = v>>32;
  					*ctxt->andptr++ = v>>40;
  					*ctxt->andptr++ = v>>48;
  					*ctxt->andptr++ = v>>56;
  				}
  			}
  		}
  		break;
  	}
  	return;
  
  domov:
  	for(mo=ymovtab; mo->as; mo++)
  		if(p->as == mo->as)
  		if(ycover[ft+mo->ft])
  		if(ycover[tt+mo->tt]){
  			t = mo->op;
  			goto mfound;
  		}
  bad:
  	if(p->mode != 64){
  		/*
  		 * here, the assembly has failed.
  		 * if its a byte instruction that has
  		 * unaddressable registers, try to
  		 * exchange registers and reissue the
  		 * instruction with the operands renamed.
  		 */
  		pp = *p;
  		z = p->from.type;
  		if(z >= D_BP && z <= D_DI) {
  			if(isax(&p->to) || p->to.type == D_NONE) {
  				// We certainly don't want to exchange
  				// with AX if the op is MUL or DIV.
  				*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
  				asmando(ctxt, &p->from, reg[D_BX]);
  				subreg(&pp, z, D_BX);
  				doasm(ctxt, &pp);
  				*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
  				asmando(ctxt, &p->from, reg[D_BX]);
  			} else {
  				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
  				subreg(&pp, z, D_AX);
  				doasm(ctxt, &pp);
  				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
  			}
  			return;
  		}
  		z = p->to.type;
  		if(z >= D_BP && z <= D_DI) {
  			if(isax(&p->from)) {
  				*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
  				asmando(ctxt, &p->to, reg[D_BX]);
  				subreg(&pp, z, D_BX);
  				doasm(ctxt, &pp);
  				*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
  				asmando(ctxt, &p->to, reg[D_BX]);
  			} else {
  				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
  				subreg(&pp, z, D_AX);
  				doasm(ctxt, &pp);
  				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
  			}
  			return;
  		}
  	}
  	ctxt->diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
  	return;
  
  mfound:
  	switch(mo->code) {
  	default:
  		ctxt->diag("asmins: unknown mov %d %P", mo->code, p);
  		break;
  
  	case 0:	/* lit */
  		for(z=0; t[z]!=E; z++)
  			*ctxt->andptr++ = t[z];
  		break;
  
  	case 1:	/* r,m */
  		*ctxt->andptr++ = t[0];
  		asmando(ctxt, &p->to, t[1]);
  		break;
  
  	case 2:	/* m,r */
  		*ctxt->andptr++ = t[0];
  		asmando(ctxt, &p->from, t[1]);
  		break;
  
  	case 3:	/* r,m - 2op */
  		*ctxt->andptr++ = t[0];
  		*ctxt->andptr++ = t[1];
  		asmando(ctxt, &p->to, t[2]);
  		ctxt->rexflag |= regrex[p->from.type] & (Rxr|0x40);
  		break;
  
  	case 4:	/* m,r - 2op */
  		*ctxt->andptr++ = t[0];
  		*ctxt->andptr++ = t[1];
  		asmando(ctxt, &p->from, t[2]);
  		ctxt->rexflag |= regrex[p->to.type] & (Rxr|0x40);
  		break;
  
  	case 5:	/* load full pointer, trash heap */
  		if(t[0])
  			*ctxt->andptr++ = t[0];
  		switch(p->to.index) {
  		default:
  			goto bad;
  		case D_DS:
  			*ctxt->andptr++ = 0xc5;
  			break;
  		case D_SS:
  			*ctxt->andptr++ = 0x0f;
  			*ctxt->andptr++ = 0xb2;
  			break;
  		case D_ES:
  			*ctxt->andptr++ = 0xc4;
  			break;
  		case D_FS:
  			*ctxt->andptr++ = 0x0f;
  			*ctxt->andptr++ = 0xb4;
  			break;
  		case D_GS:
  			*ctxt->andptr++ = 0x0f;
  			*ctxt->andptr++ = 0xb5;
  			break;
  		}
  		asmand(ctxt, &p->from, &p->to);
  		break;
  
  	case 6:	/* double shift */
  		if(t[0] == Pw){
  			if(p->mode != 64)
  				ctxt->diag("asmins: illegal 64: %P", p);
  			ctxt->rexflag |= Pw;
  			t++;
  		}else if(t[0] == Pe){
  			*ctxt->andptr++ = Pe;
  			t++;
  		}
  		z = p->from.type;
  		switch(z) {
  		default:
  			goto bad;
  		case D_CONST:
  			*ctxt->andptr++ = 0x0f;
  			*ctxt->andptr++ = t[0];
  			asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
  			*ctxt->andptr++ = p->from.offset;
  			break;
  		case D_CL:
  		case D_CX:
  			*ctxt->andptr++ = 0x0f;
  			*ctxt->andptr++ = t[1];
  			asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
  			break;
  		}
  		break;
  	
  	case 7:	/* mov tls, r */
  		// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
  		// where you load the TLS base register into a register and then index off that
  		// register to access the actual TLS variables. Systems that allow direct TLS access
  		// are handled in prefixof above and should not be listed here.
  		switch(ctxt->headtype) {
  		default:
  			sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
  
  		case Hplan9:
  			if(ctxt->plan9privates == nil)
  				ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
  			memset(&pp.from, 0, sizeof pp.from);
  			pp.from.type = D_EXTERN;
  			pp.from.sym = ctxt->plan9privates;
  			pp.from.offset = 0;
  			pp.from.index = D_NONE;
  			ctxt->rexflag |= Pw;
  			*ctxt->andptr++ = 0x8B;
  			asmand(ctxt, &pp.from, &p->to);
  			break;
  
  		case Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
  			// TLS base is 0(FS).
  			pp.from = p->from;
  			pp.from.type = D_INDIR+D_NONE;
  			pp.from.offset = 0;
  			pp.from.index = D_NONE;
  			pp.from.scale = 0;
  			ctxt->rexflag |= Pw;
  			*ctxt->andptr++ = 0x64; // FS
  			*ctxt->andptr++ = 0x8B;
  			asmand(ctxt, &pp.from, &p->to);
  			break;
  		
  		case Hwindows:
  			// Windows TLS base is always 0x28(GS).
  			pp.from = p->from;
  			pp.from.type = D_INDIR+D_GS;
  			pp.from.offset = 0x28;
  			pp.from.index = D_NONE;
  			pp.from.scale = 0;
  			ctxt->rexflag |= Pw;
  			*ctxt->andptr++ = 0x65; // GS
  			*ctxt->andptr++ = 0x8B;
  			asmand(ctxt, &pp.from, &p->to);
  			break;
  		
  		case Hhaiku:
  			// Haiku TLS base is 0(FS).
  			pp.from = p->from;
  			pp.from.type = D_INDIR+D_GS;
  			pp.from.offset = 0;
  			pp.from.index = D_NONE;
  			pp.from.scale = 0;
  			ctxt->rexflag |= Pw;
  			*ctxt->andptr++ = 0x64; // FS
  			*ctxt->andptr++ = 0x8B;
  			asmand(ctxt, &pp.from, &p->to);
  			break;
  		}
  		break;
  	}
  }
  
  static uchar naclret[] = {
  	0x5e, // POPL SI
  	// 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
  	0x83, 0xe6, 0xe0,	// ANDL $~31, SI
  	0x4c, 0x01, 0xfe,	// ADDQ R15, SI
  	0xff, 0xe6, // JMP SI
  };
  
  static uchar naclspfix[] = {
  	0x4c, 0x01, 0xfc, // ADDQ R15, SP
  };
  
  static uchar naclbpfix[] = {
  	0x4c, 0x01, 0xfd, // ADDQ R15, BP
  };
  
  static uchar naclmovs[] = {
  	0x89, 0xf6,	// MOVL SI, SI
  	0x49, 0x8d, 0x34, 0x37,	// LEAQ (R15)(SI*1), SI
  	0x89, 0xff,	// MOVL DI, DI
  	0x49, 0x8d, 0x3c, 0x3f,	// LEAQ (R15)(DI*1), DI
  };
  
  static uchar naclstos[] = {
  	0x89, 0xff,	// MOVL DI, DI
  	0x49, 0x8d, 0x3c, 0x3f,	// LEAQ (R15)(DI*1), DI
  };
  
  static void
  nacltrunc(Link *ctxt, int reg)
  {	
  	if(reg >= D_R8)
  		*ctxt->andptr++ = 0x45;
  	reg = (reg - D_AX) & 7;
  	*ctxt->andptr++ = 0x89;
  	*ctxt->andptr++ = (3<<6) | (reg<<3) | reg;
  }
  
  static void
  asmins(Link *ctxt, Prog *p)
  {
  	int i, n, np, c;
  	uchar *and0;
  	Reloc *r;
  	
  	ctxt->andptr = ctxt->and;
  	ctxt->asmode = p->mode;
  	
  	if(p->as == AUSEFIELD) {
  		r = addrel(ctxt->cursym);
  		r->off = 0;
  		r->siz = 0;
  		r->sym = p->from.sym;
  		r->type = R_USEFIELD;
  		return;
  	}
  	
  	if(ctxt->headtype == Hnacl) {
  		if(p->as == AREP) {
  			ctxt->rep++;
  			return;
  		}
  		if(p->as == AREPN) {
  			ctxt->repn++;
  			return;
  		}
  		if(p->as == ALOCK) {
  			ctxt->lock++;
  			return;
  		}
  		if(p->as != ALEAQ && p->as != ALEAL) {
  			if(p->from.index != D_NONE && p->from.scale > 0)
  				nacltrunc(ctxt, p->from.index);
  			if(p->to.index != D_NONE && p->to.scale > 0)
  				nacltrunc(ctxt, p->to.index);
  		}
  		switch(p->as) {
  		case ARET:
  			memmove(ctxt->andptr, naclret, sizeof naclret);
  			ctxt->andptr += sizeof naclret;
  			return;
  		case ACALL:
  		case AJMP:
  			if(D_AX <= p->to.type && p->to.type <= D_DI) {
  				// ANDL $~31, reg
  				*ctxt->andptr++ = 0x83;
  				*ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
  				*ctxt->andptr++ = 0xe0;
  				// ADDQ R15, reg
  				*ctxt->andptr++ = 0x4c;
  				*ctxt->andptr++ = 0x01;
  				*ctxt->andptr++ = 0xf8 | (p->to.type - D_AX);
  			}
  			if(D_R8 <= p->to.type && p->to.type <= D_R15) {
  				// ANDL $~31, reg
  				*ctxt->andptr++ = 0x41;
  				*ctxt->andptr++ = 0x83;
  				*ctxt->andptr++ = 0xe0 | (p->to.type - D_R8);
  				*ctxt->andptr++ = 0xe0;
  				// ADDQ R15, reg
  				*ctxt->andptr++ = 0x4d;
  				*ctxt->andptr++ = 0x01;
  				*ctxt->andptr++ = 0xf8 | (p->to.type - D_R8);
  			}
  			break;
  		case AINT:
  			*ctxt->andptr++ = 0xf4;
  			return;
  		case ASCASB:
  		case ASCASW:
  		case ASCASL:
  		case ASCASQ:
  		case ASTOSB:
  		case ASTOSW:
  		case ASTOSL:
  		case ASTOSQ:
  			memmove(ctxt->andptr, naclstos, sizeof naclstos);
  			ctxt->andptr += sizeof naclstos;
  			break;
  		case AMOVSB:
  		case AMOVSW:
  		case AMOVSL:
  		case AMOVSQ:
  			memmove(ctxt->andptr, naclmovs, sizeof naclmovs);
  			ctxt->andptr += sizeof naclmovs;
  			break;
  		}
  		if(ctxt->rep) {
  			*ctxt->andptr++ = 0xf3;
  			ctxt->rep = 0;
  		}
  		if(ctxt->repn) {
  			*ctxt->andptr++ = 0xf2;
  			ctxt->repn = 0;
  		}
  		if(ctxt->lock) {
  			*ctxt->andptr++ = 0xf0;
  			ctxt->lock = 0;
  		}
  	}		
  
  	ctxt->rexflag = 0;
  	and0 = ctxt->andptr;
  	ctxt->asmode = p->mode;
  	doasm(ctxt, p);
  	if(ctxt->rexflag){
  		/*
  		 * as befits the whole approach of the architecture,
  		 * the rex prefix must appear before the first opcode byte
  		 * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
  		 * before the 0f opcode escape!), or it might be ignored.
  		 * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
  		 */
  		if(p->mode != 64)
  			ctxt->diag("asmins: illegal in mode %d: %P", p->mode, p);
  		n = ctxt->andptr - and0;
  		for(np = 0; np < n; np++) {
  			c = and0[np];
  			if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
  				break;
  		}
  		memmove(and0+np+1, and0+np, n-np);
  		and0[np] = 0x40 | ctxt->rexflag;
  		ctxt->andptr++;
  	}
  	n = ctxt->andptr - ctxt->and;
  	for(i=ctxt->cursym->nr-1; i>=0; i--) {
  		r = ctxt->cursym->r+i;
  		if(r->off < p->pc)
  			break;
  		if(ctxt->rexflag)
  			r->off++;
  		if(r->type == R_PCREL || r->type == R_CALL)
  			r->add -= p->pc + n - (r->off + r->siz);
  	}
  
  	if(ctxt->headtype == Hnacl && p->as != ACMPL && p->as != ACMPQ) {
  		switch(p->to.type) {
  		case D_SP:
  			memmove(ctxt->andptr, naclspfix, sizeof naclspfix);
  			ctxt->andptr += sizeof naclspfix;
  			break;
  		case D_BP:
  			memmove(ctxt->andptr, naclbpfix, sizeof naclbpfix);
  			ctxt->andptr += sizeof naclbpfix;
  			break;
  		}
  	}
  }
  