changeset 756:a58784e0f035

Merge wilsonk's x86-64 inline assembly.
author Christian Kamm <kamm incasoftware de>
date Sat, 08 Nov 2008 22:29:19 +0100
parents 61c7a96f28c3
children 2c730d530c98
files dmd/statement.h gen/asm-x86-32.h gen/asm-x86-64.h gen/asmstmt.cpp gen/d-asm-i386.h tests/mini/asm1.d
diffstat 6 files changed, 5520 insertions(+), 2692 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/statement.h	Sat Nov 08 11:34:35 2008 +0100
+++ b/dmd/statement.h	Sat Nov 08 22:29:19 2008 +0100
@@ -890,7 +890,6 @@
     unsigned asmalign;		// alignment of this statement
     unsigned refparam;		// !=0 if function parameter is referenced
     unsigned naked;		// !=0 if function is to be naked
-    unsigned regs;		// mask of registers modified
 
     AsmStatement(Loc loc, Token *tokens);
     Statement *syntaxCopy();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/asm-x86-32.h	Sat Nov 08 22:29:19 2008 +0100
@@ -0,0 +1,2686 @@
+// Taken from GDC source tree. Original by David Friedman.
+// Released under the Artistic License found in dmd/artistic.txt
+
+#include "id.h"
+
+namespace AsmParserx8632 {
+
+typedef enum {
+    Reg_Invalid = -1,
+    Reg_EAX = 0,
+    Reg_EBX,
+    Reg_ECX,
+    Reg_EDX,
+    Reg_ESI,
+    Reg_EDI,
+    Reg_EBP,
+    Reg_ESP,
+    Reg_ST,
+    Reg_ST1, Reg_ST2, Reg_ST3, Reg_ST4, Reg_ST5, Reg_ST6, Reg_ST7,
+    Reg_MM0, Reg_MM1, Reg_MM2, Reg_MM3, Reg_MM4, Reg_MM5, Reg_MM6, Reg_MM7,
+    Reg_XMM0, Reg_XMM1, Reg_XMM2, Reg_XMM3, Reg_XMM4, Reg_XMM5, Reg_XMM6, Reg_XMM7,
+    // xmm8-15?
+    Reg_EFLAGS,
+    Reg_CS,
+    Reg_DS,
+    Reg_SS,
+    Reg_ES,
+    Reg_FS,
+    Reg_GS,
+    Reg_AX, Reg_BX, Reg_CX, Reg_DX, Reg_SI, Reg_DI, Reg_BP, Reg_SP,
+    Reg_AL, Reg_AH, Reg_BL, Reg_BH, Reg_CL, Reg_CH, Reg_DL, Reg_DH,
+    Reg_CR0, Reg_CR2, Reg_CR3, Reg_CR4,
+    Reg_DR0, Reg_DR1, Reg_DR2, Reg_DR3, Reg_DR6, Reg_DR7,
+    Reg_TR3, Reg_TR4, Reg_TR5, Reg_TR6, Reg_TR7
+} Reg;
+
+static const int N_Regs = /*gp*/ 8 + /*fp*/ 8 + /*mmx*/ 8 + /*sse*/ 8 +
+/*seg*/ 6 + /*16bit*/ 8 + /*8bit*/ 8 + /*sys*/ 4+6+5 + /*flags*/ + 1;
+
+#define NULL_TREE ""
+
+static struct {
+    const char * name;
+    std::string gccName; // GAS will take upper case, but GCC won't (needed for the clobber list)
+    Identifier * ident;
+    char size;
+    char baseReg; // %% todo: Reg, Reg_XX
+} regInfo[N_Regs] = {
+    { "EAX", NULL_TREE, NULL, 4,  Reg_EAX },
+    { "EBX", NULL_TREE, NULL, 4,  Reg_EBX },
+    { "ECX", NULL_TREE, NULL, 4,  Reg_ECX },
+    { "EDX", NULL_TREE, NULL, 4,  Reg_EDX },
+    { "ESI", NULL_TREE, NULL, 4,  Reg_ESI },
+    { "EDI", NULL_TREE, NULL, 4,  Reg_EDI },
+    { "EBP", NULL_TREE, NULL, 4,  Reg_EBP },
+    { "ESP", NULL_TREE, NULL, 4,  Reg_ESP },
+    { "ST", NULL_TREE, NULL,   10, Reg_ST },
+    { "ST(1)", NULL_TREE, NULL,10, Reg_ST1 },
+    { "ST(2)", NULL_TREE, NULL,10, Reg_ST2 },
+    { "ST(3)", NULL_TREE, NULL,10, Reg_ST3 },
+    { "ST(4)", NULL_TREE, NULL,10, Reg_ST4 },
+    { "ST(5)", NULL_TREE, NULL,10, Reg_ST5 },
+    { "ST(6)", NULL_TREE, NULL,10, Reg_ST6 },
+    { "ST(7)", NULL_TREE, NULL,10, Reg_ST7 },
+    { "MM0", NULL_TREE, NULL, 8, Reg_MM0 },
+    { "MM1", NULL_TREE, NULL, 8, Reg_MM1 },
+    { "MM2", NULL_TREE, NULL, 8, Reg_MM2 },
+    { "MM3", NULL_TREE, NULL, 8, Reg_MM3 },
+    { "MM4", NULL_TREE, NULL, 8, Reg_MM4 },
+    { "MM5", NULL_TREE, NULL, 8, Reg_MM5 },
+    { "MM6", NULL_TREE, NULL, 8, Reg_MM6 },
+    { "MM7", NULL_TREE, NULL, 8, Reg_MM7 },
+    { "XMM0", NULL_TREE, NULL, 16, Reg_XMM0 },
+    { "XMM1", NULL_TREE, NULL, 16, Reg_XMM1 },
+    { "XMM2", NULL_TREE, NULL, 16, Reg_XMM2 },
+    { "XMM3", NULL_TREE, NULL, 16, Reg_XMM3 },
+    { "XMM4", NULL_TREE, NULL, 16, Reg_XMM4 },
+    { "XMM5", NULL_TREE, NULL, 16, Reg_XMM5 },
+    { "XMM6", NULL_TREE, NULL, 16, Reg_XMM6 },
+    { "XMM7", NULL_TREE, NULL, 16, Reg_XMM7 },
+    { "FLAGS", NULL_TREE, NULL, 0, Reg_EFLAGS }, // the gcc name is "flags"; not used in assembler input
+    { "CS",  NULL_TREE, NULL, 2, -1 },
+    { "DS",  NULL_TREE, NULL, 2, -1 },
+    { "SS",  NULL_TREE, NULL, 2, -1 },
+    { "ES",  NULL_TREE, NULL, 2, -1 },
+    { "FS",  NULL_TREE, NULL, 2, -1 },
+    { "GS",  NULL_TREE, NULL, 2, -1 },
+    { "AX",  NULL_TREE, NULL, 2,  Reg_EAX },
+    { "BX",  NULL_TREE, NULL, 2,  Reg_EBX },
+    { "CX",  NULL_TREE, NULL, 2,  Reg_ECX },
+    { "DX",  NULL_TREE, NULL, 2,  Reg_EDX },
+    { "SI",  NULL_TREE, NULL, 2,  Reg_ESI },
+    { "DI",  NULL_TREE, NULL, 2,  Reg_EDI },
+    { "BP",  NULL_TREE, NULL, 2,  Reg_EBP },
+    { "SP",  NULL_TREE, NULL, 2,  Reg_ESP },
+    { "AL",  NULL_TREE, NULL, 1,  Reg_EAX },
+    { "AH",  NULL_TREE, NULL, 1,  Reg_EAX },
+    { "BL",  NULL_TREE, NULL, 1,  Reg_EBX },
+    { "BH",  NULL_TREE, NULL, 1,  Reg_EBX },
+    { "CL",  NULL_TREE, NULL, 1,  Reg_ECX },
+    { "CH",  NULL_TREE, NULL, 1,  Reg_ECX },
+    { "DL",  NULL_TREE, NULL, 1,  Reg_EDX },
+    { "DH",  NULL_TREE, NULL, 1,  Reg_EDX },
+    { "CR0", NULL_TREE, NULL, 0, -1 },
+    { "CR2", NULL_TREE, NULL, 0, -1 },
+    { "CR3", NULL_TREE, NULL, 0, -1 },
+    { "CR4", NULL_TREE, NULL, 0, -1 },
+    { "DR0", NULL_TREE, NULL, 0, -1 },
+    { "DR1", NULL_TREE, NULL, 0, -1 },
+    { "DR2", NULL_TREE, NULL, 0, -1 },
+    { "DR3", NULL_TREE, NULL, 0, -1 },
+    { "DR6", NULL_TREE, NULL, 0, -1 },
+    { "DR7", NULL_TREE, NULL, 0, -1 },
+    { "TR3", NULL_TREE, NULL, 0, -1 },
+    { "TR4", NULL_TREE, NULL, 0, -1 },
+    { "TR5", NULL_TREE, NULL, 0, -1 },
+    { "TR6", NULL_TREE, NULL, 0, -1 },
+    { "TR7", NULL_TREE, NULL, 0, -1 }
+};
+
+typedef enum {
+    No_Type_Needed,
+    Int_Types,
+    Word_Types, // same as Int_Types, but byte is not allowed
+    FP_Types,
+    FPInt_Types,
+    Byte_NoType, // byte only, but no type suffix
+} TypeNeeded;
+
+typedef enum {
+    No_Link,
+    Out_Mnemonic,
+    Next_Form
+} OpLink;
+
+typedef enum {
+    Clb_SizeAX   = 0x01,
+    Clb_SizeDXAX = 0x02,
+    Clb_EAX      = 0x03,
+    Clb_DXAX_Mask = 0x03,
+    
+    Clb_Flags    = 0x04,
+    Clb_DI       = 0x08,
+    Clb_SI       = 0x10,
+    Clb_CX       = 0x20,
+    Clb_ST       = 0x40,
+    Clb_SP       = 0x80 // Doesn't actually let GCC know the frame pointer is modified
+} ImplicitClober;
+
+// "^ +/..\([A-Za-z_0-9]+\).*" -> "    \1,"
+typedef enum {
+    Op_Invalid,
+    Op_Adjust,
+    Op_Dst,
+    Op_Upd,
+    Op_DstW,
+    Op_DstF,
+    Op_UpdF,
+    Op_DstSrc,
+    Op_DstSrcF,
+    Op_UpdSrcF,
+    Op_DstSrcFW,
+    Op_UpdSrcFW,
+    Op_DstSrcSSE,
+    Op_DstSrcMMX,
+    Op_DstSrcImmS,
+    Op_DstSrcImmM,
+    Op_UpdSrcShft,
+    Op_DstSrcNT,
+    Op_UpdSrcNT,
+    Op_DstMemNT,
+    Op_DstRMBNT,
+    Op_DstRMWNT,
+    Op_UpdUpd,
+    Op_UpdUpdF,
+    Op_Src,
+    Op_SrcRMWNT,
+    Op_SrcW,
+    Op_SrcImm,
+    Op_Src_DXAXF,
+    Op_SrcMemNT,
+    Op_SrcMemNTF,
+    Op_SrcSrc,
+    Op_SrcSrcF,
+    Op_SrcSrcFW,
+    Op_SrcSrcSSEF,
+    Op_SrcSrcMMX,
+    Op_Shift,
+    Op_Branch,
+    Op_CBranch,
+    Op_0,
+    Op_0_AX,
+    Op_0_DXAX,
+    Op_Loop,
+    Op_Flags,
+    Op_F0_ST,
+    Op_F0_P,
+    Op_Fs_P,
+    Op_Fis,
+    Op_Fis_ST,
+    Op_Fis_P,
+    Op_Fid,
+    Op_Fid_P,
+    Op_Ffd,
+    Op_FfdR,
+    Op_Ffd_P,
+    Op_FfdR_P,
+    Op_Fd_P,
+    Op_FdST,
+    Op_FMath,
+    Op_FdSTiSTi,
+    Op_FPMath,
+    Op_FCmp,
+    Op_FCmp1,
+    Op_FCmpP,
+    Op_FCmpP1,
+    Op_FCmpFlg,
+    Op_FCmpFlgP,
+    Op_fld,
+    Op_fldR,
+    Op_fxch,
+    Op_fxch1,
+    Op_fxch0,
+    Op_SizedStack,
+    Op_bound,
+    Op_bswap,
+    Op_cmps,
+    Op_cmpsd,
+    Op_cmpsX,
+    Op_cmpxchg8b,
+    Op_cmpxchg,
+    Op_cpuid,
+    Op_enter,
+    Op_fdisi,
+    Op_feni,
+    Op_fsetpm,
+    Op_fXstsw,
+    Op_imul,
+    Op_imul2,
+    Op_imul1,
+    Op_in,
+    Op_ins,
+    Op_insX,
+    Op_iret,
+    Op_iretd,
+    Op_lods,
+    Op_lodsX,
+    Op_movs,
+    Op_movsd,
+    Op_movsX,
+    Op_movsx,
+    Op_movzx,
+    Op_mul,
+    Op_out,
+    Op_outs,
+    Op_outsX,
+    Op_push,
+    Op_ret,
+    Op_retf,
+    Op_scas,
+    Op_scasX,
+    Op_stos,
+    Op_stosX,
+    Op_xlat,
+    N_AsmOpInfo,
+    Op_Align,
+    Op_Even,
+    Op_Naked,
+    Op_db,
+    Op_ds,
+    Op_di,
+    Op_dl,
+    Op_df,
+    Op_dd,
+    Op_de
+} AsmOp;
+
+typedef enum {
+    Opr_None = 0,
+    OprC_MRI  = 1,
+    OprC_MR   = 2,
+    OprC_Mem  = 3,
+    OprC_Reg  = 4,
+    OprC_Imm  = 5,
+    OprC_SSE  = 6,
+    OprC_SSE_Mem = 7,
+    OprC_R32  = 8,
+    OprC_RWord = 9,
+    OprC_RFP   = 10,
+    OprC_AbsRel = 11,
+    OprC_Relative = 12,
+    OprC_Port = 13, // DX or imm
+    OprC_AX = 14, // AL,AX,EAX
+    OprC_DX = 15, // only DX
+    OprC_MMX = 16,
+    OprC_MMX_Mem = 17,
+    OprC_Shift = 18, // imm or CL
+    
+    Opr_ClassMask = 0x1f,
+    
+    Opr_Dest     = 0x20,
+    Opr_Update   = 0x60,
+    
+    Opr_NoType = 0x80,
+} OprVals;
+
+
+typedef struct {
+} AsmOprInfo;
+
+typedef unsigned char Opr;
+
+typedef struct {
+    Opr operands[3];
+    unsigned char
+	needsType : 3,
+	implicitClobbers : 8,
+        linkType : 2;
+    unsigned link;
+
+    /*
+    bool takesLabel() {
+	return operands[0] & Opr_Label;
+    }
+    */
+    
+    unsigned nOperands() {
+	if (!operands[0])
+	    return 0;
+	else if (!operands[1])
+	    return 1;
+	else if (!operands[2])
+	    return 2;
+	else
+	    return 3;
+    }
+} AsmOpInfo;
+
+typedef enum {
+    Mn_fdisi,
+    Mn_feni,
+    Mn_fsetpm,
+    Mn_iretw,
+    Mn_iret,
+    Mn_lret,
+    Mn_cmpxchg8b,
+    N_AltMn
+} Alternate_Mnemonics;
+
+static const char * alternateMnemonics[N_AltMn] = {
+    ".byte 0xdb, 0xe1",
+    ".byte 0xdb, 0xe0",
+    ".byte 0xdb, 0xe4",
+    "iretw",
+    "iret",
+    "lret",
+    "cmpxchg8b" };
+
+#define mri  OprC_MRI
+#define mr   OprC_MR
+#define mem  OprC_Mem
+// for now mfp=mem
+#define mfp  OprC_Mem
+#define reg  OprC_Reg
+#define imm  OprC_Imm
+#define sse  OprC_SSE
+#define ssem OprC_SSE_Mem
+#define mmx  OprC_MMX
+#define mmxm OprC_MMX_Mem
+#define r32  OprC_R32
+#define rw   OprC_RWord
+#define rfp  OprC_RFP
+#define port OprC_Port
+#define ax   OprC_AX
+#define dx   OprC_DX
+#define shft OprC_Shift
+#define D    Opr_Dest
+#define U    Opr_Update
+#define N    Opr_NoType
+//#define L    Opr_Label
+
+// D=dest, N=notype
+static AsmOpInfo asmOpInfo[N_AsmOpInfo] = {
+    /* Op_Invalid   */  {},
+    /* Op_Adjust    */  { 0,0,0,             0, Clb_EAX /*just AX*/ },
+    /* Op_Dst       */  { D|mr,  0,    0,    1  },
+    /* Op_Upd       */  { U|mr,  0,    0,    1  },
+    /* Op_DstW      */  { D|mr,  0,    0,    Word_Types  },
+    /* Op_DstF      */  { D|mr,  0,    0,    1, Clb_Flags },
+    /* Op_UpdF      */  { U|mr,  0,    0,    1, Clb_Flags },
+    /* Op_DstSrc    */  { D|mr,  mri,  0,/**/1  }, 
+    /* Op_DstSrcF   */  { D|mr,  mri,  0,/**/1, Clb_Flags }, 
+    /* Op_UpdSrcF   */  { U|mr,  mri,  0,/**/1, Clb_Flags }, 
+    /* Op_DstSrcFW  */  { D|mr,  mri,  0,/**/Word_Types, Clb_Flags }, 
+    /* Op_UpdSrcFW  */  { U|mr,  mri,  0,/**/Word_Types, Clb_Flags }, 
+    /* Op_DstSrcSSE */  { U|sse, ssem, 0     },  // some may not be update %%
+    /* Op_DstSrcMMX */  { U|mmx, mmxm, 0     },  // some may not be update %%
+    /* Op_DstSrcImmS*/  { U|sse, ssem, N|imm  }, // some may not be update %%
+    /* Op_DstSrcImmM*/  { U|mmx, mmxm, N|imm  }, // some may not be update %%
+    /* Op_UpdSrcShft*/  { U|mr,  reg,  N|shft, 1, Clb_Flags }, // 16/32 only
+    /* Op_DstSrcNT  */  { D|mr,  mr,   0,    0 }, // used for movd .. operands can be rm32,sse,mmx
+    /* Op_UpdSrcNT  */  { U|mr,  mr,   0,    0 }, // used for movd .. operands can be rm32,sse,mmx
+    /* Op_DstMemNT  */  { D|mem, 0,    0     },
+    /* Op_DstRMBNT  */  { D|mr,  0,    0,    Byte_NoType },
+    /* Op_DstRMWNT  */  { D|mr,  0,    0     },
+    /* Op_UpdUpd    */  { U|mr,U|mr,   0,/**/1  }, 
+    /* Op_UpdUpdF   */  { U|mr,U|mr,   0,/**/1, Clb_Flags }, 
+    /* Op_Src       */  {   mri, 0,    0,    1  },
+    /* Op_SrcRMWNT  */  {   mr,  0,    0,    0  },
+    /* Op_SrcW      */  {   mri, 0,    0,    Word_Types  },
+    /* Op_SrcImm    */  {   imm },
+    /* Op_Src_DXAXF */  {   mr,  0,    0,    1, Clb_SizeDXAX|Clb_Flags },
+    /* Op_SrcMemNT  */  {   mem, 0,    0     },
+    /* Op_SrcMemNTF */  {   mem, 0,    0,    0, Clb_Flags },
+    /* Op_SrcSrc    */  {   mr,  mri,  0,    1  },
+    /* Op_SrcSrcF   */  {   mr,  mri,  0,    1, Clb_Flags },
+    /* Op_SrcSrcFW  */  {   mr,  mri,  0,    Word_Types, Clb_Flags },
+    /* Op_SrcSrcSSEF*/  {   sse, ssem, 0,    0, Clb_Flags },
+    /* Op_SrcSrcMMX */  {   mmx, mmx,  0, },
+    /* Op_Shift     */  { D|mr,N|shft, 0,/**/1, Clb_Flags }, 
+    /* Op_Branch    */  {   mri },
+    /* Op_CBranch   */  {   imm },
+    /* Op_0         */  {   0,0,0 },
+    /* Op_0_AX      */  {   0,0,0,           0, Clb_SizeAX },
+    /* Op_0_DXAX    */  {   0,0,0,           0, Clb_SizeDXAX }, // but for cwd/cdq -- how do know the size..
+    /* Op_Loop      */  {   imm, 0,    0,    0, Clb_CX },
+    /* Op_Flags     */  {   0,0,0,           0, Clb_Flags },
+    /* Op_F0_ST     */  {   0,0,0,           0, Clb_ST },
+    /* Op_F0_P      */  {   0,0,0,           0, Clb_ST }, // push, pops, etc. not sure how to inform gcc..
+    /* Op_Fs_P      */  {   mem, 0,    0,    0, Clb_ST }, // "
+    /* Op_Fis       */  {   mem, 0,    0,    FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
+    /* Op_Fis_ST    */  {   mem, 0,    0,    FPInt_Types, Clb_ST }, // "
+    /* Op_Fis_P     */  {   mem, 0,    0,    FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 
+    /* Op_Fid       */  { D|mem, 0,    0,    FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
+    /* Op_Fid_P     */  { D|mem, 0,    0,    FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 
+    /* Op_Ffd       */  { D|mfp, 0,    0,    FP_Types, 0, Next_Form, Op_FfdR }, // only 16bit and 32bit, DMD defaults to 16bit, reg form doesn't need type
+    /* Op_FfdR      */  { D|rfp, 0,    0  }, 
+    /* Op_Ffd_P     */  { D|mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_FfdR_P, }, // pop, fld so also 80 bit, "
+    /* Op_FfdR_P    */  { D|rfp, 0,    0,    0,        Clb_ST },
+    /* Op_Fd_P      */  { D|mem, 0,    0,    0, Clb_ST }, // "
+    /* Op_FdST      */  { D|rfp, 0,    0  },
+    /* Op_FMath     */  {   mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_FdSTiSTi  }, // and only single or double prec
+    /* Op_FdSTiSTi  */  { D|rfp, rfp,  0, },
+    /* Op_FPMath    */  { D|rfp, rfp,  0,    0,        Clb_ST, Next_Form, Op_F0_P }, // pops
+    /* Op_FCmp      */  {   mfp, 0,    0,    FP_Types, 0,      Next_Form, Op_FCmp1 }, // DMD defaults to float ptr
+    /* Op_FCmp1     */  {   rfp, 0,    0,    0,        0,      Next_Form, Op_0 },
+    /* Op_FCmpP     */  {   mfp, 0,    0,    FP_Types, 0,      Next_Form, Op_FCmpP1 }, // pops
+    /* Op_FCmpP1    */  {   rfp, 0,    0,    0,        0,      Next_Form, Op_F0_P }, // pops
+    /* Op_FCmpFlg   */  {   rfp, rfp,  0,    0,        Clb_Flags },
+    /* Op_FCmpFlgP  */  {   rfp, rfp,  0,    0,        Clb_Flags }, // pops
+    /* Op_fld       */  {   mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_fldR },
+    /* Op_fldR      */  {   rfp, 0,    0,    0,        Clb_ST },
+    /* Op_fxch      */  { D|rfp,D|rfp, 0,    0,        Clb_ST, Next_Form, Op_fxch1 }, // not in intel manual?, but DMD allows it (gas won't), second arg must be ST
+    /* Op_fxch1     */  { D|rfp, 0,    0,    0,        Clb_ST, Next_Form, Op_fxch0 },
+    /* Op_fxch0     */  {   0,   0,    0,    0,        Clb_ST }, // Also clobbers ST(1)
+    /* Op_SizedStack*/  {   0,   0,    0,    0,        Clb_SP }, // type suffix special case
+    /* Op_bound     */  {   mr,  mri,  0,    Word_Types  }, // operands *not* reversed for gas
+    /* Op_bswap     */  { D|r32      },
+    /* Op_cmps      */  {   mem, mem, 0,     1, Clb_DI|Clb_SI|Clb_Flags },
+    /* Op_cmpsd     */  {   0,   0,   0,     0, Clb_DI|Clb_SI|Clb_Flags, Next_Form, Op_DstSrcImmS },
+    /* Op_cmpsX     */  {   0,   0,   0,     0, Clb_DI|Clb_SI|Clb_Flags },
+    /* Op_cmpxchg8b */  { D|mem/*64*/,0,0,   0, Clb_SizeDXAX/*32*/|Clb_Flags, Out_Mnemonic, Mn_cmpxchg8b },
+    /* Op_cmpxchg   */  { D|mr,  reg, 0,     1, Clb_SizeAX|Clb_Flags },
+    /* Op_cpuid     */  {   0,0,0 },    // Clobbers eax, ebx, ecx, and edx. Handled specially below.
+    /* Op_enter     */  {   imm, imm }, // operands *not* reversed for gas, %% inform gcc of EBP clobber?, 
+    /* Op_fdisi     */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_fdisi },
+    /* Op_feni      */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_feni },
+    /* Op_fsetpm    */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_fsetpm },
+    /* Op_fXstsw    */  { D|mr,  0,   0,     }, // ax is the only allowed register
+    /* Op_imul      */  { D|reg, mr,  imm,   1, Clb_Flags, Next_Form, Op_imul2 }, // 16/32 only
+    /* Op_imul2     */  { D|reg, mri, 0,     1, Clb_Flags, Next_Form, Op_imul1 }, // 16/32 only
+    /* Op_imul1     */  {   mr,  0,   0,     1, Clb_Flags|Clb_SizeDXAX },
+    /* Op_in        */  { D|ax,N|port,0,     1  },        
+    /* Op_ins       */  {   mem,N|dx, 0,     1, Clb_DI }, // can't override ES segment for this one
+    /* Op_insX      */  {   0,   0,   0,     0, Clb_DI }, // output segment overrides %% needs work
+    /* Op_iret      */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_iretw },
+    /* Op_iretd     */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_iret },
+    /* Op_lods      */  {   mem, 0,   0,     1, Clb_SI },
+    /* Op_lodsX     */  {   0,   0,   0,     0, Clb_SI },
+    /* Op_movs      */  {   mem, mem, 0,     1, Clb_DI|Clb_SI }, // only src/DS can be overridden
+    /* Op_movsd     */  {   0,   0,   0,     0, Clb_DI|Clb_SI, Next_Form, Op_DstSrcSSE }, // %% gas doesn't accept movsd .. has to movsl
+    /* Op_movsX     */  {   0,   0,   0,     0, Clb_DI|Clb_SI },
+    /* Op_movsx     */  { D|reg, mr,  0,     1 }, // type suffix is special case
+    /* Op_movzx     */  { D|reg, mr,  0,     1 }, // type suffix is special case
+    /* Op_mul       */  { U|ax,  mr,  0,     1, Clb_SizeDXAX|Clb_Flags, Next_Form, Op_Src_DXAXF },
+    /* Op_out       */  { N|port,ax,  0,     1  },        
+    /* Op_outs      */  { N|dx,  mem, 0,     1, Clb_SI },
+    /* Op_outsX     */  {   0,   0,   0,     0, Clb_SI },
+    /* Op_push      */  {   mri, 0,    0,    Word_Types, Clb_SP }, // would be Op_SrcW, but DMD defaults to 32-bit for immediate form
+    /* Op_ret       */  {   imm, 0,   0,     0, 0, Next_Form, Op_0  }, 
+    /* Op_retf      */  {   0,   0,   0,     0, 0, Out_Mnemonic, Mn_lret  },
+    /* Op_scas      */  {   mem, 0,   0,     1, Clb_DI|Clb_Flags },
+    /* Op_scasX     */  {   0,   0,   0,     0, Clb_DI|Clb_Flags },
+    /* Op_stos      */  {   mem, 0,   0,     1, Clb_DI },
+    /* Op_stosX     */  {   0,   0,   0,     0, Clb_DI },
+    /* Op_xlat      */  {   mem, 0,   0,     0, Clb_SizeAX }
+    
+    /// * Op_arpl      */  { D|mr,  reg }, // 16 only -> DstSrc
+    /// * Op_bsX       */  {   rw,  mrw,  0,    1, Clb_Flags },//->srcsrcf 
+    /// * Op_bt        */  {   mrw, riw,  0,    1, Clb_Flags },//->srcsrcf
+    /// * Op_btX       */  { D|mrw, riw,  0,    1, Clb_Flags },//->dstsrcf .. immediate does not contribute to size
+    /// * Op_cmovCC    */  { D|rw,  mrw,  0,    1 } // ->dstsrc
+};
+
+#undef mri
+#undef mr
+#undef mem
+#undef mfp
+#undef reg
+#undef imm
+#undef sse
+#undef ssem
+#undef mmx
+#undef mmxm
+#undef r32
+#undef rw
+#undef rfp
+#undef port
+#undef ax
+#undef dx
+#undef shft
+#undef D
+#undef U
+#undef N
+//#undef L
+
+typedef struct {
+    const char  * inMnemonic;
+    AsmOp   asmOp;
+} AsmOpEnt;
+
+/* Some opcodes which have data size restrictions, but we don't check
+
+   cmov, l<segreg> ?, lea, lsl, shld
+
+   todo: push <immediate> is always the 32-bit form, even tho push <mem> is 16-bit
+*/
+
+static AsmOpEnt opData[] = {
+    { "aaa",    Op_Adjust },
+    { "aad",    Op_Adjust },
+    { "aam",    Op_Adjust },
+    { "aas",    Op_Adjust },
+    { "adc",    Op_UpdSrcF },
+    { "add",    Op_UpdSrcF },
+    { "addpd",  Op_DstSrcSSE },
+    { "addps",  Op_DstSrcSSE },
+    { "addsd",  Op_DstSrcSSE },
+    { "addss",  Op_DstSrcSSE },
+    { "addsubpd", Op_DstSrcSSE },
+    { "addsubps", Op_DstSrcSSE },    
+    { "align",  Op_Align },
+    { "and",    Op_UpdSrcF },
+    { "andnpd", Op_DstSrcSSE },
+    { "andnps", Op_DstSrcSSE },
+    { "andpd",  Op_DstSrcSSE },
+    { "andps",  Op_DstSrcSSE },
+    { "arpl",   Op_UpdSrcNT },
+    { "bound",  Op_bound },
+    { "bsf",    Op_SrcSrcFW },
+    { "bsr",    Op_SrcSrcFW },
+    { "bswap",  Op_bswap },
+    { "bt",     Op_SrcSrcFW },
+    { "btc",    Op_UpdSrcFW },
+    { "btr",    Op_UpdSrcFW },
+    { "bts",    Op_UpdSrcFW },
+    { "call",   Op_Branch },
+    { "cbw",    Op_0_AX },
+    { "cdq",    Op_0_DXAX },
+    { "clc",    Op_Flags },
+    { "cld",    Op_Flags },
+    { "clflush",Op_SrcMemNT },
+    { "cli",    Op_Flags },
+    { "clts",   Op_0 },
+    { "cmc",    Op_Flags },
+    { "cmova",  Op_DstSrc },
+    { "cmovae", Op_DstSrc },
+    { "cmovb",  Op_DstSrc },
+    { "cmovbe", Op_DstSrc },
+    { "cmovc",  Op_DstSrc },
+    { "cmove",  Op_DstSrc },
+    { "cmovg",  Op_DstSrc },
+    { "cmovge", Op_DstSrc },
+    { "cmovl",  Op_DstSrc },
+    { "cmovle", Op_DstSrc },
+    { "cmovna", Op_DstSrc },
+    { "cmovnae",Op_DstSrc },
+    { "cmovnb", Op_DstSrc },
+    { "cmovnbe",Op_DstSrc },
+    { "cmovnc", Op_DstSrc },
+    { "cmovne", Op_DstSrc },
+    { "cmovng", Op_DstSrc },
+    { "cmovnge",Op_DstSrc },
+    { "cmovnl", Op_DstSrc },
+    { "cmovnle",Op_DstSrc },
+    { "cmovno", Op_DstSrc },
+    { "cmovnp", Op_DstSrc },
+    { "cmovns", Op_DstSrc },
+    { "cmovnz", Op_DstSrc },
+    { "cmovo",  Op_DstSrc },
+    { "cmovp",  Op_DstSrc },
+    { "cmovpe", Op_DstSrc },
+    { "cmovpo", Op_DstSrc },
+    { "cmovs",  Op_DstSrc },
+    { "cmovz",  Op_DstSrc },
+    { "cmp",    Op_SrcSrcF },
+    { "cmppd",  Op_DstSrcImmS },
+    { "cmpps",  Op_DstSrcImmS },
+    { "cmps",   Op_cmps  },
+    { "cmpsb",  Op_cmpsX },
+    { "cmpsd",  Op_cmpsd }, // string cmp, and SSE cmp
+    { "cmpss",  Op_DstSrcImmS },
+    { "cmpsw",  Op_cmpsX },
+    { "cmpxch8b", Op_cmpxchg8b }, // %% DMD opcode typo?
+    { "cmpxchg",  Op_cmpxchg },
+    { "comisd", Op_SrcSrcSSEF },
+    { "comiss", Op_SrcSrcSSEF },
+    { "cpuid",  Op_cpuid },
+    { "cvtdq2pd", Op_DstSrcSSE },
+    { "cvtdq2ps", Op_DstSrcSSE },
+    { "cvtpd2dq", Op_DstSrcSSE },
+    { "cvtpd2pi", Op_DstSrcSSE },
+    { "cvtpd2ps", Op_DstSrcSSE },
+    { "cvtpi2pd", Op_DstSrcSSE },
+    { "cvtpi2ps", Op_DstSrcSSE },
+    { "cvtps2dq", Op_DstSrcSSE },
+    { "cvtps2pd", Op_DstSrcSSE },
+    { "cvtps2pi", Op_DstSrcSSE },
+    { "cvtsd2si", Op_DstSrcSSE },
+    { "cvtsd2ss", Op_DstSrcSSE },
+    { "cvtsi2sd", Op_DstSrcSSE },
+    { "cvtsi2ss", Op_DstSrcSSE },
+    { "cvtss2sd", Op_DstSrcSSE },
+    { "cvtss2si", Op_DstSrcSSE },
+    { "cvttpd2dq", Op_DstSrcSSE },
+    { "cvttpd2pi", Op_DstSrcSSE },
+    { "cvttps2dq", Op_DstSrcSSE },
+    { "cvttps2pi", Op_DstSrcSSE },
+    { "cvttsd2si", Op_DstSrcSSE },
+    { "cvttss2si", Op_DstSrcSSE },
+    { "cwd",  Op_0_DXAX },
+    { "cwde", Op_0_AX },
+    //{ "da", Op_ },// dunno what this is -- takes labels?
+    { "daa",   Op_Adjust },
+    { "das",   Op_Adjust },    
+    { "db",    Op_db },
+    { "dd",    Op_dd },
+    { "de",    Op_de },
+    { "dec",   Op_UpdF },
+    { "df",    Op_df },
+    { "di",    Op_di },
+    { "div",   Op_Src_DXAXF },
+    { "divpd", Op_DstSrcSSE },
+    { "divps", Op_DstSrcSSE },
+    { "divsd", Op_DstSrcSSE },
+    { "divss", Op_DstSrcSSE },
+    { "dl",    Op_dl },
+    { "dq",    Op_dl },
+    { "ds",    Op_ds },
+    { "dt",    Op_de },
+    { "dw",    Op_ds },
+    { "emms",  Op_0 }, // clobber all mmx/fp?
+    { "enter", Op_enter },
+    { "even",  Op_Even },
+    { "f2xm1",  Op_F0_ST }, // %% most of these are update...
+    { "fabs",   Op_F0_ST },
+    { "fadd",   Op_FMath },
+    { "faddp",  Op_FPMath },
+    { "fbld",   Op_Fs_P },
+    { "fbstp",  Op_Fd_P },
+    { "fchs",   Op_F0_ST },
+    { "fclex",  Op_0 },
+    { "fcmovb",   Op_FdSTiSTi }, // but only ST(0) can be the destination -- should be FdST0STi
+    { "fcmovbe",  Op_FdSTiSTi },
+    { "fcmove",   Op_FdSTiSTi },
+    { "fcmovnb",  Op_FdSTiSTi },
+    { "fcmovnbe", Op_FdSTiSTi },
+    { "fcmovne",  Op_FdSTiSTi },
+    { "fcmovnu",  Op_FdSTiSTi },
+    { "fcmovu",   Op_FdSTiSTi },
+    { "fcom",   Op_FCmp },
+    { "fcomi",  Op_FCmpFlg  }, 
+    { "fcomip", Op_FCmpFlgP },
+    { "fcomp",  Op_FCmpP },
+    { "fcompp", Op_F0_P },   // pops twice
+    { "fcos",   Op_F0_ST }, 
+    { "fdecstp",Op_F0_P },   // changes stack
+    { "fdisi",  Op_fdisi },
+    { "fdiv",   Op_FMath },
+    { "fdivp",  Op_FPMath }, 
+    { "fdivr",  Op_FMath },
+    { "fdivrp", Op_FPMath },
+    { "feni",   Op_feni },
+    { "ffree",  Op_FdST },
+    { "fiadd",  Op_Fis_ST },
+    { "ficom",  Op_Fis   },
+    { "ficomp", Op_Fis_P },
+    { "fidiv",  Op_Fis_ST },
+    { "fidivr", Op_Fis_ST },
+    { "fild",   Op_Fis_P },
+    { "fimul",  Op_Fis_ST },
+    { "fincstp",Op_F0_P },
+    { "finit",  Op_F0_P },
+    { "fist",   Op_Fid }, // only 16,32bit
+    { "fistp",  Op_Fid_P }, 
+    { "fisttp", Op_Fid_P }, 
+    { "fisub",  Op_Fis_ST },
+    { "fisubr", Op_Fis_ST },
+    { "fld",    Op_fld },
+    { "fld1",   Op_F0_P },
+    { "fldcw",  Op_SrcMemNT },
+    { "fldenv", Op_SrcMemNT },
+    { "fldl2e", Op_F0_P },
+    { "fldl2t", Op_F0_P },
+    { "fldlg2", Op_F0_P },
+    { "fldln2", Op_F0_P },
+    { "fldpi",  Op_F0_P },
+    { "fldz",   Op_F0_P },
+    { "fmul",   Op_FMath },
+    { "fmulp",  Op_FPMath },
+    { "fnclex", Op_0 },
+    { "fndisi", Op_fdisi }, // ??
+    { "fneni",  Op_feni }, // ??
+    { "fninit", Op_0 },
+    { "fnop",   Op_0 },
+    { "fnsave", Op_DstMemNT },
+    { "fnstcw", Op_DstMemNT },
+    { "fnstenv",Op_DstMemNT },
+    { "fnstsw", Op_fXstsw },
+    { "fpatan", Op_F0_P }, // pop and modify new ST
+    { "fprem",  Op_F0_ST }, 
+    { "fprem1", Op_F0_ST }, 
+    { "fptan",  Op_F0_P }, // modify ST and push 1.0
+    { "frndint",Op_F0_ST }, 
+    { "frstor", Op_SrcMemNT }, // but clobbers everything
+    { "fsave",  Op_DstMemNT },
+    { "fscale", Op_F0_ST },
+    { "fsetpm", Op_fsetpm },
+    { "fsin",   Op_F0_ST },
+    { "fsincos",Op_F0_P },
+    { "fsqrt",  Op_F0_ST },
+    { "fst",    Op_Ffd },
+    { "fstcw",  Op_DstMemNT },
+    { "fstenv", Op_DstMemNT },
+    { "fstp",   Op_Ffd_P },
+    { "fstsw",  Op_fXstsw },
+    { "fsub",   Op_FMath },
+    { "fsubp",  Op_FPMath },
+    { "fsubr",  Op_FMath },
+    { "fsubrp", Op_FPMath },
+    { "ftst",   Op_0 },
+    { "fucom",  Op_FCmp },
+    { "fucomi", Op_FCmpFlg },
+    { "fucomip",Op_FCmpFlgP },
+    { "fucomp", Op_FCmpP },
+    { "fucompp",Op_F0_P }, // pops twice
+    { "fwait",  Op_0 },
+    { "fxam",   Op_0 },
+    { "fxch",   Op_fxch },
+    { "fxrstor",Op_SrcMemNT },  // clobbers FP,MMX,SSE
+    { "fxsave", Op_DstMemNT },
+    { "fxtract",Op_F0_P }, // pushes
+    { "fyl2x",  Op_F0_P }, // pops
+    { "fyl2xp1",Op_F0_P }, // pops
+    { "haddpd", Op_DstSrcSSE },
+    { "haddps", Op_DstSrcSSE },
+    { "hlt",  Op_0 },
+    { "hsubpd", Op_DstSrcSSE },
+    { "hsubps", Op_DstSrcSSE },
+    { "idiv", Op_Src_DXAXF },
+    { "imul", Op_imul },
+    { "in",   Op_in },
+    { "inc",  Op_UpdF },
+    { "ins",  Op_ins },
+    { "insb", Op_insX },
+    { "insd", Op_insX },
+    { "insw", Op_insX },
+    { "int",  Op_SrcImm },
+    { "into", Op_0 },
+    { "invd", Op_0 },
+    { "invlpg", Op_SrcMemNT },
+    { "iret",  Op_iret },
+    { "iretd", Op_iretd },    
+    { "ja",    Op_CBranch },
+    { "jae",   Op_CBranch },
+    { "jb",    Op_CBranch },
+    { "jbe",   Op_CBranch },
+    { "jc",    Op_CBranch },
+    { "jcxz",  Op_CBranch },
+    { "je",    Op_CBranch },
+    { "jecxz", Op_CBranch },
+    { "jg",    Op_CBranch },
+    { "jge",   Op_CBranch },
+    { "jl",    Op_CBranch },
+    { "jle",   Op_CBranch },
+    { "jmp",   Op_Branch },
+    { "jna",   Op_CBranch },
+    { "jnae",  Op_CBranch },
+    { "jnb",   Op_CBranch },
+    { "jnbe",  Op_CBranch },
+    { "jnc",   Op_CBranch },
+    { "jne",   Op_CBranch },
+    { "jng",   Op_CBranch },
+    { "jnge",  Op_CBranch },
+    { "jnl",   Op_CBranch },
+    { "jnle",  Op_CBranch },
+    { "jno",   Op_CBranch },
+    { "jnp",   Op_CBranch },
+    { "jns",   Op_CBranch },
+    { "jnz",   Op_CBranch },
+    { "jo",    Op_CBranch },
+    { "jp",    Op_CBranch },
+    { "jpe",   Op_CBranch },
+    { "jpo",   Op_CBranch },
+    { "js",    Op_CBranch },
+    { "jz",    Op_CBranch },
+    { "lahf",  Op_0_AX },
+    { "lar",   Op_DstSrcFW }, // reg dest only
+    { "lddqu", Op_DstSrcSSE },
+    { "ldmxcsr", Op_SrcMemNT },
+    { "lds",   Op_DstSrc },  // reg dest only
+    { "lea",   Op_DstSrc },  // "
+    { "leave", Op_0 },       // EBP,ESP clobbers
+    { "les",   Op_DstSrc },
+    { "lfence",Op_0 },
+    { "lfs",   Op_DstSrc },
+    { "lgdt",  Op_SrcMemNT },
+    { "lgs",   Op_DstSrc },
+    { "lidt",  Op_SrcMemNT },
+    { "lldt",  Op_SrcRMWNT },
+    { "lmsw",  Op_SrcRMWNT },
+    { "lock",  Op_0 },
+    { "lods",  Op_lods },
+    { "lodsb", Op_lodsX },
+    { "lodsd", Op_lodsX },
+    { "lodsw", Op_lodsX },
+    { "loop",  Op_Loop },
+    { "loope", Op_Loop },
+    { "loopne",Op_Loop },
+    { "loopnz",Op_Loop },
+    { "loopz", Op_Loop },
+    { "lsl",   Op_DstSrcFW }, // reg dest only
+    { "lss",   Op_DstSrc },
+    { "ltr",   Op_DstMemNT },
+    { "maskmovdqu", Op_SrcSrcMMX }, // writes to [edi]
+    { "maskmovq",   Op_SrcSrcMMX }, 
+    { "maxpd", Op_DstSrcSSE },
+    { "maxps", Op_DstSrcSSE },
+    { "maxsd", Op_DstSrcSSE },
+    { "maxss", Op_DstSrcSSE },
+    { "mfence",Op_0},
+    { "minpd", Op_DstSrcSSE },
+    { "minps", Op_DstSrcSSE },
+    { "minsd", Op_DstSrcSSE },
+    { "minss", Op_DstSrcSSE },
+    { "monitor", Op_0 },
+    { "mov",   Op_DstSrc },
+    { "movapd",  Op_DstSrcSSE },
+    { "movaps",  Op_DstSrcSSE },
+    { "movd",    Op_DstSrcNT  }, // also mmx and sse
+    { "movddup", Op_DstSrcSSE },
+    { "movdq2q", Op_DstSrcNT }, // mmx/sse
+    { "movdqa",  Op_DstSrcSSE },
+    { "movdqu",  Op_DstSrcSSE },
+    { "movhlps", Op_DstSrcSSE },
+    { "movhpd",  Op_DstSrcSSE },
+    { "movhps",  Op_DstSrcSSE },
+    { "movlhps", Op_DstSrcSSE },
+    { "movlpd",  Op_DstSrcSSE },
+    { "movlps",  Op_DstSrcSSE },
+    { "movmskpd",Op_DstSrcSSE },
+    { "movmskps",Op_DstSrcSSE },
+    { "movntdq", Op_DstSrcNT  }, // limited to sse, but mem dest
+    { "movnti",  Op_DstSrcNT  }, // limited to gpr, but mem dest
+    { "movntpd", Op_DstSrcNT  }, // limited to sse, but mem dest
+    { "movntps", Op_DstSrcNT  }, // limited to sse, but mem dest
+    { "movntq",  Op_DstSrcNT  }, // limited to mmx, but mem dest
+    { "movq",    Op_DstSrcNT  }, // limited to sse and mmx
+    { "movq2dq", Op_DstSrcNT  }, // limited to sse <- mmx regs
+    { "movs",  Op_movs },
+    { "movsb", Op_movsX },
+    { "movsd", Op_movsd },
+    { "movshdup", Op_DstSrcSSE },
+    { "movsldup", Op_DstSrcSSE },
+    { "movss", Op_DstSrcSSE },
+    { "movsw", Op_movsX },
+    { "movsx", Op_movsx }, // word-only, reg dest
+    { "movupd",Op_DstSrcSSE },
+    { "movups",Op_DstSrcSSE },
+    { "movzx", Op_movzx },
+    { "mul",   Op_mul },
+    { "mulpd", Op_DstSrcSSE },
+    { "mulps", Op_DstSrcSSE },
+    { "mulsd", Op_DstSrcSSE },
+    { "mulss", Op_DstSrcSSE },
+    { "mwait", Op_0 },
+    { "naked", Op_Naked },
+    { "neg",   Op_UpdF },
+    { "nop",   Op_0 },
+    { "not",   Op_Upd },
+    { "or",    Op_UpdSrcF },
+    { "orpd",  Op_DstSrcSSE },
+    { "orps",  Op_DstSrcSSE },
+    { "out",   Op_out },
+    { "outs",  Op_outs },
+    { "outsb", Op_outsX },
+    { "outsd", Op_outsX },
+    { "outsw", Op_outsX },
+    { "packssdw", Op_DstSrcMMX }, // %% also SSE
+    { "packsswb", Op_DstSrcMMX },
+    { "packuswb", Op_DstSrcMMX },
+    { "paddb",    Op_DstSrcMMX },
+    { "paddd",    Op_DstSrcMMX },
+    { "paddq",    Op_DstSrcMMX },
+    { "paddsb",   Op_DstSrcMMX },
+    { "paddsw",   Op_DstSrcMMX },
+    { "paddusb",  Op_DstSrcMMX },
+    { "paddusw",  Op_DstSrcMMX },
+    { "paddw",    Op_DstSrcMMX },
+    { "pand",     Op_DstSrcMMX },
+    { "pandn",    Op_DstSrcMMX },
+    { "pavgb",    Op_DstSrcMMX },
+    { "pavgw",    Op_DstSrcMMX },
+    { "pcmpeqb",  Op_DstSrcMMX },
+    { "pcmpeqd",  Op_DstSrcMMX },
+    { "pcmpeqw",  Op_DstSrcMMX },
+    { "pcmpgtb",  Op_DstSrcMMX },
+    { "pcmpgtd",  Op_DstSrcMMX },
+    { "pcmpgtw",  Op_DstSrcMMX },
+    { "pextrw",   Op_DstSrcImmM }, // gpr32 dest
+    { "pinsrw",   Op_DstSrcImmM }, // gpr32(16), mem16 src, sse too
+    { "pmaddwd",  Op_DstSrcMMX },
+    { "pmaxsw",   Op_DstSrcMMX },
+    { "pmaxub",   Op_DstSrcMMX },
+    { "pminsw",   Op_DstSrcMMX },
+    { "pminub",   Op_DstSrcMMX },
+    { "pmovmskb", Op_DstSrcMMX },
+    { "pmulhuw",  Op_DstSrcMMX },
+    { "pmulhw",   Op_DstSrcMMX },
+    { "pmullw",   Op_DstSrcMMX },
+    { "pmuludq",  Op_DstSrcMMX }, // also sse
+    { "pop",      Op_DstW },
+    { "popa",     Op_SizedStack },  // For intel this is always 16-bit
+    { "popad",    Op_SizedStack },  // GAS doesn't accept 'popad' -- these clobber everything, but supposedly it would be used to preserve clobbered regs
+    { "popf",     Op_SizedStack },  // rewrite the insn with a special case
+    { "popfd",    Op_SizedStack }, 
+    { "por",      Op_DstSrcMMX },
+    { "prefetchnta", Op_SrcMemNT },
+    { "prefetcht0",  Op_SrcMemNT },
+    { "prefetcht1",  Op_SrcMemNT },
+    { "prefetcht2",  Op_SrcMemNT },
+    { "psadbw",   Op_DstSrcMMX },
+    { "pshufd",   Op_DstSrcImmM },
+    { "pshufhw",  Op_DstSrcImmM },
+    { "pshuflw",  Op_DstSrcImmM },
+    { "pshufw",   Op_DstSrcImmM },
+    { "pslld",    Op_DstSrcMMX }, // immediate operands...
+    { "pslldq",   Op_DstSrcMMX },
+    { "psllq",    Op_DstSrcMMX },
+    { "psllw",    Op_DstSrcMMX },
+    { "psrad",    Op_DstSrcMMX },
+    { "psraw",    Op_DstSrcMMX },
+    { "psrld",    Op_DstSrcMMX },
+    { "psrldq",   Op_DstSrcMMX },
+    { "psrlq",    Op_DstSrcMMX },
+    { "psrlw",    Op_DstSrcMMX },
+    { "psubb",    Op_DstSrcMMX },
+    { "psubd",    Op_DstSrcMMX },
+    { "psubq",    Op_DstSrcMMX },
+    { "psubsb",   Op_DstSrcMMX },
+    { "psubsw",   Op_DstSrcMMX },
+    { "psubusb",  Op_DstSrcMMX },
+    { "psubusw",  Op_DstSrcMMX },
+    { "psubw",    Op_DstSrcMMX },
+    { "punpckhbw", Op_DstSrcMMX },
+    { "punpckhdq", Op_DstSrcMMX },
+    { "punpckhqdq",Op_DstSrcMMX },
+    { "punpckhwd", Op_DstSrcMMX },
+    { "punpcklbw", Op_DstSrcMMX },
+    { "punpckldq", Op_DstSrcMMX },
+    { "punpcklqdq",Op_DstSrcMMX },
+    { "punpcklwd", Op_DstSrcMMX },
+    { "push",   Op_push },
+    { "pusha",  Op_SizedStack },
+    { "pushad", Op_SizedStack },
+    { "pushf",  Op_SizedStack },
+    { "pushfd", Op_SizedStack },
+    { "pxor",   Op_DstSrcMMX },
+    { "rcl",    Op_Shift }, // limited src operands -- change to shift
+    { "rcpps",  Op_DstSrcSSE },
+    { "rcpss",  Op_DstSrcSSE },
+    { "rcr",    Op_Shift },
+    { "rdmsr",  Op_0_DXAX },
+    { "rdpmc",  Op_0_DXAX },
+    { "rdtsc",  Op_0_DXAX },
+    { "rep",    Op_0 },
+    { "repe",   Op_0 },
+    { "repne",  Op_0 },
+    { "repnz",  Op_0 },
+    { "repz",   Op_0 },
+    { "ret",    Op_ret },
+    { "retf",   Op_retf },
+    { "rol",    Op_Shift },
+    { "ror",    Op_Shift },
+    { "rsm",    Op_0 },
+    { "rsqrtps", Op_DstSrcSSE },
+    { "rsqrtss", Op_DstSrcSSE },
+    { "sahf",   Op_Flags },
+    { "sal",    Op_Shift },
+    { "sar",    Op_Shift },
+    { "sbb",    Op_UpdSrcF },
+    { "scas",   Op_scas },
+    { "scasb",  Op_scasX },
+    { "scasd",  Op_scasX },
+    { "scasw",  Op_scasX },
+    { "seta",   Op_DstRMBNT }, // also gpr8
+    { "setae",  Op_DstRMBNT },
+    { "setb",   Op_DstRMBNT },
+    { "setbe",  Op_DstRMBNT },
+    { "setc",   Op_DstRMBNT },
+    { "sete",   Op_DstRMBNT },
+    { "setg",   Op_DstRMBNT },
+    { "setge",  Op_DstRMBNT },
+    { "setl",   Op_DstRMBNT },
+    { "setle",  Op_DstRMBNT },
+    { "setna",  Op_DstRMBNT },
+    { "setnae", Op_DstRMBNT },
+    { "setnb",  Op_DstRMBNT },
+    { "setnbe", Op_DstRMBNT },
+    { "setnc",  Op_DstRMBNT },
+    { "setne",  Op_DstRMBNT },
+    { "setng",  Op_DstRMBNT },
+    { "setnge", Op_DstRMBNT },
+    { "setnl",  Op_DstRMBNT },
+    { "setnle", Op_DstRMBNT },
+    { "setno",  Op_DstRMBNT },
+    { "setnp",  Op_DstRMBNT },
+    { "setns",  Op_DstRMBNT },
+    { "setnz",  Op_DstRMBNT },
+    { "seto",   Op_DstRMBNT },
+    { "setp",   Op_DstRMBNT },
+    { "setpe",  Op_DstRMBNT },
+    { "setpo",  Op_DstRMBNT },
+    { "sets",   Op_DstRMBNT },
+    { "setz",   Op_DstRMBNT },
+    { "sfence", Op_0 },
+    { "sgdt",   Op_DstMemNT },
+    { "shl",    Op_Shift },
+    { "shld",   Op_UpdSrcShft },
+    { "shr",    Op_Shift },
+    { "shrd",   Op_UpdSrcShft },
+    { "shufpd", Op_DstSrcImmS },
+    { "shufps", Op_DstSrcImmS },
+    { "sidt",   Op_DstMemNT },
+    { "sldt",   Op_DstRMWNT },
+    { "smsw",   Op_DstRMWNT },
+    { "sqrtpd", Op_DstSrcSSE },
+    { "sqrtps", Op_DstSrcSSE },
+    { "sqrtsd", Op_DstSrcSSE },
+    { "sqrtss", Op_DstSrcSSE },
+    { "stc",    Op_Flags },
+    { "std",    Op_Flags },
+    { "sti",    Op_Flags },
+    { "stmxcsr",Op_DstMemNT },
+    { "stos",   Op_stos },
+    { "stosb",  Op_stosX },
+    { "stosd",  Op_stosX },
+    { "stosw",  Op_stosX },
+    { "str",    Op_DstMemNT }, // also r16
+    { "sub",    Op_UpdSrcF },
+    { "subpd",  Op_DstSrcSSE },
+    { "subps",  Op_DstSrcSSE },
+    { "subsd",  Op_DstSrcSSE },
+    { "subss",  Op_DstSrcSSE },
+    { "sysenter",Op_0 },
+    { "sysexit", Op_0 },
+    { "test",    Op_SrcSrcF },
+    { "ucomisd", Op_SrcSrcSSEF },
+    { "ucomiss", Op_SrcSrcSSEF },
+    { "ud2",     Op_0 },
+    { "unpckhpd", Op_DstSrcSSE },
+    { "unpckhps", Op_DstSrcSSE },
+    { "unpcklpd", Op_DstSrcSSE },
+    { "unpcklps", Op_DstSrcSSE },
+    { "verr",   Op_SrcMemNTF },
+    { "verw",   Op_SrcMemNTF },
+    { "wait",   Op_0 },
+    { "wbinvd", Op_0 },
+    { "wrmsr",  Op_0 },
+    { "xadd",   Op_UpdUpdF },
+    { "xchg",   Op_UpdUpd },
+    { "xlat",   Op_xlat },
+    { "xlatb",  Op_0_AX },
+    { "xor",    Op_DstSrcF },
+    { "xorpd",  Op_DstSrcSSE },
+    { "xorps",  Op_DstSrcSSE },
+};
+
+typedef enum {
+    Default_Ptr = 0,
+    Byte_Ptr = 1,
+    Short_Ptr = 2,
+    Int_Ptr = 4,
+    QWord_Ptr =  8,
+    Float_Ptr = 4,
+    Double_Ptr = 8,
+    Extended_Ptr = 10,
+    Near_Ptr = 98,
+    Far_Ptr = 99,
+    N_PtrTypes
+} PtrType;
+
+static const int N_PtrNames = 8;
+static const char * ptrTypeNameTable[N_PtrNames] = {
+    "word", "dword", "qword",
+    "float", "double", "extended",
+    "near",  "far"
+};
+
+static Identifier * ptrTypeIdentTable[N_PtrNames];
+static PtrType ptrTypeValueTable[N_PtrNames] = {
+    Short_Ptr, Int_Ptr, QWord_Ptr,
+    Float_Ptr, Double_Ptr, Extended_Ptr,
+    Near_Ptr, Far_Ptr
+};
+
+typedef enum {
+    Opr_Invalid,
+    Opr_Immediate,
+    Opr_Reg,
+    Opr_Mem
+} OperandClass;
+
+/* kill inlining if we reference a local? */
+
+/* DMD seems to allow only one 'symbol' per operand .. include __LOCAL_SIZE */
+
+/* DMD offset usage: <parm>[<reg>] seems to always be relative to EBP+8 .. even
+   if naked.. */
+
+// mov eax, 4
+// mov eax, fs:4
+// -- have to assume we know wheter or not to use '$'
+
+static Token eof_tok;
+static Expression * Handled;
+static Identifier * ident_seg;
+
+struct AsmProcessor
+{
+    typedef struct {
+	int inBracket;
+	int hasBracket;
+	int hasNumber;
+	int isOffset;
+
+	Reg segmentPrefix;
+	Reg reg;
+	sinteger_t constDisplacement; // use to build up.. should be int constant in the end..
+	Array      symbolDisplacement; // array of expressions or..
+	Reg baseReg;
+	Reg indexReg;
+	int scale;
+	
+	OperandClass cls;
+	PtrType dataSize;
+	PtrType dataSizeHint; // DMD can use the type of a referenced variable
+    } Operand;
+
+    static const unsigned Max_Operands = 3;
+
+    AsmStatement * stmt;
+    Scope * sc;
+
+    Token * token;
+    OutBuffer * insnTemplate;
+
+    AsmOp       op;
+    AsmOpInfo * opInfo;
+    Operand operands[Max_Operands];
+    Identifier * opIdent;
+    Operand * operand;
+
+    AsmProcessor(Scope * sc, AsmStatement * stmt)
+    {
+	this->sc = sc;
+	this->stmt = stmt;
+	token = stmt->tokens;
+	insnTemplate = new OutBuffer;
+
+	opInfo = NULL;
+
+	if ( ! regInfo[0].ident ) {
+	    char buf[8], *p;
+	    
+	    for (int i = 0; i < N_Regs; i++) {
+		strncpy(buf, regInfo[i].name, sizeof(buf) - 1);
+		for (p = buf; *p; p++)
+		    *p = std::tolower(*p);
+		regInfo[i].gccName = std::string(buf, p - buf);
+		if ( (i <= Reg_ST || i > Reg_ST7) && i != Reg_EFLAGS )
+		    regInfo[i].ident = Lexer::idPool(regInfo[i].name);
+	    }
+
+	    for (int i = 0; i < N_PtrNames; i++)
+		ptrTypeIdentTable[i] = Lexer::idPool(ptrTypeNameTable[i]);
+
+	    Handled = new Expression(0, TOKvoid, sizeof(Expression));
+
+	    ident_seg = Lexer::idPool("seg");
+	
+	    eof_tok.value = TOKeof; 
+	    eof_tok.next = 0;
+	}
+    }
+
+    void run()
+    {
+	parse();
+    }
+
+    void nextToken() {
+	if (token->next)
+	    token = token->next;
+	else
+	    token = & eof_tok;
+    }
+
+    Token * peekToken() {
+	if (token->next)
+	    return token->next;
+	else
+	    return & eof_tok;
+    }
+
+    void expectEnd() {
+	if (token->value != TOKeof)
+	    stmt->error("expected end of statement"); // %% extra at end...
+    }
+
+    void parse() {
+	op = parseOpcode();
+	
+	switch (op) {
+	case Op_Align:
+	    doAlign();
+	    expectEnd();
+	    break;
+	case Op_Even:
+	    doEven();
+	    expectEnd();
+	    break;
+	case Op_Naked:
+	    doNaked();
+	    expectEnd();
+	    break;
+	case Op_Invalid:
+	    break;
+	default:
+	    if (op >= Op_db && op <= Op_de)
+		doData();
+	    else
+		doInstruction();
+	}
+    }
+
+    AsmOp parseOpcode() {
+	static const int N_ents = sizeof(opData)/sizeof(AsmOpEnt);
+
+	switch (token->value) {
+	case TOKalign:
+	    nextToken();
+	    return Op_Align;
+	case TOKin:
+	    nextToken();
+	    opIdent = Id::___in;
+	    return Op_in;
+        case TOKint32: // "int"
+            nextToken();
+            opIdent = Id::__int;
+            return Op_SrcImm;
+	case TOKout:
+	    nextToken();
+	    opIdent = Id::___out;
+	    return Op_out;
+	case TOKidentifier:
+	    // search for mnemonic below
+	    break;
+	default:
+	    stmt->error("expected opcode");
+	    return Op_Invalid;
+	}
+
+	opIdent = token->ident;
+	const char * opcode = token->ident->string;
+
+	nextToken();
+
+	// %% okay to use bsearch?
+	int i = 0, j = N_ents, k, l;
+	do {
+	    k = (i + j) / 2;
+	    l = strcmp(opcode, opData[k].inMnemonic);
+	    if (! l)
+		return opData[k].asmOp;
+	    else if (l < 0)
+		j = k;
+	    else
+		i = k + 1;
+	} while (i != j);
+
+	stmt->error("unknown opcode '%s'", opcode);
+	
+	return Op_Invalid;
+    }
+
+    // need clobber information.. use information is good too...
+    void doInstruction() {
+	bool ok = true;
+	unsigned operand_i = 0;
+	
+	opInfo = & asmOpInfo[op];
+	memset(operands, 0, sizeof(operands));
+
+	while (token->value != TOKeof) {
+	    if (operand_i < Max_Operands) {
+		operand = & operands[operand_i];
+		operand->reg = operand->baseReg = operand->indexReg =
+		    operand->segmentPrefix = Reg_Invalid;
+		parseOperand();
+		operand_i++;
+	    } else {
+		ok = false;
+		stmt->error("too many operands for instruction");
+		break;
+	    }
+
+	    if (token->value == TOKcomma)
+		nextToken();
+	    else if (token->value != TOKeof) {
+		ok = false;
+		stmt->error("expected comma after operand");
+		return;
+	    }
+	}
+// 	if (operand_i < opInfo->minOperands) {
+// 	    ok = false;
+// 	    stmt->error("too few operands for instruction");
+// 	}
+
+	if ( matchOperands(operand_i) ) {
+	    AsmCode * asmcode = new AsmCode(N_Regs);
+
+	    if (formatInstruction(operand_i, asmcode))
+		stmt->asmcode = (code *) asmcode;
+	}
+    }
+
+    void setAsmCode() {
+	AsmCode * asmcode = new AsmCode(N_Regs);
+	asmcode->insnTemplateLen = insnTemplate->offset;
+	asmcode->insnTemplate = (char*) insnTemplate->extractData();
+	stmt->asmcode = (code*) asmcode;
+    }
+
+    // note: doesn't update AsmOp op
+    bool matchOperands(unsigned nOperands) {
+	bool wrong_number = true;
+
+	for (unsigned i = 0; i < nOperands; i++)
+	    classifyOperand(& operands[i]);
+	
+	while (1) {
+	    if (nOperands == opInfo->nOperands()) {
+		wrong_number = false;
+		/*  Cases in which number of operands is not
+		    enough for a match: Op_FCmp/Op_FCmp1,
+		    Op_FCmpP/Op_FCmpP1 */
+		for (unsigned i = 0; i < nOperands; i++) {
+		    Operand * operand = & operands[i];
+		    
+		    switch (opInfo->operands[i] & Opr_ClassMask) {
+		    case OprC_Mem: // no FPMem currently
+			if (operand->cls != Opr_Mem)
+			    goto no_match;
+			break;
+		    case OprC_RFP:
+			if (! (operand->reg >= Reg_ST && operand->reg <= Reg_ST7))
+			    goto no_match;
+			break;
+		    default:
+			break;
+		    }
+		}
+
+		return true;
+	    }
+	    no_match:
+	    if (opInfo->linkType == Next_Form)
+		opInfo = & asmOpInfo[ op = (AsmOp) opInfo->link ];
+	    else
+		break;
+	}
+	if (wrong_number)
+	    stmt->error("wrong number of operands");
+	else
+	    stmt->error("wrong operand types");
+	return false;
+    }
+
+    void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
+	insnTemplate->writestring((char*) fmt);
+	insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
+	asmcode->args.push( new AsmArg(type, e, mode) );
+    }
+    void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
+    insnTemplate->writestring((char*) fmtpre);
+    insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
+    insnTemplate->writestring((char*) fmtpost);
+    asmcode->args.push( new AsmArg(type, e, mode) );
+    }
+
+    void addLabel(char* id) {
+    insnTemplate->writestring(sc->func->mangle());
+    insnTemplate->writestring("_");
+    insnTemplate->writestring(id);
+    }
+
+    /* Determines whether the operand is a register, memory reference
+       or immediate.  Immediate addresses are currently classified as
+       memory.  This function is called before the exact instructions
+       is known and thus, should not use opInfo. */
+    void classifyOperand(Operand * operand) {
+	operand->cls = classifyOperand1(operand);
+    }
+    
+    OperandClass classifyOperand1(Operand * operand) {
+	bool is_localsize = false;
+	bool really_have_symbol = false;
+
+	if (operand->symbolDisplacement.dim) {
+	    is_localsize = isLocalSize( (Expression *) operand->symbolDisplacement.data[0] );
+	    really_have_symbol = ! is_localsize;
+	}
+
+	if (operand->isOffset && ! operand->hasBracket)
+	    return Opr_Immediate;
+	
+	if (operand->hasBracket || really_have_symbol) { // %% redo for 'offset' function
+	    if (operand->reg != Reg_Invalid) {
+		invalidExpression();
+		return Opr_Invalid;
+	    }
+
+	    return Opr_Mem;
+	}
+
+	if (operand->reg != Reg_Invalid && operand->constDisplacement != 0) {
+	    invalidExpression();
+	    return Opr_Invalid;
+	}
+	
+	if (operand->segmentPrefix != Reg_Invalid) {
+	    if (operand->reg != Reg_Invalid) {
+		invalidExpression();
+		return Opr_Invalid;
+	    }
+
+	    return Opr_Mem;
+	}
+
+	if (operand->reg != Reg_Invalid && ! operand->hasNumber)
+	    return Opr_Reg;
+
+	// should check immediate given (operand->hasNumber);
+	//
+	if (operand->hasNumber || is_localsize) {
+	    // size determination not correct if there are symbols Opr_Immediate
+	    if (operand->dataSize == Default_Ptr) {
+		if (operand->constDisplacement < 0x100)
+		    operand->dataSize = Byte_Ptr;
+		else if (operand->constDisplacement < 0x10000)
+		    operand->dataSize = Short_Ptr;
+		else
+		    operand->dataSize = Int_Ptr;
+	    }
+	    return Opr_Immediate;
+	}
+
+	// probably a bug,?
+	stmt->error("invalid operand");
+	return Opr_Invalid;
+    }
+
+    void writeReg(Reg reg) {
+	insnTemplate->writestring((char*) "%");
+	insnTemplate->write(regInfo[reg].gccName.c_str(), regInfo[reg].gccName.length());
+    }
+
+    bool opTakesLabel() {
+	switch(op) {
+	case Op_Branch:
+	case Op_CBranch:
+	case Op_Loop:
+	    return true;
+	default:
+	    return false;
+	}
+    }
+
+    bool getTypeChar(TypeNeeded needed, PtrType ptrtype, char & type_char)
+    {
+	switch (needed) {
+	case Byte_NoType:
+	    return ptrtype == Byte_Ptr;
+	case Word_Types:
+	    if (ptrtype == Byte_Ptr)
+		return false;
+	    // drop through
+	case Int_Types:
+	    switch (ptrtype) {
+	    case Byte_Ptr:  type_char = 'b'; break;
+	    case Short_Ptr: type_char = 'w'; break;
+	    case Int_Ptr:   type_char = 'l'; break;
+	    default:
+		// %% these may be too strict
+		return false;
+	    }
+	    break;
+	case FPInt_Types:
+	    switch (ptrtype) {
+	    case Short_Ptr: type_char = 0;   break;
+	    case Int_Ptr:   type_char = 'l'; break;
+	    case QWord_Ptr: type_char = 'q'; break;
+	    default:
+		return false;
+	    }
+	    break;
+	case FP_Types:
+	    switch (ptrtype) {
+	    case Float_Ptr:    type_char = 's'; break;
+	    case Double_Ptr:   type_char = 'l'; break;
+	    case Extended_Ptr: type_char = 't'; break;
+	    default:
+		return false;
+	    }
+	    break;
+	default:
+	    return false;
+	}
+	return true;
+    }
+
+    // also set impl clobbers
+    bool formatInstruction(int nOperands, AsmCode * asmcode) {
+	const char *fmt;
+	const char *mnemonic;
+	char type_char = 0;
+	bool use_star;
+	AsmArgMode mode;
+
+	insnTemplate = new OutBuffer;
+	// %% todo: special case for something..
+	if (opInfo->linkType == Out_Mnemonic)
+	    mnemonic = alternateMnemonics[opInfo->link];
+	else
+	    mnemonic = opIdent->string;
+
+	if (opInfo->needsType) {
+	    PtrType exact_type = Default_Ptr;
+	    PtrType min_type = Default_Ptr;
+	    PtrType hint_type = Default_Ptr;
+
+	    /* Default types: This attempts to match the observed behavior of DMD */
+	    switch (opInfo->needsType) {
+	    case Int_Types:   min_type = Byte_Ptr; break;
+	    case Word_Types:  min_type = Short_Ptr; break;
+	    case FPInt_Types:
+		if (op == Op_Fis_ST) // integer math instructions 
+		    min_type = Int_Ptr;
+		else // compare, load, store
+		    min_type = Short_Ptr;
+		break;
+	    case FP_Types:    min_type = Float_Ptr; break;
+	    }
+	    if (op == Op_push && operands[0].cls == Opr_Immediate)
+		min_type = Int_Ptr;
+	    
+	    for (int i = 0; i < nOperands; i++) {
+		if (hint_type == Default_Ptr &&
+		    ! (opInfo->operands[i] & Opr_NoType))
+		    hint_type = operands[i].dataSizeHint;
+		    
+		if ((opInfo->operands[i] & Opr_NoType) ||
+		    operands[i].dataSize == Default_Ptr)
+		    continue;
+		if (operands[i].cls == Opr_Immediate) {
+		    min_type = operands[i].dataSize > min_type ?
+			operands[i].dataSize : min_type;
+		} else {
+		    exact_type = operands[i].dataSize; // could check for conflicting types
+		    break;
+		}
+	    }
+
+	    bool type_ok;
+	    if (exact_type == Default_Ptr) {
+		type_ok = getTypeChar((TypeNeeded) opInfo->needsType, hint_type, type_char);
+		if (! type_ok)
+		    type_ok = getTypeChar((TypeNeeded) opInfo->needsType, min_type, type_char);
+	    } else
+		type_ok = getTypeChar((TypeNeeded) opInfo->needsType, exact_type, type_char);
+
+	    if (! type_ok) {
+		stmt->error("invalid operand size");
+		return false;
+	    }
+	} else if (op == Op_Branch) {
+	    if (operands[0].dataSize == Far_Ptr) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that..
+		insnTemplate->writebyte('l');
+	} else if (op == Op_fxch) {
+	    // gas won't accept the two-operand form
+	    if (operands[1].cls == Opr_Reg && operands[1].reg == Reg_ST) {
+		nOperands = 1;
+	    } else {
+		stmt->error("invalid operands");
+		return false;
+	    }
+	}
+	
+	switch (op) {
+	case Op_SizedStack:
+	    {
+		int mlen = strlen(mnemonic);
+		if (mnemonic[mlen-1] == 'd')
+		    insnTemplate->write(mnemonic, mlen-1);
+		else {
+		    insnTemplate->writestring((char*) mnemonic);
+		    insnTemplate->writebyte('w');
+		}
+	    }
+	    break;
+	case Op_cmpsd:
+	case Op_insX:
+	case Op_lodsX:
+	case Op_movsd:
+	case Op_outsX:
+	case Op_scasX:
+	case Op_stosX:
+	    {
+		int mlen = strlen(mnemonic);
+		if (mnemonic[mlen-1] == 'd') {
+		    insnTemplate->write(mnemonic, mlen-1);
+		    insnTemplate->writebyte('l');
+		} else {
+		    insnTemplate->writestring((char*) mnemonic);
+		}
+	    }
+	    break;
+	case Op_movsx:
+	case Op_movzx:
+	    {
+		char tc_1;
+		int mlen = strlen(mnemonic);
+		PtrType op1_size = operands[1].dataSize;
+		if (op1_size == Default_Ptr)
+		    op1_size = operands[1].dataSizeHint;
+		// Need type char for source arg
+		switch (op1_size) {
+		case Byte_Ptr: 
+		case Default_Ptr:
+		    tc_1 = 'b';
+		    break;
+		case Short_Ptr:
+		    tc_1 = 'w';
+		    break;
+		default:
+		    stmt->error("invalid operand size/type");
+		    return false;
+		}
+		assert(type_char != 0);
+		insnTemplate->write(mnemonic, mlen-1);
+		insnTemplate->writebyte(tc_1);
+		insnTemplate->writebyte(type_char);
+	    }
+	    break;
+	default:
+	    insnTemplate->writestring((char*) mnemonic);
+	    if (type_char)
+		insnTemplate->writebyte(type_char);
+	    break;
+	}
+
+	switch (opInfo->implicitClobbers & Clb_DXAX_Mask) {
+	case Clb_SizeAX:
+	case Clb_EAX:
+	    asmcode->regs[Reg_EAX] = true;
+	    break;
+	case Clb_SizeDXAX:
+	    asmcode->regs[Reg_EAX] = true;
+	    if (type_char != 'b')
+		asmcode->regs[Reg_EDX] = true;
+	    break;
+	default:
+	    // nothing
+	    break;
+	}
+
+	if (opInfo->implicitClobbers & Clb_DI)
+	    asmcode->regs[Reg_EDI] = true;
+	if (opInfo->implicitClobbers & Clb_SI)
+	    asmcode->regs[Reg_ESI] = true;
+	if (opInfo->implicitClobbers & Clb_CX)
+	    asmcode->regs[Reg_ECX] = true;
+	if (opInfo->implicitClobbers & Clb_SP)
+	    asmcode->regs[Reg_ESP] = true;
+	if (opInfo->implicitClobbers & Clb_ST)
+	{
+	    /* Can't figure out how to tell GCC that an
+	       asm statement leaves an arg pushed on the stack.
+	       Maybe if the statment had and input or output
+	       operand it would work...  In any case, clobbering
+	       all FP prevents incorrect code generation. */
+	    asmcode->regs[Reg_ST] = true;
+	    asmcode->regs[Reg_ST1] = true;
+	    asmcode->regs[Reg_ST2] = true;
+	    asmcode->regs[Reg_ST3] = true;
+	    asmcode->regs[Reg_ST4] = true;
+	    asmcode->regs[Reg_ST5] = true;
+	    asmcode->regs[Reg_ST6] = true;
+	    asmcode->regs[Reg_ST7] = true;
+	}
+	if (opInfo->implicitClobbers & Clb_Flags)
+	    asmcode->regs[Reg_EFLAGS] = true;
+	if (op == Op_cpuid) {
+	    asmcode->regs[Reg_EAX] = true;
+	    asmcode->regs[Reg_ECX] = true;
+	    asmcode->regs[Reg_EDX] = true;
+	}
+
+	insnTemplate->writebyte(' ');
+	for (int i__ = 0; i__ < nOperands; i__++) {
+	    int i;
+	    if (i__ != 0)
+		insnTemplate->writestring((char*) ", ");
+
+	    fmt = "$";
+    
+	    switch (op) {
+	    case Op_mul:
+		// gas won't accept the two-operand form; skip to the source operand
+		i__ = 1;
+		// drop through
+	    case Op_bound:
+	    case Op_enter:
+		i = i__;
+		break;
+	    default:
+		i = nOperands - 1 - i__; // operand = & operands[ nOperands - 1 - i ];
+		break;
+	    }
+	    operand = & operands[ i ];
+
+	    switch (operand->cls) {
+	    case Opr_Immediate:
+		// for implementing offset:
+		// $var + $7 // fails
+		// $var + 7  // ok
+		// $7 + $var // ok
+
+		// DMD doesn't seem to allow this
+		/*
+		if (opInfo->takesLabel())  tho... (near ptr <Number> would be abs?)
+		    fmt = "$a"; // GAS won't accept "jmp $42"; must be "jmp 42" (rel) or "jmp *42" (abs)
+		*/
+		if (opTakesLabel()/*opInfo->takesLabel()*/) {
+		    // "relative addressing not allowed in branch instructions" ..
+		    stmt->error("integer constant not allowed in branch instructions");
+		    return false;
+		}
+
+		if (operand->symbolDisplacement.dim &&
+		    isLocalSize( (Expression *) operand->symbolDisplacement.data[0] )) {
+		    // handle __LOCAL_SIZE, which in this constant, is an immediate
+		    // should do this in slotexp..
+		    addOperand("$", Arg_LocalSize,
+			(Expression *) operand->symbolDisplacement.data[0], asmcode);
+		    if (operand->constDisplacement)
+			insnTemplate->writebyte('+');
+		    else
+			break;
+		}
+
+		if (operand->symbolDisplacement.dim) {
+		    fmt = "$a";
+		    addOperand("$", Arg_Pointer,
+			(Expression *) operand->symbolDisplacement.data[0],
+			asmcode);
+
+		    if (operand->constDisplacement)
+			insnTemplate->writebyte('+');
+		    else
+			// skip the addOperand(fmt, Arg_Integer...) below
+			break;
+		}
+		addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
+		break;
+	    case Opr_Reg:
+		if (opInfo->operands[i] & Opr_Dest) {
+		    Reg clbr_reg = (Reg) regInfo[operand->reg].baseReg;
+		    if (clbr_reg != Reg_Invalid) {
+			asmcode->regs[clbr_reg] = true;
+		    }
+		}
+		if (opTakesLabel()/*opInfo->takesLabel()*/)
+		    insnTemplate->writebyte('*');
+		writeReg(operand->reg);
+		/*
+		insnTemplate->writestring("%");
+		insnTemplate->writestring(regInfo[operand->reg].name);
+		*/
+		break;
+	    case Opr_Mem:
+		// better: use output operands for simple variable references
+		if ( (opInfo->operands[i] & Opr_Update) == Opr_Update) {
+		    mode = Mode_Update;
+		} else if (opInfo->operands[i] & Opr_Dest) {
+		    mode = Mode_Output;
+		} else {
+		    mode = Mode_Input;
+		}
+		
+		use_star = opTakesLabel();//opInfo->takesLabel();
+		if (operand->segmentPrefix != Reg_Invalid) {
+		    writeReg(operand->segmentPrefix);
+		    insnTemplate->writebyte(':');
+		}
+		if (operand->symbolDisplacement.dim) {
+		    Expression * e = (Expression *) operand->symbolDisplacement.data[0];
+		    Declaration * decl = 0;
+
+		    if (e->op == TOKvar)
+			decl = ((VarExp *) e)->var;
+
+		    if (operand->baseReg != Reg_Invalid &&
+			decl && ! decl->isDataseg()) {
+
+			// Use the offset from frame pointer
+
+			/* GCC doesn't give the front end access to stack offsets
+			   when optimization is turned on (3.x) or at all (4.x).
+			   
+			   Try to convert var[EBP] (or var[ESP] for naked funcs) to
+			   a memory expression that does not require us to know
+			   the stack offset.
+			*/
+
+			if (operand->indexReg == Reg_Invalid &&
+			    decl->isVarDeclaration() &&
+			    ((operand->baseReg == Reg_EBP && ! sc->func->naked ) ||
+				(operand->baseReg == Reg_ESP && sc->func->naked)) ) {
+
+                if (mode == Mode_Output)
+                {
+                    e = new AddrExp(0, e);
+                    e->type = decl->type->pointerTo();
+                }
+
+#if !IN_LLVM
+			    /* DMD uses the same frame offsets for naked functions. */
+			    if (sc->func->naked)
+				operand->constDisplacement += 4;
+
+			    if (operand->constDisplacement) {
+				e = new AddExp(0, e,
+				    new IntegerExp(0, operand->constDisplacement,
+					Type::tint32));
+				e->type = decl->type->pointerTo();
+			    }
+			    e = new PtrExp(0, e);
+			    e->type = decl->type;
+#endif
+			    operand->constDisplacement = 0;
+			    operand->baseReg = Reg_Invalid;
+
+			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
+			    
+			} else {
+			    addOperand2("${",":a}", Arg_FrameRelative, e, asmcode);
+			}
+			if (opInfo->operands[i] & Opr_Dest)
+			    asmcode->clobbersMemory = 1;
+		    } else  {
+			// Plain memory reference to variable
+			
+			/* If in a reg, DMD moves to memory.. even with -O, so we'll do the same
+			   by always using the "m" contraint.
+
+			   In order to get the correct output for function and label symbols,
+			   the %an format must be used with the "p" constraint.
+			*/
+			if (isDollar(e)) {
+			    error("dollar labels are not supported", stmt->loc.toChars());
+			    asmcode->dollarLabel = 1;
+			} else if (e->op == TOKdsymbol) {
+			    LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s;
+			    stmt->isBranchToLabel = lbl->ident;
+
+			    use_star = false;
+			    addLabel(lbl->ident->toChars());
+			} else if ((decl && decl->isCodeseg())) { // if function or label
+			    use_star = false;
+			    addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
+			} else {
+			    if (use_star) {
+				insnTemplate->writebyte('*');
+				use_star = false;
+			    }
+                Type* tt = e->type->pointerTo();
+			    e = new AddrExp(0, e);
+			    e->type = tt;
+
+			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
+			}
+		    }
+		}
+		if (use_star)
+		    insnTemplate->writebyte('*');
+		if (operand->constDisplacement) {
+		    if (operand->symbolDisplacement.dim)
+			insnTemplate->writebyte('+');
+		    //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
+		    insnTemplate->printf("%d", operand->constDisplacement);
+		    if (opInfo->operands[i] & Opr_Dest)
+			asmcode->clobbersMemory = 1;
+		}
+		if (operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid) {
+		    insnTemplate->writebyte('(');
+		    if (operand->baseReg != Reg_Invalid)
+			writeReg(operand->baseReg);
+		    if (operand->indexReg != Reg_Invalid) {
+			insnTemplate->writebyte(',');
+			writeReg(operand->indexReg);
+			if (operand->scale) {
+			    insnTemplate->printf(",%d", operand->scale);
+			}
+		    }
+		    insnTemplate->writebyte(')');
+		    if (opInfo->operands[i] & Opr_Dest)
+			asmcode->clobbersMemory = 1;
+		}
+		break;
+	    case Opr_Invalid:
+		return false;
+	    }
+	}
+
+	asmcode->insnTemplateLen = insnTemplate->offset;
+	asmcode->insnTemplate = (char*) insnTemplate->extractData();
+	return true;
+    }
+
+    bool isIntExp(Expression * exp) {
+	if (exp->op == TOKint64)
+	    return 1;
+	if (exp->op == TOKvar) {
+	    Declaration * v = ((VarExp *) exp)->var;
+	    if (v->isConst() && v->type->isintegral())
+		return 1;
+	}
+	return 0;
+    }
+    bool isRegExp(Expression * exp) { return exp->op == TOKmod; } // ewww.%%
+    bool isLocalSize(Expression * exp) {
+	// cleanup: make a static var
+	return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__LOCAL_SIZE;
+    }
+    bool isDollar(Expression * exp) {
+	return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__dollar;
+    }
+
+    Expression * newRegExp(int regno) {
+	IntegerExp * e = new IntegerExp(regno);
+	e->op = TOKmod;
+	return e;
+    }
+
+    Expression * newIntExp(int v /* %% type */) {
+	// Only handles 32-bit numbers as this is IA-32.
+	return new IntegerExp(stmt->loc, v, Type::tint32);
+    }
+
+    void slotExp(Expression * exp) {
+	/*
+	  if offset, make a note
+	
+	  if integer, add to immediate
+	  if reg:
+	      if not in bracket, set reg (else error)
+	      if in bracket:
+		 if not base, set base
+		 if not index, set index
+		 else, error
+	  if symbol:
+	    set symbol field
+	 */
+
+	bool is_offset = false;
+	if (exp->op == TOKaddress) {
+	    exp = ((AddrExp *) exp)->e1;
+	    is_offset = true;
+	}
+	
+	if (isIntExp(exp)) {
+	    if (is_offset)
+		invalidExpression();
+	    operand->constDisplacement += exp->toInteger();
+	    if (! operand->inBracket)
+		operand->hasNumber = 1;
+	} else if (isRegExp(exp)) {
+	    if (is_offset)
+		invalidExpression();
+	    if (! operand->inBracket) {
+		if (operand->reg == Reg_Invalid)
+		    operand->reg = (Reg) exp->toInteger();
+		else
+		    stmt->error("too many registers in operand (use brackets)");
+	    } else {
+		if (operand->baseReg == Reg_Invalid)
+		    operand->baseReg = (Reg) exp->toInteger();
+		else if (operand->indexReg == Reg_Invalid) {
+		    operand->indexReg = (Reg) exp->toInteger();
+		    operand->scale = 1;
+		} else {
+		    stmt->error("too many registers memory operand");
+		}
+	    }
+	} else if (exp->op == TOKvar) {
+	    VarDeclaration * v = ((VarExp *) exp)->var->isVarDeclaration();
+
+	    if (v && v->storage_class & STCfield) {
+		operand->constDisplacement += v->offset;
+		if (! operand->inBracket)
+		    operand->hasNumber = 1;
+	    } else {
+		if (v && v->type->isscalar())
+		{
+		    // DMD doesn't check Tcomplex*, and counts Tcomplex32 as Tfloat64
+		    TY ty = v->type->toBasetype()->ty;
+		    operand->dataSizeHint = ty == Tfloat80 || ty == Timaginary80 ?
+			Extended_Ptr : (PtrType) v->type->size(0);
+		}
+		
+		if (! operand->symbolDisplacement.dim) {
+		    if (is_offset && ! operand->inBracket)
+			operand->isOffset = 1;
+		    operand->symbolDisplacement.push( exp );
+		} else {
+		    stmt->error("too many symbols in operand");
+		}
+	    }
+	} else if (exp->op == TOKidentifier || exp->op == TOKdsymbol) {
+	    // %% localsize could be treated as a simple constant..
+	    // change to addSymbolDisp(e)
+	    if (! operand->symbolDisplacement.dim) {
+		operand->symbolDisplacement.push( exp );
+	    } else {
+		stmt->error("too many symbols in operand");
+	    }
+	} else if (exp == Handled) {
+	    // nothing
+	} else {
+	    stmt->error("invalid operand");
+	}
+    }
+
+    void invalidExpression() {
+	// %% report operand number
+	stmt->error("invalid expression");
+    }
+
+    Expression * intOp(TOK op, Expression * e1, Expression * e2) {
+	Expression * e;
+	if (isIntExp(e1) && (! e2 || isIntExp(e2))) {
+	    switch (op) {
+	    case TOKadd:
+		if (e2)
+		    e = new AddExp(stmt->loc, e1, e2);
+		else
+		    e = e1;
+		break;
+	    case TOKmin:
+		if (e2)
+		    e = new MinExp(stmt->loc, e1, e2);
+		else
+		    e = new NegExp(stmt->loc, e1);
+		break;
+	    case TOKmul:
+		e = new MulExp(stmt->loc, e1, e2);
+		break;
+	    case TOKdiv:
+		e = new DivExp(stmt->loc, e1, e2);
+		break;
+	    case TOKmod:
+		e = new ModExp(stmt->loc, e1, e2);
+		break;
+	    case TOKshl:
+		e = new ShlExp(stmt->loc, e1, e2);
+		break;
+	    case TOKshr:
+		e = new ShrExp(stmt->loc, e1, e2);
+		break;
+	    case TOKushr:
+		e = new UshrExp(stmt->loc, e1, e2);
+		break;
+	    case TOKnot:
+		e = new NotExp(stmt->loc, e1);
+		break;
+	    case TOKtilde:
+		e = new ComExp(stmt->loc, e1);
+		break;
+	    default:
+		assert(0);
+	    }
+	    e = e->semantic(sc);
+	    return e->optimize(WANTvalue | WANTinterpret);
+	} else {
+	    stmt->error("expected integer operand(s) for '%s'", Token::tochars[op]);
+	    return newIntExp(0);
+	}
+    }
+
+    void parseOperand() {
+	Expression * exp = parseAsmExp();
+	slotExp(exp);
+	if (isRegExp(exp))
+	    operand->dataSize = (PtrType) regInfo[exp->toInteger()].size;
+    }
+
+    Expression * parseAsmExp() {
+	return parseShiftExp();
+    }
+
+    Expression * parseShiftExp() {
+	Expression * e1 = parseAddExp();
+	Expression * e2;
+
+	while (1) {
+	    TOK tv = token->value;
+	    switch (tv) {
+	    case TOKshl:
+	    case TOKshr:
+	    case TOKushr:
+		nextToken();
+		e2 = parseAddExp();
+		e1 = intOp(tv, e1, e2);
+		continue;
+	    default:
+		break;
+	    }
+	    break;
+	}
+	return e1;
+    }
+
+    Expression * parseAddExp() {
+	Expression * e1 = parseMultExp();
+	Expression * e2;
+
+	while (1) {
+	    TOK tv = token->value;
+	    switch (tv) {
+	    case TOKadd:
+		nextToken();
+		e2 = parseMultExp();
+		if (isIntExp(e1) && isIntExp(e2))
+		    e1 = intOp(tv, e1, e2);
+		else {
+		    slotExp(e1);
+		    slotExp(e2);
+		    e1 = Handled;
+		}
+		continue;
+	    case TOKmin:
+		// Note: no support for symbol address difference
+		nextToken();
+		e2 = parseMultExp();
+		if (isIntExp(e1) && isIntExp(e2))
+		    e1 = intOp(tv, e1, e2);
+		else {
+		    slotExp(e1);
+		    e2 = intOp(TOKmin, e2, NULL); // verifies e2 is an int
+		    slotExp(e2);
+		    e1 = Handled;
+		}
+		continue;
+	    default:
+		break;
+	    }
+	    break;
+	}
+	return e1;
+    }
+
+    bool tryScale(Expression * e1, Expression * e2) {
+	Expression * et;
+	if (isIntExp(e1) && isRegExp(e2)) {
+	    et = e1;
+	    e1 = e2;
+	    e2 = et;
+	    goto do_scale;
+	} else if (isRegExp(e1) && isIntExp(e2)) {
+	do_scale:
+	    if (! operand->inBracket) {
+		invalidExpression(); // maybe should allow, e.g. DS:EBX+EAX*4
+	    }
+	    
+	    if (operand->scale || operand->indexReg != Reg_Invalid) {
+		invalidExpression();
+		return true;
+	    }
+
+	    operand->indexReg = (Reg) e1->toInteger();
+	    operand->scale = e2->toInteger();
+	    switch (operand->scale) {
+	    case 1:
+	    case 2:
+	    case 4:
+	    case 8:
+		// ok; do nothing
+		break;
+	    default:
+		stmt->error("invalid index register scale '%d'", operand->scale);
+		return true;
+	    }
+	    
+	    return true;
+	}
+	return false;
+    }
+
+    Expression * parseMultExp() {
+	Expression * e1 = parseBrExp();
+	Expression * e2;
+
+	while (1) {
+	    TOK tv = token->value;
+	    switch (tv) {
+	    case TOKmul:
+		nextToken();
+		e2 = parseMultExp();
+		if (isIntExp(e1) && isIntExp(e2))
+		    e1 = intOp(tv, e1, e2);
+		else if (tryScale(e1,e2))
+		    e1 = Handled;
+		else
+		    invalidExpression();
+		continue;
+	    case TOKdiv:
+	    case TOKmod:
+		nextToken();
+		e2 = parseMultExp();
+		e1 = intOp(tv, e1, e2);
+		continue;
+	    default:
+		break;
+	    }
+	    break;
+	}
+	return e1;
+    }
+
+    Expression * parseBrExp() {
+	// %% check (why is bracket lower precends..)
+	// 3+4[eax] -> 3 + (4 [EAX]) ..
+	
+	// only one bracked allowed, so this doesn't quite handle
+	// the spec'd syntax
+	Expression * e;
+	
+	if (token->value == TOKlbracket)
+	    e = Handled;
+	else
+	    e = parseUnaExp();
+
+	// DMD allows multiple bracket expressions.
+	while (token->value == TOKlbracket) {
+	    nextToken();
+	    
+	    operand->inBracket = operand->hasBracket = 1;
+	    slotExp(parseAsmExp());
+	    operand->inBracket = 0;
+
+	    if (token->value == TOKrbracket)
+		nextToken();
+	    else
+		stmt->error("missing ']'");
+	}
+
+	return e;
+    }
+
+    PtrType isPtrType(Token * tok) {
+	switch (tok->value) {
+	case TOKint8: return Byte_Ptr;
+	case TOKint16: return Short_Ptr;
+	case TOKint32: return Int_Ptr;
+	    // 'long ptr' isn't accepted?
+	case TOKfloat32: return Float_Ptr;
+	case TOKfloat64: return Double_Ptr;
+	case TOKfloat80: return Extended_Ptr;
+	case TOKidentifier:
+	    for (int i = 0; i < N_PtrNames; i++)
+		if (tok->ident == ptrTypeIdentTable[i])
+		    return ptrTypeValueTable[i];
+	    break;
+	default:
+	    break;
+	}
+	return Default_Ptr;
+    }
+
+    Expression * parseUnaExp() {
+	Expression * e = NULL;
+	PtrType ptr_type;
+	
+	// First, check for type prefix.
+	if (token->value != TOKeof &&
+	    peekToken()->value == TOKidentifier &&
+	    peekToken()->ident == Id::ptr) {
+
+	    ptr_type = isPtrType(token);
+	    if (ptr_type != Default_Ptr) {
+		if (operand->dataSize == Default_Ptr)
+		    operand->dataSize = ptr_type;
+		else
+		    stmt->error("multiple specifications of operand size");
+	    } else
+		stmt->error("unknown operand size '%s'", token->toChars());
+	    nextToken();
+	    nextToken();
+	    return parseAsmExp();
+	}
+
+	TOK tv = token->value;
+	switch (tv) {
+	case TOKidentifier:
+	    if (token->ident == ident_seg) {
+		nextToken();
+		stmt->error("'seg' not supported");
+		e = parseAsmExp();
+	    } else if (token->ident == Id::offset ||
+		       token->ident == Id::offsetof) {
+		if (token->ident == Id::offset && ! global.params.useDeprecated)
+		    stmt->error("offset deprecated, use offsetof");
+		nextToken();
+		e = parseAsmExp();
+		e = new AddrExp(stmt->loc, e);
+	    } else {
+		// primary exp
+		break;
+	    }
+	    return e;
+	case TOKadd:
+	case TOKmin:
+	case TOKnot:
+	case TOKtilde:
+	    nextToken();
+	    e = parseUnaExp();
+	    return intOp(tv, e, NULL);
+	default:
+	    // primary exp
+	    break;
+	}
+	return parsePrimaryExp();
+    }
+
+    Expression * parsePrimaryExp() {
+	Expression * e;
+	Identifier * ident = NULL;
+	
+	switch (token->value) {
+	case TOKint32v:
+	case TOKuns32v:
+	case TOKint64v:
+	case TOKuns64v:
+	    // semantic here?
+	    // %% for tok64 really should use 64bit type
+	    e = new IntegerExp(stmt->loc, token->uns64value, Type::tint32);
+	    nextToken();
+	    break;
+	case TOKfloat32v:
+	case TOKfloat64v:
+	case TOKfloat80v:
+	    // %% need different types?
+        e = new RealExp(stmt->loc, token->float80value, Type::tfloat80);
+	    nextToken();
+	    break;
+	case TOKidentifier:
+	    {
+		ident = token->ident;
+		nextToken();
+		
+		if (ident == Id::__LOCAL_SIZE) {
+		    return new IdentifierExp(stmt->loc, ident);
+		} else if (ident == Id::__dollar) {
+		do_dollar:
+		    return new IdentifierExp(stmt->loc, ident);
+		} else {
+		    e = new IdentifierExp(stmt->loc, ident);
+		}
+
+		// If this is more than one component ref, it gets complicated: *(&Field + n)
+		// maybe just do one step at a time..
+		// simple case is Type.f -> VarDecl(field)
+		// actually, DMD only supports on level...
+		// X.y+Y.z[EBX] is supported, tho..
+		// %% doesn't handle properties (check%%)
+		while (token->value == TOKdot) {
+		    nextToken();
+		    if (token->value == TOKidentifier) {
+			e = new DotIdExp(stmt->loc, e, token->ident);
+			nextToken();
+		    } else {
+			stmt->error("expected identifier");
+			return Handled;
+		    }
+		}
+
+		// check for reg first then dotexp is an error?
+		if (e->op == TOKidentifier) {
+		    for (int i = 0; i < N_Regs; i++) {
+			if (ident == regInfo[i].ident) {
+			    if ( (Reg) i == Reg_ST && token->value == TOKlparen) {
+				nextToken();
+				switch (token->value) {
+				case TOKint32v: case TOKuns32v:
+				case TOKint64v: case TOKuns64v:
+				    if (token->uns64value < 8)
+					e = newRegExp( (Reg) (Reg_ST + token->uns64value) );
+				    else {
+					stmt->error("invalid floating point register index");
+					e = Handled;
+				    }
+				    nextToken();
+				    if (token->value == TOKrparen)
+					nextToken();
+				    else
+					stmt->error("expected ')'");
+				    return e;
+				default:
+				    break;
+				}
+				invalidExpression();
+				return Handled;
+			    } else if (token->value == TOKcolon) {
+				nextToken();
+				if (operand->segmentPrefix != Reg_Invalid)
+				    stmt->error("too many segment prefixes");
+				else if (i >= Reg_CS && i <= Reg_GS)
+				    operand->segmentPrefix = (Reg) i;
+				else
+				    stmt->error("'%s' is not a segment register", ident->string);
+				return parseAsmExp();
+			    } else {
+				return newRegExp( (Reg) i );
+			    }
+			}
+		    }
+		}
+		
+		if (opTakesLabel()/*opInfo->takesLabel()*/ && e->op == TOKidentifier) {
+		    // DMD uses labels secondarily to other symbols, so check
+		    // if IdentifierExp::semantic won't find anything.
+		    Dsymbol *scopesym;
+		    
+		    if ( ! sc->search(stmt->loc, ident, & scopesym) )		    
+			return new DsymbolExp(stmt->loc,
+			    sc->func->searchLabel( ident ));
+		}
+
+		e = e->semantic(sc);
+
+		// Special case for floating point constant declarations.
+		if (e->op == TOKfloat64) {
+		    Dsymbol * sym = sc->search(stmt->loc, ident, NULL);
+		    if ( sym ) {
+			VarDeclaration *v = sym->isVarDeclaration();
+			if ( v ) {
+			    Expression *ve = new VarExp(stmt->loc, v);
+			    ve->type = e->type;
+			    e = ve;
+			}
+		    }			    
+		}
+		return e;
+	    }
+	    break;
+	case TOKdollar:
+	    nextToken();
+	    ident = Id::__dollar;
+	    goto do_dollar;
+	    break;
+	default:
+	    invalidExpression();
+	    return Handled;
+	}
+	return e;
+    }
+
+    void doAlign() {
+	// .align bits vs. bytes...
+	// apparently a.out platforms use bits instead of bytes...
+
+	// parse primary: DMD allows 'MyAlign' (const int) but not '2+2'
+	// GAS is padding with NOPs last time I checked.
+	Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret);
+	integer_t align = e->toInteger();
+
+	if (align >= 0) {
+	    // %% is this printf portable?
+#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 
+	    insnTemplate->printf(".balign\t%u", (unsigned) align);
+#else
+	    insnTemplate->printf(".align\t%u", (unsigned) align);
+#endif
+	} else {
+	    stmt->error("alignment must be a power of 2");
+	}
+
+	setAsmCode();
+    }
+
+    void doEven() {
+	// .align for GAS is in bits, others probably use bytes..
+#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 
+	insnTemplate->writestring((char *) ".align\t2");
+#else
+	insnTemplate->writestring((char *) ".align\t2");
+#endif
+	setAsmCode();
+    }
+
+    void doNaked() {
+	// %% can we assume sc->func != 0?
+	sc->func->naked = 1;
+    }
+
+    void doData() {
+	static const char * directives[] = { ".byte", ".short", ".long", ".long",
+					     "", "", "" };
+// FIXME
+/*
+	machine_mode mode;
+
+	insnTemplate->writestring((char*) directives[op - Op_db]);
+	insnTemplate->writebyte(' ');
+
+	do {
+	    // DMD is pretty strict here, not even constant expressions are allowed..
+	    switch (op) {
+	    case Op_db:
+	    case Op_ds:
+	    case Op_di:
+	    case Op_dl:
+		if (token->value == TOKint32v || token->value == TOKuns32v ||
+		    token->value == TOKint64v || token->value == TOKuns64v) {
+		    // As per usual with GNU, assume at least 32-bit host
+		    if (op != Op_dl)
+			insnTemplate->printf("%u", (d_uns32) token->uns64value);
+		    else {
+			// Output two .longS.  GAS has .quad, but would have to rely on 'L' format ..
+			// just need to use HOST_WIDE_INT_PRINT_DEC
+			insnTemplate->printf("%u,%u",
+			    (d_uns32) token->uns64value, (d_uns32) (token->uns64value >> 32));
+		    }
+		} else {
+		    stmt->error("expected integer constant");
+		}
+		break;
+	    case Op_df:
+		mode = SFmode;
+		goto do_float;
+	    case Op_dd:
+		mode = DFmode;
+		goto do_float;
+	    case Op_de:
+#ifndef TARGET_80387
+#define XFmode TFmode
+#endif
+		mode = XFmode; // not TFmode
+		// drop through
+	    do_float:
+		if (token->value == TOKfloat32v || token->value == TOKfloat64v ||
+		    token->value == TOKfloat80v) {
+		    long words[3];
+		    real_to_target(words, & token->float80value.rv(), mode);
+		    // don't use directives..., just use .long like GCC
+		    insnTemplate->printf(".long\t%u", words[0]);
+		    if (mode != SFmode)
+			insnTemplate->printf(",%u", words[1]);
+		    // DMD outputs 10 bytes, so we need to switch to .short here
+		    if (mode == XFmode)
+			insnTemplate->printf("\n\t.short\t%u", words[2]);
+		} else {
+		    stmt->error("expected float constant");
+		}
+		break;
+	    default:
+		abort();
+	    }
+	    
+	    nextToken();	    
+	    if (token->value == TOKcomma) {
+		insnTemplate->writebyte(',');
+		nextToken();
+	    } else if (token->value == TOKeof) {
+		break;
+	    } else {
+		stmt->error("expected comma");
+	    }
+	} while (1);
+
+	setAsmCode();*/
+    }
+};
+
+#if D_GCC_VER < 40
+// struct rtx was modified for c++; this macro from rtl.h needs to
+// be modified accordingly.
+#undef XEXP
+#define XEXP(RTX, N)	(RTL_CHECK2 (RTX, N, 'e', 'u').rt_rtx)
+#endif
+
+// FIXME
+    #define HOST_WIDE_INT long
+bool getFrameRelativeValue(LLValue* decl, HOST_WIDE_INT * result)
+{
+assert(0);
+// FIXME
+//     // Using this instead of DECL_RTL for struct args seems like a
+//     // good way to get hit by a truck because it may not agree with
+//     // non-asm access, but asm code wouldn't know what GCC does anyway. */
+//     rtx r = DECL_INCOMING_RTL(decl);
+//     rtx e1, e2;
+// 
+//     // Local variables don't have DECL_INCOMING_RTL
+//     if (r == NULL_RTX)
+// 	r = DECL_RTL(decl);
+// 
+//     if (r != NULL_RTX && GET_CODE(r) == MEM /* && r->frame_related */ ) {
+// 	r = XEXP(r, 0);
+// 	if (GET_CODE(r) == PLUS) {
+// 	    e1 = XEXP(r, 0);
+// 	    e2 = XEXP(r, 1);
+// 	    if (e1 == virtual_incoming_args_rtx && GET_CODE(e2) == CONST_INT) {
+// 		*result = INTVAL(e2) + 8; // %% 8 is 32-bit specific...
+// 		return true;
+// 	    } else if (e1 == virtual_stack_vars_rtx && GET_CODE(e2) == CONST_INT) {
+// 		*result = INTVAL(e2); // %% 8 is 32-bit specific...
+// 		return true;
+// 	    }
+// 	} else if (r == virtual_incoming_args_rtx) {
+// 	    *result = 8;
+// 	    return true; // %% same as above
+// 	}
+// 	// shouldn't have virtual_stack_vars_rtx by itself
+//     }
+//     
+    return false;
+}
+
+
+struct AsmParser : public AsmParserCommon
+{
+    virtual void run(Scope* sc, AsmStatement* asmst) {
+        AsmProcessor ap(sc, asmst);
+        ap.run();
+    }
+
+    virtual std::string getRegName(int i) {
+        return regInfo[i].gccName;
+    }
+};
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/asm-x86-64.h	Sat Nov 08 22:29:19 2008 +0100
@@ -0,0 +1,2807 @@
+// Taken from GDC source tree. Original by David Friedman.
+// Released under the Artistic License found in dmd/artistic.txt
+
+#include "id.h"
+
+namespace AsmParserx8664 {
+
+typedef enum {
+    Reg_Invalid = -1,
+    Reg_EAX = 0,
+    Reg_EBX,
+    Reg_ECX,
+    Reg_EDX,
+    Reg_ESI,
+    Reg_EDI,
+    Reg_EBP,
+    Reg_ESP,
+    Reg_ST,
+    Reg_ST1, Reg_ST2, Reg_ST3, Reg_ST4, Reg_ST5, Reg_ST6, Reg_ST7,
+    Reg_MM0, Reg_MM1, Reg_MM2, Reg_MM3, Reg_MM4, Reg_MM5, Reg_MM6, Reg_MM7,
+    Reg_XMM0, Reg_XMM1, Reg_XMM2, Reg_XMM3, Reg_XMM4, Reg_XMM5, Reg_XMM6, Reg_XMM7,
+
+    Reg_RAX, Reg_RBX, Reg_RCX, Reg_RDX, Reg_RSI, Reg_RDI, Reg_RBP, Reg_RSP, 
+    Reg_R8, Reg_R9, Reg_R10, Reg_R11, Reg_R12, Reg_R13, Reg_R14, Reg_R15,
+    Reg_R8B, Reg_R9B, Reg_R10B, Reg_R11B, Reg_R12B, Reg_R13B, Reg_R14B, Reg_R15B,
+    Reg_R8W, Reg_R9W, Reg_R10W, Reg_R11W, Reg_R12W, Reg_R13W, Reg_R14W, Reg_R15W,
+    Reg_R8D, Reg_R9D, Reg_R10D, Reg_R11D, Reg_R12D, Reg_R13D, Reg_R14D, Reg_R15D,
+    Reg_XMM8, Reg_XMM9, Reg_XMM10, Reg_XMM11, Reg_XMM12, Reg_XMM13, Reg_XMM14, Reg_XMM15,
+    Reg_RIP,
+    Reg_SIL, Reg_DIL, Reg_BPL, Reg_SPL, 
+
+    Reg_EFLAGS,
+    Reg_CS,
+    Reg_DS,
+    Reg_SS,
+    Reg_ES,
+    Reg_FS,
+    Reg_GS,
+    Reg_AX, Reg_BX, Reg_CX, Reg_DX, Reg_SI, Reg_DI, Reg_BP, Reg_SP,
+    Reg_AL, Reg_AH, Reg_BL, Reg_BH, Reg_CL, Reg_CH, Reg_DL, Reg_DH,
+    Reg_CR0, Reg_CR2, Reg_CR3, Reg_CR4,
+    Reg_DR0, Reg_DR1, Reg_DR2, Reg_DR3, Reg_DR6, Reg_DR7,
+    Reg_TR3, Reg_TR4, Reg_TR5, Reg_TR6, Reg_TR7
+} Reg;
+
+static const int N_Regs = /*gp*/ 8 + /*fp*/ 8 + /*mmx*/ 8 + /*sse*/ 8 +
+/*seg*/ 6 + /*16bit*/ 8 + /*8bit*/ 8 + /*sys*/ 4+6+5 + /*flags*/ + 1
++ 8 /*RAX, etc*/ 
++ 8 /*R8-15*/ 
++ 4 /*SIL, etc. 8-bit*/ 
++ 8 /*R8-15B*/ 
++ 8 /*R8-15W*/ 
++ 8 /*R8-15D*/ 
++ 8 /*XMM8-15*/
++ 1 /*RIP*/ 
+
+;
+
+#define NULL_TREE ""
+
+static struct {
+    const char * name;
+    std::string gccName; // GAS will take upper case, but GCC won't (needed for the clobber list)
+    Identifier * ident;
+    char size;
+    char baseReg; // %% todo: Reg, Reg_XX
+} regInfo[N_Regs] = {
+    { "EAX", NULL_TREE, NULL, 4,  Reg_EAX },
+    { "EBX", NULL_TREE, NULL, 4,  Reg_EBX },
+    { "ECX", NULL_TREE, NULL, 4,  Reg_ECX },
+    { "EDX", NULL_TREE, NULL, 4,  Reg_EDX },
+    { "ESI", NULL_TREE, NULL, 4,  Reg_ESI },
+    { "EDI", NULL_TREE, NULL, 4,  Reg_EDI },
+    { "EBP", NULL_TREE, NULL, 4,  Reg_EBP },
+    { "ESP", NULL_TREE, NULL, 4,  Reg_ESP },
+    { "ST", NULL_TREE, NULL,   10, Reg_ST },
+    { "ST(1)", NULL_TREE, NULL,10, Reg_ST1 },
+    { "ST(2)", NULL_TREE, NULL,10, Reg_ST2 },
+    { "ST(3)", NULL_TREE, NULL,10, Reg_ST3 },
+    { "ST(4)", NULL_TREE, NULL,10, Reg_ST4 },
+    { "ST(5)", NULL_TREE, NULL,10, Reg_ST5 },
+    { "ST(6)", NULL_TREE, NULL,10, Reg_ST6 },
+    { "ST(7)", NULL_TREE, NULL,10, Reg_ST7 },
+    { "MM0", NULL_TREE, NULL, 8, Reg_MM0 },
+    { "MM1", NULL_TREE, NULL, 8, Reg_MM1 },
+    { "MM2", NULL_TREE, NULL, 8, Reg_MM2 },
+    { "MM3", NULL_TREE, NULL, 8, Reg_MM3 },
+    { "MM4", NULL_TREE, NULL, 8, Reg_MM4 },
+    { "MM5", NULL_TREE, NULL, 8, Reg_MM5 },
+    { "MM6", NULL_TREE, NULL, 8, Reg_MM6 },
+    { "MM7", NULL_TREE, NULL, 8, Reg_MM7 },
+    { "XMM0", NULL_TREE, NULL, 16, Reg_XMM0 },
+    { "XMM1", NULL_TREE, NULL, 16, Reg_XMM1 },
+    { "XMM2", NULL_TREE, NULL, 16, Reg_XMM2 },
+    { "XMM3", NULL_TREE, NULL, 16, Reg_XMM3 },
+    { "XMM4", NULL_TREE, NULL, 16, Reg_XMM4 },
+    { "XMM5", NULL_TREE, NULL, 16, Reg_XMM5 },
+    { "XMM6", NULL_TREE, NULL, 16, Reg_XMM6 },
+    { "XMM7", NULL_TREE, NULL, 16, Reg_XMM7 },
+
+    { "RAX", NULL_TREE, NULL, 8,  Reg_RAX },
+    { "RBX", NULL_TREE, NULL, 8,  Reg_RBX },
+    { "RCX", NULL_TREE, NULL, 8,  Reg_RCX },
+    { "RDX", NULL_TREE, NULL, 8,  Reg_RDX },
+    { "RSI", NULL_TREE, NULL, 8,  Reg_RSI },
+    { "RDI", NULL_TREE, NULL, 8,  Reg_RDI },
+    { "RBP", NULL_TREE, NULL, 8,  Reg_RBP },
+    { "RSP", NULL_TREE, NULL, 8,  Reg_RSP },
+    { "R8", NULL_TREE, NULL, 8,  Reg_R8 },
+    { "R9", NULL_TREE, NULL, 8,  Reg_R9 },
+    { "R10", NULL_TREE, NULL, 8,  Reg_R10 },
+    { "R11", NULL_TREE, NULL, 8,  Reg_R11 },
+    { "R12", NULL_TREE, NULL, 8,  Reg_R12 },
+    { "R13", NULL_TREE, NULL, 8,  Reg_R13 },
+    { "R14", NULL_TREE, NULL, 8,  Reg_R14 },
+    { "R15", NULL_TREE, NULL, 8,  Reg_R15 },
+    { "R8B", NULL_TREE, NULL, 1,  Reg_R8 },
+    { "R9B", NULL_TREE, NULL, 1,  Reg_R9 },
+    { "R10B", NULL_TREE, NULL, 1,  Reg_R10 },
+    { "R11B", NULL_TREE, NULL, 1,  Reg_R11 },
+    { "R12B", NULL_TREE, NULL, 1,  Reg_R12 },
+    { "R13B", NULL_TREE, NULL, 1,  Reg_R13 },
+    { "R14B", NULL_TREE, NULL, 1,  Reg_R14 },
+    { "R15B", NULL_TREE, NULL, 1,  Reg_R15 },
+    { "R8W", NULL_TREE, NULL, 2,  Reg_R8 },
+    { "R9W", NULL_TREE, NULL, 2,  Reg_R9 },
+    { "R10W", NULL_TREE, NULL, 2,  Reg_R10 },
+    { "R11W", NULL_TREE, NULL, 2,  Reg_R11 },
+    { "R12W", NULL_TREE, NULL, 2,  Reg_R12 },
+    { "R13W", NULL_TREE, NULL, 2,  Reg_R13 },
+    { "R14W", NULL_TREE, NULL, 2,  Reg_R14 },
+    { "R15W", NULL_TREE, NULL, 2,  Reg_R15 },
+    { "R8D", NULL_TREE, NULL, 4,  Reg_R8 },
+    { "R9D", NULL_TREE, NULL, 4,  Reg_R9 },
+    { "R10D", NULL_TREE, NULL, 4,  Reg_R10 },
+    { "R11D", NULL_TREE, NULL, 4,  Reg_R11 },
+    { "R12D", NULL_TREE, NULL, 4,  Reg_R12 },
+    { "R13D", NULL_TREE, NULL, 4,  Reg_R13 },
+    { "R14D", NULL_TREE, NULL, 4,  Reg_R14 },
+    { "R15D", NULL_TREE, NULL, 4,  Reg_R15 },
+    { "XMM8", NULL_TREE, NULL, 16, Reg_XMM8 },
+    { "XMM9", NULL_TREE, NULL, 16, Reg_XMM9 },
+    { "XMM10", NULL_TREE, NULL, 16, Reg_XMM10 },
+    { "XMM11", NULL_TREE, NULL, 16, Reg_XMM11 },
+    { "XMM12", NULL_TREE, NULL, 16, Reg_XMM12 },
+    { "XMM13", NULL_TREE, NULL, 16, Reg_XMM13 },
+    { "XMM14", NULL_TREE, NULL, 16, Reg_XMM14 },
+    { "XMM15", NULL_TREE, NULL, 16, Reg_XMM15 },
+    { "RIP", NULL_TREE, NULL, 8,  Reg_RIP },
+    { "SIL", NULL_TREE, NULL, 1,  Reg_SIL },
+    { "DIL", NULL_TREE, NULL, 1,  Reg_DIL },
+    { "BPL", NULL_TREE, NULL, 1,  Reg_BPL },
+    { "SPL", NULL_TREE, NULL, 1,  Reg_SPL },
+
+    { "FLAGS", NULL_TREE, NULL, 0, Reg_EFLAGS }, // the gcc name is "flags"; not used in assembler input
+    { "CS",  NULL_TREE, NULL, 2, -1 },
+    { "DS",  NULL_TREE, NULL, 2, -1 },
+    { "SS",  NULL_TREE, NULL, 2, -1 },
+    { "ES",  NULL_TREE, NULL, 2, -1 },
+    { "FS",  NULL_TREE, NULL, 2, -1 },
+    { "GS",  NULL_TREE, NULL, 2, -1 },
+    { "AX",  NULL_TREE, NULL, 2,  Reg_EAX },
+    { "BX",  NULL_TREE, NULL, 2,  Reg_EBX },
+    { "CX",  NULL_TREE, NULL, 2,  Reg_ECX },
+    { "DX",  NULL_TREE, NULL, 2,  Reg_EDX },
+    { "SI",  NULL_TREE, NULL, 2,  Reg_ESI },
+    { "DI",  NULL_TREE, NULL, 2,  Reg_EDI },
+    { "BP",  NULL_TREE, NULL, 2,  Reg_EBP },
+    { "SP",  NULL_TREE, NULL, 2,  Reg_ESP },
+    { "AL",  NULL_TREE, NULL, 1,  Reg_EAX },
+    { "AH",  NULL_TREE, NULL, 1,  Reg_EAX },
+    { "BL",  NULL_TREE, NULL, 1,  Reg_EBX },
+    { "BH",  NULL_TREE, NULL, 1,  Reg_EBX },
+    { "CL",  NULL_TREE, NULL, 1,  Reg_ECX },
+    { "CH",  NULL_TREE, NULL, 1,  Reg_ECX },
+    { "DL",  NULL_TREE, NULL, 1,  Reg_EDX },
+    { "DH",  NULL_TREE, NULL, 1,  Reg_EDX },
+    { "CR0", NULL_TREE, NULL, 0, -1 },
+    { "CR2", NULL_TREE, NULL, 0, -1 },
+    { "CR3", NULL_TREE, NULL, 0, -1 },
+    { "CR4", NULL_TREE, NULL, 0, -1 },
+    { "DR0", NULL_TREE, NULL, 0, -1 },
+    { "DR1", NULL_TREE, NULL, 0, -1 },
+    { "DR2", NULL_TREE, NULL, 0, -1 },
+    { "DR3", NULL_TREE, NULL, 0, -1 },
+    { "DR6", NULL_TREE, NULL, 0, -1 },
+    { "DR7", NULL_TREE, NULL, 0, -1 },
+    { "TR3", NULL_TREE, NULL, 0, -1 },
+    { "TR4", NULL_TREE, NULL, 0, -1 },
+    { "TR5", NULL_TREE, NULL, 0, -1 },
+    { "TR6", NULL_TREE, NULL, 0, -1 },
+    { "TR7", NULL_TREE, NULL, 0, -1 }
+};
+
+typedef enum {
+    No_Type_Needed,
+    Int_Types,
+    Word_Types, // same as Int_Types, but byte is not allowed
+    FP_Types,
+    FPInt_Types,
+    Byte_NoType, // byte only, but no type suffix
+} TypeNeeded;
+
+typedef enum {
+    No_Link,
+    Out_Mnemonic,
+    Next_Form
+} OpLink;
+
+typedef enum {
+    Clb_SizeAX   = 0x01,
+    Clb_SizeDXAX = 0x02,
+    Clb_EAX      = 0x03,
+    Clb_DXAX_Mask = 0x03,
+    
+    Clb_Flags    = 0x04,
+    Clb_DI       = 0x08,
+    Clb_SI       = 0x10,
+    Clb_CX       = 0x20,
+    Clb_ST       = 0x40,
+    Clb_SP       = 0x80 // Doesn't actually let GCC know the frame pointer is modified
+} ImplicitClober;
+
+// "^ +/..\([A-Za-z_0-9]+\).*" -> "    \1,"
+typedef enum {
+    Op_Invalid,
+    Op_Adjust,
+    Op_Dst,
+    Op_Upd,
+    Op_DstW,
+    Op_DstF,
+    Op_UpdF,
+    Op_DstSrc,
+    Op_DstSrcF,
+    Op_UpdSrcF,
+    Op_DstSrcFW,
+    Op_UpdSrcFW,
+    Op_DstSrcSSE,
+    Op_DstSrcMMX,
+    Op_DstSrcImmS,
+    Op_DstSrcImmM,
+    Op_UpdSrcShft,
+    Op_DstSrcNT,
+    Op_UpdSrcNT,
+    Op_DstMemNT,
+    Op_DstRMBNT,
+    Op_DstRMWNT,
+    Op_UpdUpd,
+    Op_UpdUpdF,
+    Op_Src,
+    Op_SrcRMWNT,
+    Op_SrcW,
+    Op_SrcImm,
+    Op_Src_DXAXF,
+    Op_SrcMemNT,
+    Op_SrcMemNTF,
+    Op_SrcSrc,
+    Op_SrcSrcF,
+    Op_SrcSrcFW,
+    Op_SrcSrcSSEF,
+    Op_SrcSrcMMX,
+    Op_Shift,
+    Op_Branch,
+    Op_CBranch,
+    Op_0,
+    Op_0_AX,
+    Op_0_DXAX,
+    Op_Loop,
+    Op_Flags,
+    Op_F0_ST,
+    Op_F0_P,
+    Op_Fs_P,
+    Op_Fis,
+    Op_Fis_ST,
+    Op_Fis_P,
+    Op_Fid,
+    Op_Fid_P,
+    Op_Ffd,
+    Op_FfdR,
+    Op_Ffd_P,
+    Op_FfdR_P,
+    Op_Fd_P,
+    Op_FdST,
+    Op_FMath,
+    Op_FdSTiSTi,
+    Op_FPMath,
+    Op_FCmp,
+    Op_FCmp1,
+    Op_FCmpP,
+    Op_FCmpP1,
+    Op_FCmpFlg,
+    Op_FCmpFlgP,
+    Op_fld,
+    Op_fldR,
+    Op_fxch,
+    Op_fxch1,
+    Op_fxch0,
+    Op_SizedStack,
+    Op_bound,
+    Op_bswap,
+    Op_cmps,
+    Op_cmpsd,
+    Op_cmpsX,
+    Op_cmpxchg8b,
+    Op_cmpxchg,
+    Op_cpuid,
+    Op_enter,
+    Op_fdisi,
+    Op_feni,
+    Op_fsetpm,
+    Op_fXstsw,
+    Op_imul,
+    Op_imul2,
+    Op_imul1,
+    Op_in,
+    Op_ins,
+    Op_insX,
+    Op_iret,
+    Op_iretd,
+    Op_lods,
+    Op_lodsX,
+    Op_movs,
+    Op_movsd,
+    Op_movsX,
+    Op_movsx,
+    Op_movzx,
+    Op_mul,
+    Op_out,
+    Op_outs,
+    Op_outsX,
+    Op_push,
+    Op_ret,
+    Op_retf,
+    Op_scas,
+    Op_scasX,
+    Op_stos,
+    Op_stosX,
+    Op_xlat,
+    N_AsmOpInfo,
+    Op_Align,
+    Op_Even,
+    Op_Naked,
+    Op_db,
+    Op_ds,
+    Op_di,
+    Op_dl,
+    Op_df,
+    Op_dd,
+    Op_de
+} AsmOp;
+
+typedef enum {
+    Opr_None = 0,
+    OprC_MRI  = 1,
+    OprC_MR   = 2,
+    OprC_Mem  = 3,
+    OprC_Reg  = 4,
+    OprC_Imm  = 5,
+    OprC_SSE  = 6,
+    OprC_SSE_Mem = 7,
+    OprC_R32  = 8,
+    OprC_RWord = 9,
+    OprC_RFP   = 10,
+    OprC_AbsRel = 11,
+    OprC_Relative = 12,
+    OprC_Port = 13, // DX or imm
+    OprC_AX = 14, // AL,AX,EAX
+    OprC_DX = 15, // only DX
+    OprC_MMX = 16,
+    OprC_MMX_Mem = 17,
+    OprC_Shift = 18, // imm or CL
+    
+    Opr_ClassMask = 0x1f,
+    
+    Opr_Dest     = 0x20,
+    Opr_Update   = 0x60,
+    
+    Opr_NoType = 0x80,
+} OprVals;
+
+
+typedef struct {
+} AsmOprInfo;
+
+typedef unsigned char Opr;
+
+typedef struct {
+    Opr operands[3];
+    unsigned char
+	needsType : 3,
+	implicitClobbers : 8,
+        linkType : 2;
+    unsigned link;
+
+    /*
+    bool takesLabel() {
+	return operands[0] & Opr_Label;
+    }
+    */
+    
+    unsigned nOperands() {
+	if (!operands[0])
+	    return 0;
+	else if (!operands[1])
+	    return 1;
+	else if (!operands[2])
+	    return 2;
+	else
+	    return 3;
+    }
+} AsmOpInfo;
+
+typedef enum {
+    Mn_fdisi,
+    Mn_feni,
+    Mn_fsetpm,
+    Mn_iretw,
+    Mn_iret,
+    Mn_lret,
+    Mn_cmpxchg8b,
+    N_AltMn
+} Alternate_Mnemonics;
+
+static const char * alternateMnemonics[N_AltMn] = {
+    ".byte 0xdb, 0xe1",
+    ".byte 0xdb, 0xe0",
+    ".byte 0xdb, 0xe4",
+    "iretw",
+    "iret",
+    "lret",
+    "cmpxchg8b" };
+
+#define mri  OprC_MRI
+#define mr   OprC_MR
+#define mem  OprC_Mem
+// for now mfp=mem
+#define mfp  OprC_Mem
+#define reg  OprC_Reg
+#define imm  OprC_Imm
+#define sse  OprC_SSE
+#define ssem OprC_SSE_Mem
+#define mmx  OprC_MMX
+#define mmxm OprC_MMX_Mem
+#define r32  OprC_R32
+#define rw   OprC_RWord
+#define rfp  OprC_RFP
+#define port OprC_Port
+#define ax   OprC_AX
+#define dx   OprC_DX
+#define shft OprC_Shift
+#define D    Opr_Dest
+#define U    Opr_Update
+#define N    Opr_NoType
+//#define L    Opr_Label
+
+// D=dest, N=notype
+static AsmOpInfo asmOpInfo[N_AsmOpInfo] = {
+    /* Op_Invalid   */  {},
+    /* Op_Adjust    */  { 0,0,0,             0, Clb_EAX /*just AX*/ },
+    /* Op_Dst       */  { D|mr,  0,    0,    1  },
+    /* Op_Upd       */  { U|mr,  0,    0,    1  },
+    /* Op_DstW      */  { D|mr,  0,    0,    Word_Types  },
+    /* Op_DstF      */  { D|mr,  0,    0,    1, Clb_Flags },
+    /* Op_UpdF      */  { U|mr,  0,    0,    1, Clb_Flags },
+    /* Op_DstSrc    */  { D|mr,  mri,  0,/**/1  }, 
+    /* Op_DstSrcF   */  { D|mr,  mri,  0,/**/1, Clb_Flags }, 
+    /* Op_UpdSrcF   */  { U|mr,  mri,  0,/**/1, Clb_Flags }, 
+    /* Op_DstSrcFW  */  { D|mr,  mri,  0,/**/Word_Types, Clb_Flags }, 
+    /* Op_UpdSrcFW  */  { U|mr,  mri,  0,/**/Word_Types, Clb_Flags }, 
+    /* Op_DstSrcSSE */  { U|sse, ssem, 0     },  // some may not be update %%
+    /* Op_DstSrcMMX */  { U|mmx, mmxm, 0     },  // some may not be update %%
+    /* Op_DstSrcImmS*/  { U|sse, ssem, N|imm  }, // some may not be update %%
+    /* Op_DstSrcImmM*/  { U|mmx, mmxm, N|imm  }, // some may not be update %%
+    /* Op_UpdSrcShft*/  { U|mr,  reg,  N|shft, 1, Clb_Flags }, // 16/32 only
+    /* Op_DstSrcNT  */  { D|mr,  mr,   0,    0 }, // used for movd .. operands can be rm32,sse,mmx
+    /* Op_UpdSrcNT  */  { U|mr,  mr,   0,    0 }, // used for movd .. operands can be rm32,sse,mmx
+    /* Op_DstMemNT  */  { D|mem, 0,    0     },
+    /* Op_DstRMBNT  */  { D|mr,  0,    0,    Byte_NoType },
+    /* Op_DstRMWNT  */  { D|mr,  0,    0     },
+    /* Op_UpdUpd    */  { U|mr,U|mr,   0,/**/1  }, 
+    /* Op_UpdUpdF   */  { U|mr,U|mr,   0,/**/1, Clb_Flags }, 
+    /* Op_Src       */  {   mri, 0,    0,    1  },
+    /* Op_SrcRMWNT  */  {   mr,  0,    0,    0  },
+    /* Op_SrcW      */  {   mri, 0,    0,    Word_Types  },
+    /* Op_SrcImm    */  {   imm },
+    /* Op_Src_DXAXF */  {   mr,  0,    0,    1, Clb_SizeDXAX|Clb_Flags },
+    /* Op_SrcMemNT  */  {   mem, 0,    0     },
+    /* Op_SrcMemNTF */  {   mem, 0,    0,    0, Clb_Flags },
+    /* Op_SrcSrc    */  {   mr,  mri,  0,    1  },
+    /* Op_SrcSrcF   */  {   mr,  mri,  0,    1, Clb_Flags },
+    /* Op_SrcSrcFW  */  {   mr,  mri,  0,    Word_Types, Clb_Flags },
+    /* Op_SrcSrcSSEF*/  {   sse, ssem, 0,    0, Clb_Flags },
+    /* Op_SrcSrcMMX */  {   mmx, mmx,  0, },
+    /* Op_Shift     */  { D|mr,N|shft, 0,/**/1, Clb_Flags }, 
+    /* Op_Branch    */  {   mri },
+    /* Op_CBranch   */  {   imm },
+    /* Op_0         */  {   0,0,0 },
+    /* Op_0_AX      */  {   0,0,0,           0, Clb_SizeAX },
+    /* Op_0_DXAX    */  {   0,0,0,           0, Clb_SizeDXAX }, // but for cwd/cdq -- how do know the size..
+    /* Op_Loop      */  {   imm, 0,    0,    0, Clb_CX },
+    /* Op_Flags     */  {   0,0,0,           0, Clb_Flags },
+    /* Op_F0_ST     */  {   0,0,0,           0, Clb_ST },
+    /* Op_F0_P      */  {   0,0,0,           0, Clb_ST }, // push, pops, etc. not sure how to inform gcc..
+    /* Op_Fs_P      */  {   mem, 0,    0,    0, Clb_ST }, // "
+    /* Op_Fis       */  {   mem, 0,    0,    FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
+    /* Op_Fis_ST    */  {   mem, 0,    0,    FPInt_Types, Clb_ST }, // "
+    /* Op_Fis_P     */  {   mem, 0,    0,    FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 
+    /* Op_Fid       */  { D|mem, 0,    0,    FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
+    /* Op_Fid_P     */  { D|mem, 0,    0,    FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 
+    /* Op_Ffd       */  { D|mfp, 0,    0,    FP_Types, 0, Next_Form, Op_FfdR }, // only 16bit and 32bit, DMD defaults to 16bit, reg form doesn't need type
+    /* Op_FfdR      */  { D|rfp, 0,    0  }, 
+    /* Op_Ffd_P     */  { D|mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_FfdR_P, }, // pop, fld so also 80 bit, "
+    /* Op_FfdR_P    */  { D|rfp, 0,    0,    0,        Clb_ST },
+    /* Op_Fd_P      */  { D|mem, 0,    0,    0, Clb_ST }, // "
+    /* Op_FdST      */  { D|rfp, 0,    0  },
+    /* Op_FMath     */  {   mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_FdSTiSTi  }, // and only single or double prec
+    /* Op_FdSTiSTi  */  { D|rfp, rfp,  0, },
+    /* Op_FPMath    */  { D|rfp, rfp,  0,    0,        Clb_ST, Next_Form, Op_F0_P }, // pops
+    /* Op_FCmp      */  {   mfp, 0,    0,    FP_Types, 0,      Next_Form, Op_FCmp1 }, // DMD defaults to float ptr
+    /* Op_FCmp1     */  {   rfp, 0,    0,    0,        0,      Next_Form, Op_0 },
+    /* Op_FCmpP     */  {   mfp, 0,    0,    FP_Types, 0,      Next_Form, Op_FCmpP1 }, // pops
+    /* Op_FCmpP1    */  {   rfp, 0,    0,    0,        0,      Next_Form, Op_F0_P }, // pops
+    /* Op_FCmpFlg   */  {   rfp, rfp,  0,    0,        Clb_Flags },
+    /* Op_FCmpFlgP  */  {   rfp, rfp,  0,    0,        Clb_Flags }, // pops
+    /* Op_fld       */  {   mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_fldR },
+    /* Op_fldR      */  {   rfp, 0,    0,    0,        Clb_ST },
+    /* Op_fxch      */  { D|rfp,D|rfp, 0,    0,        Clb_ST, Next_Form, Op_fxch1 }, // not in intel manual?, but DMD allows it (gas won't), second arg must be ST
+    /* Op_fxch1     */  { D|rfp, 0,    0,    0,        Clb_ST, Next_Form, Op_fxch0 },
+    /* Op_fxch0     */  {   0,   0,    0,    0,        Clb_ST }, // Also clobbers ST(1)
+    /* Op_SizedStack*/  {   0,   0,    0,    0,        Clb_SP }, // type suffix special case
+    /* Op_bound     */  {   mr,  mri,  0,    Word_Types  }, // operands *not* reversed for gas
+    /* Op_bswap     */  { D|r32      },
+    /* Op_cmps      */  {   mem, mem, 0,     1, Clb_DI|Clb_SI|Clb_Flags },
+    /* Op_cmpsd     */  {   0,   0,   0,     0, Clb_DI|Clb_SI|Clb_Flags, Next_Form, Op_DstSrcImmS },
+    /* Op_cmpsX     */  {   0,   0,   0,     0, Clb_DI|Clb_SI|Clb_Flags },
+    /* Op_cmpxchg8b */  { D|mem/*64*/,0,0,   0, Clb_SizeDXAX/*32*/|Clb_Flags, Out_Mnemonic, Mn_cmpxchg8b },
+    /* Op_cmpxchg   */  { D|mr,  reg, 0,     1, Clb_SizeAX|Clb_Flags },
+    /* Op_cpuid     */  {   0,0,0 },    // Clobbers eax, ebx, ecx, and edx. Handled specially below.
+    /* Op_enter     */  {   imm, imm }, // operands *not* reversed for gas, %% inform gcc of EBP clobber?, 
+    /* Op_fdisi     */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_fdisi },
+    /* Op_feni      */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_feni },
+    /* Op_fsetpm    */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_fsetpm },
+    /* Op_fXstsw    */  { D|mr,  0,   0,     }, // ax is the only allowed register
+    /* Op_imul      */  { D|reg, mr,  imm,   1, Clb_Flags, Next_Form, Op_imul2 }, // 16/32 only
+    /* Op_imul2     */  { D|reg, mri, 0,     1, Clb_Flags, Next_Form, Op_imul1 }, // 16/32 only
+    /* Op_imul1     */  {   mr,  0,   0,     1, Clb_Flags|Clb_SizeDXAX },
+    /* Op_in        */  { D|ax,N|port,0,     1  },        
+    /* Op_ins       */  {   mem,N|dx, 0,     1, Clb_DI }, // can't override ES segment for this one
+    /* Op_insX      */  {   0,   0,   0,     0, Clb_DI }, // output segment overrides %% needs work
+    /* Op_iret      */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_iretw },
+    /* Op_iretd     */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_iret },
+    /* Op_lods      */  {   mem, 0,   0,     1, Clb_SI },
+    /* Op_lodsX     */  {   0,   0,   0,     0, Clb_SI },
+    /* Op_movs      */  {   mem, mem, 0,     1, Clb_DI|Clb_SI }, // only src/DS can be overridden
+    /* Op_movsd     */  {   0,   0,   0,     0, Clb_DI|Clb_SI, Next_Form, Op_DstSrcSSE }, // %% gas doesn't accept movsd .. has to movsl
+    /* Op_movsX     */  {   0,   0,   0,     0, Clb_DI|Clb_SI },
+    /* Op_movsx     */  { D|reg, mr,  0,     1 }, // type suffix is special case
+    /* Op_movzx     */  { D|reg, mr,  0,     1 }, // type suffix is special case
+    /* Op_mul       */  { U|ax,  mr,  0,     1, Clb_SizeDXAX|Clb_Flags, Next_Form, Op_Src_DXAXF },
+    /* Op_out       */  { N|port,ax,  0,     1  },        
+    /* Op_outs      */  { N|dx,  mem, 0,     1, Clb_SI },
+    /* Op_outsX     */  {   0,   0,   0,     0, Clb_SI },
+    /* Op_push      */  {   mri, 0,    0,    0, Clb_SP }, // would be Op_SrcW, but DMD defaults to 32-bit for immediate form
+    /* Op_ret       */  {   imm, 0,   0,     0, 0, Next_Form, Op_0  }, 
+    /* Op_retf      */  {   0,   0,   0,     0, 0, Out_Mnemonic, Mn_lret  },
+    /* Op_scas      */  {   mem, 0,   0,     1, Clb_DI|Clb_Flags },
+    /* Op_scasX     */  {   0,   0,   0,     0, Clb_DI|Clb_Flags },
+    /* Op_stos      */  {   mem, 0,   0,     1, Clb_DI },
+    /* Op_stosX     */  {   0,   0,   0,     0, Clb_DI },
+    /* Op_xlat      */  {   mem, 0,   0,     0, Clb_SizeAX }
+    
+    /// * Op_arpl      */  { D|mr,  reg }, // 16 only -> DstSrc
+    /// * Op_bsX       */  {   rw,  mrw,  0,    1, Clb_Flags },//->srcsrcf 
+    /// * Op_bt        */  {   mrw, riw,  0,    1, Clb_Flags },//->srcsrcf
+    /// * Op_btX       */  { D|mrw, riw,  0,    1, Clb_Flags },//->dstsrcf .. immediate does not contribute to size
+    /// * Op_cmovCC    */  { D|rw,  mrw,  0,    1 } // ->dstsrc
+};
+
+#undef mri
+#undef mr
+#undef mem
+#undef mfp
+#undef reg
+#undef imm
+#undef sse
+#undef ssem
+#undef mmx
+#undef mmxm
+#undef r32
+#undef rw
+#undef rfp
+#undef port
+#undef ax
+#undef dx
+#undef shft
+#undef D
+#undef U
+#undef N
+//#undef L
+
+typedef struct {
+    const char  * inMnemonic;
+    AsmOp   asmOp;
+} AsmOpEnt;
+
+/* Some opcodes which have data size restrictions, but we don't check
+
+   cmov, l<segreg> ?, lea, lsl, shld
+
+   todo: push <immediate> is always the 32-bit form, even tho push <mem> is 16-bit
+*/
+
+static AsmOpEnt opData[] = {
+    { "adc",    Op_UpdSrcF },
+
+    { "add",    Op_DstSrcNT }, //Op_UpdSrcF },
+    { "addpd",  Op_DstSrcSSE },
+    { "addps",  Op_DstSrcSSE },
+    { "addsd",  Op_DstSrcSSE },
+    { "addss",  Op_DstSrcSSE },
+    { "addsubpd", Op_DstSrcSSE },
+    { "addsubps", Op_DstSrcSSE },    
+    { "and",    Op_UpdSrcF },
+    { "andnpd", Op_DstSrcSSE },
+    { "andnps", Op_DstSrcSSE },
+    { "andpd",  Op_DstSrcSSE },
+    { "andps",  Op_DstSrcSSE },
+    { "bsf",    Op_SrcSrcFW },
+    { "bsr",    Op_SrcSrcFW },
+    { "bswap",  Op_bswap },
+    { "bt",     Op_SrcSrcFW },
+    { "btc",    Op_UpdSrcFW },
+    { "btr",    Op_UpdSrcFW },
+    { "bts",    Op_UpdSrcFW },
+    { "call",   Op_Branch },
+    { "callf",   Op_Branch },
+    { "cbw",    Op_0_AX },
+    { "cdqe",    Op_0_DXAX },
+    { "clc",    Op_Flags },
+    { "cld",    Op_Flags },
+    { "clflush",Op_SrcMemNT },
+    { "cli",    Op_Flags },
+    { "clts",   Op_0 },
+    { "cmc",    Op_Flags },
+    { "cmova",  Op_DstSrc },
+    { "cmovae", Op_DstSrc },
+    { "cmovb",  Op_DstSrc },
+    { "cmovbe", Op_DstSrc },
+    { "cmovc",  Op_DstSrc },
+    { "cmove",  Op_DstSrc },
+    { "cmovg",  Op_DstSrc },
+    { "cmovge", Op_DstSrc },
+    { "cmovl",  Op_DstSrc },
+    { "cmovle", Op_DstSrc },
+    { "cmovna", Op_DstSrc },
+    { "cmovnae",Op_DstSrc },
+    { "cmovnb", Op_DstSrc },
+    { "cmovnbe",Op_DstSrc },
+    { "cmovnc", Op_DstSrc },
+    { "cmovne", Op_DstSrc },
+    { "cmovng", Op_DstSrc },
+    { "cmovnge",Op_DstSrc },
+    { "cmovnl", Op_DstSrc },
+    { "cmovnle",Op_DstSrc },
+    { "cmovno", Op_DstSrc },
+    { "cmovnp", Op_DstSrc },
+    { "cmovns", Op_DstSrc },
+    { "cmovnz", Op_DstSrc },
+    { "cmovo",  Op_DstSrc },
+    { "cmovp",  Op_DstSrc },
+    { "cmovpe", Op_DstSrc },
+    { "cmovpo", Op_DstSrc },
+    { "cmovs",  Op_DstSrc },
+    { "cmovz",  Op_DstSrc },
+    { "cmp",    Op_SrcSrcF },
+    { "cmppd",  Op_DstSrcImmS },
+    { "cmpps",  Op_DstSrcImmS },
+    { "cmps",   Op_cmps  },
+    { "cmpsb",  Op_cmpsX },
+    { "cmpsd",  Op_cmpsd }, // string cmp, and SSE cmp
+    { "cmpss",  Op_DstSrcImmS },
+    { "cmpsw",  Op_cmpsX },
+    { "cmpsq",  Op_cmpsX },
+    /*
+    { "cdqe",  Op_0_DXAX },
+    { "cmpsq",  Op_cmpsX },
+    { "cmpxch16b", Op_cmpxchg16b }, 
+    { "cqo",    Op_0_DXAX },
+    { "lodsq", Op_lodsX },
+    { "movsq", Op_movsX },
+    { "popfq", Op_SizedStack },
+    { "pushfq", Op_SizedStack },
+    { "scasq",  Op_scasX },
+    { "stosq",  Op_stosX },
+    { "iretq", Op_iretd },  
+    { "swapgs", Op_0 },  
+    { "extrq",  Op_Extrq },
+    { "movsxq", Op_movsxq },
+    
+    { "clgi",    Op_Flags },
+    { "invlpga", Op_SrcMemNT },
+    { "rdtscp",  Op_0_DXAX },
+    { "stgi",    Op_Flags },
+    { "sysret", Op_0 },
+    */
+
+    { "cmpxch16b", Op_cmpxchg8b },
+    { "cmpxch8b", Op_cmpxchg8b }, // %% DMD opcode typo?
+    { "cmpxchg",  Op_cmpxchg },
+    { "comisd", Op_SrcSrcSSEF },
+    { "comiss", Op_SrcSrcSSEF },
+    { "cpuid",  Op_cpuid },
+    { "cvtdq2pd", Op_DstSrcSSE },
+    { "cvtdq2ps", Op_DstSrcSSE },
+    { "cvtpd2dq", Op_DstSrcSSE },
+    { "cvtpd2pi", Op_DstSrcSSE },
+    { "cvtpd2ps", Op_DstSrcSSE },
+    { "cvtpi2pd", Op_DstSrcSSE },
+    { "cvtpi2ps", Op_DstSrcSSE },
+    { "cvtps2dq", Op_DstSrcSSE },
+    { "cvtps2pd", Op_DstSrcSSE },
+    { "cvtps2pi", Op_DstSrcSSE },
+    { "cvtsd2si", Op_DstSrcSSE },
+    { "cvtsd2ss", Op_DstSrcSSE },
+    { "cvtsi2sd", Op_DstSrcSSE },
+    { "cvtsi2ss", Op_DstSrcSSE },
+    { "cvtss2sd", Op_DstSrcSSE },
+    { "cvtss2si", Op_DstSrcSSE },
+    { "cvttpd2dq", Op_DstSrcSSE },
+    { "cvttpd2pi", Op_DstSrcSSE },
+    { "cvttps2dq", Op_DstSrcSSE },
+    { "cvttps2pi", Op_DstSrcSSE },
+    { "cvttsd2si", Op_DstSrcSSE },
+    { "cvttss2si", Op_DstSrcSSE },
+    { "cwd",  Op_0_DXAX },
+    { "cwde", Op_0_DXAX },
+    //{ "da", Op_ },// dunno what this is -- takes labels?
+    { "db",    Op_db },
+    { "dd",    Op_dd },
+    { "de",    Op_de },
+    { "dec",   Op_UpdF },
+    { "df",    Op_df },
+    { "di",    Op_di },
+    { "div",   Op_Src_DXAXF },
+    { "divpd", Op_DstSrcSSE },
+    { "divps", Op_DstSrcSSE },
+    { "divsd", Op_DstSrcSSE },
+    { "divss", Op_DstSrcSSE },
+    { "dl",    Op_dl },
+    { "dq",    Op_dl },
+    { "ds",    Op_ds },
+    { "dt",    Op_de },
+    { "dw",    Op_ds },
+    { "emms",  Op_0 }, // clobber all mmx/fp?
+    { "enter", Op_enter },
+    { "f2xm1",  Op_F0_ST }, // %% most of these are update...
+    { "fabs",   Op_F0_ST },
+    { "fadd",   Op_FMath },
+    { "faddp",  Op_FPMath },
+    { "fbld",   Op_Fs_P },
+    { "fbstp",  Op_Fd_P },
+    { "fchs",   Op_F0_ST },
+    { "fclex",  Op_0 },
+    { "fcmovb",   Op_FdSTiSTi }, // but only ST(0) can be the destination -- should be FdST0STi
+    { "fcmovbe",  Op_FdSTiSTi },
+    { "fcmove",   Op_FdSTiSTi },
+    { "fcmovnb",  Op_FdSTiSTi },
+    { "fcmovnbe", Op_FdSTiSTi },
+    { "fcmovne",  Op_FdSTiSTi },
+    { "fcmovnu",  Op_FdSTiSTi },
+    { "fcmovu",   Op_FdSTiSTi },
+    { "fcom",   Op_FCmp },
+    { "fcomi",  Op_FCmpFlg  }, 
+    { "fcomip", Op_FCmpFlgP },
+    { "fcomp",  Op_FCmpP },
+    { "fcompp", Op_F0_P },   // pops twice
+    { "fcos",   Op_F0_ST }, 
+    { "fdecstp",Op_F0_P },   // changes stack
+    { "fdisi",  Op_fdisi },
+    { "fdiv",   Op_FMath },
+    { "fdivp",  Op_FPMath }, 
+    { "fdivr",  Op_FMath },
+    { "fdivrp", Op_FPMath },
+    { "feni",   Op_feni },
+    { "ffree",  Op_FdST },
+    { "fiadd",  Op_Fis_ST },
+    { "ficom",  Op_Fis   },
+    { "ficomp", Op_Fis_P },
+    { "fidiv",  Op_Fis_ST },
+    { "fidivr", Op_Fis_ST },
+    { "fild",   Op_Fis_P },
+    { "fimul",  Op_Fis_ST },
+    { "fincstp",Op_F0_P },
+    { "finit",  Op_F0_P },
+    { "fist",   Op_Fid }, // only 16,32bit
+    { "fistp",  Op_Fid_P }, 
+    { "fisttp", Op_Fid_P }, 
+    { "fisub",  Op_Fis_ST },
+    { "fisubr", Op_Fis_ST },
+    { "fld",    Op_fld },
+    { "fld1",   Op_F0_P },
+    { "fldcw",  Op_SrcMemNT },
+    { "fldenv", Op_SrcMemNT },
+    { "fldl2e", Op_F0_P },
+    { "fldl2t", Op_F0_P },
+    { "fldlg2", Op_F0_P },
+    { "fldln2", Op_F0_P },
+    { "fldpi",  Op_F0_P },
+    { "fldz",   Op_F0_P },
+    { "fmul",   Op_FMath },
+    { "fmulp",  Op_FPMath },
+    { "fnclex", Op_0 },
+    { "fndisi", Op_fdisi }, // ??
+    { "fneni",  Op_feni }, // ??
+    { "fninit", Op_0 },
+    { "fnop",   Op_0 },
+    { "fnsave", Op_DstMemNT },
+    { "fnstcw", Op_DstMemNT },
+    { "fnstenv",Op_DstMemNT },
+    { "fnstsw", Op_fXstsw },
+    { "fpatan", Op_F0_P }, // pop and modify new ST
+    { "fprem",  Op_F0_ST }, 
+    { "fprem1", Op_F0_ST }, 
+    { "fptan",  Op_F0_P }, // modify ST and push 1.0
+    { "frndint",Op_F0_ST }, 
+    { "frstor", Op_SrcMemNT }, // but clobbers everything
+    { "fsave",  Op_DstMemNT },
+    { "fscale", Op_F0_ST },
+    { "fsetpm", Op_fsetpm },
+    { "fsin",   Op_F0_ST },
+    { "fsincos",Op_F0_P },
+    { "fsqrt",  Op_F0_ST },
+    { "fst",    Op_Ffd },
+    { "fstcw",  Op_DstMemNT },
+    { "fstenv", Op_DstMemNT },
+    { "fstp",   Op_Ffd_P },
+    { "fstsw",  Op_fXstsw },
+    { "fsub",   Op_FMath },
+    { "fsubp",  Op_FPMath },
+    { "fsubr",  Op_FMath },
+    { "fsubrp", Op_FPMath },
+    { "ftst",   Op_0 },
+    { "fucom",  Op_FCmp },
+    { "fucomi", Op_FCmpFlg },
+    { "fucomip",Op_FCmpFlgP },
+    { "fucomp", Op_FCmpP },
+    { "fucompp",Op_F0_P }, // pops twice
+    { "fwait",  Op_0 },
+    { "fxam",   Op_0 },
+    { "fxch",   Op_fxch },
+    { "fxrstor",Op_SrcMemNT },  // clobbers FP,MMX,SSE
+    { "fxsave", Op_DstMemNT },
+    { "fxtract",Op_F0_P }, // pushes
+    { "fyl2x",  Op_F0_P }, // pops
+    { "fyl2xp1",Op_F0_P }, // pops
+    { "haddpd", Op_DstSrcSSE },
+    { "haddps", Op_DstSrcSSE },
+    { "hlt",  Op_0 },
+    { "hsubpd", Op_DstSrcSSE },
+    { "hsubps", Op_DstSrcSSE },
+    { "idiv", Op_Src_DXAXF },
+    { "imul",   Op_DstSrcNT  },
+    { "in",   Op_in },
+    { "inc",  Op_UpdF },
+    { "ins",  Op_ins },
+    { "insb", Op_insX },
+    { "insd", Op_insX },
+    { "insw", Op_insX },
+    { "int",  Op_SrcImm },
+    { "into", Op_0 },
+    { "invd", Op_0 },
+    { "invlpg", Op_SrcMemNT },
+    { "iret",  Op_iret },
+    { "iretd", Op_iretd },    
+    { "iretq", Op_iretd },    
+    { "ja",    Op_CBranch },
+    { "jae",   Op_CBranch },
+    { "jb",    Op_CBranch },
+    { "jbe",   Op_CBranch },
+    { "jc",    Op_CBranch },
+    { "jcxz",  Op_CBranch },
+    { "je",    Op_CBranch },
+    { "jecxz", Op_CBranch },
+    { "jg",    Op_CBranch },
+    { "jge",   Op_CBranch },
+    { "jl",    Op_CBranch },
+    { "jle",   Op_CBranch },
+    { "jmp",   Op_Branch },
+    { "jmpe",   Op_Branch },
+    { "jmpf",   Op_Branch },
+    { "jna",   Op_CBranch },
+    { "jnae",  Op_CBranch },
+    { "jnb",   Op_CBranch },
+    { "jnbe",  Op_CBranch },
+    { "jnc",   Op_CBranch },
+    { "jne",   Op_CBranch },
+    { "jng",   Op_CBranch },
+    { "jnge",  Op_CBranch },
+    { "jnl",   Op_CBranch },
+    { "jnle",  Op_CBranch },
+    { "jno",   Op_CBranch },
+    { "jnp",   Op_CBranch },
+    { "jns",   Op_CBranch },
+    { "jnz",   Op_CBranch },
+    { "jo",    Op_CBranch },
+    { "jp",    Op_CBranch },
+    { "jpe",   Op_CBranch },
+    { "jpo",   Op_CBranch },
+    { "jrcxz", Op_CBranch },
+    { "js",    Op_CBranch },
+    { "jz",    Op_CBranch },
+    { "lahf",  Op_0_AX },
+    { "lar",   Op_DstSrcFW }, // reg dest only
+    { "lddqu", Op_DstSrcSSE },
+    { "ldmxcsr", Op_SrcMemNT },
+    { "lds",   Op_DstSrc },  // reg dest only
+    { "lea",   Op_DstSrc },  // "
+    { "leaq",   Op_DstSrcSSE },  // "
+    { "leave", Op_0 },       // EBP,ESP clobbers
+    { "lfence",Op_0 },
+    { "lfs",   Op_DstSrc },
+    { "lgdt",  Op_SrcMemNT },
+    { "lgs",   Op_DstSrc },
+    { "lidt",  Op_SrcMemNT },
+    { "lldt",  Op_SrcRMWNT },
+    { "lmsw",  Op_SrcRMWNT },
+    { "lock",  Op_0 },
+    { "lods",  Op_lods },
+    { "lodsb", Op_lodsX },
+    { "lodsd", Op_lodsX },
+    { "lodsw", Op_lodsX },
+    { "lodsq", Op_lodsX },
+    { "loop",  Op_Loop },
+    { "loope", Op_Loop },
+    { "loopne",Op_Loop },
+    { "loopnz",Op_Loop },
+    { "loopz", Op_Loop },
+    { "lsl",   Op_DstSrcFW }, // reg dest only
+    { "lss",   Op_DstSrc },
+    { "ltr",   Op_DstMemNT },
+    { "maskmovdqu", Op_SrcSrcMMX }, // writes to [edi]
+    { "maskmovq",   Op_SrcSrcMMX }, 
+    { "maxpd", Op_DstSrcSSE },
+    { "maxps", Op_DstSrcSSE },
+    { "maxsd", Op_DstSrcSSE },
+    { "maxss", Op_DstSrcSSE },
+    { "mfence",Op_0},
+    { "minpd", Op_DstSrcSSE },
+    { "minps", Op_DstSrcSSE },
+    { "minsd", Op_DstSrcSSE },
+    { "minss", Op_DstSrcSSE },
+    { "monitor", Op_0 },
+    { "mov",   Op_DstSrc },
+    { "movb",   Op_DstSrcNT  },
+    { "movapd",  Op_DstSrcSSE },
+    { "movaps",  Op_DstSrcSSE },
+    { "movd",    Op_DstSrcNT  }, // also mmx and sse
+    { "movddup", Op_DstSrcSSE },
+    { "movdq2q", Op_DstSrcNT }, // mmx/sse
+    { "movdqa",  Op_DstSrcSSE },
+    { "movdqu",  Op_DstSrcSSE },
+    { "movhlps", Op_DstSrcSSE },
+    { "movhpd",  Op_DstSrcSSE },
+    { "movhps",  Op_DstSrcSSE },
+    { "movlhps", Op_DstSrcSSE },
+    { "movlpd",  Op_DstSrcSSE },
+    { "movlps",  Op_DstSrcSSE },
+    { "movmskpd",Op_DstSrcSSE },
+    { "movmskps",Op_DstSrcSSE },
+    { "movntdq", Op_DstSrcNT  }, // limited to sse, but mem dest
+    { "movnti",  Op_DstSrcNT  }, // limited to gpr, but mem dest
+    { "movntpd", Op_DstSrcNT  }, // limited to sse, but mem dest
+    { "movntps", Op_DstSrcNT  }, // limited to sse, but mem dest
+    { "movntq",  Op_DstSrcNT  }, // limited to mmx, but mem dest
+    { "movq",    Op_DstSrcNT  }, // limited to sse and mmx
+    { "movq2dq", Op_DstSrcNT  }, // limited to sse <- mmx regs
+    { "movs",  Op_movs },
+    { "movsb", Op_movsX },
+    { "movsd", Op_movsd },
+    { "movsq", Op_movsd },
+    { "movshdup", Op_DstSrcSSE },
+    { "movsldup", Op_DstSrcSSE },
+    { "movss", Op_DstSrcSSE },
+    { "movsw", Op_movsX },
+    { "movsx", Op_movsx }, // word-only, reg dest
+    { "movsxd", Op_movsx }, 
+    { "movupd",Op_DstSrcSSE },
+    { "movups",Op_DstSrcSSE },
+    { "movzbl",   Op_DstSrcNT  },
+    { "movzx", Op_movzx },
+    { "mul",   Op_DstSrcNT  },
+    { "mulpd", Op_DstSrcSSE },
+    { "mulps", Op_DstSrcSSE },
+    { "mulsd", Op_DstSrcSSE },
+    { "mulss", Op_DstSrcSSE },
+    { "mwait", Op_0 },
+    { "neg",   Op_UpdF },
+    { "nop",   Op_0 },
+    { "not",   Op_Upd },
+    { "or",    Op_UpdSrcF },
+    { "orpd",  Op_DstSrcSSE },
+    { "orps",  Op_DstSrcSSE },
+    { "out",   Op_out },
+    { "outs",  Op_outs },
+    { "outsb", Op_outsX },
+    { "outsd", Op_outsX },
+    { "outsw", Op_outsX },
+    { "pabsb",    Op_DstSrcSSE },
+    { "pabsw",    Op_DstSrcSSE },
+    { "pabsq",    Op_DstSrcSSE },
+    { "packssdw", Op_DstSrcMMX }, // %% also SSE
+    { "packsswb", Op_DstSrcMMX },
+    { "packuswb", Op_DstSrcMMX },
+    { "paddb",    Op_DstSrcMMX },
+    { "paddd",    Op_DstSrcMMX },
+    { "paddq",    Op_DstSrcMMX },
+    { "paddsb",   Op_DstSrcMMX },
+    { "paddsw",   Op_DstSrcMMX },
+    { "paddusb",  Op_DstSrcMMX },
+    { "paddusw",  Op_DstSrcMMX },
+    { "paddw",    Op_DstSrcMMX },
+    { "palignr",     Op_DstSrcSSE },
+    { "pand",     Op_DstSrcMMX },
+    { "pandn",    Op_DstSrcMMX },
+    { "pause",    Op_DstSrcMMX },
+    { "pavgb",    Op_DstSrcMMX },
+    { "pavgw",    Op_DstSrcMMX },
+    { "pcmpeqb",  Op_DstSrcMMX },
+    { "pcmpeqd",  Op_DstSrcMMX },
+    { "pcmpeqw",  Op_DstSrcMMX },
+    { "pcmpgtb",  Op_DstSrcMMX },
+    { "pcmpgtd",  Op_DstSrcMMX },
+    { "pcmpgtw",  Op_DstSrcMMX },
+    { "pextrw",   Op_DstSrcImmM }, // gpr32 dest
+    { "phaddd",     Op_DstSrcSSE },
+    { "phaddsw",     Op_DstSrcSSE },
+    { "phaddw",     Op_DstSrcSSE },
+    { "phsubd",     Op_DstSrcSSE },
+    { "phsubsw",     Op_DstSrcSSE },
+    { "phsubw",     Op_DstSrcSSE },
+    { "pinsrw",   Op_DstSrcImmM }, // gpr32(16), mem16 src, sse too
+    { "pmaddubsw",  Op_DstSrcSSE },
+    { "pmaddwd",  Op_DstSrcMMX },
+    { "pmaxsw",   Op_DstSrcMMX },
+    { "pmaxub",   Op_DstSrcMMX },
+    { "pminsw",   Op_DstSrcMMX },
+    { "pminub",   Op_DstSrcMMX },
+    { "pmovmskb", Op_DstSrcMMX },
+    { "pmulhrsw",  Op_DstSrcMMX },
+    { "pmulhuw",  Op_DstSrcMMX },
+    { "pmulhw",   Op_DstSrcMMX },
+    { "pmullw",   Op_DstSrcMMX },
+    { "pmuludq",  Op_DstSrcMMX }, // also sse
+    { "pop",      Op_DstW },
+    { "popf",     Op_SizedStack },  // rewrite the insn with a special case
+    { "popfq",    Op_SizedStack }, 
+    { "popq",    Op_push }, 
+    { "por",      Op_DstSrcMMX },
+    { "prefetchnta", Op_SrcMemNT },
+    { "prefetcht0",  Op_SrcMemNT },
+    { "prefetcht1",  Op_SrcMemNT },
+    { "prefetcht2",  Op_SrcMemNT },
+    { "psadbw",   Op_DstSrcMMX },
+    { "pshufb",   Op_DstSrcImmM },
+    { "pshufd",   Op_DstSrcImmM },
+    { "pshufhw",  Op_DstSrcImmM },
+    { "pshuflw",  Op_DstSrcImmM },
+    { "pshufw",   Op_DstSrcImmM },
+    { "psignb",   Op_DstSrcSSE },
+    { "psignd",   Op_DstSrcSSE },
+    { "psignw",   Op_DstSrcSSE },
+    { "pslld",    Op_DstSrcMMX }, // immediate operands...
+    { "pslldq",   Op_DstSrcMMX },
+    { "psllq",    Op_DstSrcMMX },
+    { "psllw",    Op_DstSrcMMX },
+    { "psrad",    Op_DstSrcMMX },
+    { "psraw",    Op_DstSrcMMX },
+    { "psrld",    Op_DstSrcMMX },
+    { "psrldq",   Op_DstSrcMMX },
+    { "psrlq",    Op_DstSrcMMX },
+    { "psrlw",    Op_DstSrcMMX },
+    { "psubb",    Op_DstSrcMMX },
+    { "psubd",    Op_DstSrcMMX },
+    { "psubq",    Op_DstSrcMMX },
+    { "psubsb",   Op_DstSrcMMX },
+    { "psubsw",   Op_DstSrcMMX },
+    { "psubusb",  Op_DstSrcMMX },
+    { "psubusw",  Op_DstSrcMMX },
+    { "psubw",    Op_DstSrcMMX },
+    { "punpckhbw", Op_DstSrcMMX },
+    { "punpckhdq", Op_DstSrcMMX },
+    { "punpckhqdq",Op_DstSrcMMX },
+    { "punpckhwd", Op_DstSrcMMX },
+    { "punpcklbw", Op_DstSrcMMX },
+    { "punpckldq", Op_DstSrcMMX },
+    { "punpcklqdq",Op_DstSrcMMX },
+    { "punpcklwd", Op_DstSrcMMX },
+    { "push",   Op_push },
+    { "pushf",  Op_SizedStack },
+    { "pushfq", Op_SizedStack },
+    { "pushq", Op_push },
+    { "pxor",   Op_DstSrcMMX },
+    { "rcl",    Op_Shift }, // limited src operands -- change to shift
+    { "rcpps",  Op_DstSrcSSE },
+    { "rcpss",  Op_DstSrcSSE },
+    { "rcr",    Op_Shift },
+    { "rdmsr",  Op_0_DXAX },
+    { "rdpmc",  Op_0_DXAX },
+    { "rdtsc",  Op_0_DXAX },
+    { "rep",    Op_0 },
+    { "repe",   Op_0 },
+    { "repne",  Op_0 },
+    { "repnz",  Op_0 },
+    { "repz",   Op_0 },
+    { "ret",    Op_ret },
+    { "retf",   Op_retf },
+    { "retn",   Op_retf },
+    { "rol",    Op_Shift },
+    { "ror",    Op_Shift },
+    { "rsm",    Op_0 },
+    { "rsqrtps", Op_DstSrcSSE },
+    { "rsqrtss", Op_DstSrcSSE },
+    { "sahf",   Op_Flags },
+    { "sal",    Op_Shift },
+    { "salq",   Op_DstSrcNT  },
+    { "sar",    Op_Shift },
+    { "sbb",    Op_UpdSrcF },
+    { "scas",   Op_scas },
+    { "scasb",  Op_scasX },
+    { "scasd",  Op_scasX },
+    { "scasw",  Op_scasX },
+    { "scasq",  Op_scasX },
+    { "seta",   Op_DstRMBNT }, // also gpr8
+    { "setae",  Op_DstRMBNT },
+    { "setb",   Op_DstRMBNT },
+    { "setbe",  Op_DstRMBNT },
+    { "setc",   Op_DstRMBNT },
+    { "sete",   Op_DstRMBNT },
+    { "setg",   Op_DstRMBNT },
+    { "setge",  Op_DstRMBNT },
+    { "setl",   Op_DstRMBNT },
+    { "setle",  Op_DstRMBNT },
+    { "setna",  Op_DstRMBNT },
+    { "setnae", Op_DstRMBNT },
+    { "setnb",  Op_DstRMBNT },
+    { "setnbe", Op_DstRMBNT },
+    { "setnc",  Op_DstRMBNT },
+    { "setne",  Op_DstRMBNT },
+    { "setng",  Op_DstRMBNT },
+    { "setnge", Op_DstRMBNT },
+    { "setnl",  Op_DstRMBNT },
+    { "setnle", Op_DstRMBNT },
+    { "setno",  Op_DstRMBNT },
+    { "setnp",  Op_DstRMBNT },
+    { "setns",  Op_DstRMBNT },
+    { "setnz",  Op_DstRMBNT },
+    { "seto",   Op_DstRMBNT },
+    { "setp",   Op_DstRMBNT },
+    { "setpe",  Op_DstRMBNT },
+    { "setpo",  Op_DstRMBNT },
+    { "sets",   Op_DstRMBNT },
+    { "setz",   Op_DstRMBNT },
+    { "sfence", Op_0 },
+    { "sgdt",   Op_DstMemNT },
+    { "shl",    Op_Shift },
+    { "shld",   Op_UpdSrcShft },
+    { "shr",    Op_Shift },
+    { "shrd",   Op_UpdSrcShft },
+    { "shufpd", Op_DstSrcImmS },
+    { "shufps", Op_DstSrcImmS },
+    { "sidt",   Op_DstMemNT },
+    { "sldt",   Op_DstRMWNT },
+    { "smsw",   Op_DstRMWNT },
+    { "sqrtpd", Op_DstSrcSSE },
+    { "sqrtps", Op_DstSrcSSE },
+    { "sqrtsd", Op_DstSrcSSE },
+    { "sqrtss", Op_DstSrcSSE },
+    { "stc",    Op_Flags },
+    { "std",    Op_Flags },
+    { "sti",    Op_Flags },
+    { "stmxcsr",Op_DstMemNT },
+    { "stos",   Op_stos },
+    { "stosb",  Op_stosX },
+    { "stosd",  Op_stosX },
+    { "stosw",  Op_stosX },
+    { "stosq",  Op_stosX },
+    { "str",    Op_DstMemNT }, // also r16
+    { "sub",    Op_UpdSrcF },
+    { "subpd",  Op_DstSrcSSE },
+    { "subps",  Op_DstSrcSSE },
+    { "subsd",  Op_DstSrcSSE },
+    { "subss",  Op_DstSrcSSE },
+    { "swapgs",  Op_DstSrcSSE },
+    { "sysenter",Op_0 },
+    { "sysexit", Op_0 },
+    { "sysret", Op_0 },
+    { "testl",   Op_DstSrcNT  },
+    { "ucomisd", Op_SrcSrcSSEF },
+    { "ucomiss", Op_SrcSrcSSEF },
+    { "ud2",     Op_0 },
+    { "unpckhpd", Op_DstSrcSSE },
+    { "unpckhps", Op_DstSrcSSE },
+    { "unpcklpd", Op_DstSrcSSE },
+    { "unpcklps", Op_DstSrcSSE },
+    { "verr",   Op_SrcMemNTF },
+    { "verw",   Op_SrcMemNTF },
+    { "wbinvd", Op_0 },
+    { "wrmsr",  Op_0 },
+    { "xadd",   Op_UpdUpdF },
+    { "xchg",   Op_UpdUpd },
+    { "xlat",   Op_xlat },
+    { "xlatb",  Op_0_AX },
+    { "xor",    Op_DstSrcF },
+    { "xorpd",  Op_DstSrcSSE },
+    { "xorps",  Op_DstSrcSSE },
+    { "xorq",   Op_DstSrcNT  },
+};
+
+typedef enum {
+    Default_Ptr = 0,
+    Byte_Ptr = 1,
+    Short_Ptr = 2,
+    Int_Ptr = 4,
+    QWord_Ptr =  8,
+    Float_Ptr = 4,
+    Double_Ptr = 8,
+    Extended_Ptr = 10,
+    Near_Ptr = 98,
+    Far_Ptr = 99,
+    N_PtrTypes
+} PtrType;
+
+static const int N_PtrNames = 8;
+static const char * ptrTypeNameTable[N_PtrNames] = {
+    "word", "dword", "qword",
+    "float", "double", "extended",
+    "near",  "far"
+};
+
+static Identifier * ptrTypeIdentTable[N_PtrNames];
+static PtrType ptrTypeValueTable[N_PtrNames] = {
+    Short_Ptr, Int_Ptr, QWord_Ptr,
+    Float_Ptr, Double_Ptr, Extended_Ptr,
+    Near_Ptr, Far_Ptr
+};
+
+typedef enum {
+    Opr_Invalid,
+    Opr_Immediate,
+    Opr_Reg,
+    Opr_Mem
+} OperandClass;
+
+/* kill inlining if we reference a local? */
+
+/* DMD seems to allow only one 'symbol' per operand .. include __LOCAL_SIZE */
+
+/* DMD offset usage: <parm>[<reg>] seems to always be relative to EBP+8 .. even
+   if naked.. */
+
+// mov eax, 4
+// mov eax, fs:4
+// -- have to assume we know wheter or not to use '$'
+
+static Token eof_tok;
+static Expression * Handled;
+static Identifier * ident_seg;
+
+struct AsmProcessor
+{
+    typedef struct {
+	int inBracket;
+	int hasBracket;
+	int hasNumber;
+	int isOffset;
+
+	Reg segmentPrefix;
+	Reg reg;
+	sinteger_t constDisplacement; // use to build up.. should be int constant in the end..
+	Array      symbolDisplacement; // array of expressions or..
+	Reg baseReg;
+	Reg indexReg;
+	int scale;
+	
+	OperandClass cls;
+	PtrType dataSize;
+	PtrType dataSizeHint; // DMD can use the type of a referenced variable
+    } Operand;
+
+    static const unsigned Max_Operands = 3;
+
+    AsmStatement * stmt;
+    Scope * sc;
+
+    Token * token;
+    OutBuffer * insnTemplate;
+
+    AsmOp       op;
+    AsmOpInfo * opInfo;
+    Operand operands[Max_Operands];
+    Identifier * opIdent;
+    Operand * operand;
+
+    AsmProcessor(Scope * sc, AsmStatement * stmt)
+    {
+	this->sc = sc;
+	this->stmt = stmt;
+	token = stmt->tokens;
+	insnTemplate = new OutBuffer;
+
+	opInfo = NULL;
+
+	if ( ! regInfo[0].ident ) {
+	    char buf[8], *p;
+	    
+	    for (int i = 0; i < N_Regs; i++) {
+		strncpy(buf, regInfo[i].name, sizeof(buf) - 1);
+		for (p = buf; *p; p++)
+		    *p = std::tolower(*p);
+		regInfo[i].gccName = std::string(buf, p - buf);
+		if ( (i <= Reg_ST || i > Reg_ST7) && i != Reg_EFLAGS )
+		    regInfo[i].ident = Lexer::idPool(regInfo[i].name);
+	    }
+
+	    for (int i = 0; i < N_PtrNames; i++)
+		ptrTypeIdentTable[i] = Lexer::idPool(ptrTypeNameTable[i]);
+
+	    Handled = new Expression(0, TOKvoid, sizeof(Expression));
+
+	    ident_seg = Lexer::idPool("seg");
+	
+	    eof_tok.value = TOKeof; 
+	    eof_tok.next = 0;
+	}
+    }
+
+    void run()
+    {
+	parse();
+    }
+
+    void nextToken() {
+	if (token->next)
+	    token = token->next;
+	else
+	    token = & eof_tok;
+    }
+
+    Token * peekToken() {
+	if (token->next)
+	    return token->next;
+	else
+	    return & eof_tok;
+    }
+
+    void expectEnd() {
+	if (token->value != TOKeof)
+	    stmt->error("expected end of statement"); // %% extra at end...
+    }
+
+    void parse() {
+	op = parseOpcode();
+	
+	switch (op) {
+	case Op_Align:
+	    doAlign();
+	    expectEnd();
+	    break;
+	case Op_Even:
+	    doEven();
+	    expectEnd();
+	    break;
+	case Op_Naked:
+	    doNaked();
+	    expectEnd();
+	    break;
+	case Op_Invalid:
+	    break;
+	default:
+	    if (op >= Op_db && op <= Op_de)
+		doData();
+	    else
+		doInstruction();
+	}
+    }
+
+    AsmOp parseOpcode() {
+	static const int N_ents = sizeof(opData)/sizeof(AsmOpEnt);
+
+	switch (token->value) {
+	case TOKalign:
+	    nextToken();
+	    return Op_Align;
+	case TOKin:
+	    nextToken();
+	    opIdent = Id::___in;
+	    return Op_in;
+        case TOKint32: // "int"
+            nextToken();
+            opIdent = Id::__int;
+            return Op_SrcImm;
+	case TOKout:
+	    nextToken();
+	    opIdent = Id::___out;
+	    return Op_out;
+	case TOKidentifier:
+	    // search for mnemonic below
+	    break;
+	default:
+	    stmt->error("expected opcode");
+	    return Op_Invalid;
+	}
+
+	opIdent = token->ident;
+	const char * opcode = token->ident->string;
+
+	nextToken();
+
+	// %% okay to use bsearch?
+	int i = 0, j = N_ents, k, l;
+	do {
+	    k = (i + j) / 2;
+	    l = strcmp(opcode, opData[k].inMnemonic);
+	    if (! l)
+		return opData[k].asmOp;
+	    else if (l < 0)
+		j = k;
+	    else
+		i = k + 1;
+	} while (i != j);
+
+	stmt->error("unknown opcode '%s'", opcode);
+	
+	return Op_Invalid;
+    }
+
+    // need clobber information.. use information is good too...
+    void doInstruction() {
+	bool ok = true;
+	unsigned operand_i = 0;
+	
+	opInfo = & asmOpInfo[op];
+	memset(operands, 0, sizeof(operands));
+
+	while (token->value != TOKeof) {
+	    if (operand_i < Max_Operands) {
+		operand = & operands[operand_i];
+		operand->reg = operand->baseReg = operand->indexReg =
+		    operand->segmentPrefix = Reg_Invalid;
+		parseOperand();
+		operand_i++;
+	    } else {
+		ok = false;
+		stmt->error("too many operands for instruction");
+		break;
+	    }
+
+	    if (token->value == TOKcomma)
+		nextToken();
+	    else if (token->value != TOKeof) {
+		ok = false;
+		stmt->error("expected comma after operand");
+		return;
+	    }
+	}
+// 	if (operand_i < opInfo->minOperands) {
+// 	    ok = false;
+// 	    stmt->error("too few operands for instruction");
+// 	}
+
+	if ( matchOperands(operand_i) ) {
+	    AsmCode * asmcode = new AsmCode(N_Regs);
+
+	    if (formatInstruction(operand_i, asmcode))
+		stmt->asmcode = (code *) asmcode;
+	}
+    }
+
+    void setAsmCode() {
+	AsmCode * asmcode = new AsmCode(N_Regs);
+	asmcode->insnTemplateLen = insnTemplate->offset;
+	asmcode->insnTemplate = (char*) insnTemplate->extractData();
+	stmt->asmcode = (code*) asmcode;
+    }
+
+    // note: doesn't update AsmOp op
+    bool matchOperands(unsigned nOperands) {
+	bool wrong_number = true;
+
+	for (unsigned i = 0; i < nOperands; i++)
+	    classifyOperand(& operands[i]);
+	
+	while (1) {
+	    if (nOperands == opInfo->nOperands()) {
+		wrong_number = false;
+		/*  Cases in which number of operands is not
+		    enough for a match: Op_FCmp/Op_FCmp1,
+		    Op_FCmpP/Op_FCmpP1 */
+		for (unsigned i = 0; i < nOperands; i++) {
+		    Operand * operand = & operands[i];
+		    
+		    switch (opInfo->operands[i] & Opr_ClassMask) {
+		    case OprC_Mem: // no FPMem currently
+			if (operand->cls != Opr_Mem)
+			    goto no_match;
+			break;
+		    case OprC_RFP:
+			if (! (operand->reg >= Reg_ST && operand->reg <= Reg_ST7))
+			    goto no_match;
+			break;
+		    default:
+			break;
+		    }
+		}
+
+		return true;
+	    }
+	    no_match:
+	    if (opInfo->linkType == Next_Form)
+		opInfo = & asmOpInfo[ op = (AsmOp) opInfo->link ];
+	    else
+		break;
+	}
+	if (wrong_number)
+	    stmt->error("wrong number of operands");
+	else
+	    stmt->error("wrong operand types");
+	return false;
+    }
+
+    void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
+	insnTemplate->writestring((char*) fmt);
+	insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
+	asmcode->args.push( new AsmArg(type, e, mode) );
+    }
+    void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
+    insnTemplate->writestring((char*) fmtpre);
+    insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
+    insnTemplate->writestring((char*) fmtpost);
+    asmcode->args.push( new AsmArg(type, e, mode) );
+    }
+
+    void addLabel(char* id) {
+    insnTemplate->writestring(sc->func->mangle());
+    insnTemplate->writestring("_");
+    insnTemplate->writestring(id);
+    }
+
+    /* Determines whether the operand is a register, memory reference
+       or immediate.  Immediate addresses are currently classified as
+       memory.  This function is called before the exact instructions
+       is known and thus, should not use opInfo. */
+    void classifyOperand(Operand * operand) {
+	operand->cls = classifyOperand1(operand);
+    }
+    
+    OperandClass classifyOperand1(Operand * operand) {
+	bool is_localsize = false;
+	bool really_have_symbol = false;
+
+	if (operand->symbolDisplacement.dim) {
+	    is_localsize = isLocalSize( (Expression *) operand->symbolDisplacement.data[0] );
+	    really_have_symbol = ! is_localsize;
+	}
+
+	if (operand->isOffset && ! operand->hasBracket)
+	    return Opr_Immediate;
+	
+	if (operand->hasBracket || really_have_symbol) { // %% redo for 'offset' function
+	    if (operand->reg != Reg_Invalid) {
+		invalidExpression();
+		return Opr_Invalid;
+	    }
+
+	    return Opr_Mem;
+	}
+
+	if (operand->reg != Reg_Invalid && operand->constDisplacement != 0) {
+	    invalidExpression();
+	    return Opr_Invalid;
+	}
+	
+	if (operand->segmentPrefix != Reg_Invalid) {
+	    if (operand->reg != Reg_Invalid) {
+		invalidExpression();
+		return Opr_Invalid;
+	    }
+
+	    return Opr_Mem;
+	}
+
+	if (operand->reg != Reg_Invalid && ! operand->hasNumber)
+	    return Opr_Reg;
+
+	// should check immediate given (operand->hasNumber);
+	//
+	if (operand->hasNumber || is_localsize) {
+	    // size determination not correct if there are symbols Opr_Immediate
+	    if (operand->dataSize == Default_Ptr) {
+		if (operand->constDisplacement < 0x100)
+		    operand->dataSize = Byte_Ptr;
+		else if (operand->constDisplacement < 0x10000)
+		    operand->dataSize = Short_Ptr;
+		else
+		    operand->dataSize = Int_Ptr;
+	    }
+	    return Opr_Immediate;
+	}
+
+	// probably a bug,?
+	stmt->error("invalid operand");
+	return Opr_Invalid;
+    }
+
+    void writeReg(Reg reg) {
+	insnTemplate->writestring((char*) "%");
+	insnTemplate->write(regInfo[reg].gccName.c_str(), regInfo[reg].gccName.length());
+    }
+
+    bool opTakesLabel() {
+	switch(op) {
+	case Op_Branch:
+	case Op_CBranch:
+	case Op_Loop:
+	    return true;
+	default:
+	    return false;
+	}
+    }
+
+    bool getTypeChar(TypeNeeded needed, PtrType ptrtype, char & type_char)
+    {
+	switch (needed) {
+	case Byte_NoType:
+	    return ptrtype == Byte_Ptr;
+	case Word_Types:
+	    if (ptrtype == Byte_Ptr)
+		return false;
+	    // drop through
+	case Int_Types:
+	    switch (ptrtype) {
+	    case Byte_Ptr:  type_char = 'b'; break;
+	    case Short_Ptr: type_char = 'w'; break;
+	    case Int_Ptr:   type_char = 'l'; break;
+	    default:
+		// %% these may be too strict
+		return false;
+	    }
+	    break;
+	case FPInt_Types:
+	    switch (ptrtype) {
+	    case Short_Ptr: type_char = 0;   break;
+	    case Int_Ptr:   type_char = 'l'; break;
+	    case QWord_Ptr: type_char = 'q'; break;
+	    default:
+		return false;
+	    }
+	    break;
+	case FP_Types:
+	    switch (ptrtype) {
+	    case Float_Ptr:    type_char = 's'; break;
+	    case Double_Ptr:   type_char = 'l'; break;
+	    case Extended_Ptr: type_char = 't'; break;
+	    default:
+		return false;
+	    }
+	    break;
+	default:
+	    return false;
+	}
+	return true;
+    }
+
+    // also set impl clobbers
+    bool formatInstruction(int nOperands, AsmCode * asmcode) {
+	const char *fmt;
+	const char *mnemonic;
+	char type_char = 0;
+	bool use_star;
+	AsmArgMode mode;
+
+	insnTemplate = new OutBuffer;
+	// %% todo: special case for something..
+	if (opInfo->linkType == Out_Mnemonic)
+	    mnemonic = alternateMnemonics[opInfo->link];
+	else
+	    mnemonic = opIdent->string;
+
+	if (opInfo->needsType) {
+	    PtrType exact_type = Default_Ptr;
+	    PtrType min_type = Default_Ptr;
+	    PtrType hint_type = Default_Ptr;
+
+	    /* Default types: This attempts to match the observed behavior of DMD */
+	    switch (opInfo->needsType) {
+	    case Int_Types:   min_type = Byte_Ptr; break;
+	    case Word_Types:  min_type = Short_Ptr; break;
+	    case FPInt_Types:
+		if (op == Op_Fis_ST) // integer math instructions 
+		    min_type = Int_Ptr;
+		else // compare, load, store
+		    min_type = Short_Ptr;
+		break;
+	    case FP_Types:    min_type = Float_Ptr; break;
+	    }
+	    if (op == Op_push && operands[0].cls == Opr_Immediate)
+		min_type = Int_Ptr;
+	    
+	    for (int i = 0; i < nOperands; i++) {
+		if (hint_type == Default_Ptr &&
+		    ! (opInfo->operands[i] & Opr_NoType))
+		    hint_type = operands[i].dataSizeHint;
+		    
+		if ((opInfo->operands[i] & Opr_NoType) ||
+		    operands[i].dataSize == Default_Ptr)
+		    continue;
+		if (operands[i].cls == Opr_Immediate) {
+		    min_type = operands[i].dataSize > min_type ?
+			operands[i].dataSize : min_type;
+		} else {
+		    exact_type = operands[i].dataSize; // could check for conflicting types
+		    break;
+		}
+	    }
+
+	    bool type_ok;
+	    if (exact_type == Default_Ptr) {
+		type_ok = getTypeChar((TypeNeeded) opInfo->needsType, hint_type, type_char);
+		if (! type_ok)
+		    type_ok = getTypeChar((TypeNeeded) opInfo->needsType, min_type, type_char);
+	    } else
+		type_ok = getTypeChar((TypeNeeded) opInfo->needsType, exact_type, type_char);
+
+	    if (! type_ok) {
+		stmt->error("invalid operand size");
+		return false;
+	    }
+	} else if (op == Op_Branch) {
+	    if (operands[0].dataSize == Far_Ptr) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that..
+		insnTemplate->writebyte('l');
+	} else if (op == Op_fxch) {
+	    // gas won't accept the two-operand form
+	    if (operands[1].cls == Opr_Reg && operands[1].reg == Reg_ST) {
+		nOperands = 1;
+	    } else {
+		stmt->error("invalid operands");
+		return false;
+	    }
+	}
+	
+	switch (op) {
+	case Op_SizedStack:
+	    {
+		int mlen = strlen(mnemonic);
+		if (mnemonic[mlen-1] == 'd')
+		    insnTemplate->write(mnemonic, mlen-1);
+		else {
+		    insnTemplate->writestring((char*) mnemonic);
+		    insnTemplate->writebyte('w');
+		}
+	    }
+	    break;
+	case Op_cmpsd:
+	case Op_insX:
+	case Op_lodsX:
+	case Op_movsd:
+	case Op_outsX:
+	case Op_scasX:
+	case Op_stosX:
+	    {
+		int mlen = strlen(mnemonic);
+		if (mnemonic[mlen-1] == 'd') {
+		    insnTemplate->write(mnemonic, mlen-1);
+		    insnTemplate->writebyte('l');
+		} else {
+		    insnTemplate->writestring((char*) mnemonic);
+		}
+	    }
+	    break;
+	case Op_movsx:
+	case Op_movzx:
+	    {
+		char tc_1;
+		int mlen = strlen(mnemonic);
+		PtrType op1_size = operands[1].dataSize;
+		if (op1_size == Default_Ptr)
+		    op1_size = operands[1].dataSizeHint;
+		// Need type char for source arg
+		switch (op1_size) {
+		case Byte_Ptr: 
+		case Default_Ptr:
+		    tc_1 = 'b';
+		    break;
+		case Short_Ptr:
+		    tc_1 = 'w';
+		    break;
+		default:
+		    stmt->error("invalid operand size/type");
+		    return false;
+		}
+		assert(type_char != 0);
+		insnTemplate->write(mnemonic, mlen-1);
+		insnTemplate->writebyte(tc_1);
+		insnTemplate->writebyte(type_char);
+	    }
+	    break;
+	default:
+	    insnTemplate->writestring((char*) mnemonic);
+	    if (type_char)
+		insnTemplate->writebyte(type_char);
+	    break;
+	}
+
+	switch (opInfo->implicitClobbers & Clb_DXAX_Mask) {
+	case Clb_SizeAX:
+	case Clb_EAX:
+	    asmcode->regs[Reg_EAX] = true;
+	    break;
+	case Clb_SizeDXAX:
+	    asmcode->regs[Reg_EAX] = true;
+	    if (type_char != 'b')
+		asmcode->regs[Reg_EDX] = true;
+	    break;
+	default:
+	    // nothing
+	    break;
+	}
+
+	if (opInfo->implicitClobbers & Clb_DI)
+	    asmcode->regs[Reg_EDI] = true;
+	if (opInfo->implicitClobbers & Clb_SI)
+	    asmcode->regs[Reg_ESI] = true;
+	if (opInfo->implicitClobbers & Clb_CX)
+	    asmcode->regs[Reg_ECX] = true;
+	if (opInfo->implicitClobbers & Clb_SP)
+	    asmcode->regs[Reg_ESP] = true;
+	if (opInfo->implicitClobbers & Clb_ST)
+	{
+	    /* Can't figure out how to tell GCC that an
+	       asm statement leaves an arg pushed on the stack.
+	       Maybe if the statment had and input or output
+	       operand it would work...  In any case, clobbering
+	       all FP prevents incorrect code generation. */
+	    asmcode->regs[Reg_ST] = true;
+	    asmcode->regs[Reg_ST1] = true;
+	    asmcode->regs[Reg_ST2] = true;
+	    asmcode->regs[Reg_ST3] = true;
+	    asmcode->regs[Reg_ST4] = true;
+	    asmcode->regs[Reg_ST5] = true;
+	    asmcode->regs[Reg_ST6] = true;
+	    asmcode->regs[Reg_ST7] = true;
+	}
+	if (opInfo->implicitClobbers & Clb_Flags)
+	    asmcode->regs[Reg_EFLAGS] = true;
+	if (op == Op_cpuid) {
+	    asmcode->regs[Reg_EAX] = true;
+	    asmcode->regs[Reg_ECX] = true;
+	    asmcode->regs[Reg_EDX] = true;
+	}
+
+	insnTemplate->writebyte(' ');
+	for (int i__ = 0; i__ < nOperands; i__++) {
+	    int i;
+	    if (i__ != 0)
+		insnTemplate->writestring((char*) ", ");
+
+	    fmt = "$";
+    
+	    switch (op) {
+	    case Op_mul:
+		// gas won't accept the two-operand form; skip to the source operand
+		i__ = 1;
+		// drop through
+	    case Op_bound:
+	    case Op_enter:
+		i = i__;
+		break;
+	    default:
+		i = nOperands - 1 - i__; // operand = & operands[ nOperands - 1 - i ];
+		break;
+	    }
+	    operand = & operands[ i ];
+
+	    switch (operand->cls) {
+	    case Opr_Immediate:
+		// for implementing offset:
+		// $var + $7 // fails
+		// $var + 7  // ok
+		// $7 + $var // ok
+
+		// DMD doesn't seem to allow this
+		/*
+		if (opInfo->takesLabel())  tho... (near ptr <Number> would be abs?)
+		    fmt = "$a"; // GAS won't accept "jmp $42"; must be "jmp 42" (rel) or "jmp *42" (abs)
+		*/
+		if (opTakesLabel()/*opInfo->takesLabel()*/) {
+		    // "relative addressing not allowed in branch instructions" ..
+		    stmt->error("integer constant not allowed in branch instructions");
+		    return false;
+		}
+
+		if (operand->symbolDisplacement.dim &&
+		    isLocalSize( (Expression *) operand->symbolDisplacement.data[0] )) {
+		    // handle __LOCAL_SIZE, which in this constant, is an immediate
+		    // should do this in slotexp..
+		    addOperand("$", Arg_LocalSize,
+			(Expression *) operand->symbolDisplacement.data[0], asmcode);
+		    if (operand->constDisplacement)
+			insnTemplate->writebyte('+');
+		    else
+			break;
+		}
+
+		if (operand->symbolDisplacement.dim) {
+		    fmt = "$a";
+		    addOperand("$", Arg_Pointer,
+			(Expression *) operand->symbolDisplacement.data[0],
+			asmcode);
+
+		    if (operand->constDisplacement)
+			insnTemplate->writebyte('+');
+		    else
+			// skip the addOperand(fmt, Arg_Integer...) below
+			break;
+		}
+		addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
+		break;
+	    case Opr_Reg:
+		if (opInfo->operands[i] & Opr_Dest) {
+		    Reg clbr_reg = (Reg) regInfo[operand->reg].baseReg;
+		    if (clbr_reg != Reg_Invalid) {
+			asmcode->regs[clbr_reg] = true;
+		    }
+		}
+		if (opTakesLabel()/*opInfo->takesLabel()*/)
+		    insnTemplate->writebyte('*');
+		writeReg(operand->reg);
+		/*
+		insnTemplate->writestring("%");
+		insnTemplate->writestring(regInfo[operand->reg].name);
+		*/
+		break;
+	    case Opr_Mem:
+		// better: use output operands for simple variable references
+		if ( (opInfo->operands[i] & Opr_Update) == Opr_Update) {
+		    mode = Mode_Update;
+		} else if (opInfo->operands[i] & Opr_Dest) {
+		    mode = Mode_Output;
+		} else {
+		    mode = Mode_Input;
+		}
+		
+		use_star = opTakesLabel();//opInfo->takesLabel();
+		if (operand->segmentPrefix != Reg_Invalid) {
+		    writeReg(operand->segmentPrefix);
+		    insnTemplate->writebyte(':');
+		}
+		if (operand->symbolDisplacement.dim) {
+		    Expression * e = (Expression *) operand->symbolDisplacement.data[0];
+		    Declaration * decl = 0;
+
+		    if (e->op == TOKvar)
+			decl = ((VarExp *) e)->var;
+
+		    if (operand->baseReg != Reg_Invalid &&
+			decl && ! decl->isDataseg()) {
+
+			// Use the offset from frame pointer
+
+			/* GCC doesn't give the front end access to stack offsets
+			   when optimization is turned on (3.x) or at all (4.x).
+			   
+			   Try to convert var[EBP] (or var[ESP] for naked funcs) to
+			   a memory expression that does not require us to know
+			   the stack offset.
+			*/
+
+			if (operand->indexReg == Reg_Invalid &&
+			    decl->isVarDeclaration() &&
+			    ( ((operand->baseReg == Reg_EBP || (operand->baseReg == Reg_RBP)) && ! sc->func->naked ) ||
+			      ((operand->baseReg == Reg_ESP || (operand->baseReg == Reg_RSP)) && sc->func->naked)) ) 
+			  {
+
+                if (mode == Mode_Output)
+                {
+                    e = new AddrExp(0, e);
+                    e->type = decl->type->pointerTo();
+                }
+
+#if !IN_LLVM
+			    /* DMD uses the same frame offsets for naked functions. */
+			    if (sc->func->naked)
+				operand->constDisplacement += 4;
+
+			    if (operand->constDisplacement) {
+				e = new AddExp(0, e,
+				    new IntegerExp(0, operand->constDisplacement,
+					Type::tint32));
+				e->type = decl->type->pointerTo();
+			    }
+			    e = new PtrExp(0, e);
+			    e->type = decl->type;
+#endif
+			    operand->constDisplacement = 0;
+			    operand->baseReg = Reg_Invalid;
+
+			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
+			    
+			} else {
+			    addOperand2("${",":a}", Arg_FrameRelative, e, asmcode);
+			}
+			if (opInfo->operands[i] & Opr_Dest)
+			    asmcode->clobbersMemory = 1;
+		    } else  {
+			// Plain memory reference to variable
+			
+			/* If in a reg, DMD moves to memory.. even with -O, so we'll do the same
+			   by always using the "m" contraint.
+
+			   In order to get the correct output for function and label symbols,
+			   the %an format must be used with the "p" constraint.
+			*/
+			if (isDollar(e)) {
+			    error("dollar labels are not supported", stmt->loc.toChars());
+			    asmcode->dollarLabel = 1;
+			} else if (e->op == TOKdsymbol) {
+			    LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s;
+			    stmt->isBranchToLabel = lbl->ident;
+
+			    use_star = false;
+			    addLabel(lbl->ident->toChars());
+			} else if ((decl && decl->isCodeseg())) { // if function or label
+			    use_star = false;
+			    addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
+			} else {
+			    if (use_star) {
+				insnTemplate->writebyte('*');
+				use_star = false;
+			    }
+                Type* tt = e->type->pointerTo();
+			    e = new AddrExp(0, e);
+			    e->type = tt;
+
+			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
+			}
+		    }
+		}
+		if (use_star)
+		    insnTemplate->writebyte('*');
+		if (operand->constDisplacement) {
+		    if (operand->symbolDisplacement.dim)
+			insnTemplate->writebyte('+');
+		    //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
+		    insnTemplate->printf("%d", operand->constDisplacement);
+		    if (opInfo->operands[i] & Opr_Dest)
+			asmcode->clobbersMemory = 1;
+		}
+		if (operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid) {
+		    insnTemplate->writebyte('(');
+		    if (operand->baseReg != Reg_Invalid)
+			writeReg(operand->baseReg);
+		    if (operand->indexReg != Reg_Invalid) {
+			insnTemplate->writebyte(',');
+			writeReg(operand->indexReg);
+			if (operand->scale) {
+			    insnTemplate->printf(",%d", operand->scale);
+			}
+		    }
+		    insnTemplate->writebyte(')');
+		    if (opInfo->operands[i] & Opr_Dest)
+			asmcode->clobbersMemory = 1;
+		}
+		break;
+	    case Opr_Invalid:
+		return false;
+	    }
+	}
+
+	asmcode->insnTemplateLen = insnTemplate->offset;
+	asmcode->insnTemplate = (char*) insnTemplate->extractData();
+	return true;
+    }
+
+    bool isIntExp(Expression * exp) {
+	if (exp->op == TOKint64)
+	    return 1;
+	if (exp->op == TOKvar) {
+	    Declaration * v = ((VarExp *) exp)->var;
+	    if (v->isConst() && v->type->isintegral())
+		return 1;
+	}
+	return 0;
+    }
+    bool isRegExp(Expression * exp) { return exp->op == TOKmod; } // ewww.%%
+    bool isLocalSize(Expression * exp) {
+	// cleanup: make a static var
+	return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__LOCAL_SIZE;
+    }
+    bool isDollar(Expression * exp) {
+	return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__dollar;
+    }
+
+    Expression * newRegExp(int regno) {
+	IntegerExp * e = new IntegerExp(regno);
+	e->op = TOKmod;
+	return e;
+    }
+
+    Expression * newIntExp(int v /* %% type */) {
+	// Only handles 32-bit numbers as this is IA-32.
+	return new IntegerExp(stmt->loc, v, Type::tint32);
+    }
+
+    void slotExp(Expression * exp) {
+	/*
+	  if offset, make a note
+	
+	  if integer, add to immediate
+	  if reg:
+	      if not in bracket, set reg (else error)
+	      if in bracket:
+		 if not base, set base
+		 if not index, set index
+		 else, error
+	  if symbol:
+	    set symbol field
+	 */
+
+	bool is_offset = false;
+	if (exp->op == TOKaddress) {
+	    exp = ((AddrExp *) exp)->e1;
+	    is_offset = true;
+	}
+	
+	if (isIntExp(exp)) {
+	    if (is_offset)
+		invalidExpression();
+	    operand->constDisplacement += exp->toInteger();
+	    if (! operand->inBracket)
+		operand->hasNumber = 1;
+	} else if (isRegExp(exp)) {
+	    if (is_offset)
+		invalidExpression();
+	    if (! operand->inBracket) {
+		if (operand->reg == Reg_Invalid)
+		    operand->reg = (Reg) exp->toInteger();
+		else
+		    stmt->error("too many registers in operand (use brackets)");
+	    } else {
+		if (operand->baseReg == Reg_Invalid)
+		    operand->baseReg = (Reg) exp->toInteger();
+		else if (operand->indexReg == Reg_Invalid) {
+		    operand->indexReg = (Reg) exp->toInteger();
+		    operand->scale = 1;
+		} else {
+		    stmt->error("too many registers memory operand");
+		}
+	    }
+	} else if (exp->op == TOKvar) {
+	    VarDeclaration * v = ((VarExp *) exp)->var->isVarDeclaration();
+
+	    if (v && v->storage_class & STCfield) {
+		operand->constDisplacement += v->offset;
+		if (! operand->inBracket)
+		    operand->hasNumber = 1;
+	    } else {
+		if (v && v->type->isscalar())
+		{
+		    // DMD doesn't check Tcomplex*, and counts Tcomplex32 as Tfloat64
+		    TY ty = v->type->toBasetype()->ty;
+		    operand->dataSizeHint = ty == Tfloat80 || ty == Timaginary80 ?
+			Extended_Ptr : (PtrType) v->type->size(0);
+		}
+		
+		if (! operand->symbolDisplacement.dim) {
+		    if (is_offset && ! operand->inBracket)
+			operand->isOffset = 1;
+		    operand->symbolDisplacement.push( exp );
+		} else {
+		    stmt->error("too many symbols in operand");
+		}
+	    }
+	} else if (exp->op == TOKidentifier || exp->op == TOKdsymbol) {
+	    // %% localsize could be treated as a simple constant..
+	    // change to addSymbolDisp(e)
+	    if (! operand->symbolDisplacement.dim) {
+		operand->symbolDisplacement.push( exp );
+	    } else {
+		stmt->error("too many symbols in operand");
+	    }
+	} else if (exp == Handled) {
+	    // nothing
+	} else {
+	    stmt->error("invalid operand");
+	}
+    }
+
+    void invalidExpression() {
+	// %% report operand number
+	stmt->error("invalid expression");
+    }
+
+    Expression * intOp(TOK op, Expression * e1, Expression * e2) {
+	Expression * e;
+	if (isIntExp(e1) && (! e2 || isIntExp(e2))) {
+	    switch (op) {
+	    case TOKadd:
+		if (e2)
+		    e = new AddExp(stmt->loc, e1, e2);
+		else
+		    e = e1;
+		break;
+	    case TOKmin:
+		if (e2)
+		    e = new MinExp(stmt->loc, e1, e2);
+		else
+		    e = new NegExp(stmt->loc, e1);
+		break;
+	    case TOKmul:
+		e = new MulExp(stmt->loc, e1, e2);
+		break;
+	    case TOKdiv:
+		e = new DivExp(stmt->loc, e1, e2);
+		break;
+	    case TOKmod:
+		e = new ModExp(stmt->loc, e1, e2);
+		break;
+	    case TOKshl:
+		e = new ShlExp(stmt->loc, e1, e2);
+		break;
+	    case TOKshr:
+		e = new ShrExp(stmt->loc, e1, e2);
+		break;
+	    case TOKushr:
+		e = new UshrExp(stmt->loc, e1, e2);
+		break;
+	    case TOKnot:
+		e = new NotExp(stmt->loc, e1);
+		break;
+	    case TOKtilde:
+		e = new ComExp(stmt->loc, e1);
+		break;
+	    default:
+		assert(0);
+	    }
+	    e = e->semantic(sc);
+	    return e->optimize(WANTvalue | WANTinterpret);
+	} else {
+	    stmt->error("expected integer operand(s) for '%s'", Token::tochars[op]);
+	    return newIntExp(0);
+	}
+    }
+
+    void parseOperand() {
+	Expression * exp = parseAsmExp();
+	slotExp(exp);
+	if (isRegExp(exp))
+	    operand->dataSize = (PtrType) regInfo[exp->toInteger()].size;
+    }
+
+    Expression * parseAsmExp() {
+	return parseShiftExp();
+    }
+
+    Expression * parseShiftExp() {
+	Expression * e1 = parseAddExp();
+	Expression * e2;
+
+	while (1) {
+	    TOK tv = token->value;
+	    switch (tv) {
+	    case TOKshl:
+	    case TOKshr:
+	    case TOKushr:
+		nextToken();
+		e2 = parseAddExp();
+		e1 = intOp(tv, e1, e2);
+		continue;
+	    default:
+		break;
+	    }
+	    break;
+	}
+	return e1;
+    }
+
+    Expression * parseAddExp() {
+	Expression * e1 = parseMultExp();
+	Expression * e2;
+
+	while (1) {
+	    TOK tv = token->value;
+	    switch (tv) {
+	    case TOKadd:
+		nextToken();
+		e2 = parseMultExp();
+		if (isIntExp(e1) && isIntExp(e2))
+		    e1 = intOp(tv, e1, e2);
+		else {
+		    slotExp(e1);
+		    slotExp(e2);
+		    e1 = Handled;
+		}
+		continue;
+	    case TOKmin:
+		// Note: no support for symbol address difference
+		nextToken();
+		e2 = parseMultExp();
+		if (isIntExp(e1) && isIntExp(e2))
+		    e1 = intOp(tv, e1, e2);
+		else {
+		    slotExp(e1);
+		    e2 = intOp(TOKmin, e2, NULL); // verifies e2 is an int
+		    slotExp(e2);
+		    e1 = Handled;
+		}
+		continue;
+	    default:
+		break;
+	    }
+	    break;
+	}
+	return e1;
+    }
+
+    bool tryScale(Expression * e1, Expression * e2) {
+	Expression * et;
+	if (isIntExp(e1) && isRegExp(e2)) {
+	    et = e1;
+	    e1 = e2;
+	    e2 = et;
+	    goto do_scale;
+	} else if (isRegExp(e1) && isIntExp(e2)) {
+	do_scale:
+	    if (! operand->inBracket) {
+		invalidExpression(); // maybe should allow, e.g. DS:EBX+EAX*4
+	    }
+	    
+	    if (operand->scale || operand->indexReg != Reg_Invalid) {
+		invalidExpression();
+		return true;
+	    }
+
+	    operand->indexReg = (Reg) e1->toInteger();
+	    operand->scale = e2->toInteger();
+	    switch (operand->scale) {
+	    case 1:
+	    case 2:
+	    case 4:
+	    case 8:
+		// ok; do nothing
+		break;
+	    default:
+		stmt->error("invalid index register scale '%d'", operand->scale);
+		return true;
+	    }
+	    
+	    return true;
+	}
+	return false;
+    }
+
+    Expression * parseMultExp() {
+	Expression * e1 = parseBrExp();
+	Expression * e2;
+
+	while (1) {
+	    TOK tv = token->value;
+	    switch (tv) {
+	    case TOKmul:
+		nextToken();
+		e2 = parseMultExp();
+		if (isIntExp(e1) && isIntExp(e2))
+		    e1 = intOp(tv, e1, e2);
+		else if (tryScale(e1,e2))
+		    e1 = Handled;
+		else
+		    invalidExpression();
+		continue;
+	    case TOKdiv:
+	    case TOKmod:
+		nextToken();
+		e2 = parseMultExp();
+		e1 = intOp(tv, e1, e2);
+		continue;
+	    default:
+		break;
+	    }
+	    break;
+	}
+	return e1;
+    }
+
+    Expression * parseBrExp() {
+	// %% check (why is bracket lower precends..)
+	// 3+4[eax] -> 3 + (4 [EAX]) ..
+	
+	// only one bracked allowed, so this doesn't quite handle
+	// the spec'd syntax
+	Expression * e;
+	
+	if (token->value == TOKlbracket)
+	    e = Handled;
+	else
+	    e = parseUnaExp();
+
+	// DMD allows multiple bracket expressions.
+	while (token->value == TOKlbracket) {
+	    nextToken();
+	    
+	    operand->inBracket = operand->hasBracket = 1;
+	    slotExp(parseAsmExp());
+	    operand->inBracket = 0;
+
+	    if (token->value == TOKrbracket)
+		nextToken();
+	    else
+		stmt->error("missing ']'");
+	}
+
+	return e;
+    }
+
+    PtrType isPtrType(Token * tok) {
+	switch (tok->value) {
+	case TOKint8: return Byte_Ptr;
+	case TOKint16: return Short_Ptr;
+	case TOKint32: return Int_Ptr;
+	    // 'long ptr' isn't accepted?
+	case TOKfloat32: return Float_Ptr;
+	case TOKfloat64: return Double_Ptr;
+	case TOKfloat80: return Extended_Ptr;
+	case TOKidentifier:
+	    for (int i = 0; i < N_PtrNames; i++)
+		if (tok->ident == ptrTypeIdentTable[i])
+		    return ptrTypeValueTable[i];
+	    break;
+	default:
+	    break;
+	}
+	return Default_Ptr;
+    }
+
+    Expression * parseUnaExp() {
+	Expression * e = NULL;
+	PtrType ptr_type;
+	
+	// First, check for type prefix.
+	if (token->value != TOKeof &&
+	    peekToken()->value == TOKidentifier &&
+	    peekToken()->ident == Id::ptr) {
+
+	    ptr_type = isPtrType(token);
+	    if (ptr_type != Default_Ptr) {
+		if (operand->dataSize == Default_Ptr)
+		    operand->dataSize = ptr_type;
+		else
+		    stmt->error("multiple specifications of operand size");
+	    } else
+		stmt->error("unknown operand size '%s'", token->toChars());
+	    nextToken();
+	    nextToken();
+	    return parseAsmExp();
+	}
+
+	TOK tv = token->value;
+	switch (tv) {
+	case TOKidentifier:
+	    if (token->ident == ident_seg) {
+		nextToken();
+		stmt->error("'seg' not supported");
+		e = parseAsmExp();
+	    } else if (token->ident == Id::offset ||
+		       token->ident == Id::offsetof) {
+		if (token->ident == Id::offset && ! global.params.useDeprecated)
+		    stmt->error("offset deprecated, use offsetof");
+		nextToken();
+		e = parseAsmExp();
+		e = new AddrExp(stmt->loc, e);
+	    } else {
+		// primary exp
+		break;
+	    }
+	    return e;
+	case TOKadd:
+	case TOKmin:
+	case TOKnot:
+	case TOKtilde:
+	    nextToken();
+	    e = parseUnaExp();
+	    return intOp(tv, e, NULL);
+	default:
+	    // primary exp
+	    break;
+	}
+	return parsePrimaryExp();
+    }
+
+    Expression * parsePrimaryExp() {
+	Expression * e;
+	Identifier * ident = NULL;
+	
+	switch (token->value) {
+	case TOKint32v:
+	case TOKuns32v:
+	case TOKint64v:
+	case TOKuns64v:
+	    // semantic here?
+	    // %% for tok64 really should use 64bit type
+	    e = new IntegerExp(stmt->loc, token->uns64value, Type::tint32);
+	    nextToken();
+	    break;
+	case TOKfloat32v:
+	case TOKfloat64v:
+	case TOKfloat80v:
+	    // %% need different types?
+        e = new RealExp(stmt->loc, token->float80value, Type::tfloat80);
+	    nextToken();
+	    break;
+	case TOKidentifier:
+	    {
+		ident = token->ident;
+		nextToken();
+		
+		if (ident == Id::__LOCAL_SIZE) {
+		    return new IdentifierExp(stmt->loc, ident);
+		} else if (ident == Id::__dollar) {
+		do_dollar:
+		    return new IdentifierExp(stmt->loc, ident);
+		} else {
+		    e = new IdentifierExp(stmt->loc, ident);
+		}
+
+		// If this is more than one component ref, it gets complicated: *(&Field + n)
+		// maybe just do one step at a time..
+		// simple case is Type.f -> VarDecl(field)
+		// actually, DMD only supports on level...
+		// X.y+Y.z[EBX] is supported, tho..
+		// %% doesn't handle properties (check%%)
+		while (token->value == TOKdot) {
+		    nextToken();
+		    if (token->value == TOKidentifier) {
+			e = new DotIdExp(stmt->loc, e, token->ident);
+			nextToken();
+		    } else {
+			stmt->error("expected identifier");
+			return Handled;
+		    }
+		}
+
+		// check for reg first then dotexp is an error?
+		if (e->op == TOKidentifier) {
+		    for (int i = 0; i < N_Regs; i++) {
+			if (ident == regInfo[i].ident) {
+			    if ( (Reg) i == Reg_ST && token->value == TOKlparen) {
+				nextToken();
+				switch (token->value) {
+				case TOKint32v: case TOKuns32v:
+				case TOKint64v: case TOKuns64v:
+				    if (token->uns64value < 8)
+					e = newRegExp( (Reg) (Reg_ST + token->uns64value) );
+				    else {
+					stmt->error("invalid floating point register index");
+					e = Handled;
+				    }
+				    nextToken();
+				    if (token->value == TOKrparen)
+					nextToken();
+				    else
+					stmt->error("expected ')'");
+				    return e;
+				default:
+				    break;
+				}
+				invalidExpression();
+				return Handled;
+			    } else if (token->value == TOKcolon) {
+				nextToken();
+				if (operand->segmentPrefix != Reg_Invalid)
+				    stmt->error("too many segment prefixes");
+				else if (i >= Reg_CS && i <= Reg_GS)
+				    operand->segmentPrefix = (Reg) i;
+				else
+				    stmt->error("'%s' is not a segment register", ident->string);
+				return parseAsmExp();
+			    } else {
+				return newRegExp( (Reg) i );
+			    }
+			}
+		    }
+		}
+		
+		if (opTakesLabel()/*opInfo->takesLabel()*/ && e->op == TOKidentifier) {
+		    // DMD uses labels secondarily to other symbols, so check
+		    // if IdentifierExp::semantic won't find anything.
+		    Dsymbol *scopesym;
+		    
+		    if ( ! sc->search(stmt->loc, ident, & scopesym) )		    
+			return new DsymbolExp(stmt->loc,
+			    sc->func->searchLabel( ident ));
+		}
+
+		e = e->semantic(sc);
+
+		// Special case for floating point constant declarations.
+		if (e->op == TOKfloat64) {
+		    Dsymbol * sym = sc->search(stmt->loc, ident, NULL);
+		    if ( sym ) {
+			VarDeclaration *v = sym->isVarDeclaration();
+			if ( v ) {
+			    Expression *ve = new VarExp(stmt->loc, v);
+			    ve->type = e->type;
+			    e = ve;
+			}
+		    }			    
+		}
+		return e;
+	    }
+	    break;
+	case TOKdollar:
+	    nextToken();
+	    ident = Id::__dollar;
+	    goto do_dollar;
+	    break;
+	default:
+	    invalidExpression();
+	    return Handled;
+	}
+	return e;
+    }
+
+    void doAlign() {
+	// .align bits vs. bytes...
+	// apparently a.out platforms use bits instead of bytes...
+
+	// parse primary: DMD allows 'MyAlign' (const int) but not '2+2'
+	// GAS is padding with NOPs last time I checked.
+	Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret);
+	integer_t align = e->toInteger();
+
+	if (align >= 0) {
+	    // %% is this printf portable?
+#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 
+	    insnTemplate->printf(".balign\t%u", (unsigned) align);
+#else
+	    insnTemplate->printf(".align\t%u", (unsigned) align);
+#endif
+	} else {
+	    stmt->error("alignment must be a power of 2");
+	}
+
+	setAsmCode();
+    }
+
+    void doEven() {
+	// .align for GAS is in bits, others probably use bytes..
+#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 
+	insnTemplate->writestring((char *) ".align\t2");
+#else
+	insnTemplate->writestring((char *) ".align\t2");
+#endif
+	setAsmCode();
+    }
+
+    void doNaked() {
+	// %% can we assume sc->func != 0?
+	sc->func->naked = 1;
+    }
+
+    void doData() {
+	static const char * directives[] = { ".byte", ".short", ".long", ".long",
+					     "", "", "" };
+// FIXME
+/*
+	machine_mode mode;
+
+	insnTemplate->writestring((char*) directives[op - Op_db]);
+	insnTemplate->writebyte(' ');
+
+	do {
+	    // DMD is pretty strict here, not even constant expressions are allowed..
+	    switch (op) {
+	    case Op_db:
+	    case Op_ds:
+	    case Op_di:
+	    case Op_dl:
+		if (token->value == TOKint32v || token->value == TOKuns32v ||
+		    token->value == TOKint64v || token->value == TOKuns64v) {
+		    // As per usual with GNU, assume at least 32-bit host
+		    if (op != Op_dl)
+			insnTemplate->printf("%u", (d_uns32) token->uns64value);
+		    else {
+			// Output two .longS.  GAS has .quad, but would have to rely on 'L' format ..
+			// just need to use HOST_WIDE_INT_PRINT_DEC
+			insnTemplate->printf("%u,%u",
+			    (d_uns32) token->uns64value, (d_uns32) (token->uns64value >> 32));
+		    }
+		} else {
+		    stmt->error("expected integer constant");
+		}
+		break;
+	    case Op_df:
+		mode = SFmode;
+		goto do_float;
+	    case Op_dd:
+		mode = DFmode;
+		goto do_float;
+	    case Op_de:
+#ifndef TARGET_80387
+#define XFmode TFmode
+#endif
+		mode = XFmode; // not TFmode
+		// drop through
+	    do_float:
+		if (token->value == TOKfloat32v || token->value == TOKfloat64v ||
+		    token->value == TOKfloat80v) {
+		    long words[3];
+		    real_to_target(words, & token->float80value.rv(), mode);
+		    // don't use directives..., just use .long like GCC
+		    insnTemplate->printf(".long\t%u", words[0]);
+		    if (mode != SFmode)
+			insnTemplate->printf(",%u", words[1]);
+		    // DMD outputs 10 bytes, so we need to switch to .short here
+		    if (mode == XFmode)
+			insnTemplate->printf("\n\t.short\t%u", words[2]);
+		} else {
+		    stmt->error("expected float constant");
+		}
+		break;
+	    default:
+		abort();
+	    }
+	    
+	    nextToken();	    
+	    if (token->value == TOKcomma) {
+		insnTemplate->writebyte(',');
+		nextToken();
+	    } else if (token->value == TOKeof) {
+		break;
+	    } else {
+		stmt->error("expected comma");
+	    }
+	} while (1);
+
+	setAsmCode();*/
+    }
+};
+
+#if D_GCC_VER < 40
+// struct rtx was modified for c++; this macro from rtl.h needs to
+// be modified accordingly.
+#undef XEXP
+#define XEXP(RTX, N)	(RTL_CHECK2 (RTX, N, 'e', 'u').rt_rtx)
+#endif
+
+// FIXME
+    #define HOST_WIDE_INT long
+bool getFrameRelativeValue(LLValue* decl, HOST_WIDE_INT * result)
+{
+    assert(0);
+// FIXME
+//     // Using this instead of DECL_RTL for struct args seems like a
+//     // good way to get hit by a truck because it may not agree with
+//     // non-asm access, but asm code wouldn't know what GCC does anyway. */
+//     rtx r = DECL_INCOMING_RTL(decl);
+//     rtx e1, e2;
+// 
+//     // Local variables don't have DECL_INCOMING_RTL
+//     if (r == NULL_RTX)
+// 	r = DECL_RTL(decl);
+// 
+//     if (r != NULL_RTX && GET_CODE(r) == MEM /* && r->frame_related */ ) {
+// 	r = XEXP(r, 0);
+// 	if (GET_CODE(r) == PLUS) {
+// 	    e1 = XEXP(r, 0);
+// 	    e2 = XEXP(r, 1);
+// 	    if (e1 == virtual_incoming_args_rtx && GET_CODE(e2) == CONST_INT) {
+// 		*result = INTVAL(e2) + 8; // %% 8 is 32-bit specific...
+// 		return true;
+// 	    } else if (e1 == virtual_stack_vars_rtx && GET_CODE(e2) == CONST_INT) {
+// 		*result = INTVAL(e2); // %% 8 is 32-bit specific...
+// 		return true;
+// 	    }
+// 	} else if (r == virtual_incoming_args_rtx) {
+// 	    *result = 8;
+// 	    return true; // %% same as above
+// 	}
+// 	// shouldn't have virtual_stack_vars_rtx by itself
+//     }
+//     
+    return false;
+}
+
+
+struct AsmParser : public AsmParserCommon
+{
+    virtual void run(Scope* sc, AsmStatement* asmst) {
+        AsmProcessor ap(sc, asmst);
+        ap.run();
+    }
+
+    virtual std::string getRegName(int i) {
+        return regInfo[i].gccName;
+    }
+};
+
+}
--- a/gen/asmstmt.cpp	Sat Nov 08 11:34:35 2008 +0100
+++ b/gen/asmstmt.cpp	Sat Nov 08 22:29:19 2008 +0100
@@ -57,13 +57,13 @@
     char *   insnTemplate;
     unsigned insnTemplateLen;
     Array    args; // of AsmArg
-    unsigned moreRegs;
+    std::vector<bool> regs;
     unsigned dollarLabel;
     int      clobbersMemory;
-    AsmCode() {
+    AsmCode(int n_regs) {
 	insnTemplate = NULL;
 	insnTemplateLen = 0;
-	moreRegs = 0;
+	regs.resize(n_regs, false);
 	dollarLabel = 0;
 	clobbersMemory = 0;
     }
@@ -77,7 +77,6 @@
     asmalign = 0;
     refparam = 0;
     naked = 0;
-    regs = 0;
 
     isBranchToLabel = NULL;
 }
@@ -89,7 +88,6 @@
     a_s->asmcode = asmcode;
     a_s->refparam = refparam;
     a_s->naked = naked;
-    a_s->regs = a_s->regs;
     return a_s;
 }
 
@@ -130,15 +128,22 @@
     return FALSE;
 }
 
+struct AsmParserCommon
+{
+    virtual void run(Scope* sc, AsmStatement* asmst) = 0;
+    virtual std::string getRegName(int i) = 0;
+};
+AsmParserCommon* asmparser = NULL;
 
-#include "d-asm-i386.h"
+#include "asm-x86-32.h"
+#include "asm-x86-64.h"
 
 bool d_have_inline_asm() { return true; }
 
 Statement *AsmStatement::semantic(Scope *sc)
 {
     bool err = false;
-    if (global.params.cpu != ARCHx86)
+    if ((global.params.cpu != ARCHx86) && (global.params.cpu != ARCHx86_64))
     {
         error("inline asm is not supported for the \"%s\" architecture", global.params.llvmArch);
         err = true;
@@ -160,8 +165,14 @@
     if (! tokens)
 	return this;
     
-    AsmProcessor ap(sc, this);
-    ap.run();
+    if (!asmparser)
+        if (global.params.cpu == ARCHx86)
+            asmparser = new AsmParserx8632::AsmParser;
+        else if (global.params.cpu == ARCHx86_64)
+            asmparser = new AsmParserx8664::AsmParser;
+
+    asmparser->run(sc, this);
+
     return this;
 }
 
@@ -251,7 +262,7 @@
 /*	    if (arg->expr->op == TOKvar)
 		arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
 	    else
-		assert(0);*/
+		assert(0);
 	    if ( getFrameRelativeValue(arg_val, & var_frame_offset) ) {
 //		arg_val = irs->integerConstant(var_frame_offset);
 		cns = i_cns;
@@ -261,7 +272,7 @@
 	    }
 	    if (arg->mode != Mode_Input)
 		clobbers_mem = true;
-	    break;
+	    break;*/
 	case Arg_LocalSize:
 // FIXME
 std::cout << "asm fixme Arg_LocalSize" << std::endl;
@@ -294,16 +305,11 @@
     
 // FIXME
 //    if (! irs->func->naked) {
-	for (int i = 0; i < 32; i++) {
-	    if (regs & (1 << i)) {
+        assert(asmparser);
+	for (int i = 0; i < code->regs.size(); i++) {
+	    if (code->regs[i]) {
 		//clobbers.cons(NULL_TREE, regInfo[i].gccName);
-		clobbers.push_back(regInfo[i].gccName);
-	    }
-	}
-	for (int i = 0; i < 32; i++) {
-	    if (code->moreRegs & (1 << (i-32))) {
-		//clobbers.cons(NULL_TREE, regInfo[i].gccName);
-		clobbers.push_back(regInfo[i].gccName);
+		clobbers.push_back(asmparser->getRegName(i));
 	    }
 	}
 	if (clobbers_mem)
--- a/gen/d-asm-i386.h	Sat Nov 08 11:34:35 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2670 +0,0 @@
-// Taken from GDC source tree. Original by David Friedman.
-// Released under the Artistic License found in dmd/artistic.txt
-
-#include "id.h"
-
-typedef enum {
-    Reg_Invalid = -1,
-    Reg_EAX = 0,
-    Reg_EBX,
-    Reg_ECX,
-    Reg_EDX,
-    Reg_ESI,
-    Reg_EDI,
-    Reg_EBP,
-    Reg_ESP,
-    Reg_ST,
-    Reg_ST1, Reg_ST2, Reg_ST3, Reg_ST4, Reg_ST5, Reg_ST6, Reg_ST7,
-    Reg_MM0, Reg_MM1, Reg_MM2, Reg_MM3, Reg_MM4, Reg_MM5, Reg_MM6, Reg_MM7,
-    Reg_XMM0, Reg_XMM1, Reg_XMM2, Reg_XMM3, Reg_XMM4, Reg_XMM5, Reg_XMM6, Reg_XMM7,
-    // will need 64-bit rax,etc. eventually
-    // xmm8-15?
-    Reg_EFLAGS,
-    Reg_CS,
-    Reg_DS,
-    Reg_SS,
-    Reg_ES,
-    Reg_FS,
-    Reg_GS,
-    Reg_AX, Reg_BX, Reg_CX, Reg_DX, Reg_SI, Reg_DI, Reg_BP, Reg_SP,
-    Reg_AL, Reg_AH, Reg_BL, Reg_BH, Reg_CL, Reg_CH, Reg_DL, Reg_DH,
-    Reg_CR0, Reg_CR2, Reg_CR3, Reg_CR4,
-    Reg_DR0, Reg_DR1, Reg_DR2, Reg_DR3, Reg_DR6, Reg_DR7,
-    Reg_TR3, Reg_TR4, Reg_TR5, Reg_TR6, Reg_TR7
-} Reg;
-
-static const int N_Regs = /*gp*/ 8 + /*fp*/ 8 + /*mmx*/ 8 + /*sse*/ 8 +
-/*seg*/ 6 + /*16bit*/ 8 + /*8bit*/ 8 + /*sys*/ 4+6+5 + /*flags*/ + 1;
-
-#define NULL_TREE ""
-
-static struct {
-    const char * name;
-    std::string gccName; // GAS will take upper case, but GCC won't (needed for the clobber list)
-    Identifier * ident;
-    char size;
-    char baseReg; // %% todo: Reg, Reg_XX
-} regInfo[N_Regs] = {
-    { "EAX", NULL_TREE, NULL, 4,  Reg_EAX },
-    { "EBX", NULL_TREE, NULL, 4,  Reg_EBX },
-    { "ECX", NULL_TREE, NULL, 4,  Reg_ECX },
-    { "EDX", NULL_TREE, NULL, 4,  Reg_EDX },
-    { "ESI", NULL_TREE, NULL, 4,  Reg_ESI },
-    { "EDI", NULL_TREE, NULL, 4,  Reg_EDI },
-    { "EBP", NULL_TREE, NULL, 4,  Reg_EBP },
-    { "ESP", NULL_TREE, NULL, 4,  Reg_ESP },
-    { "ST", NULL_TREE, NULL,   10, Reg_ST },
-    { "ST(1)", NULL_TREE, NULL,10, Reg_ST1 },
-    { "ST(2)", NULL_TREE, NULL,10, Reg_ST2 },
-    { "ST(3)", NULL_TREE, NULL,10, Reg_ST3 },
-    { "ST(4)", NULL_TREE, NULL,10, Reg_ST4 },
-    { "ST(5)", NULL_TREE, NULL,10, Reg_ST5 },
-    { "ST(6)", NULL_TREE, NULL,10, Reg_ST6 },
-    { "ST(7)", NULL_TREE, NULL,10, Reg_ST7 },
-    { "MM0", NULL_TREE, NULL, 8, Reg_MM0 },
-    { "MM1", NULL_TREE, NULL, 8, Reg_MM1 },
-    { "MM2", NULL_TREE, NULL, 8, Reg_MM2 },
-    { "MM3", NULL_TREE, NULL, 8, Reg_MM3 },
-    { "MM4", NULL_TREE, NULL, 8, Reg_MM4 },
-    { "MM5", NULL_TREE, NULL, 8, Reg_MM5 },
-    { "MM6", NULL_TREE, NULL, 8, Reg_MM6 },
-    { "MM7", NULL_TREE, NULL, 8, Reg_MM7 },
-    { "XMM0", NULL_TREE, NULL, 16, Reg_XMM0 },
-    { "XMM1", NULL_TREE, NULL, 16, Reg_XMM1 },
-    { "XMM2", NULL_TREE, NULL, 16, Reg_XMM2 },
-    { "XMM3", NULL_TREE, NULL, 16, Reg_XMM3 },
-    { "XMM4", NULL_TREE, NULL, 16, Reg_XMM4 },
-    { "XMM5", NULL_TREE, NULL, 16, Reg_XMM5 },
-    { "XMM6", NULL_TREE, NULL, 16, Reg_XMM6 },
-    { "XMM7", NULL_TREE, NULL, 16, Reg_XMM7 },
-    { "FLAGS", NULL_TREE, NULL, 0, Reg_EFLAGS }, // the gcc name is "flags"; not used in assembler input
-    { "CS",  NULL_TREE, NULL, 2, -1 },
-    { "DS",  NULL_TREE, NULL, 2, -1 },
-    { "SS",  NULL_TREE, NULL, 2, -1 },
-    { "ES",  NULL_TREE, NULL, 2, -1 },
-    { "FS",  NULL_TREE, NULL, 2, -1 },
-    { "GS",  NULL_TREE, NULL, 2, -1 },
-    { "AX",  NULL_TREE, NULL, 2,  Reg_EAX },
-    { "BX",  NULL_TREE, NULL, 2,  Reg_EBX },
-    { "CX",  NULL_TREE, NULL, 2,  Reg_ECX },
-    { "DX",  NULL_TREE, NULL, 2,  Reg_EDX },
-    { "SI",  NULL_TREE, NULL, 2,  Reg_ESI },
-    { "DI",  NULL_TREE, NULL, 2,  Reg_EDI },
-    { "BP",  NULL_TREE, NULL, 2,  Reg_EBP },
-    { "SP",  NULL_TREE, NULL, 2,  Reg_ESP },
-    { "AL",  NULL_TREE, NULL, 1,  Reg_EAX },
-    { "AH",  NULL_TREE, NULL, 1,  Reg_EAX },
-    { "BL",  NULL_TREE, NULL, 1,  Reg_EBX },
-    { "BH",  NULL_TREE, NULL, 1,  Reg_EBX },
-    { "CL",  NULL_TREE, NULL, 1,  Reg_ECX },
-    { "CH",  NULL_TREE, NULL, 1,  Reg_ECX },
-    { "DL",  NULL_TREE, NULL, 1,  Reg_EDX },
-    { "DH",  NULL_TREE, NULL, 1,  Reg_EDX },
-    { "CR0", NULL_TREE, NULL, 0, -1 },
-    { "CR2", NULL_TREE, NULL, 0, -1 },
-    { "CR3", NULL_TREE, NULL, 0, -1 },
-    { "CR4", NULL_TREE, NULL, 0, -1 },
-    { "DR0", NULL_TREE, NULL, 0, -1 },
-    { "DR1", NULL_TREE, NULL, 0, -1 },
-    { "DR2", NULL_TREE, NULL, 0, -1 },
-    { "DR3", NULL_TREE, NULL, 0, -1 },
-    { "DR6", NULL_TREE, NULL, 0, -1 },
-    { "DR7", NULL_TREE, NULL, 0, -1 },
-    { "TR3", NULL_TREE, NULL, 0, -1 },
-    { "TR4", NULL_TREE, NULL, 0, -1 },
-    { "TR5", NULL_TREE, NULL, 0, -1 },
-    { "TR6", NULL_TREE, NULL, 0, -1 },
-    { "TR7", NULL_TREE, NULL, 0, -1 }
-};
-
-typedef enum {
-    No_Type_Needed,
-    Int_Types,
-    Word_Types, // same as Int_Types, but byte is not allowed
-    FP_Types,
-    FPInt_Types,
-    Byte_NoType, // byte only, but no type suffix
-} TypeNeeded;
-
-typedef enum {
-    No_Link,
-    Out_Mnemonic,
-    Next_Form
-} OpLink;
-
-typedef enum {
-    Clb_SizeAX   = 0x01,
-    Clb_SizeDXAX = 0x02,
-    Clb_EAX      = 0x03,
-    Clb_DXAX_Mask = 0x03,
-    
-    Clb_Flags    = 0x04,
-    Clb_DI       = 0x08,
-    Clb_SI       = 0x10,
-    Clb_CX       = 0x20,
-    Clb_ST       = 0x40,
-    Clb_SP       = 0x80 // Doesn't actually let GCC know the frame pointer is modified
-} ImplicitClober;
-
-// "^ +/..\([A-Za-z_0-9]+\).*" -> "    \1,"
-typedef enum {
-    Op_Invalid,
-    Op_Adjust,
-    Op_Dst,
-    Op_Upd,
-    Op_DstW,
-    Op_DstF,
-    Op_UpdF,
-    Op_DstSrc,
-    Op_DstSrcF,
-    Op_UpdSrcF,
-    Op_DstSrcFW,
-    Op_UpdSrcFW,
-    Op_DstSrcSSE,
-    Op_DstSrcMMX,
-    Op_DstSrcImmS,
-    Op_DstSrcImmM,
-    Op_UpdSrcShft,
-    Op_DstSrcNT,
-    Op_UpdSrcNT,
-    Op_DstMemNT,
-    Op_DstRMBNT,
-    Op_DstRMWNT,
-    Op_UpdUpd,
-    Op_UpdUpdF,
-    Op_Src,
-    Op_SrcRMWNT,
-    Op_SrcW,
-    Op_SrcImm,
-    Op_Src_DXAXF,
-    Op_SrcMemNT,
-    Op_SrcMemNTF,
-    Op_SrcSrc,
-    Op_SrcSrcF,
-    Op_SrcSrcFW,
-    Op_SrcSrcSSEF,
-    Op_SrcSrcMMX,
-    Op_Shift,
-    Op_Branch,
-    Op_CBranch,
-    Op_0,
-    Op_0_AX,
-    Op_0_DXAX,
-    Op_Loop,
-    Op_Flags,
-    Op_F0_ST,
-    Op_F0_P,
-    Op_Fs_P,
-    Op_Fis,
-    Op_Fis_ST,
-    Op_Fis_P,
-    Op_Fid,
-    Op_Fid_P,
-    Op_Ffd,
-    Op_FfdR,
-    Op_Ffd_P,
-    Op_FfdR_P,
-    Op_Fd_P,
-    Op_FdST,
-    Op_FMath,
-    Op_FdSTiSTi,
-    Op_FPMath,
-    Op_FCmp,
-    Op_FCmp1,
-    Op_FCmpP,
-    Op_FCmpP1,
-    Op_FCmpFlg,
-    Op_FCmpFlgP,
-    Op_fld,
-    Op_fldR,
-    Op_fxch,
-    Op_fxch1,
-    Op_fxch0,
-    Op_SizedStack,
-    Op_bound,
-    Op_bswap,
-    Op_cmps,
-    Op_cmpsd,
-    Op_cmpsX,
-    Op_cmpxchg8b,
-    Op_cmpxchg,
-    Op_cpuid,
-    Op_enter,
-    Op_fdisi,
-    Op_feni,
-    Op_fsetpm,
-    Op_fXstsw,
-    Op_imul,
-    Op_imul2,
-    Op_imul1,
-    Op_in,
-    Op_ins,
-    Op_insX,
-    Op_iret,
-    Op_iretd,
-    Op_lods,
-    Op_lodsX,
-    Op_movs,
-    Op_movsd,
-    Op_movsX,
-    Op_movsx,
-    Op_movzx,
-    Op_mul,
-    Op_out,
-    Op_outs,
-    Op_outsX,
-    Op_push,
-    Op_ret,
-    Op_retf,
-    Op_scas,
-    Op_scasX,
-    Op_stos,
-    Op_stosX,
-    Op_xlat,
-    N_AsmOpInfo,
-    Op_Align,
-    Op_Even,
-    Op_Naked,
-    Op_db,
-    Op_ds,
-    Op_di,
-    Op_dl,
-    Op_df,
-    Op_dd,
-    Op_de
-} AsmOp;
-
-typedef enum {
-    Opr_None = 0,
-    OprC_MRI  = 1,
-    OprC_MR   = 2,
-    OprC_Mem  = 3,
-    OprC_Reg  = 4,
-    OprC_Imm  = 5,
-    OprC_SSE  = 6,
-    OprC_SSE_Mem = 7,
-    OprC_R32  = 8,
-    OprC_RWord = 9,
-    OprC_RFP   = 10,
-    OprC_AbsRel = 11,
-    OprC_Relative = 12,
-    OprC_Port = 13, // DX or imm
-    OprC_AX = 14, // AL,AX,EAX
-    OprC_DX = 15, // only DX
-    OprC_MMX = 16,
-    OprC_MMX_Mem = 17,
-    OprC_Shift = 18, // imm or CL
-    
-    Opr_ClassMask = 0x1f,
-    
-    Opr_Dest     = 0x20,
-    Opr_Update   = 0x60,
-    
-    Opr_NoType = 0x80,
-} OprVals;
-
-
-typedef struct {
-} AsmOprInfo;
-
-typedef unsigned char Opr;
-
-typedef struct {
-    Opr operands[3];
-    unsigned char
-	needsType : 3,
-	implicitClobbers : 8,
-        linkType : 2;
-    unsigned link;
-
-    /*
-    bool takesLabel() {
-	return operands[0] & Opr_Label;
-    }
-    */
-    
-    unsigned nOperands() {
-	if (!operands[0])
-	    return 0;
-	else if (!operands[1])
-	    return 1;
-	else if (!operands[2])
-	    return 2;
-	else
-	    return 3;
-    }
-} AsmOpInfo;
-
-typedef enum {
-    Mn_fdisi,
-    Mn_feni,
-    Mn_fsetpm,
-    Mn_iretw,
-    Mn_iret,
-    Mn_lret,
-    Mn_cmpxchg8b,
-    N_AltMn
-} Alternate_Mnemonics;
-
-static const char * alternateMnemonics[N_AltMn] = {
-    ".byte 0xdb, 0xe1",
-    ".byte 0xdb, 0xe0",
-    ".byte 0xdb, 0xe4",
-    "iretw",
-    "iret",
-    "lret",
-    "cmpxchg8b" };
-
-#define mri  OprC_MRI
-#define mr   OprC_MR
-#define mem  OprC_Mem
-// for now mfp=mem
-#define mfp  OprC_Mem
-#define reg  OprC_Reg
-#define imm  OprC_Imm
-#define sse  OprC_SSE
-#define ssem OprC_SSE_Mem
-#define mmx  OprC_MMX
-#define mmxm OprC_MMX_Mem
-#define r32  OprC_R32
-#define rw   OprC_RWord
-#define rfp  OprC_RFP
-#define port OprC_Port
-#define ax   OprC_AX
-#define dx   OprC_DX
-#define shft OprC_Shift
-#define D    Opr_Dest
-#define U    Opr_Update
-#define N    Opr_NoType
-//#define L    Opr_Label
-
-// D=dest, N=notype
-static AsmOpInfo asmOpInfo[N_AsmOpInfo] = {
-    /* Op_Invalid   */  {},
-    /* Op_Adjust    */  { 0,0,0,             0, Clb_EAX /*just AX*/ },
-    /* Op_Dst       */  { D|mr,  0,    0,    1  },
-    /* Op_Upd       */  { U|mr,  0,    0,    1  },
-    /* Op_DstW      */  { D|mr,  0,    0,    Word_Types  },
-    /* Op_DstF      */  { D|mr,  0,    0,    1, Clb_Flags },
-    /* Op_UpdF      */  { U|mr,  0,    0,    1, Clb_Flags },
-    /* Op_DstSrc    */  { D|mr,  mri,  0,/**/1  }, 
-    /* Op_DstSrcF   */  { D|mr,  mri,  0,/**/1, Clb_Flags }, 
-    /* Op_UpdSrcF   */  { U|mr,  mri,  0,/**/1, Clb_Flags }, 
-    /* Op_DstSrcFW  */  { D|mr,  mri,  0,/**/Word_Types, Clb_Flags }, 
-    /* Op_UpdSrcFW  */  { U|mr,  mri,  0,/**/Word_Types, Clb_Flags }, 
-    /* Op_DstSrcSSE */  { U|sse, ssem, 0     },  // some may not be update %%
-    /* Op_DstSrcMMX */  { U|mmx, mmxm, 0     },  // some may not be update %%
-    /* Op_DstSrcImmS*/  { U|sse, ssem, N|imm  }, // some may not be update %%
-    /* Op_DstSrcImmM*/  { U|mmx, mmxm, N|imm  }, // some may not be update %%
-    /* Op_UpdSrcShft*/  { U|mr,  reg,  N|shft, 1, Clb_Flags }, // 16/32 only
-    /* Op_DstSrcNT  */  { D|mr,  mr,   0,    0 }, // used for movd .. operands can be rm32,sse,mmx
-    /* Op_UpdSrcNT  */  { U|mr,  mr,   0,    0 }, // used for movd .. operands can be rm32,sse,mmx
-    /* Op_DstMemNT  */  { D|mem, 0,    0     },
-    /* Op_DstRMBNT  */  { D|mr,  0,    0,    Byte_NoType },
-    /* Op_DstRMWNT  */  { D|mr,  0,    0     },
-    /* Op_UpdUpd    */  { U|mr,U|mr,   0,/**/1  }, 
-    /* Op_UpdUpdF   */  { U|mr,U|mr,   0,/**/1, Clb_Flags }, 
-    /* Op_Src       */  {   mri, 0,    0,    1  },
-    /* Op_SrcRMWNT  */  {   mr,  0,    0,    0  },
-    /* Op_SrcW      */  {   mri, 0,    0,    Word_Types  },
-    /* Op_SrcImm    */  {   imm },
-    /* Op_Src_DXAXF */  {   mr,  0,    0,    1, Clb_SizeDXAX|Clb_Flags },
-    /* Op_SrcMemNT  */  {   mem, 0,    0     },
-    /* Op_SrcMemNTF */  {   mem, 0,    0,    0, Clb_Flags },
-    /* Op_SrcSrc    */  {   mr,  mri,  0,    1  },
-    /* Op_SrcSrcF   */  {   mr,  mri,  0,    1, Clb_Flags },
-    /* Op_SrcSrcFW  */  {   mr,  mri,  0,    Word_Types, Clb_Flags },
-    /* Op_SrcSrcSSEF*/  {   sse, ssem, 0,    0, Clb_Flags },
-    /* Op_SrcSrcMMX */  {   mmx, mmx,  0, },
-    /* Op_Shift     */  { D|mr,N|shft, 0,/**/1, Clb_Flags }, 
-    /* Op_Branch    */  {   mri },
-    /* Op_CBranch   */  {   imm },
-    /* Op_0         */  {   0,0,0 },
-    /* Op_0_AX      */  {   0,0,0,           0, Clb_SizeAX },
-    /* Op_0_DXAX    */  {   0,0,0,           0, Clb_SizeDXAX }, // but for cwd/cdq -- how do know the size..
-    /* Op_Loop      */  {   imm, 0,    0,    0, Clb_CX },
-    /* Op_Flags     */  {   0,0,0,           0, Clb_Flags },
-    /* Op_F0_ST     */  {   0,0,0,           0, Clb_ST },
-    /* Op_F0_P      */  {   0,0,0,           0, Clb_ST }, // push, pops, etc. not sure how to inform gcc..
-    /* Op_Fs_P      */  {   mem, 0,    0,    0, Clb_ST }, // "
-    /* Op_Fis       */  {   mem, 0,    0,    FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
-    /* Op_Fis_ST    */  {   mem, 0,    0,    FPInt_Types, Clb_ST }, // "
-    /* Op_Fis_P     */  {   mem, 0,    0,    FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 
-    /* Op_Fid       */  { D|mem, 0,    0,    FPInt_Types }, // only 16bit and 32bit, DMD defaults to 16bit
-    /* Op_Fid_P     */  { D|mem, 0,    0,    FPInt_Types, Clb_ST }, // push and pop, fild so also 64 bit 
-    /* Op_Ffd       */  { D|mfp, 0,    0,    FP_Types, 0, Next_Form, Op_FfdR }, // only 16bit and 32bit, DMD defaults to 16bit, reg form doesn't need type
-    /* Op_FfdR      */  { D|rfp, 0,    0  }, 
-    /* Op_Ffd_P     */  { D|mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_FfdR_P, }, // pop, fld so also 80 bit, "
-    /* Op_FfdR_P    */  { D|rfp, 0,    0,    0,        Clb_ST },
-    /* Op_Fd_P      */  { D|mem, 0,    0,    0, Clb_ST }, // "
-    /* Op_FdST      */  { D|rfp, 0,    0  },
-    /* Op_FMath     */  {   mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_FdSTiSTi  }, // and only single or double prec
-    /* Op_FdSTiSTi  */  { D|rfp, rfp,  0, },
-    /* Op_FPMath    */  { D|rfp, rfp,  0,    0,        Clb_ST, Next_Form, Op_F0_P }, // pops
-    /* Op_FCmp      */  {   mfp, 0,    0,    FP_Types, 0,      Next_Form, Op_FCmp1 }, // DMD defaults to float ptr
-    /* Op_FCmp1     */  {   rfp, 0,    0,    0,        0,      Next_Form, Op_0 },
-    /* Op_FCmpP     */  {   mfp, 0,    0,    FP_Types, 0,      Next_Form, Op_FCmpP1 }, // pops
-    /* Op_FCmpP1    */  {   rfp, 0,    0,    0,        0,      Next_Form, Op_F0_P }, // pops
-    /* Op_FCmpFlg   */  {   rfp, rfp,  0,    0,        Clb_Flags },
-    /* Op_FCmpFlgP  */  {   rfp, rfp,  0,    0,        Clb_Flags }, // pops
-    /* Op_fld       */  {   mfp, 0,    0,    FP_Types, Clb_ST, Next_Form, Op_fldR },
-    /* Op_fldR      */  {   rfp, 0,    0,    0,        Clb_ST },
-    /* Op_fxch      */  { D|rfp,D|rfp, 0,    0,        Clb_ST, Next_Form, Op_fxch1 }, // not in intel manual?, but DMD allows it (gas won't), second arg must be ST
-    /* Op_fxch1     */  { D|rfp, 0,    0,    0,        Clb_ST, Next_Form, Op_fxch0 },
-    /* Op_fxch0     */  {   0,   0,    0,    0,        Clb_ST }, // Also clobbers ST(1)
-    /* Op_SizedStack*/  {   0,   0,    0,    0,        Clb_SP }, // type suffix special case
-    /* Op_bound     */  {   mr,  mri,  0,    Word_Types  }, // operands *not* reversed for gas
-    /* Op_bswap     */  { D|r32      },
-    /* Op_cmps      */  {   mem, mem, 0,     1, Clb_DI|Clb_SI|Clb_Flags },
-    /* Op_cmpsd     */  {   0,   0,   0,     0, Clb_DI|Clb_SI|Clb_Flags, Next_Form, Op_DstSrcImmS },
-    /* Op_cmpsX     */  {   0,   0,   0,     0, Clb_DI|Clb_SI|Clb_Flags },
-    /* Op_cmpxchg8b */  { D|mem/*64*/,0,0,   0, Clb_SizeDXAX/*32*/|Clb_Flags, Out_Mnemonic, Mn_cmpxchg8b },
-    /* Op_cmpxchg   */  { D|mr,  reg, 0,     1, Clb_SizeAX|Clb_Flags },
-    /* Op_cpuid     */  {   0,0,0 },    // Clobbers eax, ebx, ecx, and edx. Handled specially below.
-    /* Op_enter     */  {   imm, imm }, // operands *not* reversed for gas, %% inform gcc of EBP clobber?, 
-    /* Op_fdisi     */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_fdisi },
-    /* Op_feni      */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_feni },
-    /* Op_fsetpm    */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_fsetpm },
-    /* Op_fXstsw    */  { D|mr,  0,   0,     }, // ax is the only allowed register
-    /* Op_imul      */  { D|reg, mr,  imm,   1, Clb_Flags, Next_Form, Op_imul2 }, // 16/32 only
-    /* Op_imul2     */  { D|reg, mri, 0,     1, Clb_Flags, Next_Form, Op_imul1 }, // 16/32 only
-    /* Op_imul1     */  {   mr,  0,   0,     1, Clb_Flags|Clb_SizeDXAX },
-    /* Op_in        */  { D|ax,N|port,0,     1  },        
-    /* Op_ins       */  {   mem,N|dx, 0,     1, Clb_DI }, // can't override ES segment for this one
-    /* Op_insX      */  {   0,   0,   0,     0, Clb_DI }, // output segment overrides %% needs work
-    /* Op_iret      */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_iretw },
-    /* Op_iretd     */  {   0,0,0,           0, 0, Out_Mnemonic, Mn_iret },
-    /* Op_lods      */  {   mem, 0,   0,     1, Clb_SI },
-    /* Op_lodsX     */  {   0,   0,   0,     0, Clb_SI },
-    /* Op_movs      */  {   mem, mem, 0,     1, Clb_DI|Clb_SI }, // only src/DS can be overridden
-    /* Op_movsd     */  {   0,   0,   0,     0, Clb_DI|Clb_SI, Next_Form, Op_DstSrcSSE }, // %% gas doesn't accept movsd .. has to movsl
-    /* Op_movsX     */  {   0,   0,   0,     0, Clb_DI|Clb_SI },
-    /* Op_movsx     */  { D|reg, mr,  0,     1 }, // type suffix is special case
-    /* Op_movzx     */  { D|reg, mr,  0,     1 }, // type suffix is special case
-    /* Op_mul       */  { U|ax,  mr,  0,     1, Clb_SizeDXAX|Clb_Flags, Next_Form, Op_Src_DXAXF },
-    /* Op_out       */  { N|port,ax,  0,     1  },        
-    /* Op_outs      */  { N|dx,  mem, 0,     1, Clb_SI },
-    /* Op_outsX     */  {   0,   0,   0,     0, Clb_SI },
-    /* Op_push      */  {   mri, 0,    0,    Word_Types, Clb_SP }, // would be Op_SrcW, but DMD defaults to 32-bit for immediate form
-    /* Op_ret       */  {   imm, 0,   0,     0, 0, Next_Form, Op_0  }, 
-    /* Op_retf      */  {   0,   0,   0,     0, 0, Out_Mnemonic, Mn_lret  },
-    /* Op_scas      */  {   mem, 0,   0,     1, Clb_DI|Clb_Flags },
-    /* Op_scasX     */  {   0,   0,   0,     0, Clb_DI|Clb_Flags },
-    /* Op_stos      */  {   mem, 0,   0,     1, Clb_DI },
-    /* Op_stosX     */  {   0,   0,   0,     0, Clb_DI },
-    /* Op_xlat      */  {   mem, 0,   0,     0, Clb_SizeAX }
-    
-    /// * Op_arpl      */  { D|mr,  reg }, // 16 only -> DstSrc
-    /// * Op_bsX       */  {   rw,  mrw,  0,    1, Clb_Flags },//->srcsrcf 
-    /// * Op_bt        */  {   mrw, riw,  0,    1, Clb_Flags },//->srcsrcf
-    /// * Op_btX       */  { D|mrw, riw,  0,    1, Clb_Flags },//->dstsrcf .. immediate does not contribute to size
-    /// * Op_cmovCC    */  { D|rw,  mrw,  0,    1 } // ->dstsrc
-};
-
-#undef mri
-#undef mr
-#undef mem
-#undef mfp
-#undef reg
-#undef imm
-#undef sse
-#undef ssem
-#undef mmx
-#undef mmxm
-#undef r32
-#undef rw
-#undef rfp
-#undef port
-#undef ax
-#undef dx
-#undef shft
-#undef D
-#undef U
-#undef N
-//#undef L
-
-typedef struct {
-    const char  * inMnemonic;
-    AsmOp   asmOp;
-} AsmOpEnt;
-
-/* Some opcodes which have data size restrictions, but we don't check
-
-   cmov, l<segreg> ?, lea, lsl, shld
-
-   todo: push <immediate> is always the 32-bit form, even tho push <mem> is 16-bit
-*/
-
-static AsmOpEnt opData[] = {
-    { "aaa",    Op_Adjust },
-    { "aad",    Op_Adjust },
-    { "aam",    Op_Adjust },
-    { "aas",    Op_Adjust },
-    { "adc",    Op_UpdSrcF },
-    { "add",    Op_UpdSrcF },
-    { "addpd",  Op_DstSrcSSE },
-    { "addps",  Op_DstSrcSSE },
-    { "addsd",  Op_DstSrcSSE },
-    { "addss",  Op_DstSrcSSE },
-    { "addsubpd", Op_DstSrcSSE },
-    { "addsubps", Op_DstSrcSSE },    
-    { "align",  Op_Align },
-    { "and",    Op_UpdSrcF },
-    { "andnpd", Op_DstSrcSSE },
-    { "andnps", Op_DstSrcSSE },
-    { "andpd",  Op_DstSrcSSE },
-    { "andps",  Op_DstSrcSSE },
-    { "arpl",   Op_UpdSrcNT },
-    { "bound",  Op_bound },
-    { "bsf",    Op_SrcSrcFW },
-    { "bsr",    Op_SrcSrcFW },
-    { "bswap",  Op_bswap },
-    { "bt",     Op_SrcSrcFW },
-    { "btc",    Op_UpdSrcFW },
-    { "btr",    Op_UpdSrcFW },
-    { "bts",    Op_UpdSrcFW },
-    { "call",   Op_Branch },
-    { "cbw",    Op_0_AX },
-    { "cdq",    Op_0_DXAX },
-    { "clc",    Op_Flags },
-    { "cld",    Op_Flags },
-    { "clflush",Op_SrcMemNT },
-    { "cli",    Op_Flags },
-    { "clts",   Op_0 },
-    { "cmc",    Op_Flags },
-    { "cmova",  Op_DstSrc },
-    { "cmovae", Op_DstSrc },
-    { "cmovb",  Op_DstSrc },
-    { "cmovbe", Op_DstSrc },
-    { "cmovc",  Op_DstSrc },
-    { "cmove",  Op_DstSrc },
-    { "cmovg",  Op_DstSrc },
-    { "cmovge", Op_DstSrc },
-    { "cmovl",  Op_DstSrc },
-    { "cmovle", Op_DstSrc },
-    { "cmovna", Op_DstSrc },
-    { "cmovnae",Op_DstSrc },
-    { "cmovnb", Op_DstSrc },
-    { "cmovnbe",Op_DstSrc },
-    { "cmovnc", Op_DstSrc },
-    { "cmovne", Op_DstSrc },
-    { "cmovng", Op_DstSrc },
-    { "cmovnge",Op_DstSrc },
-    { "cmovnl", Op_DstSrc },
-    { "cmovnle",Op_DstSrc },
-    { "cmovno", Op_DstSrc },
-    { "cmovnp", Op_DstSrc },
-    { "cmovns", Op_DstSrc },
-    { "cmovnz", Op_DstSrc },
-    { "cmovo",  Op_DstSrc },
-    { "cmovp",  Op_DstSrc },
-    { "cmovpe", Op_DstSrc },
-    { "cmovpo", Op_DstSrc },
-    { "cmovs",  Op_DstSrc },
-    { "cmovz",  Op_DstSrc },
-    { "cmp",    Op_SrcSrcF },
-    { "cmppd",  Op_DstSrcImmS },
-    { "cmpps",  Op_DstSrcImmS },
-    { "cmps",   Op_cmps  },
-    { "cmpsb",  Op_cmpsX },
-    { "cmpsd",  Op_cmpsd }, // string cmp, and SSE cmp
-    { "cmpss",  Op_DstSrcImmS },
-    { "cmpsw",  Op_cmpsX },
-    { "cmpxch8b", Op_cmpxchg8b }, // %% DMD opcode typo?
-    { "cmpxchg",  Op_cmpxchg },
-    { "comisd", Op_SrcSrcSSEF },
-    { "comiss", Op_SrcSrcSSEF },
-    { "cpuid",  Op_cpuid },
-    { "cvtdq2pd", Op_DstSrcSSE },
-    { "cvtdq2ps", Op_DstSrcSSE },
-    { "cvtpd2dq", Op_DstSrcSSE },
-    { "cvtpd2pi", Op_DstSrcSSE },
-    { "cvtpd2ps", Op_DstSrcSSE },
-    { "cvtpi2pd", Op_DstSrcSSE },
-    { "cvtpi2ps", Op_DstSrcSSE },
-    { "cvtps2dq", Op_DstSrcSSE },
-    { "cvtps2pd", Op_DstSrcSSE },
-    { "cvtps2pi", Op_DstSrcSSE },
-    { "cvtsd2si", Op_DstSrcSSE },
-    { "cvtsd2ss", Op_DstSrcSSE },
-    { "cvtsi2sd", Op_DstSrcSSE },
-    { "cvtsi2ss", Op_DstSrcSSE },
-    { "cvtss2sd", Op_DstSrcSSE },
-    { "cvtss2si", Op_DstSrcSSE },
-    { "cvttpd2dq", Op_DstSrcSSE },
-    { "cvttpd2pi", Op_DstSrcSSE },
-    { "cvttps2dq", Op_DstSrcSSE },
-    { "cvttps2pi", Op_DstSrcSSE },
-    { "cvttsd2si", Op_DstSrcSSE },
-    { "cvttss2si", Op_DstSrcSSE },
-    { "cwd",  Op_0_DXAX },
-    { "cwde", Op_0_AX },
-    //{ "da", Op_ },// dunno what this is -- takes labels?
-    { "daa",   Op_Adjust },
-    { "das",   Op_Adjust },    
-    { "db",    Op_db },
-    { "dd",    Op_dd },
-    { "de",    Op_de },
-    { "dec",   Op_UpdF },
-    { "df",    Op_df },
-    { "di",    Op_di },
-    { "div",   Op_Src_DXAXF },
-    { "divpd", Op_DstSrcSSE },
-    { "divps", Op_DstSrcSSE },
-    { "divsd", Op_DstSrcSSE },
-    { "divss", Op_DstSrcSSE },
-    { "dl",    Op_dl },
-    { "dq",    Op_dl },
-    { "ds",    Op_ds },
-    { "dt",    Op_de },
-    { "dw",    Op_ds },
-    { "emms",  Op_0 }, // clobber all mmx/fp?
-    { "enter", Op_enter },
-    { "even",  Op_Even },
-    { "f2xm1",  Op_F0_ST }, // %% most of these are update...
-    { "fabs",   Op_F0_ST },
-    { "fadd",   Op_FMath },
-    { "faddp",  Op_FPMath },
-    { "fbld",   Op_Fs_P },
-    { "fbstp",  Op_Fd_P },
-    { "fchs",   Op_F0_ST },
-    { "fclex",  Op_0 },
-    { "fcmovb",   Op_FdSTiSTi }, // but only ST(0) can be the destination -- should be FdST0STi
-    { "fcmovbe",  Op_FdSTiSTi },
-    { "fcmove",   Op_FdSTiSTi },
-    { "fcmovnb",  Op_FdSTiSTi },
-    { "fcmovnbe", Op_FdSTiSTi },
-    { "fcmovne",  Op_FdSTiSTi },
-    { "fcmovnu",  Op_FdSTiSTi },
-    { "fcmovu",   Op_FdSTiSTi },
-    { "fcom",   Op_FCmp },
-    { "fcomi",  Op_FCmpFlg  }, 
-    { "fcomip", Op_FCmpFlgP },
-    { "fcomp",  Op_FCmpP },
-    { "fcompp", Op_F0_P },   // pops twice
-    { "fcos",   Op_F0_ST }, 
-    { "fdecstp",Op_F0_P },   // changes stack
-    { "fdisi",  Op_fdisi },
-    { "fdiv",   Op_FMath },
-    { "fdivp",  Op_FPMath }, 
-    { "fdivr",  Op_FMath },
-    { "fdivrp", Op_FPMath },
-    { "feni",   Op_feni },
-    { "ffree",  Op_FdST },
-    { "fiadd",  Op_Fis_ST },
-    { "ficom",  Op_Fis   },
-    { "ficomp", Op_Fis_P },
-    { "fidiv",  Op_Fis_ST },
-    { "fidivr", Op_Fis_ST },
-    { "fild",   Op_Fis_P },
-    { "fimul",  Op_Fis_ST },
-    { "fincstp",Op_F0_P },
-    { "finit",  Op_F0_P },
-    { "fist",   Op_Fid }, // only 16,32bit
-    { "fistp",  Op_Fid_P }, 
-    { "fisttp", Op_Fid_P }, 
-    { "fisub",  Op_Fis_ST },
-    { "fisubr", Op_Fis_ST },
-    { "fld",    Op_fld },
-    { "fld1",   Op_F0_P },
-    { "fldcw",  Op_SrcMemNT },
-    { "fldenv", Op_SrcMemNT },
-    { "fldl2e", Op_F0_P },
-    { "fldl2t", Op_F0_P },
-    { "fldlg2", Op_F0_P },
-    { "fldln2", Op_F0_P },
-    { "fldpi",  Op_F0_P },
-    { "fldz",   Op_F0_P },
-    { "fmul",   Op_FMath },
-    { "fmulp",  Op_FPMath },
-    { "fnclex", Op_0 },
-    { "fndisi", Op_fdisi }, // ??
-    { "fneni",  Op_feni }, // ??
-    { "fninit", Op_0 },
-    { "fnop",   Op_0 },
-    { "fnsave", Op_DstMemNT },
-    { "fnstcw", Op_DstMemNT },
-    { "fnstenv",Op_DstMemNT },
-    { "fnstsw", Op_fXstsw },
-    { "fpatan", Op_F0_P }, // pop and modify new ST
-    { "fprem",  Op_F0_ST }, 
-    { "fprem1", Op_F0_ST }, 
-    { "fptan",  Op_F0_P }, // modify ST and push 1.0
-    { "frndint",Op_F0_ST }, 
-    { "frstor", Op_SrcMemNT }, // but clobbers everything
-    { "fsave",  Op_DstMemNT },
-    { "fscale", Op_F0_ST },
-    { "fsetpm", Op_fsetpm },
-    { "fsin",   Op_F0_ST },
-    { "fsincos",Op_F0_P },
-    { "fsqrt",  Op_F0_ST },
-    { "fst",    Op_Ffd },
-    { "fstcw",  Op_DstMemNT },
-    { "fstenv", Op_DstMemNT },
-    { "fstp",   Op_Ffd_P },
-    { "fstsw",  Op_fXstsw },
-    { "fsub",   Op_FMath },
-    { "fsubp",  Op_FPMath },
-    { "fsubr",  Op_FMath },
-    { "fsubrp", Op_FPMath },
-    { "ftst",   Op_0 },
-    { "fucom",  Op_FCmp },
-    { "fucomi", Op_FCmpFlg },
-    { "fucomip",Op_FCmpFlgP },
-    { "fucomp", Op_FCmpP },
-    { "fucompp",Op_F0_P }, // pops twice
-    { "fwait",  Op_0 },
-    { "fxam",   Op_0 },
-    { "fxch",   Op_fxch },
-    { "fxrstor",Op_SrcMemNT },  // clobbers FP,MMX,SSE
-    { "fxsave", Op_DstMemNT },
-    { "fxtract",Op_F0_P }, // pushes
-    { "fyl2x",  Op_F0_P }, // pops
-    { "fyl2xp1",Op_F0_P }, // pops
-    { "haddpd", Op_DstSrcSSE },
-    { "haddps", Op_DstSrcSSE },
-    { "hlt",  Op_0 },
-    { "hsubpd", Op_DstSrcSSE },
-    { "hsubps", Op_DstSrcSSE },
-    { "idiv", Op_Src_DXAXF },
-    { "imul", Op_imul },
-    { "in",   Op_in },
-    { "inc",  Op_UpdF },
-    { "ins",  Op_ins },
-    { "insb", Op_insX },
-    { "insd", Op_insX },
-    { "insw", Op_insX },
-    { "int",  Op_SrcImm },
-    { "into", Op_0 },
-    { "invd", Op_0 },
-    { "invlpg", Op_SrcMemNT },
-    { "iret",  Op_iret },
-    { "iretd", Op_iretd },    
-    { "ja",    Op_CBranch },
-    { "jae",   Op_CBranch },
-    { "jb",    Op_CBranch },
-    { "jbe",   Op_CBranch },
-    { "jc",    Op_CBranch },
-    { "jcxz",  Op_CBranch },
-    { "je",    Op_CBranch },
-    { "jecxz", Op_CBranch },
-    { "jg",    Op_CBranch },
-    { "jge",   Op_CBranch },
-    { "jl",    Op_CBranch },
-    { "jle",   Op_CBranch },
-    { "jmp",   Op_Branch },
-    { "jna",   Op_CBranch },
-    { "jnae",  Op_CBranch },
-    { "jnb",   Op_CBranch },
-    { "jnbe",  Op_CBranch },
-    { "jnc",   Op_CBranch },
-    { "jne",   Op_CBranch },
-    { "jng",   Op_CBranch },
-    { "jnge",  Op_CBranch },
-    { "jnl",   Op_CBranch },
-    { "jnle",  Op_CBranch },
-    { "jno",   Op_CBranch },
-    { "jnp",   Op_CBranch },
-    { "jns",   Op_CBranch },
-    { "jnz",   Op_CBranch },
-    { "jo",    Op_CBranch },
-    { "jp",    Op_CBranch },
-    { "jpe",   Op_CBranch },
-    { "jpo",   Op_CBranch },
-    { "js",    Op_CBranch },
-    { "jz",    Op_CBranch },
-    { "lahf",  Op_0_AX },
-    { "lar",   Op_DstSrcFW }, // reg dest only
-    { "lddqu", Op_DstSrcSSE },
-    { "ldmxcsr", Op_SrcMemNT },
-    { "lds",   Op_DstSrc },  // reg dest only
-    { "lea",   Op_DstSrc },  // "
-    { "leave", Op_0 },       // EBP,ESP clobbers
-    { "les",   Op_DstSrc },
-    { "lfence",Op_0 },
-    { "lfs",   Op_DstSrc },
-    { "lgdt",  Op_SrcMemNT },
-    { "lgs",   Op_DstSrc },
-    { "lidt",  Op_SrcMemNT },
-    { "lldt",  Op_SrcRMWNT },
-    { "lmsw",  Op_SrcRMWNT },
-    { "lock",  Op_0 },
-    { "lods",  Op_lods },
-    { "lodsb", Op_lodsX },
-    { "lodsd", Op_lodsX },
-    { "lodsw", Op_lodsX },
-    { "loop",  Op_Loop },
-    { "loope", Op_Loop },
-    { "loopne",Op_Loop },
-    { "loopnz",Op_Loop },
-    { "loopz", Op_Loop },
-    { "lsl",   Op_DstSrcFW }, // reg dest only
-    { "lss",   Op_DstSrc },
-    { "ltr",   Op_DstMemNT },
-    { "maskmovdqu", Op_SrcSrcMMX }, // writes to [edi]
-    { "maskmovq",   Op_SrcSrcMMX }, 
-    { "maxpd", Op_DstSrcSSE },
-    { "maxps", Op_DstSrcSSE },
-    { "maxsd", Op_DstSrcSSE },
-    { "maxss", Op_DstSrcSSE },
-    { "mfence",Op_0},
-    { "minpd", Op_DstSrcSSE },
-    { "minps", Op_DstSrcSSE },
-    { "minsd", Op_DstSrcSSE },
-    { "minss", Op_DstSrcSSE },
-    { "monitor", Op_0 },
-    { "mov",   Op_DstSrc },
-    { "movapd",  Op_DstSrcSSE },
-    { "movaps",  Op_DstSrcSSE },
-    { "movd",    Op_DstSrcNT  }, // also mmx and sse
-    { "movddup", Op_DstSrcSSE },
-    { "movdq2q", Op_DstSrcNT }, // mmx/sse
-    { "movdqa",  Op_DstSrcSSE },
-    { "movdqu",  Op_DstSrcSSE },
-    { "movhlps", Op_DstSrcSSE },
-    { "movhpd",  Op_DstSrcSSE },
-    { "movhps",  Op_DstSrcSSE },
-    { "movlhps", Op_DstSrcSSE },
-    { "movlpd",  Op_DstSrcSSE },
-    { "movlps",  Op_DstSrcSSE },
-    { "movmskpd",Op_DstSrcSSE },
-    { "movmskps",Op_DstSrcSSE },
-    { "movntdq", Op_DstSrcNT  }, // limited to sse, but mem dest
-    { "movnti",  Op_DstSrcNT  }, // limited to gpr, but mem dest
-    { "movntpd", Op_DstSrcNT  }, // limited to sse, but mem dest
-    { "movntps", Op_DstSrcNT  }, // limited to sse, but mem dest
-    { "movntq",  Op_DstSrcNT  }, // limited to mmx, but mem dest
-    { "movq",    Op_DstSrcNT  }, // limited to sse and mmx
-    { "movq2dq", Op_DstSrcNT  }, // limited to sse <- mmx regs
-    { "movs",  Op_movs },
-    { "movsb", Op_movsX },
-    { "movsd", Op_movsd },
-    { "movshdup", Op_DstSrcSSE },
-    { "movsldup", Op_DstSrcSSE },
-    { "movss", Op_DstSrcSSE },
-    { "movsw", Op_movsX },
-    { "movsx", Op_movsx }, // word-only, reg dest
-    { "movupd",Op_DstSrcSSE },
-    { "movups",Op_DstSrcSSE },
-    { "movzx", Op_movzx },
-    { "mul",   Op_mul },
-    { "mulpd", Op_DstSrcSSE },
-    { "mulps", Op_DstSrcSSE },
-    { "mulsd", Op_DstSrcSSE },
-    { "mulss", Op_DstSrcSSE },
-    { "mwait", Op_0 },
-    { "naked", Op_Naked },
-    { "neg",   Op_UpdF },
-    { "nop",   Op_0 },
-    { "not",   Op_Upd },
-    { "or",    Op_UpdSrcF },
-    { "orpd",  Op_DstSrcSSE },
-    { "orps",  Op_DstSrcSSE },
-    { "out",   Op_out },
-    { "outs",  Op_outs },
-    { "outsb", Op_outsX },
-    { "outsd", Op_outsX },
-    { "outsw", Op_outsX },
-    { "packssdw", Op_DstSrcMMX }, // %% also SSE
-    { "packsswb", Op_DstSrcMMX },
-    { "packuswb", Op_DstSrcMMX },
-    { "paddb",    Op_DstSrcMMX },
-    { "paddd",    Op_DstSrcMMX },
-    { "paddq",    Op_DstSrcMMX },
-    { "paddsb",   Op_DstSrcMMX },
-    { "paddsw",   Op_DstSrcMMX },
-    { "paddusb",  Op_DstSrcMMX },
-    { "paddusw",  Op_DstSrcMMX },
-    { "paddw",    Op_DstSrcMMX },
-    { "pand",     Op_DstSrcMMX },
-    { "pandn",    Op_DstSrcMMX },
-    { "pavgb",    Op_DstSrcMMX },
-    { "pavgw",    Op_DstSrcMMX },
-    { "pcmpeqb",  Op_DstSrcMMX },
-    { "pcmpeqd",  Op_DstSrcMMX },
-    { "pcmpeqw",  Op_DstSrcMMX },
-    { "pcmpgtb",  Op_DstSrcMMX },
-    { "pcmpgtd",  Op_DstSrcMMX },
-    { "pcmpgtw",  Op_DstSrcMMX },
-    { "pextrw",   Op_DstSrcImmM }, // gpr32 dest
-    { "pinsrw",   Op_DstSrcImmM }, // gpr32(16), mem16 src, sse too
-    { "pmaddwd",  Op_DstSrcMMX },
-    { "pmaxsw",   Op_DstSrcMMX },
-    { "pmaxub",   Op_DstSrcMMX },
-    { "pminsw",   Op_DstSrcMMX },
-    { "pminub",   Op_DstSrcMMX },
-    { "pmovmskb", Op_DstSrcMMX },
-    { "pmulhuw",  Op_DstSrcMMX },
-    { "pmulhw",   Op_DstSrcMMX },
-    { "pmullw",   Op_DstSrcMMX },
-    { "pmuludq",  Op_DstSrcMMX }, // also sse
-    { "pop",      Op_DstW },
-    { "popa",     Op_SizedStack },  // For intel this is always 16-bit
-    { "popad",    Op_SizedStack },  // GAS doesn't accept 'popad' -- these clobber everything, but supposedly it would be used to preserve clobbered regs
-    { "popf",     Op_SizedStack },  // rewrite the insn with a special case
-    { "popfd",    Op_SizedStack }, 
-    { "por",      Op_DstSrcMMX },
-    { "prefetchnta", Op_SrcMemNT },
-    { "prefetcht0",  Op_SrcMemNT },
-    { "prefetcht1",  Op_SrcMemNT },
-    { "prefetcht2",  Op_SrcMemNT },
-    { "psadbw",   Op_DstSrcMMX },
-    { "pshufd",   Op_DstSrcImmM },
-    { "pshufhw",  Op_DstSrcImmM },
-    { "pshuflw",  Op_DstSrcImmM },
-    { "pshufw",   Op_DstSrcImmM },
-    { "pslld",    Op_DstSrcMMX }, // immediate operands...
-    { "pslldq",   Op_DstSrcMMX },
-    { "psllq",    Op_DstSrcMMX },
-    { "psllw",    Op_DstSrcMMX },
-    { "psrad",    Op_DstSrcMMX },
-    { "psraw",    Op_DstSrcMMX },
-    { "psrld",    Op_DstSrcMMX },
-    { "psrldq",   Op_DstSrcMMX },
-    { "psrlq",    Op_DstSrcMMX },
-    { "psrlw",    Op_DstSrcMMX },
-    { "psubb",    Op_DstSrcMMX },
-    { "psubd",    Op_DstSrcMMX },
-    { "psubq",    Op_DstSrcMMX },
-    { "psubsb",   Op_DstSrcMMX },
-    { "psubsw",   Op_DstSrcMMX },
-    { "psubusb",  Op_DstSrcMMX },
-    { "psubusw",  Op_DstSrcMMX },
-    { "psubw",    Op_DstSrcMMX },
-    { "punpckhbw", Op_DstSrcMMX },
-    { "punpckhdq", Op_DstSrcMMX },
-    { "punpckhqdq",Op_DstSrcMMX },
-    { "punpckhwd", Op_DstSrcMMX },
-    { "punpcklbw", Op_DstSrcMMX },
-    { "punpckldq", Op_DstSrcMMX },
-    { "punpcklqdq",Op_DstSrcMMX },
-    { "punpcklwd", Op_DstSrcMMX },
-    { "push",   Op_push },
-    { "pusha",  Op_SizedStack },
-    { "pushad", Op_SizedStack },
-    { "pushf",  Op_SizedStack },
-    { "pushfd", Op_SizedStack },
-    { "pxor",   Op_DstSrcMMX },
-    { "rcl",    Op_Shift }, // limited src operands -- change to shift
-    { "rcpps",  Op_DstSrcSSE },
-    { "rcpss",  Op_DstSrcSSE },
-    { "rcr",    Op_Shift },
-    { "rdmsr",  Op_0_DXAX },
-    { "rdpmc",  Op_0_DXAX },
-    { "rdtsc",  Op_0_DXAX },
-    { "rep",    Op_0 },
-    { "repe",   Op_0 },
-    { "repne",  Op_0 },
-    { "repnz",  Op_0 },
-    { "repz",   Op_0 },
-    { "ret",    Op_ret },
-    { "retf",   Op_retf },
-    { "rol",    Op_Shift },
-    { "ror",    Op_Shift },
-    { "rsm",    Op_0 },
-    { "rsqrtps", Op_DstSrcSSE },
-    { "rsqrtss", Op_DstSrcSSE },
-    { "sahf",   Op_Flags },
-    { "sal",    Op_Shift },
-    { "sar",    Op_Shift },
-    { "sbb",    Op_UpdSrcF },
-    { "scas",   Op_scas },
-    { "scasb",  Op_scasX },
-    { "scasd",  Op_scasX },
-    { "scasw",  Op_scasX },
-    { "seta",   Op_DstRMBNT }, // also gpr8
-    { "setae",  Op_DstRMBNT },
-    { "setb",   Op_DstRMBNT },
-    { "setbe",  Op_DstRMBNT },
-    { "setc",   Op_DstRMBNT },
-    { "sete",   Op_DstRMBNT },
-    { "setg",   Op_DstRMBNT },
-    { "setge",  Op_DstRMBNT },
-    { "setl",   Op_DstRMBNT },
-    { "setle",  Op_DstRMBNT },
-    { "setna",  Op_DstRMBNT },
-    { "setnae", Op_DstRMBNT },
-    { "setnb",  Op_DstRMBNT },
-    { "setnbe", Op_DstRMBNT },
-    { "setnc",  Op_DstRMBNT },
-    { "setne",  Op_DstRMBNT },
-    { "setng",  Op_DstRMBNT },
-    { "setnge", Op_DstRMBNT },
-    { "setnl",  Op_DstRMBNT },
-    { "setnle", Op_DstRMBNT },
-    { "setno",  Op_DstRMBNT },
-    { "setnp",  Op_DstRMBNT },
-    { "setns",  Op_DstRMBNT },
-    { "setnz",  Op_DstRMBNT },
-    { "seto",   Op_DstRMBNT },
-    { "setp",   Op_DstRMBNT },
-    { "setpe",  Op_DstRMBNT },
-    { "setpo",  Op_DstRMBNT },
-    { "sets",   Op_DstRMBNT },
-    { "setz",   Op_DstRMBNT },
-    { "sfence", Op_0 },
-    { "sgdt",   Op_DstMemNT },
-    { "shl",    Op_Shift },
-    { "shld",   Op_UpdSrcShft },
-    { "shr",    Op_Shift },
-    { "shrd",   Op_UpdSrcShft },
-    { "shufpd", Op_DstSrcImmS },
-    { "shufps", Op_DstSrcImmS },
-    { "sidt",   Op_DstMemNT },
-    { "sldt",   Op_DstRMWNT },
-    { "smsw",   Op_DstRMWNT },
-    { "sqrtpd", Op_DstSrcSSE },
-    { "sqrtps", Op_DstSrcSSE },
-    { "sqrtsd", Op_DstSrcSSE },
-    { "sqrtss", Op_DstSrcSSE },
-    { "stc",    Op_Flags },
-    { "std",    Op_Flags },
-    { "sti",    Op_Flags },
-    { "stmxcsr",Op_DstMemNT },
-    { "stos",   Op_stos },
-    { "stosb",  Op_stosX },
-    { "stosd",  Op_stosX },
-    { "stosw",  Op_stosX },
-    { "str",    Op_DstMemNT }, // also r16
-    { "sub",    Op_UpdSrcF },
-    { "subpd",  Op_DstSrcSSE },
-    { "subps",  Op_DstSrcSSE },
-    { "subsd",  Op_DstSrcSSE },
-    { "subss",  Op_DstSrcSSE },
-    { "sysenter",Op_0 },
-    { "sysexit", Op_0 },
-    { "test",    Op_SrcSrcF },
-    { "ucomisd", Op_SrcSrcSSEF },
-    { "ucomiss", Op_SrcSrcSSEF },
-    { "ud2",     Op_0 },
-    { "unpckhpd", Op_DstSrcSSE },
-    { "unpckhps", Op_DstSrcSSE },
-    { "unpcklpd", Op_DstSrcSSE },
-    { "unpcklps", Op_DstSrcSSE },
-    { "verr",   Op_SrcMemNTF },
-    { "verw",   Op_SrcMemNTF },
-    { "wait",   Op_0 },
-    { "wbinvd", Op_0 },
-    { "wrmsr",  Op_0 },
-    { "xadd",   Op_UpdUpdF },
-    { "xchg",   Op_UpdUpd },
-    { "xlat",   Op_xlat },
-    { "xlatb",  Op_0_AX },
-    { "xor",    Op_DstSrcF },
-    { "xorpd",  Op_DstSrcSSE },
-    { "xorps",  Op_DstSrcSSE },
-};
-
-typedef enum {
-    Default_Ptr = 0,
-    Byte_Ptr = 1,
-    Short_Ptr = 2,
-    Int_Ptr = 4,
-    QWord_Ptr =  8,
-    Float_Ptr = 4,
-    Double_Ptr = 8,
-    Extended_Ptr = 10,
-    Near_Ptr = 98,
-    Far_Ptr = 99,
-    N_PtrTypes
-} PtrType;
-
-static const int N_PtrNames = 8;
-static const char * ptrTypeNameTable[N_PtrNames] = {
-    "word", "dword", "qword",
-    "float", "double", "extended",
-    "near",  "far"
-};
-
-static Identifier * ptrTypeIdentTable[N_PtrNames];
-static PtrType ptrTypeValueTable[N_PtrNames] = {
-    Short_Ptr, Int_Ptr, QWord_Ptr,
-    Float_Ptr, Double_Ptr, Extended_Ptr,
-    Near_Ptr, Far_Ptr
-};
-
-typedef enum {
-    Opr_Invalid,
-    Opr_Immediate,
-    Opr_Reg,
-    Opr_Mem
-} OperandClass;
-
-/* kill inlining if we reference a local? */
-
-/* DMD seems to allow only one 'symbol' per operand .. include __LOCAL_SIZE */
-
-/* DMD offset usage: <parm>[<reg>] seems to always be relative to EBP+8 .. even
-   if naked.. */
-
-// mov eax, 4
-// mov eax, fs:4
-// -- have to assume we know wheter or not to use '$'
-
-static Token eof_tok;
-static Expression * Handled;
-static Identifier * ident_seg;
-
-struct AsmProcessor
-{
-    typedef struct {
-	int inBracket;
-	int hasBracket;
-	int hasNumber;
-	int isOffset;
-
-	Reg segmentPrefix;
-	Reg reg;
-	sinteger_t constDisplacement; // use to build up.. should be int constant in the end..
-	Array      symbolDisplacement; // array of expressions or..
-	Reg baseReg;
-	Reg indexReg;
-	int scale;
-	
-	OperandClass cls;
-	PtrType dataSize;
-	PtrType dataSizeHint; // DMD can use the type of a referenced variable
-    } Operand;
-
-    static const unsigned Max_Operands = 3;
-
-    AsmStatement * stmt;
-    Scope * sc;
-
-    Token * token;
-    OutBuffer * insnTemplate;
-
-    AsmOp       op;
-    AsmOpInfo * opInfo;
-    Operand operands[Max_Operands];
-    Identifier * opIdent;
-    Operand * operand;
-
-    AsmProcessor(Scope * sc, AsmStatement * stmt)
-    {
-	this->sc = sc;
-	this->stmt = stmt;
-	token = stmt->tokens;
-	insnTemplate = new OutBuffer;
-
-	opInfo = NULL;
-
-	if ( ! regInfo[0].ident ) {
-	    char buf[8], *p;
-	    
-	    for (int i = 0; i < N_Regs; i++) {
-		strncpy(buf, regInfo[i].name, sizeof(buf) - 1);
-		for (p = buf; *p; p++)
-		    *p = std::tolower(*p);
-		regInfo[i].gccName = std::string(buf, p - buf);
-		if ( (i <= Reg_ST || i > Reg_ST7) && i != Reg_EFLAGS )
-		    regInfo[i].ident = Lexer::idPool(regInfo[i].name);
-	    }
-
-	    for (int i = 0; i < N_PtrNames; i++)
-		ptrTypeIdentTable[i] = Lexer::idPool(ptrTypeNameTable[i]);
-
-	    Handled = new Expression(0, TOKvoid, sizeof(Expression));
-
-	    ident_seg = Lexer::idPool("seg");
-	
-	    eof_tok.value = TOKeof; 
-	    eof_tok.next = 0;
-	}
-    }
-
-    void run()
-    {
-	parse();
-    }
-
-    void nextToken() {
-	if (token->next)
-	    token = token->next;
-	else
-	    token = & eof_tok;
-    }
-
-    Token * peekToken() {
-	if (token->next)
-	    return token->next;
-	else
-	    return & eof_tok;
-    }
-
-    void expectEnd() {
-	if (token->value != TOKeof)
-	    stmt->error("expected end of statement"); // %% extra at end...
-    }
-
-    void parse() {
-	op = parseOpcode();
-	
-	switch (op) {
-	case Op_Align:
-	    doAlign();
-	    expectEnd();
-	    break;
-	case Op_Even:
-	    doEven();
-	    expectEnd();
-	    break;
-	case Op_Naked:
-	    doNaked();
-	    expectEnd();
-	    break;
-	case Op_Invalid:
-	    break;
-	default:
-	    if (op >= Op_db && op <= Op_de)
-		doData();
-	    else
-		doInstruction();
-	}
-    }
-
-    AsmOp parseOpcode() {
-	static const int N_ents = sizeof(opData)/sizeof(AsmOpEnt);
-
-	switch (token->value) {
-	case TOKalign:
-	    nextToken();
-	    return Op_Align;
-	case TOKin:
-	    nextToken();
-	    opIdent = Id::___in;
-	    return Op_in;
-        case TOKint32: // "int"
-            nextToken();
-            opIdent = Id::__int;
-            return Op_SrcImm;
-	case TOKout:
-	    nextToken();
-	    opIdent = Id::___out;
-	    return Op_out;
-	case TOKidentifier:
-	    // search for mnemonic below
-	    break;
-	default:
-	    stmt->error("expected opcode");
-	    return Op_Invalid;
-	}
-
-	opIdent = token->ident;
-	const char * opcode = token->ident->string;
-
-	nextToken();
-
-	// %% okay to use bsearch?
-	int i = 0, j = N_ents, k, l;
-	do {
-	    k = (i + j) / 2;
-	    l = strcmp(opcode, opData[k].inMnemonic);
-	    if (! l)
-		return opData[k].asmOp;
-	    else if (l < 0)
-		j = k;
-	    else
-		i = k + 1;
-	} while (i != j);
-
-	stmt->error("unknown opcode '%s'", opcode);
-	
-	return Op_Invalid;
-    }
-
-    // need clobber information.. use information is good too...
-    void doInstruction() {
-	bool ok = true;
-	unsigned operand_i = 0;
-	
-	opInfo = & asmOpInfo[op];
-	memset(operands, 0, sizeof(operands));
-
-	while (token->value != TOKeof) {
-	    if (operand_i < Max_Operands) {
-		operand = & operands[operand_i];
-		operand->reg = operand->baseReg = operand->indexReg =
-		    operand->segmentPrefix = Reg_Invalid;
-		parseOperand();
-		operand_i++;
-	    } else {
-		ok = false;
-		stmt->error("too many operands for instruction");
-		break;
-	    }
-
-	    if (token->value == TOKcomma)
-		nextToken();
-	    else if (token->value != TOKeof) {
-		ok = false;
-		stmt->error("expected comma after operand");
-		return;
-	    }
-	}
-// 	if (operand_i < opInfo->minOperands) {
-// 	    ok = false;
-// 	    stmt->error("too few operands for instruction");
-// 	}
-
-	if ( matchOperands(operand_i) ) {
-	    AsmCode * asmcode = new AsmCode;
-
-	    if (formatInstruction(operand_i, asmcode))
-		stmt->asmcode = (code *) asmcode;
-	}
-    }
-
-    void setAsmCode() {
-	AsmCode * asmcode = new AsmCode;
-	asmcode->insnTemplateLen = insnTemplate->offset;
-	asmcode->insnTemplate = (char*) insnTemplate->extractData();
-	stmt->asmcode = (code*) asmcode;
-    }
-
-    // note: doesn't update AsmOp op
-    bool matchOperands(unsigned nOperands) {
-	bool wrong_number = true;
-
-	for (unsigned i = 0; i < nOperands; i++)
-	    classifyOperand(& operands[i]);
-	
-	while (1) {
-	    if (nOperands == opInfo->nOperands()) {
-		wrong_number = false;
-		/*  Cases in which number of operands is not
-		    enough for a match: Op_FCmp/Op_FCmp1,
-		    Op_FCmpP/Op_FCmpP1 */
-		for (unsigned i = 0; i < nOperands; i++) {
-		    Operand * operand = & operands[i];
-		    
-		    switch (opInfo->operands[i] & Opr_ClassMask) {
-		    case OprC_Mem: // no FPMem currently
-			if (operand->cls != Opr_Mem)
-			    goto no_match;
-			break;
-		    case OprC_RFP:
-			if (! (operand->reg >= Reg_ST && operand->reg <= Reg_ST7))
-			    goto no_match;
-			break;
-		    default:
-			break;
-		    }
-		}
-
-		return true;
-	    }
-	    no_match:
-	    if (opInfo->linkType == Next_Form)
-		opInfo = & asmOpInfo[ op = (AsmOp) opInfo->link ];
-	    else
-		break;
-	}
-	if (wrong_number)
-	    stmt->error("wrong number of operands");
-	else
-	    stmt->error("wrong operand types");
-	return false;
-    }
-
-    void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
-	insnTemplate->writestring((char*) fmt);
-	insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
-	asmcode->args.push( new AsmArg(type, e, mode) );
-    }
-    void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) {
-    insnTemplate->writestring((char*) fmtpre);
-    insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim);
-    insnTemplate->writestring((char*) fmtpost);
-    asmcode->args.push( new AsmArg(type, e, mode) );
-    }
-
-    void addLabel(char* id) {
-    insnTemplate->writestring(sc->func->mangle());
-    insnTemplate->writestring("_");
-    insnTemplate->writestring(id);
-    }
-
-    /* Determines whether the operand is a register, memory reference
-       or immediate.  Immediate addresses are currently classified as
-       memory.  This function is called before the exact instructions
-       is known and thus, should not use opInfo. */
-    void classifyOperand(Operand * operand) {
-	operand->cls = classifyOperand1(operand);
-    }
-    
-    OperandClass classifyOperand1(Operand * operand) {
-	bool is_localsize = false;
-	bool really_have_symbol = false;
-
-	if (operand->symbolDisplacement.dim) {
-	    is_localsize = isLocalSize( (Expression *) operand->symbolDisplacement.data[0] );
-	    really_have_symbol = ! is_localsize;
-	}
-
-	if (operand->isOffset && ! operand->hasBracket)
-	    return Opr_Immediate;
-	
-	if (operand->hasBracket || really_have_symbol) { // %% redo for 'offset' function
-	    if (operand->reg != Reg_Invalid) {
-		invalidExpression();
-		return Opr_Invalid;
-	    }
-
-	    return Opr_Mem;
-	}
-
-	if (operand->reg != Reg_Invalid && operand->constDisplacement != 0) {
-	    invalidExpression();
-	    return Opr_Invalid;
-	}
-	
-	if (operand->segmentPrefix != Reg_Invalid) {
-	    if (operand->reg != Reg_Invalid) {
-		invalidExpression();
-		return Opr_Invalid;
-	    }
-
-	    return Opr_Mem;
-	}
-
-	if (operand->reg != Reg_Invalid && ! operand->hasNumber)
-	    return Opr_Reg;
-
-	// should check immediate given (operand->hasNumber);
-	//
-	if (operand->hasNumber || is_localsize) {
-	    // size determination not correct if there are symbols Opr_Immediate
-	    if (operand->dataSize == Default_Ptr) {
-		if (operand->constDisplacement < 0x100)
-		    operand->dataSize = Byte_Ptr;
-		else if (operand->constDisplacement < 0x10000)
-		    operand->dataSize = Short_Ptr;
-		else
-		    operand->dataSize = Int_Ptr;
-	    }
-	    return Opr_Immediate;
-	}
-
-	// probably a bug,?
-	stmt->error("invalid operand");
-	return Opr_Invalid;
-    }
-
-    void writeReg(Reg reg) {
-	insnTemplate->writestring((char*) "%");
-	insnTemplate->write(regInfo[reg].gccName.c_str(), regInfo[reg].gccName.length());
-    }
-
-    bool opTakesLabel() {
-	switch(op) {
-	case Op_Branch:
-	case Op_CBranch:
-	case Op_Loop:
-	    return true;
-	default:
-	    return false;
-	}
-    }
-
-    bool getTypeChar(TypeNeeded needed, PtrType ptrtype, char & type_char)
-    {
-	switch (needed) {
-	case Byte_NoType:
-	    return ptrtype == Byte_Ptr;
-	case Word_Types:
-	    if (ptrtype == Byte_Ptr)
-		return false;
-	    // drop through
-	case Int_Types:
-	    switch (ptrtype) {
-	    case Byte_Ptr:  type_char = 'b'; break;
-	    case Short_Ptr: type_char = 'w'; break;
-	    case Int_Ptr:   type_char = 'l'; break;
-	    default:
-		// %% these may be too strict
-		return false;
-	    }
-	    break;
-	case FPInt_Types:
-	    switch (ptrtype) {
-	    case Short_Ptr: type_char = 0;   break;
-	    case Int_Ptr:   type_char = 'l'; break;
-	    case QWord_Ptr: type_char = 'q'; break;
-	    default:
-		return false;
-	    }
-	    break;
-	case FP_Types:
-	    switch (ptrtype) {
-	    case Float_Ptr:    type_char = 's'; break;
-	    case Double_Ptr:   type_char = 'l'; break;
-	    case Extended_Ptr: type_char = 't'; break;
-	    default:
-		return false;
-	    }
-	    break;
-	default:
-	    return false;
-	}
-	return true;
-    }
-
-    // also set impl clobbers
-    bool formatInstruction(int nOperands, AsmCode * asmcode) {
-	const char *fmt;
-	const char *mnemonic;
-	char type_char = 0;
-	bool use_star;
-	AsmArgMode mode;
-
-	insnTemplate = new OutBuffer;
-	// %% todo: special case for something..
-	if (opInfo->linkType == Out_Mnemonic)
-	    mnemonic = alternateMnemonics[opInfo->link];
-	else
-	    mnemonic = opIdent->string;
-
-	if (opInfo->needsType) {
-	    PtrType exact_type = Default_Ptr;
-	    PtrType min_type = Default_Ptr;
-	    PtrType hint_type = Default_Ptr;
-
-	    /* Default types: This attempts to match the observed behavior of DMD */
-	    switch (opInfo->needsType) {
-	    case Int_Types:   min_type = Byte_Ptr; break;
-	    case Word_Types:  min_type = Short_Ptr; break;
-	    case FPInt_Types:
-		if (op == Op_Fis_ST) // integer math instructions 
-		    min_type = Int_Ptr;
-		else // compare, load, store
-		    min_type = Short_Ptr;
-		break;
-	    case FP_Types:    min_type = Float_Ptr; break;
-	    }
-	    if (op == Op_push && operands[0].cls == Opr_Immediate)
-		min_type = Int_Ptr;
-	    
-	    for (int i = 0; i < nOperands; i++) {
-		if (hint_type == Default_Ptr &&
-		    ! (opInfo->operands[i] & Opr_NoType))
-		    hint_type = operands[i].dataSizeHint;
-		    
-		if ((opInfo->operands[i] & Opr_NoType) ||
-		    operands[i].dataSize == Default_Ptr)
-		    continue;
-		if (operands[i].cls == Opr_Immediate) {
-		    min_type = operands[i].dataSize > min_type ?
-			operands[i].dataSize : min_type;
-		} else {
-		    exact_type = operands[i].dataSize; // could check for conflicting types
-		    break;
-		}
-	    }
-
-	    bool type_ok;
-	    if (exact_type == Default_Ptr) {
-		type_ok = getTypeChar((TypeNeeded) opInfo->needsType, hint_type, type_char);
-		if (! type_ok)
-		    type_ok = getTypeChar((TypeNeeded) opInfo->needsType, min_type, type_char);
-	    } else
-		type_ok = getTypeChar((TypeNeeded) opInfo->needsType, exact_type, type_char);
-
-	    if (! type_ok) {
-		stmt->error("invalid operand size");
-		return false;
-	    }
-	} else if (op == Op_Branch) {
-	    if (operands[0].dataSize == Far_Ptr) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that..
-		insnTemplate->writebyte('l');
-	} else if (op == Op_fxch) {
-	    // gas won't accept the two-operand form
-	    if (operands[1].cls == Opr_Reg && operands[1].reg == Reg_ST) {
-		nOperands = 1;
-	    } else {
-		stmt->error("invalid operands");
-		return false;
-	    }
-	}
-	
-	switch (op) {
-	case Op_SizedStack:
-	    {
-		int mlen = strlen(mnemonic);
-		if (mnemonic[mlen-1] == 'd')
-		    insnTemplate->write(mnemonic, mlen-1);
-		else {
-		    insnTemplate->writestring((char*) mnemonic);
-		    insnTemplate->writebyte('w');
-		}
-	    }
-	    break;
-	case Op_cmpsd:
-	case Op_insX:
-	case Op_lodsX:
-	case Op_movsd:
-	case Op_outsX:
-	case Op_scasX:
-	case Op_stosX:
-	    {
-		int mlen = strlen(mnemonic);
-		if (mnemonic[mlen-1] == 'd') {
-		    insnTemplate->write(mnemonic, mlen-1);
-		    insnTemplate->writebyte('l');
-		} else {
-		    insnTemplate->writestring((char*) mnemonic);
-		}
-	    }
-	    break;
-	case Op_movsx:
-	case Op_movzx:
-	    {
-		char tc_1;
-		int mlen = strlen(mnemonic);
-		PtrType op1_size = operands[1].dataSize;
-		if (op1_size == Default_Ptr)
-		    op1_size = operands[1].dataSizeHint;
-		// Need type char for source arg
-		switch (op1_size) {
-		case Byte_Ptr: 
-		case Default_Ptr:
-		    tc_1 = 'b';
-		    break;
-		case Short_Ptr:
-		    tc_1 = 'w';
-		    break;
-		default:
-		    stmt->error("invalid operand size/type");
-		    return false;
-		}
-		assert(type_char != 0);
-		insnTemplate->write(mnemonic, mlen-1);
-		insnTemplate->writebyte(tc_1);
-		insnTemplate->writebyte(type_char);
-	    }
-	    break;
-	default:
-	    insnTemplate->writestring((char*) mnemonic);
-	    if (type_char)
-		insnTemplate->writebyte(type_char);
-	    break;
-	}
-
-	switch (opInfo->implicitClobbers & Clb_DXAX_Mask) {
-	case Clb_SizeAX:
-	case Clb_EAX:
-	    stmt->regs |= (1<<Reg_EAX);
-	    break;
-	case Clb_SizeDXAX:
-	    stmt->regs |= (1<<Reg_EAX);
-	    if (type_char != 'b')
-		stmt->regs |= (1<<Reg_EDX);
-	    break;
-	default:
-	    // nothing
-	    break;
-	}
-
-	if (opInfo->implicitClobbers & Clb_DI)
-	    stmt->regs |= (1 << Reg_EDI);
-	if (opInfo->implicitClobbers & Clb_SI)
-	    stmt->regs |= (1 << Reg_ESI);
-	if (opInfo->implicitClobbers & Clb_CX)
-	    stmt->regs |= (1 << Reg_ECX);
-	if (opInfo->implicitClobbers & Clb_SP)
-	    stmt->regs |= (1 << Reg_ESP);
-	if (opInfo->implicitClobbers & Clb_ST)
-	{
-	    /* Can't figure out how to tell GCC that an
-	       asm statement leaves an arg pushed on the stack.
-	       Maybe if the statment had and input or output
-	       operand it would work...  In any case, clobbering
-	       all FP prevents incorrect code generation. */
-	    stmt->regs |= (1 << Reg_ST);
-	    stmt->regs |= (1 << Reg_ST1);
-	    stmt->regs |= (1 << Reg_ST2);
-	    stmt->regs |= (1 << Reg_ST3);
-	    stmt->regs |= (1 << Reg_ST4);
-	    stmt->regs |= (1 << Reg_ST5);
-	    stmt->regs |= (1 << Reg_ST6);
-	    stmt->regs |= (1 << Reg_ST7);
-	}
-	if (opInfo->implicitClobbers & Clb_Flags)
-	    asmcode->moreRegs |= (1 << (Reg_EFLAGS - 32));
-	if (op == Op_cpuid)
-	    stmt->regs |= (1 << Reg_EAX)|
-		(1 << Reg_ECX)|(1 << Reg_EDX);
-
-	insnTemplate->writebyte(' ');
-	for (int i__ = 0; i__ < nOperands; i__++) {
-	    int i;
-	    if (i__ != 0)
-		insnTemplate->writestring((char*) ", ");
-
-	    fmt = "$";
-    
-	    switch (op) {
-	    case Op_mul:
-		// gas won't accept the two-operand form; skip to the source operand
-		i__ = 1;
-		// drop through
-	    case Op_bound:
-	    case Op_enter:
-		i = i__;
-		break;
-	    default:
-		i = nOperands - 1 - i__; // operand = & operands[ nOperands - 1 - i ];
-		break;
-	    }
-	    operand = & operands[ i ];
-
-	    switch (operand->cls) {
-	    case Opr_Immediate:
-		// for implementing offset:
-		// $var + $7 // fails
-		// $var + 7  // ok
-		// $7 + $var // ok
-
-		// DMD doesn't seem to allow this
-		/*
-		if (opInfo->takesLabel())  tho... (near ptr <Number> would be abs?)
-		    fmt = "$a"; // GAS won't accept "jmp $42"; must be "jmp 42" (rel) or "jmp *42" (abs)
-		*/
-		if (opTakesLabel()/*opInfo->takesLabel()*/) {
-		    // "relative addressing not allowed in branch instructions" ..
-		    stmt->error("integer constant not allowed in branch instructions");
-		    return false;
-		}
-
-		if (operand->symbolDisplacement.dim &&
-		    isLocalSize( (Expression *) operand->symbolDisplacement.data[0] )) {
-		    // handle __LOCAL_SIZE, which in this constant, is an immediate
-		    // should do this in slotexp..
-		    addOperand("$", Arg_LocalSize,
-			(Expression *) operand->symbolDisplacement.data[0], asmcode);
-		    if (operand->constDisplacement)
-			insnTemplate->writebyte('+');
-		    else
-			break;
-		}
-
-		if (operand->symbolDisplacement.dim) {
-		    fmt = "$a";
-		    addOperand("$", Arg_Pointer,
-			(Expression *) operand->symbolDisplacement.data[0],
-			asmcode);
-
-		    if (operand->constDisplacement)
-			insnTemplate->writebyte('+');
-		    else
-			// skip the addOperand(fmt, Arg_Integer...) below
-			break;
-		}
-		addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
-		break;
-	    case Opr_Reg:
-		if (opInfo->operands[i] & Opr_Dest) {
-		    Reg clbr_reg = (Reg) regInfo[operand->reg].baseReg;
-		    if (clbr_reg != Reg_Invalid) {
-			if (clbr_reg < 32)
-			    stmt->regs |= (1 << clbr_reg);
-			else
-			    asmcode->moreRegs |= (1 << (clbr_reg - 32));
-		    }
-		}
-		if (opTakesLabel()/*opInfo->takesLabel()*/)
-		    insnTemplate->writebyte('*');
-		writeReg(operand->reg);
-		/*
-		insnTemplate->writestring("%");
-		insnTemplate->writestring(regInfo[operand->reg].name);
-		*/
-		break;
-	    case Opr_Mem:
-		// better: use output operands for simple variable references
-		if ( (opInfo->operands[i] & Opr_Update) == Opr_Update) {
-		    mode = Mode_Update;
-		} else if (opInfo->operands[i] & Opr_Dest) {
-		    mode = Mode_Output;
-		} else {
-		    mode = Mode_Input;
-		}
-		
-		use_star = opTakesLabel();//opInfo->takesLabel();
-		if (operand->segmentPrefix != Reg_Invalid) {
-		    writeReg(operand->segmentPrefix);
-		    insnTemplate->writebyte(':');
-		}
-		if (operand->symbolDisplacement.dim) {
-		    Expression * e = (Expression *) operand->symbolDisplacement.data[0];
-		    Declaration * decl = 0;
-
-		    if (e->op == TOKvar)
-			decl = ((VarExp *) e)->var;
-
-		    if (operand->baseReg != Reg_Invalid &&
-			decl && ! decl->isDataseg()) {
-
-			// Use the offset from frame pointer
-
-			/* GCC doesn't give the front end access to stack offsets
-			   when optimization is turned on (3.x) or at all (4.x).
-			   
-			   Try to convert var[EBP] (or var[ESP] for naked funcs) to
-			   a memory expression that does not require us to know
-			   the stack offset.
-			*/
-
-			if (operand->indexReg == Reg_Invalid &&
-			    decl->isVarDeclaration() &&
-			    ((operand->baseReg == Reg_EBP && ! sc->func->naked ) ||
-				(operand->baseReg == Reg_ESP && sc->func->naked)) ) {
-
-                if (mode == Mode_Output)
-                {
-                    e = new AddrExp(0, e);
-                    e->type = decl->type->pointerTo();
-                }
-
-#if !IN_LLVM
-			    /* DMD uses the same frame offsets for naked functions. */
-			    if (sc->func->naked)
-				operand->constDisplacement += 4;
-
-			    if (operand->constDisplacement) {
-				e = new AddExp(0, e,
-				    new IntegerExp(0, operand->constDisplacement,
-					Type::tint32));
-				e->type = decl->type->pointerTo();
-			    }
-			    e = new PtrExp(0, e);
-			    e->type = decl->type;
-#endif
-			    operand->constDisplacement = 0;
-			    operand->baseReg = Reg_Invalid;
-
-			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
-			    
-			} else {
-			    addOperand2("${",":a}", Arg_FrameRelative, e, asmcode);
-			}
-			if (opInfo->operands[i] & Opr_Dest)
-			    asmcode->clobbersMemory = 1;
-		    } else  {
-			// Plain memory reference to variable
-			
-			/* If in a reg, DMD moves to memory.. even with -O, so we'll do the same
-			   by always using the "m" contraint.
-
-			   In order to get the correct output for function and label symbols,
-			   the %an format must be used with the "p" constraint.
-			*/
-			if (isDollar(e)) {
-			    error("dollar labels are not supported", stmt->loc.toChars());
-			    asmcode->dollarLabel = 1;
-			} else if (e->op == TOKdsymbol) {
-			    LabelDsymbol * lbl = (LabelDsymbol *) ((DsymbolExp *) e)->s;
-			    stmt->isBranchToLabel = lbl->ident;
-
-			    use_star = false;
-			    addLabel(lbl->ident->toChars());
-			} else if ((decl && decl->isCodeseg())) { // if function or label
-			    use_star = false;
-			    addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
-			} else {
-			    if (use_star) {
-				insnTemplate->writebyte('*');
-				use_star = false;
-			    }
-                Type* tt = e->type->pointerTo();
-			    e = new AddrExp(0, e);
-			    e->type = tt;
-
-			    addOperand(fmt, Arg_Memory, e, asmcode, mode);
-			}
-		    }
-		}
-		if (use_star)
-		    insnTemplate->writebyte('*');
-		if (operand->constDisplacement) {
-		    if (operand->symbolDisplacement.dim)
-			insnTemplate->writebyte('+');
-		    //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
-		    insnTemplate->printf("%d", operand->constDisplacement);
-		    if (opInfo->operands[i] & Opr_Dest)
-			asmcode->clobbersMemory = 1;
-		}
-		if (operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid) {
-		    insnTemplate->writebyte('(');
-		    if (operand->baseReg != Reg_Invalid)
-			writeReg(operand->baseReg);
-		    if (operand->indexReg != Reg_Invalid) {
-			insnTemplate->writebyte(',');
-			writeReg(operand->indexReg);
-			if (operand->scale) {
-			    insnTemplate->printf(",%d", operand->scale);
-			}
-		    }
-		    insnTemplate->writebyte(')');
-		    if (opInfo->operands[i] & Opr_Dest)
-			asmcode->clobbersMemory = 1;
-		}
-		break;
-	    case Opr_Invalid:
-		return false;
-	    }
-	}
-
-	asmcode->insnTemplateLen = insnTemplate->offset;
-	asmcode->insnTemplate = (char*) insnTemplate->extractData();
-	return true;
-    }
-
-    bool isIntExp(Expression * exp) {
-	if (exp->op == TOKint64)
-	    return 1;
-	if (exp->op == TOKvar) {
-	    Declaration * v = ((VarExp *) exp)->var;
-	    if (v->isConst() && v->type->isintegral())
-		return 1;
-	}
-	return 0;
-    }
-    bool isRegExp(Expression * exp) { return exp->op == TOKmod; } // ewww.%%
-    bool isLocalSize(Expression * exp) {
-	// cleanup: make a static var
-	return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__LOCAL_SIZE;
-    }
-    bool isDollar(Expression * exp) {
-	return exp->op == TOKidentifier && ((IdentifierExp *) exp)->ident == Id::__dollar;
-    }
-
-    Expression * newRegExp(int regno) {
-	IntegerExp * e = new IntegerExp(regno);
-	e->op = TOKmod;
-	return e;
-    }
-
-    Expression * newIntExp(int v /* %% type */) {
-	// Only handles 32-bit numbers as this is IA-32.
-	return new IntegerExp(stmt->loc, v, Type::tint32);
-    }
-
-    void slotExp(Expression * exp) {
-	/*
-	  if offset, make a note
-	
-	  if integer, add to immediate
-	  if reg:
-	      if not in bracket, set reg (else error)
-	      if in bracket:
-		 if not base, set base
-		 if not index, set index
-		 else, error
-	  if symbol:
-	    set symbol field
-	 */
-
-	bool is_offset = false;
-	if (exp->op == TOKaddress) {
-	    exp = ((AddrExp *) exp)->e1;
-	    is_offset = true;
-	}
-	
-	if (isIntExp(exp)) {
-	    if (is_offset)
-		invalidExpression();
-	    operand->constDisplacement += exp->toInteger();
-	    if (! operand->inBracket)
-		operand->hasNumber = 1;
-	} else if (isRegExp(exp)) {
-	    if (is_offset)
-		invalidExpression();
-	    if (! operand->inBracket) {
-		if (operand->reg == Reg_Invalid)
-		    operand->reg = (Reg) exp->toInteger();
-		else
-		    stmt->error("too many registers in operand (use brackets)");
-	    } else {
-		if (operand->baseReg == Reg_Invalid)
-		    operand->baseReg = (Reg) exp->toInteger();
-		else if (operand->indexReg == Reg_Invalid) {
-		    operand->indexReg = (Reg) exp->toInteger();
-		    operand->scale = 1;
-		} else {
-		    stmt->error("too many registers memory operand");
-		}
-	    }
-	} else if (exp->op == TOKvar) {
-	    VarDeclaration * v = ((VarExp *) exp)->var->isVarDeclaration();
-
-	    if (v && v->storage_class & STCfield) {
-		operand->constDisplacement += v->offset;
-		if (! operand->inBracket)
-		    operand->hasNumber = 1;
-	    } else {
-		if (v && v->type->isscalar())
-		{
-		    // DMD doesn't check Tcomplex*, and counts Tcomplex32 as Tfloat64
-		    TY ty = v->type->toBasetype()->ty;
-		    operand->dataSizeHint = ty == Tfloat80 || ty == Timaginary80 ?
-			Extended_Ptr : (PtrType) v->type->size(0);
-		}
-		
-		if (! operand->symbolDisplacement.dim) {
-		    if (is_offset && ! operand->inBracket)
-			operand->isOffset = 1;
-		    operand->symbolDisplacement.push( exp );
-		} else {
-		    stmt->error("too many symbols in operand");
-		}
-	    }
-	} else if (exp->op == TOKidentifier || exp->op == TOKdsymbol) {
-	    // %% localsize could be treated as a simple constant..
-	    // change to addSymbolDisp(e)
-	    if (! operand->symbolDisplacement.dim) {
-		operand->symbolDisplacement.push( exp );
-	    } else {
-		stmt->error("too many symbols in operand");
-	    }
-	} else if (exp == Handled) {
-	    // nothing
-	} else {
-	    stmt->error("invalid operand");
-	}
-    }
-
-    void invalidExpression() {
-	// %% report operand number
-	stmt->error("invalid expression");
-    }
-
-    Expression * intOp(TOK op, Expression * e1, Expression * e2) {
-	Expression * e;
-	if (isIntExp(e1) && (! e2 || isIntExp(e2))) {
-	    switch (op) {
-	    case TOKadd:
-		if (e2)
-		    e = new AddExp(stmt->loc, e1, e2);
-		else
-		    e = e1;
-		break;
-	    case TOKmin:
-		if (e2)
-		    e = new MinExp(stmt->loc, e1, e2);
-		else
-		    e = new NegExp(stmt->loc, e1);
-		break;
-	    case TOKmul:
-		e = new MulExp(stmt->loc, e1, e2);
-		break;
-	    case TOKdiv:
-		e = new DivExp(stmt->loc, e1, e2);
-		break;
-	    case TOKmod:
-		e = new ModExp(stmt->loc, e1, e2);
-		break;
-	    case TOKshl:
-		e = new ShlExp(stmt->loc, e1, e2);
-		break;
-	    case TOKshr:
-		e = new ShrExp(stmt->loc, e1, e2);
-		break;
-	    case TOKushr:
-		e = new UshrExp(stmt->loc, e1, e2);
-		break;
-	    case TOKnot:
-		e = new NotExp(stmt->loc, e1);
-		break;
-	    case TOKtilde:
-		e = new ComExp(stmt->loc, e1);
-		break;
-	    default:
-		assert(0);
-	    }
-	    e = e->semantic(sc);
-	    return e->optimize(WANTvalue | WANTinterpret);
-	} else {
-	    stmt->error("expected integer operand(s) for '%s'", Token::tochars[op]);
-	    return newIntExp(0);
-	}
-    }
-
-    void parseOperand() {
-	Expression * exp = parseAsmExp();
-	slotExp(exp);
-	if (isRegExp(exp))
-	    operand->dataSize = (PtrType) regInfo[exp->toInteger()].size;
-    }
-
-    Expression * parseAsmExp() {
-	return parseShiftExp();
-    }
-
-    Expression * parseShiftExp() {
-	Expression * e1 = parseAddExp();
-	Expression * e2;
-
-	while (1) {
-	    TOK tv = token->value;
-	    switch (tv) {
-	    case TOKshl:
-	    case TOKshr:
-	    case TOKushr:
-		nextToken();
-		e2 = parseAddExp();
-		e1 = intOp(tv, e1, e2);
-		continue;
-	    default:
-		break;
-	    }
-	    break;
-	}
-	return e1;
-    }
-
-    Expression * parseAddExp() {
-	Expression * e1 = parseMultExp();
-	Expression * e2;
-
-	while (1) {
-	    TOK tv = token->value;
-	    switch (tv) {
-	    case TOKadd:
-		nextToken();
-		e2 = parseMultExp();
-		if (isIntExp(e1) && isIntExp(e2))
-		    e1 = intOp(tv, e1, e2);
-		else {
-		    slotExp(e1);
-		    slotExp(e2);
-		    e1 = Handled;
-		}
-		continue;
-	    case TOKmin:
-		// Note: no support for symbol address difference
-		nextToken();
-		e2 = parseMultExp();
-		if (isIntExp(e1) && isIntExp(e2))
-		    e1 = intOp(tv, e1, e2);
-		else {
-		    slotExp(e1);
-		    e2 = intOp(TOKmin, e2, NULL); // verifies e2 is an int
-		    slotExp(e2);
-		    e1 = Handled;
-		}
-		continue;
-	    default:
-		break;
-	    }
-	    break;
-	}
-	return e1;
-    }
-
-    bool tryScale(Expression * e1, Expression * e2) {
-	Expression * et;
-	if (isIntExp(e1) && isRegExp(e2)) {
-	    et = e1;
-	    e1 = e2;
-	    e2 = et;
-	    goto do_scale;
-	} else if (isRegExp(e1) && isIntExp(e2)) {
-	do_scale:
-	    if (! operand->inBracket) {
-		invalidExpression(); // maybe should allow, e.g. DS:EBX+EAX*4
-	    }
-	    
-	    if (operand->scale || operand->indexReg != Reg_Invalid) {
-		invalidExpression();
-		return true;
-	    }
-
-	    operand->indexReg = (Reg) e1->toInteger();
-	    operand->scale = e2->toInteger();
-	    switch (operand->scale) {
-	    case 1:
-	    case 2:
-	    case 4:
-	    case 8:
-		// ok; do nothing
-		break;
-	    default:
-		stmt->error("invalid index register scale '%d'", operand->scale);
-		return true;
-	    }
-	    
-	    return true;
-	}
-	return false;
-    }
-
-    Expression * parseMultExp() {
-	Expression * e1 = parseBrExp();
-	Expression * e2;
-
-	while (1) {
-	    TOK tv = token->value;
-	    switch (tv) {
-	    case TOKmul:
-		nextToken();
-		e2 = parseMultExp();
-		if (isIntExp(e1) && isIntExp(e2))
-		    e1 = intOp(tv, e1, e2);
-		else if (tryScale(e1,e2))
-		    e1 = Handled;
-		else
-		    invalidExpression();
-		continue;
-	    case TOKdiv:
-	    case TOKmod:
-		nextToken();
-		e2 = parseMultExp();
-		e1 = intOp(tv, e1, e2);
-		continue;
-	    default:
-		break;
-	    }
-	    break;
-	}
-	return e1;
-    }
-
-    Expression * parseBrExp() {
-	// %% check (why is bracket lower precends..)
-	// 3+4[eax] -> 3 + (4 [EAX]) ..
-	
-	// only one bracked allowed, so this doesn't quite handle
-	// the spec'd syntax
-	Expression * e;
-	
-	if (token->value == TOKlbracket)
-	    e = Handled;
-	else
-	    e = parseUnaExp();
-
-	// DMD allows multiple bracket expressions.
-	while (token->value == TOKlbracket) {
-	    nextToken();
-	    
-	    operand->inBracket = operand->hasBracket = 1;
-	    slotExp(parseAsmExp());
-	    operand->inBracket = 0;
-
-	    if (token->value == TOKrbracket)
-		nextToken();
-	    else
-		stmt->error("missing ']'");
-	}
-
-	return e;
-    }
-
-    PtrType isPtrType(Token * tok) {
-	switch (tok->value) {
-	case TOKint8: return Byte_Ptr;
-	case TOKint16: return Short_Ptr;
-	case TOKint32: return Int_Ptr;
-	    // 'long ptr' isn't accepted?
-	case TOKfloat32: return Float_Ptr;
-	case TOKfloat64: return Double_Ptr;
-	case TOKfloat80: return Extended_Ptr;
-	case TOKidentifier:
-	    for (int i = 0; i < N_PtrNames; i++)
-		if (tok->ident == ptrTypeIdentTable[i])
-		    return ptrTypeValueTable[i];
-	    break;
-	default:
-	    break;
-	}
-	return Default_Ptr;
-    }
-
-    Expression * parseUnaExp() {
-	Expression * e = NULL;
-	PtrType ptr_type;
-	
-	// First, check for type prefix.
-	if (token->value != TOKeof &&
-	    peekToken()->value == TOKidentifier &&
-	    peekToken()->ident == Id::ptr) {
-
-	    ptr_type = isPtrType(token);
-	    if (ptr_type != Default_Ptr) {
-		if (operand->dataSize == Default_Ptr)
-		    operand->dataSize = ptr_type;
-		else
-		    stmt->error("multiple specifications of operand size");
-	    } else
-		stmt->error("unknown operand size '%s'", token->toChars());
-	    nextToken();
-	    nextToken();
-	    return parseAsmExp();
-	}
-
-	TOK tv = token->value;
-	switch (tv) {
-	case TOKidentifier:
-	    if (token->ident == ident_seg) {
-		nextToken();
-		stmt->error("'seg' not supported");
-		e = parseAsmExp();
-	    } else if (token->ident == Id::offset ||
-		       token->ident == Id::offsetof) {
-		if (token->ident == Id::offset && ! global.params.useDeprecated)
-		    stmt->error("offset deprecated, use offsetof");
-		nextToken();
-		e = parseAsmExp();
-		e = new AddrExp(stmt->loc, e);
-	    } else {
-		// primary exp
-		break;
-	    }
-	    return e;
-	case TOKadd:
-	case TOKmin:
-	case TOKnot:
-	case TOKtilde:
-	    nextToken();
-	    e = parseUnaExp();
-	    return intOp(tv, e, NULL);
-	default:
-	    // primary exp
-	    break;
-	}
-	return parsePrimaryExp();
-    }
-
-    Expression * parsePrimaryExp() {
-	Expression * e;
-	Identifier * ident = NULL;
-	
-	switch (token->value) {
-	case TOKint32v:
-	case TOKuns32v:
-	case TOKint64v:
-	case TOKuns64v:
-	    // semantic here?
-	    // %% for tok64 really should use 64bit type
-	    e = new IntegerExp(stmt->loc, token->uns64value, Type::tint32);
-	    nextToken();
-	    break;
-	case TOKfloat32v:
-	case TOKfloat64v:
-	case TOKfloat80v:
-	    // %% need different types?
-        e = new RealExp(stmt->loc, token->float80value, Type::tfloat80);
-	    nextToken();
-	    break;
-	case TOKidentifier:
-	    {
-		ident = token->ident;
-		nextToken();
-		
-		if (ident == Id::__LOCAL_SIZE) {
-		    return new IdentifierExp(stmt->loc, ident);
-		} else if (ident == Id::__dollar) {
-		do_dollar:
-		    return new IdentifierExp(stmt->loc, ident);
-		} else {
-		    e = new IdentifierExp(stmt->loc, ident);
-		}
-
-		// If this is more than one component ref, it gets complicated: *(&Field + n)
-		// maybe just do one step at a time..
-		// simple case is Type.f -> VarDecl(field)
-		// actually, DMD only supports on level...
-		// X.y+Y.z[EBX] is supported, tho..
-		// %% doesn't handle properties (check%%)
-		while (token->value == TOKdot) {
-		    nextToken();
-		    if (token->value == TOKidentifier) {
-			e = new DotIdExp(stmt->loc, e, token->ident);
-			nextToken();
-		    } else {
-			stmt->error("expected identifier");
-			return Handled;
-		    }
-		}
-
-		// check for reg first then dotexp is an error?
-		if (e->op == TOKidentifier) {
-		    for (int i = 0; i < N_Regs; i++) {
-			if (ident == regInfo[i].ident) {
-			    if ( (Reg) i == Reg_ST && token->value == TOKlparen) {
-				nextToken();
-				switch (token->value) {
-				case TOKint32v: case TOKuns32v:
-				case TOKint64v: case TOKuns64v:
-				    if (token->uns64value < 8)
-					e = newRegExp( (Reg) (Reg_ST + token->uns64value) );
-				    else {
-					stmt->error("invalid floating point register index");
-					e = Handled;
-				    }
-				    nextToken();
-				    if (token->value == TOKrparen)
-					nextToken();
-				    else
-					stmt->error("expected ')'");
-				    return e;
-				default:
-				    break;
-				}
-				invalidExpression();
-				return Handled;
-			    } else if (token->value == TOKcolon) {
-				nextToken();
-				if (operand->segmentPrefix != Reg_Invalid)
-				    stmt->error("too many segment prefixes");
-				else if (i >= Reg_CS && i <= Reg_GS)
-				    operand->segmentPrefix = (Reg) i;
-				else
-				    stmt->error("'%s' is not a segment register", ident->string);
-				return parseAsmExp();
-			    } else {
-				return newRegExp( (Reg) i );
-			    }
-			}
-		    }
-		}
-		
-		if (opTakesLabel()/*opInfo->takesLabel()*/ && e->op == TOKidentifier) {
-		    // DMD uses labels secondarily to other symbols, so check
-		    // if IdentifierExp::semantic won't find anything.
-		    Dsymbol *scopesym;
-		    
-		    if ( ! sc->search(stmt->loc, ident, & scopesym) )		    
-			return new DsymbolExp(stmt->loc,
-			    sc->func->searchLabel( ident ));
-		}
-
-		e = e->semantic(sc);
-
-		// Special case for floating point constant declarations.
-		if (e->op == TOKfloat64) {
-		    Dsymbol * sym = sc->search(stmt->loc, ident, NULL);
-		    if ( sym ) {
-			VarDeclaration *v = sym->isVarDeclaration();
-			if ( v ) {
-			    Expression *ve = new VarExp(stmt->loc, v);
-			    ve->type = e->type;
-			    e = ve;
-			}
-		    }			    
-		}
-		return e;
-	    }
-	    break;
-	case TOKdollar:
-	    nextToken();
-	    ident = Id::__dollar;
-	    goto do_dollar;
-	    break;
-	default:
-	    invalidExpression();
-	    return Handled;
-	}
-	return e;
-    }
-
-    void doAlign() {
-	// .align bits vs. bytes...
-	// apparently a.out platforms use bits instead of bytes...
-
-	// parse primary: DMD allows 'MyAlign' (const int) but not '2+2'
-	// GAS is padding with NOPs last time I checked.
-	Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret);
-	integer_t align = e->toInteger();
-
-	if (align >= 0) {
-	    // %% is this printf portable?
-#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 
-	    insnTemplate->printf(".balign\t%u", (unsigned) align);
-#else
-	    insnTemplate->printf(".align\t%u", (unsigned) align);
-#endif
-	} else {
-	    stmt->error("alignment must be a power of 2");
-	}
-
-	setAsmCode();
-    }
-
-    void doEven() {
-	// .align for GAS is in bits, others probably use bytes..
-#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 
-	insnTemplate->writestring((char *) ".align\t2");
-#else
-	insnTemplate->writestring((char *) ".align\t2");
-#endif
-	setAsmCode();
-    }
-
-    void doNaked() {
-	// %% can we assume sc->func != 0?
-	sc->func->naked = 1;
-    }
-
-    void doData() {
-	static const char * directives[] = { ".byte", ".short", ".long", ".long",
-					     "", "", "" };
-// FIXME
-/*
-	machine_mode mode;
-
-	insnTemplate->writestring((char*) directives[op - Op_db]);
-	insnTemplate->writebyte(' ');
-
-	do {
-	    // DMD is pretty strict here, not even constant expressions are allowed..
-	    switch (op) {
-	    case Op_db:
-	    case Op_ds:
-	    case Op_di:
-	    case Op_dl:
-		if (token->value == TOKint32v || token->value == TOKuns32v ||
-		    token->value == TOKint64v || token->value == TOKuns64v) {
-		    // As per usual with GNU, assume at least 32-bit host
-		    if (op != Op_dl)
-			insnTemplate->printf("%u", (d_uns32) token->uns64value);
-		    else {
-			// Output two .longS.  GAS has .quad, but would have to rely on 'L' format ..
-			// just need to use HOST_WIDE_INT_PRINT_DEC
-			insnTemplate->printf("%u,%u",
-			    (d_uns32) token->uns64value, (d_uns32) (token->uns64value >> 32));
-		    }
-		} else {
-		    stmt->error("expected integer constant");
-		}
-		break;
-	    case Op_df:
-		mode = SFmode;
-		goto do_float;
-	    case Op_dd:
-		mode = DFmode;
-		goto do_float;
-	    case Op_de:
-#ifndef TARGET_80387
-#define XFmode TFmode
-#endif
-		mode = XFmode; // not TFmode
-		// drop through
-	    do_float:
-		if (token->value == TOKfloat32v || token->value == TOKfloat64v ||
-		    token->value == TOKfloat80v) {
-		    long words[3];
-		    real_to_target(words, & token->float80value.rv(), mode);
-		    // don't use directives..., just use .long like GCC
-		    insnTemplate->printf(".long\t%u", words[0]);
-		    if (mode != SFmode)
-			insnTemplate->printf(",%u", words[1]);
-		    // DMD outputs 10 bytes, so we need to switch to .short here
-		    if (mode == XFmode)
-			insnTemplate->printf("\n\t.short\t%u", words[2]);
-		} else {
-		    stmt->error("expected float constant");
-		}
-		break;
-	    default:
-		abort();
-	    }
-	    
-	    nextToken();	    
-	    if (token->value == TOKcomma) {
-		insnTemplate->writebyte(',');
-		nextToken();
-	    } else if (token->value == TOKeof) {
-		break;
-	    } else {
-		stmt->error("expected comma");
-	    }
-	} while (1);
-
-	setAsmCode();*/
-    }
-};
-
-#if D_GCC_VER < 40
-// struct rtx was modified for c++; this macro from rtl.h needs to
-// be modified accordingly.
-#undef XEXP
-#define XEXP(RTX, N)	(RTL_CHECK2 (RTX, N, 'e', 'u').rt_rtx)
-#endif
-
-// FIXME
-    #define HOST_WIDE_INT long
-bool getFrameRelativeValue(LLValue* decl, HOST_WIDE_INT * result)
-{
-// FIXME
-//     // Using this instead of DECL_RTL for struct args seems like a
-//     // good way to get hit by a truck because it may not agree with
-//     // non-asm access, but asm code wouldn't know what GCC does anyway. */
-//     rtx r = DECL_INCOMING_RTL(decl);
-//     rtx e1, e2;
-// 
-//     // Local variables don't have DECL_INCOMING_RTL
-//     if (r == NULL_RTX)
-// 	r = DECL_RTL(decl);
-// 
-//     if (r != NULL_RTX && GET_CODE(r) == MEM /* && r->frame_related */ ) {
-// 	r = XEXP(r, 0);
-// 	if (GET_CODE(r) == PLUS) {
-// 	    e1 = XEXP(r, 0);
-// 	    e2 = XEXP(r, 1);
-// 	    if (e1 == virtual_incoming_args_rtx && GET_CODE(e2) == CONST_INT) {
-// 		*result = INTVAL(e2) + 8; // %% 8 is 32-bit specific...
-// 		return true;
-// 	    } else if (e1 == virtual_stack_vars_rtx && GET_CODE(e2) == CONST_INT) {
-// 		*result = INTVAL(e2); // %% 8 is 32-bit specific...
-// 		return true;
-// 	    }
-// 	} else if (r == virtual_incoming_args_rtx) {
-// 	    *result = 8;
-// 	    return true; // %% same as above
-// 	}
-// 	// shouldn't have virtual_stack_vars_rtx by itself
-//     }
-//     
-    return false;
-}
--- a/tests/mini/asm1.d	Sat Nov 08 11:34:35 2008 +0100
+++ b/tests/mini/asm1.d	Sat Nov 08 22:29:19 2008 +0100
@@ -4,7 +4,7 @@
 
 void main()
 {
-    version(D_InlineAsm_X86)
+    version(LLVM_InlineAsm_X86)
     {
 	int x;
 	asm