$PJ,"Project: OSMain2.SPZ","/LT/OSMain2/OSMain2.SPZ"$
$WW,1$/*$FG,5$$TX+CX,"Intermediate Code"$
$TX+CX,"To"$
$TX+CX,"Machine Code"$
$FG$
$FG,2$RAX$FG$,$FG,2$RBX$FG$,$FG,2$RCX$FG$ and $FG,2$RDX$FG$ can be trashed by each intermediate code's
output code.  However, intermediate codes must be coupled together based on the arg and result type
specifications in the $LK,"IcArg","MN:IcArg"$.  $FG,2$RAX$FG$ is the most common register for coupling
intermediate codes.

Internal calculations take place on 64-bit values, so anything which has found it's way into a register
has been sign or zero extended to 64-bits.

The $LK,"IcMov","MN:IcMov"$() routine is commonly used.  It needs a register for zero-extensions when
dealing with U4's and when shuffling things around.  I try to use the $FG,2$RBX$FG$ register as a
scratch register available for sub-intermediate codes to trash.  Don't assume $FG,2$RBX$FG$ will be
preserved by $LK,"IcMov","MN:IcMov"$() or other sub-intermediate code routines.  If you are not calling
such routines, you can use it.

You might get away with returning a value from a $UL,1$sub$UL,0$intermediate code helper routine in
$FG,2$RBX$FG$, but maybe not because it has to zero-extend $FG,2$U4$FG$'s and I know no way besides
XORing ahead and moving a $FG,2$U4$FG$ in, which requires two registers.




Code size changing during passes could cause problems.  Jumps will be shortened (not lengthened) on
successive passes and contraction does not hurt jumps, but contraction can hurt a glbl displacement.  I
decided all code must reside in the lowest 2Gig allowing 32-bit relative addressing for $FG,2$CALLS$FG$
and $FG,2$JMPS$FG$.  To allow code beyond 2Gig, indirect calls and jmps could be used.  (Load a 64-bit
value in a register and call the register.)

*/$WW,0$

void IcU1(IntermediateCode *tempi,U1 b)
{
 if (tempi->ic_cnt>=IC_BODY_SIZE-1|| tempi->ic_ext_body) {
     if (!tempi->ic_ext_body) {
         tempi->ic_ext_body=MAlloc(256);
         MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
     }
     tempi->ic_ext_body[tempi->ic_cnt++]=b;
 } else
     tempi->ic_body[tempi->ic_cnt++]=b;
}

void IcRex(IntermediateCode *tempi,U1 b)
{
 if (b) {
     if (tempi->ic_cnt>=IC_BODY_SIZE-1|| tempi->ic_ext_body) {
         if (!tempi->ic_ext_body) {
             tempi->ic_ext_body=MAlloc(256);
             MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
         }
         tempi->ic_ext_body[tempi->ic_cnt++]=b;
     } else
         tempi->ic_body[tempi->ic_cnt++]=b;
 }
}

void Ic66Rex(IntermediateCode *tempi,U1 b)
{
 if (!b) {
     if (tempi->ic_cnt>=IC_BODY_SIZE-1|| tempi->ic_ext_body) {
         if (!tempi->ic_ext_body) {
             tempi->ic_ext_body=MAlloc(256);
             MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
         }
         tempi->ic_ext_body[tempi->ic_cnt++]=0x66;
     } else
         tempi->ic_body[tempi->ic_cnt++]=0x66;
 } else {
     if (tempi->ic_cnt>=IC_BODY_SIZE-2|| tempi->ic_ext_body) {
         if (!tempi->ic_ext_body) {
             tempi->ic_ext_body=MAlloc(256);
             MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
         }
         tempi->ic_ext_body[tempi->ic_cnt++]=0x66;
         tempi->ic_ext_body[tempi->ic_cnt++]=b;
     } else {
         tempi->ic_body[tempi->ic_cnt++]=0x66;
         tempi->ic_body[tempi->ic_cnt++]=b;
     }
 }
}

void IcU2(IntermediateCode *tempi,U2 w)
{
 if (tempi->ic_cnt>=IC_BODY_SIZE-2|| tempi->ic_ext_body) {
     if (!tempi->ic_ext_body) {
         tempi->ic_ext_body=MAlloc(256);
         MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
     }
     tempi->ic_ext_body[tempi->ic_cnt++]=w.u1[0];
     tempi->ic_ext_body[tempi->ic_cnt++]=w.u1[1];
 } else {
     tempi->ic_body[tempi->ic_cnt++]=w.u1[0];
     tempi->ic_body[tempi->ic_cnt++]=w.u1[1];
 }
}

void IcU3(IntermediateCode *tempi,U4 d)
{
 if (tempi->ic_cnt>=IC_BODY_SIZE-3|| tempi->ic_ext_body) {
     if (!tempi->ic_ext_body) {
         tempi->ic_ext_body=MAlloc(256);
         MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
     }
     tempi->ic_ext_body[tempi->ic_cnt++]=d.u1[0];
     tempi->ic_ext_body[tempi->ic_cnt++]=d.u1[1];
     tempi->ic_ext_body[tempi->ic_cnt++]=d.u1[2];
 } else {
     tempi->ic_body[tempi->ic_cnt++]=d.u1[0];
     tempi->ic_body[tempi->ic_cnt++]=d.u1[1];
     tempi->ic_body[tempi->ic_cnt++]=d.u1[2];
 }
}

void IcU4(IntermediateCode *tempi,U4 d)
{
 U4 *dd;
 if (tempi->ic_cnt>=IC_BODY_SIZE-4|| tempi->ic_ext_body) {
     if (!tempi->ic_ext_body) {
         tempi->ic_ext_body=MAlloc(256);
         MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
     }
     dd=&tempi->ic_ext_body[tempi->ic_cnt];
 } else {
     dd=&tempi->ic_body[tempi->ic_cnt];
 }
 *dd=d;
 tempi->ic_cnt+=4;
}

void IcU8(IntermediateCode *tempi,U8 q)
{
 U8 *qq;
 if (tempi->ic_cnt>=IC_BODY_SIZE-8 || tempi->ic_ext_body) {
     if (!tempi->ic_ext_body) {
         tempi->ic_ext_body=MAlloc(256);
         MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
     }
     qq=&tempi->ic_ext_body[tempi->ic_cnt];
 } else
     qq=&tempi->ic_body[tempi->ic_cnt];
 *qq=q;
 tempi->ic_cnt+=8;
}

void IcCopyTemplate(LexStruct *lx,IntermediateCode *tempi,U8 op,
 BoolI1 override=FALSE,BoolI1 dont_push=FALSE,BoolI1 dont_pop=FALSE,BoolI1 alt=FALSE)
{
 U1 *ptr;
 I8 i=0;
 if (!override) {
     if (tempi->ic_flags&ICF_ALTERNATE_TEMPLATE)
         alt=TRUE;
     else
         alt=FALSE;
     dont_push=Bt(&tempi->ic_flags,ICf_DONT_PUSH_FLOAT0+lx->float_template_cnt);
     dont_pop=Bt(&tempi->ic_flags,ICf_DONT_POP_FLOAT0+lx->float_template_cnt);
 }
 if (alt) {
     if (dont_push) {
         if (dont_pop) {
             ptr=cmp_templates_dont_push_pop2[op];
             i=cmp_templates_dont_push_pop2[op+1]-ptr;
         } else {
             ptr=cmp_templates_dont_push2[op];
             i=cmp_templates_dont_push2[op+1]-ptr;
         }
     }
 }
 if (!i) {
     if (dont_push) {
         if (dont_pop) {
             ptr=cmp_templates_dont_push_pop[op];
             i=cmp_templates_dont_push_pop[op+1]-ptr;
         } else {
             ptr=cmp_templates_dont_push[op];
             i=cmp_templates_dont_push[op+1]-ptr;
         }
     } else {
         if (dont_pop) {
             ptr=cmp_templates_dont_pop[op];
             i=cmp_templates_dont_pop[op+1]-ptr;
         } else {
             ptr=cmp_templates[op];
             i=cmp_templates[op+1]-ptr;
         }
     }
 }
 if (tempi->ic_cnt+i>=IC_BODY_SIZE) {
     if (!tempi->ic_ext_body) {
         tempi->ic_ext_body=MAlloc(256);
         MemCpy(tempi->ic_ext_body,tempi->ic_body,tempi->ic_cnt);
     }
     MemCpy(&tempi->ic_ext_body[tempi->ic_cnt],ptr,i);
 } else
     MemCpy(&tempi->ic_body[tempi->ic_cnt],ptr,i);
 if (!override) {
     if (++lx->float_template_cnt>4)
         Debugger("Internal Compiler Error: float template");
 }
 tempi->ic_cnt+=i;
}

extern void IcMov(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,U8 t2,U8 r2,I8 d2,I8 ip);

U8 IcModr(U8 r,U8 t2,U8 r2,I8 d2)
{
 //result.u[0] is type 0=[REG],1=disp8[REG],2=disp32[REG],3=REG,4=RIP_REL
 //result.u[1] is REX
 //result.u[2] is ModR
 //result.u[3] is SIB
 U8 result=0;
 if (t2&IT_MASK<IT_I8)
     result.u1[1]=0x40;
 else
     result.u1[1]=0x48;
 if (r>7) {
     result.u1[1]+=4;
     r&=7;
 }
 switch (t2>>4) {
     case TY_RIP_DISP32>>4:
         result.u1[2]=0x05+r<<3;
         result.u1[0]=4;
         if (result.u1[1]==0x40 &&
                 (t2&IT_MASK>=IT_I2 ||
                   r<4))
             result.u1[1]=0;
         break;
     case TY_REG>>4:
         if (r2>7) {
             result.u1[1]++;
             r2&=7;
         }
         result.u1[2]=0xC0+r<<3+r2;
         result.u1[0]=3;
         if (result.u1[1]==0x40 &&
                 (t2&IT_MASK>=IT_I2 ||
                   r<4 && r2<4))
             result.u1[1]=0;
         break;
     case TY_DISP>>4:
         if (r2>7) {
             result.u1[1]++;
             r2&=7;
         }
         if (!d2) {
             result.u1[2]=r<<3+r2;
             result.u1[0]=0;
         } else if (MIN_I1<=d2<=MAX_I1) {
             result.u1[2]=0x40+r<<3+r2;
             result.u1[0]=1;
         } else {
             result.u1[2]=0x80+r<<3+r2;
             result.u1[0]=2;
         }
         if (result.u1[1]==0x40 &&
                 (t2&IT_MASK>=IT_I2 ||
                   r<4))
             result.u1[1]=0;
         break;
     case TY_SIB>>4:
         if (7<r2.u1[0]<16)
             result.u1[1]++;
         if (r2.u1[1]&15>7)
             result.u1[1]+=2;
         if (r2.u1[0]==16) {
             result.u1[3]=CREG_RBP+(r2.u1[1]&7)<<3+r2.u1[1]&0xC0;
             result.u1[2]=4+r<<3;
             result.u1[0]=2;
         } else {
             result.u1[3]=r2.u1[0]&7+(r2.u1[1]&7)<<3+r2.u1[1]&0xC0;
             if (!d2 && r2.u1[0]&7!=CREG_RBP) {
                 result.u1[2]=4+r<<3;
                 result.u1[0]=0;
             } else if (MIN_I1<=d2<=MAX_I1) {
                 result.u1[2]=0x44+r<<3;
                 result.u1[0]=1;
             } else {
                 result.u1[2]=0x84+r<<3;
                 result.u1[0]=2;
             }
         }
         if (result.u1[1]==0x40 &&
                 (t2&IT_MASK>=IT_I2 ||
                   r<4))
             result.u1[1]=0;
         break;
 }
 return result;
}

#define SLASH_OP_INC        0xFFFE00
#define SLASH_OP_DEC        0xFFFE01
#define SLASH_OP_NOT        0xF7F602
#define SLASH_OP_NEG        0xF7F603
#define SLASH_OP_MUL        0xF7F604
#define SLASH_OP_MOV        0x898800

void IcSlashOp(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,U8 op,I8 ip)
{
 I8 i=IcModr(op.u1[0],t1,r1,d1);
 switch (t1&IT_MASK) {
     case IT_I1:
     case IT_U1:
         IcRex(tempi,i.u1[1]);
         IcU2(tempi,i.u1[2]<<8+op.u1[1]);
         break;
     case IT_I2:
     case IT_U2:
         Ic66Rex(tempi,i.u1[1]);
         IcU2(tempi,i.u1[2]<<8+op.u1[2]);
         break;
     default:
         IcRex(tempi,i.u1[1]);
         IcU2(tempi,i.u1[2]<<8+op.u1[2]);
 }
 if (t1&TY_MASK==TY_SIB)
     IcU1(tempi,i.u1[3]);
 if (i.u1[0]==1)
     IcU1(tempi,d1);
 else if (i.u1[0]==2)
     IcU4(tempi,d1);
 else if (i.u1[0]==4) {
     IcU4(tempi,d1-(ip+tempi->ic_cnt+4));
     tempi->ic_flags&=~ICF_CODE_FINAL;
 }
}

void IcPush(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,I8 ip)
{
 U8 i;
 IntermediateCode *tempi_last=tempi-1;
 switch (t1>>4) {
     case TY_REG>>4:
         if (t1&IT_MASK<IT_I8) {
             IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,t1,r1,d1,ip);
             IcU1(tempi,0x50+CREG_RBX);
         } else {
             if (r1>7)
                 IcU2(tempi,0x5049+(r1&7)<<8);
             else
                 IcU1(tempi,0x50+r1);
         }
         break;
     case TY_IMM>>4:
         if (MIN_I1<=d1<=MAX_I1)
             IcU3(tempi,0x6A48+d1<<16);
         else if (MIN_I4<=d1<=MAX_I4) {
             IcU2(tempi,0x6848);
             IcU4(tempi,d1);
         } else {
             IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,t1,r1,d1,ip);
             IcU2(tempi,0x5048+CREG_RBX<<8);
         }
         break;
     case TY_DISP>>4:
         i=0x48;
         switch (t1&IT_MASK) {
             case IT_I8:
             case IT_U8:
             case IT_DOUBLE:
                 if (r1>7) {
                     i++;
                     r1&=7;
                 }
                 if (!d1)
                     IcU3(tempi,0x30FF00+r1<<16+i);
                 else if (MIN_I1<=d1<=MAX_I1) {
                     IcU3(tempi,0x70FF00+r1<<16+i);
                     IcU1(tempi,d1);
                 } else {
                     IcU3(tempi,0xB0FF00+r1<<16+i);
                     IcU4(tempi,d1);
                 }
                 break;
             default:
                 IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,t1,r1,d1,ip);
                 IcU2(tempi,0x5048+CREG_RBX<<8);
         }
         break;
     case TY_SIB>>4:
         i=0x48;
         switch (t1&IT_MASK) {
             case IT_I8:
             case IT_U8:
             case IT_DOUBLE:
                 if (7<r1.u1[0]<16)
                     i++;
                 if (r1.u1[1]&15>7)
                     i+=2;
                 if (r1.u1[0]==16) {
                     r1=CREG_RBP+(r1.u1[1]&7)<<3+r1.u1[1]&0xC0;
                     IcU4(tempi,0x34FF00+r1<<24+i);
                     IcU4(tempi,d1);
                 } else {
                     r1=r1.u1[0]&7+(r1.u1[1]&7)<<3+r1.u1[1]&0xC0;
                     if (!d1 && r1.u1[0]&7!=CREG_RBP)
                         IcU4(tempi,0x34FF00+r1<<24+i);
                     else if (MIN_I1<=d1<=MAX_I1) {
                         IcU4(tempi,0x74FF00+r1<<24+i);
                         IcU1(tempi,d1);
                     } else {
                         IcU4(tempi,0xB4FF00+r1<<24+i);
                         IcU4(tempi,d1);
                     }
                 }
                 break;
             default:
                 IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,t1,r1,d1,ip);
                 IcU2(tempi,0x5048+CREG_RBX<<8);
         }
         break;
     case TY_RIP_DISP32>>4:
         switch (t1&IT_MASK) {
             case IT_I8:
             case IT_U8:
             case IT_DOUBLE:
                 IcU3(tempi,0x35FF48);
                 IcU4(tempi,d1-(ip+tempi->ic_cnt+4));
                 tempi->ic_flags&=~ICF_CODE_FINAL;
                 break;
             default:
                 IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,t1,r1,d1,ip);
                 IcU2(tempi,0x5048+CREG_RBX<<8);
         }
         break;
     default:
         IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,t1,r1,d1,ip);
         IcU2(tempi,0x5048+CREG_RBX<<8);
 }
}

void IcPushRegs(IntermediateCode *tempi,U8 mask)
{
 I8 i;
 for (i=0;i<NUM_REGS;i++) {
     if (Bt(&mask,i)) {
         if (i>7)
             IcU2(tempi,0x5049+(i&7)<<8);
         else
             IcU1(tempi,0x50+i);
     }
 }
}

void IcPop(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,I8 ip)
{
 switch (t1>>4) {
     case TY_REG>>4:
         if (r1>7)
             IcU2(tempi,0x5849+(r1&7)<<8);
         else
             IcU1(tempi,0x58+r1);
         break;
     case TY_NULL>>4:
         break;
     default:
         IcU1(tempi,0x58+CREG_RBX);
         IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,CREG_RBX,0,ip);
 }
}

void IcPopRegs(IntermediateCode *tempi,U8 mask)
{
 I8 i;
 for (i=NUM_REGS-1;i>=0;i--) {
     if (Bt(&mask,i)) {
         if (i>7)
             IcU2(tempi,0x5849+(i&7)<<8);
         else
             IcU1(tempi,0x58+i);
     }
 }
}

void IcZero(IntermediateCode *tempi,U8 r)
{
 if (r>7) {
     r&=7;
     IcU3(tempi,0xC0334D+r<<16+r<<19);
 } else
     IcU2(tempi,0xC033+r<<8+r<<11);
}

void IcOr(IntermediateCode *tempi,U8 r)
{
 U8 i=0xC00B48; //OR R,R
 if (r>7) {
     i+=5;
     r&=7;
 }
 IcU3(tempi,i+r<<16+r<<19);
}

void IcMov(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,U8 t2,U8 r2,I8 d2,I8 ip)
{
 I8 i,last_cnt=tempi->ic_cnt;
 BoolI1 copy_from_rbx;
 switch (t1>>4) {
     case TY_REG>>4:
         if (t2&TY_MASK==TY_IMM) {
             if (!d2)
                 IcZero(tempi,r1);
             else if (0<=d2<=MAX_U1) {
                 IcZero(tempi,r1);
                 if (r1>7)
                     IcU3(tempi,d2<<16+(0xB0+r1&7)<<8+0x41);
                 else if (r1>3)
                     IcU3(tempi,d2<<16+(0xB0+r1)<<8+0x40);
                 else
                     IcU2(tempi,d2<<8+0xB0+r1);
             } else if (MIN_I1<=d2<=MAX_I1) {
                 if (r1>7) {
                     r1&=7;
                     IcU3(tempi,d2<<16+(0xB0+r1)<<8+0x41);
                     IcU4(tempi,0xC0BE0F4D+r1<<24+r1<<27);
                 } else {
                     IcU2(tempi,d2<<8+0xB0+r1);
                     IcU4(tempi,0xC0BE0F48+r1<<24+r1<<27);
                 }
             } else if (MIN_I4<=d2<=MAX_I4) {
                 if (r1>7) {
                     r1&=7;
                     IcU2(tempi,(0xB8+r1)<<8+0x41);
                     IcU4(tempi,d2);
                     IcU3(tempi,0xC0634D+r1<<16+r1<<19);
                 } else {
                     IcU1(tempi,0xB8+r1);
                     IcU4(tempi,d2);
                     IcU3(tempi,0xC06348+r1<<16+r1<<19);
                 }
             } else {
                 i=0xB848;
                 if (r1>7) {
                     i++;
                     r1&=7;
                 }
                 IcU2(tempi,i+r1<<8);
                 IcU8(tempi,d2);
             }
         } else if (t2&TY_MASK==TY_STK)
             IcPop(tempi,t1,r1,d1,ip);
         else {
             if (r1==r2 && t2&TY_MASK==TY_REG)
                 return;
             if (t2&TY_MASK==TY_REG) {
                 t2=TY_REG+IT_I8;
                 i=tempi->ic_cnt;
                 if (tempi->ic_last_cnt==i-3 && i>=3 &&
                         tempi->ic_body[i-2]==0x8B &&
                         tempi->ic_body[i-1]==0xC0+r1&7+(r2&7)<<3 &&
                         tempi->ic_body[i-3]==0x48+ (r2>7 ? 4:0)+(r1>7 ? 1:0) )
                     return;
             }
             i=IcModr(r1,t2,r2,d2);
             if (t2&IT_MASK==IT_U4) {
                 if (r1!=r2) {
                     IcZero(tempi,r1);
                     copy_from_rbx=FALSE;
                 } else {
                     if (r2!=CREG_RBX)
                         IcZero(tempi,CREG_RBX);
                     else
                         throw(EXCEPT_COMPILER,19); //internal error, fatal, out of registers
                     copy_from_rbx=TRUE;
                     i=IcModr(CREG_RBX,t2,r2,d2);
                 }
             } else
                 i|=0x4800;
             IcRex(tempi,i.u1[1]);
             switch (t2&IT_MASK) {
                 case IT_I1:
                     IcU3(tempi,i.u1[2]<<16+0xBE0F);
                     break;
                 case IT_I2:
                     IcU3(tempi,i.u1[2]<<16+0xBF0F);
                     break;
                 case IT_I4:
                     IcU2(tempi,i.u1[2]<<8+0x63);
                     break;

                 case IT_U1:
                     IcU3(tempi,i.u1[2]<<16+0xB60F);
                     break;
                 case IT_U2:
                     IcU3(tempi,i.u1[2]<<16+0xB70F);
                     break;
                 case IT_U4:
                     IcU2(tempi,i.u1[2]<<8+0x8B);
                     if (t2&TY_MASK==TY_SIB)
                         IcU1(tempi,i.u1[3]);
                     if (i.u1[0]==1)
                         IcU1(tempi,d2);
                     else if (i.u1[0]==2)
                         IcU4(tempi,d2);
                     else if (i.u1[0]==4) {
                         IcU4(tempi,d2-(ip+tempi->ic_cnt+4));
                         tempi->ic_flags&=~ICF_CODE_FINAL;
                     }
                     if (copy_from_rbx) {
                         if (r1>7)
                             IcU3(tempi,0xC38B4C+(r1&7)<<19);
                         else
                             IcU3(tempi,0xC38B48+r1<<19);
                     }
                     goto done1;
                 default:
                     IcU2(tempi,i.u1[2]<<8+0x8B);
             }
             if (t2&TY_MASK==TY_SIB)
                 IcU1(tempi,i.u1[3]);
             if (i.u1[0]==1)
                 IcU1(tempi,d2);
             else if (i.u1[0]==2)
                 IcU4(tempi,d2);
             else if (i.u1[0]==4) {
                 IcU4(tempi,d2-(ip+tempi->ic_cnt+4));
                 tempi->ic_flags&=~ICF_CODE_FINAL;
             }
done1:
         }
         break;
     case TY_STK>>4:
         if (t1&IT_MASK<t2&IT_MASK)
             IcPush(tempi,t2&TY_MASK+t1&IT_MASK,r2,d2,ip);
         else
             IcPush(tempi,t2,r2,d2,ip);
         break;
     case TY_DISP>>4:
     case TY_RIP_DISP32>>4:
     case TY_SIB>>4:
         if (t2&TY_MASK==TY_IMM &&
                 (t1&IT_MASK<IT_I8 || (MIN_I4<=d2<=MAX_I4))) {
             i=IcModr(0,t1,r1,d1);
             switch (t1&IT_MASK) {
                 case IT_I1:
                 case IT_U1:
                     IcRex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0xC6);
                     break;
                 case IT_U2:
                 case IT_I2:
                     Ic66Rex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0xC7);
                     break;
                 default:
                     IcRex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0xC7);
             }
             if (t1&TY_MASK==TY_SIB)
                 IcU1(tempi,i.u1[3]);
             if (i.u1[0]==1)
                 IcU1(tempi,d1);
             else if (i.u1[0]==2)
                 IcU4(tempi,d1);
             else if (i.u1[0]==4) {
                 i=d1-(ip+tempi->ic_cnt+4);
                 switch (t1&IT_MASK) {
                     case IT_I1:
                     case IT_U1:
                         i--;
                         break;
                     case IT_I2:
                     case IT_U2:
                         i-=2;
                         break;
                     default:
                         i-=4;
                 }
                 IcU4(tempi,i);
                 tempi->ic_flags&=~ICF_CODE_FINAL;
             }
             switch (t1&IT_MASK) {
                 case IT_I1:
                 case IT_U1:
                     IcU1(tempi,d2);
                     break;
                 case IT_I2:
                 case IT_U2:
                     IcU2(tempi,d2);
                     break;
                 default:
                     IcU4(tempi,d2);
             }
         } else {
             if (t2&TY_MASK==TY_REG)
                 IcSlashOp(tempi,t1,r1,d1,r2+SLASH_OP_MOV,ip);
             else {
                 IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,t2,r2,d2,ip);
                 IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,CREG_RBX,0,ip);
             }
         }
         break;
 }
 tempi->ic_last_cnt=last_cnt;
}

void IcLea(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,U8 t2,U8 r2,I8 d2,I8 ip)
{
 I8 i;
 if (t1&TY_MASK==TY_REG) {
     i=IcModr(r1,t2,r2,d2);
     i.u1[1]|=0x48;
     IcU3(tempi,i.u1[2]<<16+0x8D00+i.u1[1]);
     if (t2&TY_MASK==TY_SIB)
         IcU1(tempi,i.u1[3]);
     if (i.u1[0]==1)
         IcU1(tempi,d2);
     else if (i.u1[0]==2)
         IcU4(tempi,d2);
     else if (i.u1[0]==4) {
         IcU4(tempi,d2-(ip+tempi->ic_cnt+4));
         tempi->ic_flags&=~ICF_CODE_FINAL;
     }
 } else {
     IcLea(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
     IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,CREG_RCX,0,ip);
 }
}

void IcDeref(IntermediateCode *tempi,I8 ip)
{
 I8 t;
 t=tempi->r.type&IT_MASK;
 if (t>tempi->p1.ptype)
     t=tempi->p1.ptype;

 if (tempi->p1.type&TY_MASK==TY_REG)
     IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,
                 TY_DISP+t,tempi->p1.reg,tempi->p1.disp,ip);
 else {
     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,
         tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
     IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,
                 TY_DISP+t,CREG_RCX,0,ip);
 }
}

void IcAddEct(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,
                   U8 t2,U8 r2,I8 d2,U8 t3,U8 r3,I8 d3,U8 op,I8 ip)
{
 I8 i,temp,result_reg=CREG_RAX;
 BoolI1 swap=FALSE;
 if (r3!=result_reg) {
     swap^=TRUE;
     temp=t2; t2=t3; t3=temp;
     temp=r2; r2=r3; r3=temp;
     temp=d2; d2=d3; d3=temp;
 }
 if (t2&IT_MASK>=IT_I8 && r2!=result_reg &&
         TY_REG<=t2&TY_MASK<=TY_RIP_DISP32) {
     if (t1&TY_MASK==TY_REG && !(r2==r1 && TY_REG<=t2&TY_MASK<=TY_SIB))
         result_reg=r1;
     IcMov(tempi,TY_REG+IT_I8,result_reg,0,t3,r3,d3,ip);
     i=IcModr(result_reg,t2,r2,d2);
     IcRex(tempi,i.u1[1]);
     IcU2(tempi,i.u1[2]<<8+op);
     if (t2&TY_MASK==TY_SIB)
         IcU1(tempi,i.u1[3]);
     if (i.u1[0]==1)
         IcU1(tempi,d2);
     else if (i.u1[0]==2)
         IcU4(tempi,d2);
     else if (i.u1[0]==4) {
         IcU4(tempi,d2-(ip+tempi->ic_cnt+4));
         tempi->ic_flags&=~ICF_CODE_FINAL;
     }
 } else {
     if (t2&TY_MASK==TY_REG)
         temp=r2;
     else
         temp=CREG_RCX;

     if (t1&TY_MASK==TY_REG)
         result_reg=r1;

     if (temp==result_reg)
         result_reg=CREG_RDX;
     if (swap ^^ tempi->ic_flags & ICF_P1_FIRST) {
         if (r3==temp && TY_REG<=t3&TY_MASK<=TY_SIB)
             temp=CREG_RCX;
         IcMov(tempi,TY_REG+IT_I8,temp,0,t2,r2,d2,ip);
         IcMov(tempi,TY_REG+IT_I8,result_reg,0,t3,r3,d3,ip);
     } else {
         if (r2==result_reg && TY_REG<=t2&TY_MASK<=TY_SIB)
             result_reg=CREG_RDX;
         IcMov(tempi,TY_REG+IT_I8,result_reg,0,t3,r3,d3,ip);
         IcMov(tempi,TY_REG+IT_I8,temp,0,t2,r2,d2,ip);
     }
     i=0x48;
     if (result_reg>7)
         i+=4;
     if (temp>7)
         i++;
     IcU3(tempi,0xC00000+i+(temp&7)<<16+(result_reg&7)<<19+op<<8);
 }
 IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,result_reg,0,ip);
}

void IcAddConst(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,
                   U8 t2,U8 r2,I8 d2,I8 disp,U8 op,I8 ip)
{
 I8 i,r;
 if (op.u1[0]==0x2B) {
     op=0x0003;
     disp=-disp;
 }
 if (t1&TY_MASK==TY_REG) {
     if (t2&TY_MASK!=TY_REG) {
         IcMov(tempi,t1,r1,d1,t2,r2,d2,ip);
         t2=t1;
         r2=r1;
         d2=d1;
     }
     if (r1==r2) {
         if (r1>7)
             i=0x49;
         else
             i=0x48;
         if (!disp &&
             (op.u1[0]==0x03||op.u1[0]==0x2B||
               op.u1[0]==0x33||op.u1[0]==0x0B))
             return;
         else if (disp==1 && op.u1[0]==0x03) {
             IcU3(tempi,0xC0FF00+op.u1[1]<<19+i+(r1&7)<<16);
             return;
         } else if (disp==-1 && op.u1[0]==0x03) {
             IcU3(tempi,0xC8FF00+i+(r1&7)<<16);
             return;
         } else if (MIN_I1<=disp<=MAX_I1) {
             IcU3(tempi,0xC08300+op.u1[1]<<19+i+(r1&7)<<16);
             IcU1(tempi,disp);
             return;
         } else if (MIN_I4<=disp<=MAX_I4) {
             IcU3(tempi,0xC08100+op.u1[1]<<19+i+(r1&7)<<16);
             IcU4(tempi,disp);
             return;
         }
     }
     if (op.u1[0]==0x03 && MIN_I4<=disp<=MAX_I4 &&
         !Bt(&non_ptr_vars_mask,r2)) {
         i=IcModr(r1,TY_DISP+IT_I8,r2,disp);
         i.u1[1]|=0x48;
         IcU3(tempi,i.u1[2]<<16+0x8D00+i.u1[1]);
         if (i.u1[0]==1)
             IcU1(tempi,disp);
         else if (i.u1[0]==2)
             IcU4(tempi,disp);
         else if (i.u1[0]==4) {
             IcU4(tempi,disp-(ip+tempi->ic_cnt+4));
             tempi->ic_flags&=~ICF_CODE_FINAL;
         }
         return;
     }
 }
 switch (t1>>4) {
     case TY_REG>>4:
     case TY_DISP>>4:
     case TY_SIB>>4:
     case TY_RIP_DISP32>>4:
         if (t1!=t2 || r1!=r2 || d1!=d2) {
             IcMov(tempi,t1,r1,d1,t2,r2,d2,ip);
             t2=t1;
             r2=r1;
             d2=d1;
         }

         if (!disp &&
             (op.u1[0]==0x03||op.u1[0]==0x2B||
               op.u1[0]==0x33||op.u1[0]==0x0B))
             return;
         r=op.u1[1];
         if (op.u1[0]==0x03 && disp==-1)
             r=1;

         if (op.u1[0]==0x03 && (disp==1 || disp==-1)) {
             i=IcModr(r,t1,r1,d1);
             switch (t1&IT_MASK) {
                 case IT_I1:
                 case IT_U1:
                     IcRex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0xFE);
                     break;
                 case IT_I2:
                 case IT_U2:
                     Ic66Rex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0xFF);
                     break;
                 default:
                     IcRex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0xFF);
             }
             if (t1&TY_MASK==TY_SIB)
                 IcU1(tempi,i.u1[3]);
             if (i.u1[0]==1)
                 IcU1(tempi,d1);
             else if (i.u1[0]==2)
                 IcU4(tempi,d1);
             else if (i.u1[0]==4) {
                 IcU4(tempi,d1-(ip+tempi->ic_cnt+4));
                 tempi->ic_flags&=~ICF_CODE_FINAL;
             }
             return;
         }
         if (MIN_I1<=disp<=MAX_I1 ||
                 t1&IT_MASK==IT_I1 ||
                 t1&IT_MASK==IT_U1) {
             i=IcModr(r,t1,r1,d1);
             switch (t1&IT_MASK) {
                 case IT_I1:
                 case IT_U1:
                     IcRex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0x80);
                     break;
                 case IT_I1:
                 case IT_U1:
                     Ic66Rex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0x83);
                     break;
                 default:
                     IcRex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0x83);
             }
             if (t1&TY_MASK==TY_SIB)
                 IcU1(tempi,i.u1[3]);
             if (i.u1[0]==1)
                 IcU1(tempi,d1);
             else if (i.u1[0]==2)
                 IcU4(tempi,d1);
             else if (i.u1[0]==4) {
                 IcU4(tempi,d1-(ip+tempi->ic_cnt+5));
                 tempi->ic_flags&=~ICF_CODE_FINAL;
             }
             IcU1(tempi,disp);
             return;
         }
         if (MIN_I4<=disp<=MAX_I4 ||
                 t1&IT_MASK<IT_I8) {
             i=IcModr(r,t1,r1,d1);
             switch (t1&IT_MASK) {
                 case IT_I2:
                 case IT_U2:
                     Ic66Rex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0x81);
                     break;
                 default:
                     IcRex(tempi,i.u1[1]);
                     IcU2(tempi,i.u1[2]<<8+0x81);
             }
             if (t1&TY_MASK==TY_SIB)
                 IcU1(tempi,i.u1[3]);
             if (i.u1[0]==1)
                 IcU1(tempi,d1);
             else if (i.u1[0]==2)
                 IcU4(tempi,d1);
             else if (i.u1[0]==4) {
                 if (t1&IT_MASK==IT_U2 ||
                         t1&IT_MASK==IT_I2)
                     IcU4(tempi,d1-(ip+tempi->ic_cnt+6));
                 else
                     IcU4(tempi,d1-(ip+tempi->ic_cnt+8));
                 tempi->ic_flags&=~ICF_CODE_FINAL;
             }
             if (t1&IT_MASK==IT_U2 ||
                     t1&IT_MASK==IT_I2)
                 IcU2(tempi,disp);
             else
                 IcU4(tempi,disp);
             return;
         }
         break;
     case TY_STK>>4:
         IcAddConst(tempi,TY_REG+IT_I8,CREG_RAX,0,t2,r2,d2,disp,op,ip);
         IcPushRegs(tempi,1<<CREG_RAX);
         return;
 }
 IcAddEct(tempi,t1,r1,d1,TY_IMM+IT_I8,0,disp,t2,r2,d2,op.u1[0],ip);
}

void IcSub(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,
                   U8 t2,U8 r2,I8 d2,U8 t3,U8 r3,I8 d3,I8 ip)
{
 I8 i=0x48,temp,op=0x2B;
 BoolI1 swap=FALSE;
 if (r3!=CREG_RAX) {
     swap=TRUE;
     temp=t2; t2=t3; t3=temp;
     temp=r2; r2=r3; r3=temp;
     temp=d2; d2=d3; d3=temp;
 }
 if (t2&IT_MASK>=IT_I8 && r2.u1[0]!=CREG_RAX && (t2&TY_MASK!=TY_SIB || r2.u1[1]&15!=CREG_RAX) &&
         TY_REG<=t2&TY_MASK<=TY_RIP_DISP32) {
     IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
     if (!swap) {
         op=0x03;
         IcU3(tempi,0xD8F748);
     }
     i=IcModr(CREG_RAX,t2,r2,d2);
     IcRex(tempi,i.u1[1]);
     IcU2(tempi,i.u1[2]<<8+op);
     if (t2&TY_MASK==TY_SIB)
         IcU1(tempi,i.u1[3]);
     if (i.u1[0]==1)
         IcU1(tempi,d2);
     else if (i.u1[0]==2)
         IcU4(tempi,d2);
     else if (i.u1[0]==4) {
         IcU4(tempi,d2-(ip+tempi->ic_cnt+4));
         tempi->ic_flags&=~ICF_CODE_FINAL;
     }
     IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,CREG_RAX,0,ip);
 } else {
     if (tempi->ic_flags & ICF_P1_FIRST) {
         if (t3&TY_MASK!=TY_REG || t3&IT_MASK<IT_I8) {
             if (swap) {
                 swap=FALSE;
                 IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
                 r3=CREG_RCX;
                 r2=CREG_RAX;
             } else {
                 IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
                 r2=CREG_RCX;
                 r3=CREG_RAX;
             }
         } else {
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
             r2=CREG_RCX;
         }
     } else {
         if (t3&TY_MASK!=TY_REG || t3&IT_MASK<IT_I8) {
             if (swap) {
                 swap=FALSE;
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
                 IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
                 r2=CREG_RAX;
                 r3=CREG_RCX;
             } else {
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
                 IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
                 r3=CREG_RAX;
                 r2=CREG_RCX;
             }
         } else {
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
             r2=CREG_RCX;
         }
     }
     if (swap) {
         op=0x03;
         IcU3(tempi,0xD9F748);
     }
     if (r3>7)
         i++;
     if (r2>7)
         i+=4;
     IcU3(tempi,0xC00000+i+(r3&7)<<16+(r2&7)<<19+op<<8);
     IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,r2,0,ip);
 }
}

void IcMul(IntermediateCode *tempi,I8 ip)
{
 I8 i,r2,r=CREG_RAX,j;
 IcArg *p1,*p2;
 if (tempi->p1.type&TY_MASK==TY_IMM) {
     p1=&tempi->p2;
     p2=&tempi->p1;
     tempi->ic_flags|=ICF_P1_FIRST;
 } else {
     p1=&tempi->p1;
     p2=&tempi->p2;
 }
 i=p2->disp;
 if (!(tempi->ic_class->sub_type&1) &&
         p2->type&TY_MASK==TY_IMM && MIN_I4<=i<=MAX_I4) {
     if (tempi->r.type==TY_REG+IT_I8) {
         IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,p1->type,p1->reg,p1->disp,ip);
         r=tempi->r.reg;
     } else
         IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,p1->type,p1->reg,p1->disp,ip);
     if (r>7)
         j=0xC0004D;
     else
         j=0xC00048;
     if (MIN_I1<=i<=MAX_I1)
         IcU4(tempi,i<<24+0x6B00+j+(r&7)<<16+(r&7)<<19);
     else {
         IcU3(tempi,0x6900+j+(r&7)<<16+(r&7)<<19);
         IcU4(tempi,i);
     }
 } else {
     if (tempi->ic_class->sub_type&1)
         i=0xE0F748;
     else
         i=0xE8F748;
     if (tempi->ic_flags & ICF_P1_FIRST) {
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,p1->type,p1->reg,p1->disp,ip);
         r2=CREG_RCX;
         IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,p2->type,p2->reg,p2->disp,ip);
     } else {
         IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,p2->type,p2->reg,p2->disp,ip);
         if (p1->type&TY_MASK!=TY_REG ||
                 p1->type&IT_MASK<IT_I8) {
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,p1->type,p1->reg,p1->disp,ip);
             r2=CREG_RCX;
         } else
             r2=p1->reg;
     }
     if (r2>7) {
         i++;
         r2&=7;
     }
     IcU3(tempi,i+r2<<16);
 }
 IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,TY_REG+IT_I8,r,0,ip);
}

void IcMulEqual(IntermediateCode *tempi,I8 ip)
{
 I8 i=tempi->p2.disp,r=CREG_RAX,j;
 if (!(tempi->ic_class->sub_type&1) &&
         tempi->p2.type&TY_MASK==TY_IMM && MIN_I4<=i<=MAX_I4) {
     if (tempi->ic_flags & ICF_NOT_ADDRESS) {
         if (tempi->p1.type==TY_REG+IT_I8)
             r=tempi->p1.reg;
         else
             
IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,i
p);
         if (r>7)
             j=0xC0004D;
         else
             j=0xC00048;
         if (MIN_I1<=i<=MAX_I1)
             IcU4(tempi,i<<24+0x6B00+j+(r&7)<<16+(r&7)<<19);
         else {
             IcU3(tempi,0x6900+j+(r&7)<<16+(r&7)<<19);
             IcU4(tempi,i);
         }
         IcMov(tempi,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,
             TY_REG+IT_I8,r,0,ip);
     } else {
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
         IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,TY_DISP+tempi->p1.ptype,CREG_RCX,0,ip);
         r=CREG_RBX;
         if (MIN_I1<=i<=MAX_I1)
             IcU4(tempi,i<<24+0xDB6B48);
         else {
             IcU3(tempi,0xDB6948);
             IcU4(tempi,i);
         }
         IcMov(tempi,TY_DISP+tempi->p1.ptype,CREG_RCX,0,TY_REG+IT_I8,CREG_RBX,0,ip);
     }
 } else {
     if (tempi->ic_class->sub_type&1)
         i=0xE3F748;
     else
         i=0xEBF748;
     if (tempi->ic_flags & ICF_NOT_ADDRESS) {
         if (tempi->ic_flags & ICF_P1_FIRST) {
             
IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,i
p);
             IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
         } else {
             IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
             
IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,i
p);
         }
         IcU3(tempi,i);
         IcMov(tempi,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,
             TY_REG+IT_I8,CREG_RAX,0,ip);
     } else {
         if (tempi->ic_flags & ICF_P1_FIRST) {
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
             IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
         } else {
             IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
         }
         IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,TY_DISP+tempi->p1.ptype,CREG_RCX,0,ip);
         IcU3(tempi,i);
         IcMov(tempi,TY_DISP+tempi->p1.ptype,CREG_RCX,0,TY_REG+IT_I8,CREG_RAX,0,ip);
     }
 }
 if (tempi->r.type&TY_MASK)
     IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,TY_REG+IT_I8,r,0,ip);
}


void IcDiv(IntermediateCode *tempi,I8 ip)
{
 if (tempi->ic_flags & ICF_P1_FIRST) {
     IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
 } else {
     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
     IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
 }
 if (tempi->ic_class->sub_type&1) {
     IcZero(tempi,CREG_RDX);
     IcU3(tempi,0xF1F748);
 } else {
     IcU2(tempi,0x9948);
     IcU3(tempi,0xF9F748);
 }
 IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,TY_REG+IT_I8,CREG_RAX,0,ip);
}

void IcDivEqual(IntermediateCode *tempi,BoolI1 is_mod,I8 ip)
{
 if (tempi->ic_flags & ICF_NOT_ADDRESS) {
     if (tempi->ic_flags & ICF_P1_FIRST) {
         
IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,i
p);
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
     } else {
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
         
IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,i
p);
     }
     if (tempi->ic_class->sub_type&1) {
         IcZero(tempi,CREG_RDX);
         IcU3(tempi,0xF1F748);
     } else {
         IcU2(tempi,0x9948);
         IcU3(tempi,0xF9F748);
     }
     if (is_mod)
         IcMov(tempi,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,
             TY_REG+IT_I8,CREG_RDX,0,ip);
     else
         IcMov(tempi,tempi->p1.type&TY_MASK+tempi->p1.ptype,tempi->p1.reg,tempi->p1.disp,
             TY_REG+IT_I8,CREG_RAX,0,ip);
 } else {
     if (tempi->ic_flags & ICF_P1_FIRST) {
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
         IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
         IcU3(tempi,0xD98748); //xchg bx,cx
     } else {
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
         IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
     }
     //dangerous might trash RBX in Mov, but it doesn't
     IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,TY_DISP+tempi->p1.ptype,CREG_RBX,0,ip);
     if (tempi->ic_class->sub_type&1) {
         IcZero(tempi,CREG_RDX);
         IcU3(tempi,0xF1F748);
     } else {
         IcU2(tempi,0x9948);
         IcU3(tempi,0xF9F748);
     }
     if (is_mod)
         IcMov(tempi,TY_DISP+tempi->p1.ptype,CREG_RBX,0,TY_REG+IT_I8,CREG_RDX,0,ip);
     else
         IcMov(tempi,TY_DISP+tempi->p1.ptype,CREG_RBX,0,TY_REG+IT_I8,CREG_RAX,0,ip);
 }
 if (tempi->r.type&TY_MASK) {
     if (is_mod)
         IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,TY_REG+IT_I8,CREG_RDX,0,ip);
     else
         IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,TY_REG+IT_I8,CREG_RAX,0,ip);
 }
}

void IcMod(IntermediateCode *tempi,I8 ip)
{
 if (tempi->ic_flags & ICF_P1_FIRST) {
     IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
 } else {
     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,tempi->p2.type,tempi->p2.reg,tempi->p2.disp,ip);
     IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,tempi->p1.type,tempi->p1.reg,tempi->p1.disp,ip);
 }
 if (tempi->ic_class->sub_type&1) {
     IcZero(tempi,CREG_RDX);
     IcU3(tempi,0xF1F748);
 } else {
     IcU2(tempi,0x9948);
     IcU3(tempi,0xF9F748);
 }
 IcMov(tempi,tempi->r.type,tempi->r.reg,tempi->r.disp,TY_REG+IT_I8,CREG_RDX,0,ip);
}

void IcAddSubEctEqual(IntermediateCode *tempi,U8 ptype,U8 t1,U8 r1,I8 d1,
                   U8 t2,U8 r2,I8 d2,U8 t3,U8 r3,I8 d3,U8 op,I8 ip)
{
 BoolI1 done;
 I8 result_reg,temp,i;
 if (tempi->ic_flags & ICF_NOT_ADDRESS) {
     if (t3&TY_MASK==TY_IMM) {
         IcAddConst(tempi,
             t2,r2,d2,t2,r2,d2,d3,op,ip);
         if (t1&TY_MASK)
             IcMov(tempi,t1,r1,d1,t2,r2,d2,ip);
         return;
     } else {
         done=FALSE;
         if (ptype>=IT_I8) {
             if (!(t1&TY_MASK) &&
                     TY_REG<=t2&TY_MASK<=TY_RIP_DISP32) {
                 if (t3&TY_MASK==TY_REG)
                     temp=r3;
                 else {
                     temp=CREG_RCX;
                     IcMov(tempi,TY_REG+IT_I8,temp,0,t3,r3,d3,ip);
                 }
                 i=IcModr(temp,t2&TY_MASK+ptype,r2,d2);
                 IcRex(tempi,i.u1[1]);
                 IcU2(tempi,i.u1[2]<<8+op.u1[5]);
                 if (t2&TY_MASK==TY_SIB)
                     IcU1(tempi,i.u1[3]);
                 if (i.u1[0]==1)
                     IcU1(tempi,d2);
                 else if (i.u1[0]==2)
                     IcU4(tempi,d2);
                 else if (i.u1[0]==4) {
                     IcU4(tempi,d2-(ip+tempi->ic_cnt+4));
                     tempi->ic_flags&=~ICF_CODE_FINAL;
                 }
                 return;
             }
             if (t3&IT_MASK>=IT_I8 &&
                     TY_REG<=t3&TY_MASK<=TY_RIP_DISP32) {
                 if (t2&TY_MASK==TY_REG)
                     result_reg=r2;
                 else {
                     result_reg=CREG_RCX;
                     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
                 }
                 i=IcModr(result_reg,t3&TY_MASK+ptype,r3,d3);
                 IcRex(tempi,i.u1[1]);
                 IcU2(tempi,i.u1[2]<<8+op.u1[0]);
                 if (t3&TY_MASK==TY_SIB)
                     IcU1(tempi,i.u1[3]);
                 if (i.u1[0]==1)
                     IcU1(tempi,d3);
                 else if (i.u1[0]==2)
                     IcU4(tempi,d3);
                 else if (i.u1[0]==4) {
                     IcU4(tempi,d3-(ip+tempi->ic_cnt+4));
                     tempi->ic_flags&=~ICF_CODE_FINAL;
                 }
                 IcMov(tempi,t2&TY_MASK+ptype,r2,d2,TY_REG+IT_I8,result_reg,0,ip);
                 done=TRUE;
             }
         }
         if (!done) {
             if (tempi->ic_flags & ICF_P1_FIRST) {
                 if (t2&TY_MASK==TY_REG && r2!=CREG_RAX)
                     result_reg=r2;
                 else {
                     result_reg=CREG_RCX;
                     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2&TY_MASK+ptype,r2,d2,ip);
                 }
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
             } else {
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
                 if (t2&TY_MASK==TY_REG && r2!=CREG_RAX)
                     result_reg=r2;
                 else {
                     result_reg=CREG_RCX;
                     IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2&TY_MASK+ptype,r2,d2,ip);
                 }
             }
             if (result_reg>7)
                 IcU1(tempi,0x4C);
             else
                 IcU1(tempi,0x48);
             IcU2(tempi,0xC000+op.u1[0]+(result_reg&7)<<11);
             IcMov(tempi,t2&TY_MASK+ptype,r2,d2,TY_REG+IT_I8,result_reg,0,ip);
         }
     }
 } else {
     done=FALSE;
     if (t3&TY_MASK==TY_IMM && op.u1[2]) {
         if (!d3.u4[1]) {
             if (tempi->ic_flags&ICF_NO_DEPEND_RESULT &&
                     t2&TY_MASK==TY_REG && d3><(U8)<=MAX_I1) {
                 IcSlashOp(tempi,TY_DISP+ptype,r2,0,0x838000+op.u1[4],ip);
                 IcU1(tempi,d3);
                 done=TRUE;
             } else if (op.u1[2]==0x24) { //AND
                 IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,TY_DISP+ptype,CREG_RCX,0,ip);
                 result_reg=CREG_RAX;
                 IcU2(tempi,op.u1[3]<<8+0x40);
                 IcU4(tempi,d3);
                 IcMov(tempi,TY_DISP+ptype,CREG_RCX,0,TY_REG+IT_I8,result_reg,0,ip);
                 done=TRUE;
             } else if (ptype&IT_MASK<IT_I8) { //OR/XOR
                 IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
                 IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,TY_DISP+ptype,CREG_RCX,0,ip);
                 result_reg=CREG_RAX;
                 if (d3.u2[1]) {
                     IcU2(tempi,op.u1[3]<<8+0x40);
                     IcU4(tempi,d3);
                 } else if (d3.u1[1]) {
                     IcU3(tempi,op.u1[3]<<16+0x4066);
                     IcU2(tempi,d3);
                 } else {
                     IcU2(tempi,op.u1[2]<<8+0x40);
                     IcU1(tempi,d3);
                 }
                 IcMov(tempi,TY_DISP+ptype,CREG_RCX,0,TY_REG+IT_I8,result_reg,0,ip);
                 done=TRUE;
             }
         }
     }
     if (!done) {
         if (tempi->ic_flags & ICF_P1_FIRST) {
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
             IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
         } else {
             IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t3,r3,d3,ip);
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t2,r2,d2,ip);
         }
         IcMov(tempi,TY_REG+IT_I8,CREG_RBX,0,TY_DISP+ptype,CREG_RCX,0,ip);
         result_reg=CREG_RBX;
         IcU1(tempi,0x48);
         IcU2(tempi,0xC000+op.u1[0]+(result_reg&7)<<11);
         IcMov(tempi,TY_DISP+ptype,CREG_RCX,0,TY_REG+IT_I8,result_reg,0,ip);
     }
 }
 if (t1&TY_MASK)
     IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,result_reg,0,ip);
}

void IcShift(IntermediateCode *tempi,U8 t1,U8 r1,I8 d1,
                   U8 t2,U8 r2,I8 d2,U8 t3,U8 r3,I8 d3,U8 us,U8 is,I8 ip)
{
 if (tempi->ic_class->sub_type&1 || tempi->ic_flags & ICF_USE_UNSIGNED)
     is=us;
 if (t3&TY_MASK==TY_IMM) {
     IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t2,r2,d2,ip);
     IcU3(tempi,0x00C148+is<<16);
     IcU1(tempi,d3);
 } else {
     if (tempi->ic_flags & ICF_P1_FIRST) {
         IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t2,r2,d2,ip);
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t3,r3,d3,ip);
     } else {
         IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t3,r3,d3,ip);
         IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t2,r2,d2,ip);
     }
     IcU3(tempi,0x00D348+is<<16);
 }
 IcMov(tempi,t1,r1,d1,TY_REG+IT_I8,CREG_RAX,0,ip);
}

void IcShiftEqual(IntermediateCode *tempi,U8 ptype,U8 t1,U8 r1,I8 d1,
                   U8 t2,U8 r2,I8 d2,U8 t3,U8 r3,I8 d3,U8 us,U8 is,I8 ip)
{
 I8 result_reg;
 if (tempi->ic_class->sub_type&1 || tempi->ic_flags & ICF_USE_UNSIGNED)
     is=us;
 if (tempi->ic_flags & ICF_NOT_ADDRESS) {
     if (tempi->ic_flags & ICF_P1_FIRST) {
         if (t2&TY_MASK==TY_REG)
             result_reg=r2;
         else {
             result_reg=CREG_RAX;
             IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t2&TY_MASK+ptype,r2,d2,ip);
         }
         if (t3&TY_MASK!=TY_IMM)
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t3,r3,d3,ip);
     } else {
         if (t3&TY_MASK!=TY_IMM)
             IcMov(tempi,TY_REG+IT_I8,CREG_RCX,0,t3,r3,d3,ip);
         if (t2&TY_MASK==TY_REG)
             result_reg=r2;
         else {
             result_reg=CREG_RAX;
             IcMov(tempi,TY_REG+IT_I8,CREG_RAX,0,t2&TY_MASK+ptype,r2,d2,ip);
         }
     }
     if (result_reg>7)
         IcU1(tempi,0x49);
     else