U0 ICAndBranch(CIntermediateCode *tmpi, I64 rip, I64 is, U8 *buf, I64 rip2)
{
	U64			 i;
	I64			 it, t1, r1, d1, r2;
	Bool		 short_jmp, swap, override;
	CCodeMisc	*lb;
	CICArg		*arg1, *arg2;

	if (tmpi->arg1.type & MDF_IMM)
	{
		swap = TRUE;
		arg1 = &tmpi->arg2;
		arg2 = &tmpi->arg1;
	}
	else
	{
		swap = FALSE;
		arg1 = &tmpi->arg1;
		arg2 = &tmpi->arg2;
	}

	if (arg2->type & MDF_IMM && arg2->disp > U32_MAX)
		override = TRUE;
	else
		override = FALSE;

	if (arg1->type.raw_type < arg2->type.raw_type)
		it = arg1->type.raw_type;
	else
		it = arg2->type.raw_type;

	i = arg2->disp;
	if (arg2->type & MDF_IMM && i <= U32_MAX)
	{
		ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, arg1->type, arg1->reg, arg1->disp, rip2);
		if (i <= U8_MAX)
			ICU16(tmpi, i << 8 + 0xA8);
		else if (i <= U16_MAX)
			ICU32(tmpi, i << 16 + 0xA900 + OC_OP_SIZE_PREFIX);
		else
		{
			ICU8(tmpi, 0xA9);
			ICU32(tmpi, i);
		}
	}
	else
	{
		t1 = MDF_REG + it;
		d1 = 0;
		if (swap && !override)
		{
			if (arg1->type & MDF_REG)
			{
				r1 = arg1->reg;
				swap = TRUE;
			}
			else
			{
				r1 = REG_RCX;
				swap = FALSE;
			}
			if (arg2->type & MDF_REG)
			{
				r2 = arg2->reg;
				swap = FALSE;
			}
			else
				r2 = REG_RDX;
			if (swap)
			{
				if (!(arg1->type & MDF_REG) || r1 != arg1->reg)
					ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
				if (arg2->type & MDG_REG_DISP_SIB_RIP)
				{
					t1 = arg2->type & MDG_MASK + it;
					r2 = arg2->reg;
					d1 = arg2->disp;
				}
				else
					ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
				i = ICModr1(r1, t1, r2, d1);
			}
			else
			{
				if (arg1->type & MDG_REG_DISP_SIB_RIP)
				{
					t1 = arg1->type & MDG_MASK + it;
					r1 = arg1->reg;
					d1 = arg1->disp;
				}
				else
					ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
				if (!(arg2->type & MDF_REG) || r2 != arg2->reg)
					ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
				i = ICModr1(r2, t1, r1, d1);
			}
		}
		else
		{
			if (arg2->type & MDF_REG)
			{
				r2 = arg2->reg;
				swap = FALSE;
			}
			else
			{
				r2 = REG_RDX;
				swap = TRUE;
			}
			if (arg1->type & MDF_REG)
			{
				r1 = arg1->reg;
				swap = TRUE;
			}
			else
				r1 = REG_RCX;
			if (override)
				swap = FALSE;
			if (swap)
			{
				if (arg2->type & MDG_REG_DISP_SIB_RIP)
				{
					t1 = arg2->type & MDG_MASK + it;
					r2 = arg2->reg;
					d1 = arg2->disp;
				}
				else
					ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
				if (!(arg1->type & MDF_REG) || r1 != arg1->reg)
					ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
				i = ICModr1(r1, t1, r2, d1);
			}
			else
			{
				if (!(arg2->type & MDF_REG) || r2 != arg2->reg)
					ICMov(tmpi, MDF_REG + RT_I64, r2, 0, arg2->type, arg2->reg, arg2->disp, rip2);
				if (arg1->type & MDG_REG_DISP_SIB_RIP)
				{
					t1 = arg1->type & MDG_MASK + it;
					r1 = arg1->reg;
					d1 = arg1->disp;
				}
				else
					ICMov(tmpi, MDF_REG + RT_I64, r1, 0, arg1->type, arg1->reg, arg1->disp, rip2);
				i = ICModr1(r2, t1, r1, d1);
			}
		}
		switch (it)
		{
			case RT_I8:
			case RT_U8:
				ICRex(tmpi, i.u8[1]);
				ICU16(tmpi, i.u8[2] << 8 + 0x84);
				break;

			case RT_U16:
			case RT_I16:
				ICOpSizeRex(tmpi, i.u8[1]);
				ICU16(tmpi, i.u8[2] << 8 + 0x85);
				break;

			default:
				ICRex(tmpi, i.u8[1]);
				ICU16(tmpi, i.u8[2] << 8 + 0x85);
		}
		ICModr2(tmpi, i,, d1, rip2);
	}

	rip += tmpi->ic_count;
	lb = OptLabelFwd(tmpi->ic_data);
	short_jmp = ToBool(tmpi->ic_flags & ICF_SHORT_JMP);
	if (!buf && lb->addr != INVALID_PTR)
	{
		i = lb->addr - (rip + 2);
		if (lb->flags & CMF_POP_CMP)
			i += 8;
		if (I8_MIN <= i <= I8_MAX)
			short_jmp = TRUE;
	}

	if (short_jmp)
	{
		tmpi->ic_flags |= ICF_SHORT_JMP;
		i = lb->addr - (rip + 2);
		if (lb->flags & CMF_POP_CMP)
			i += 8;
		ICU16(tmpi, i << 8 + is.u8[2]);
	}
	else
	{
		tmpi->ic_flags &= ~ICF_SHORT_JMP;
		i = lb->addr - (rip + 6);
		if (lb->flags & CMF_POP_CMP)
			i += 8;
		ICU16(tmpi, is.u16[0]);
		ICU32(tmpi, i);
	}
}

U0 ICAssign(CIntermediateCode *tmpi, I64 rip)
{
	CIntermediateCode *tmpi1;

	if (tmpi->ic_flags & ICF_BY_VAL)
	{
		ICMov(tmpi, tmpi->arg1.type & MDG_MASK + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp,
			  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
		if (tmpi->res.type.mode)
			ICMov(tmpi, tmpi->res.type & MDG_MASK + tmpi->arg1_type_pointed_to, tmpi->res.reg, tmpi->res.disp,
				  tmpi->arg1.type & MDG_MASK + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp, rip);
	}
	else
	{
		if (tmpi->arg1.type & MDF_REG)
		{
			if (!(tmpi1 = OptLag1(tmpi)) || tmpi1->ic_code != IC_ADD_CONST ||
				tmpi1->res.type != MDF_REG + RT_I64 || tmpi1->res.reg != tmpi->arg1.reg ||
				tmpi1->arg1.type != MDF_REG + RT_I64 ||
				tmpi1->arg1.reg != tmpi->arg1.reg ||
				(tmpi->arg2.type & MDF_REG || tmpi->arg2.type & MDF_DISP) &&
				tmpi->arg2.reg == tmpi->arg1.reg ||
				tmpi->res.type.mode || tmpi1->ic_flags & ~ICG_NO_CONVERT_MASK)
			{
				ICMov(tmpi, MDF_DISP + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp,
					  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
				if (tmpi->res.type.mode)
					ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp,
						  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
			}
			else
			{
				tmpi->ic_flags = (tmpi->ic_flags | tmpi1->ic_flags) & ~ICF_CODE_FINAL | ICF_DONT_RESTORE;
				tmpi->arg1.disp = tmpi1->ic_data;
				OptSetNOP1(tmpi1); //This better not be last pass!
				ICMov(tmpi, MDF_DISP + tmpi->arg1_type_pointed_to, tmpi->arg1.reg, tmpi->arg1.disp,
					  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
			}
		}
		else
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip);
			ICMov(tmpi, MDF_DISP + tmpi->arg1_type_pointed_to, REG_RCX, 0,
				  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
			if (tmpi->res.type.mode)
				ICMov(tmpi, tmpi->res.type, tmpi->res.reg, tmpi->res.disp,
					  tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip);
		}
	}
}

U0 ICBrBitOps(CIntermediateCode *tmpi, I64 rip, I64 op, I64 op_imm, I64 is, U8 *buf, I64 rip2)
{
	I64			 i, t, r1, r2, d1, d2, t1, t2;
	CICArg		*arg1 = &tmpi->arg1, *arg2 = &tmpi->arg2;
	Bool		 short_jmp;
	CCodeMisc	*lb;

	if (tmpi->ic_flags & ICF_BY_VAL)
	{
		if (tmpi->ic_flags & ICF_SWAP && !(arg2->type & MDF_REG) &&
			(!(arg2->type & MDF_IMM) || arg2->disp > 63) ||
			!(tmpi->ic_flags & ICF_SWAP) && arg2->type & MDF_IMM &&
			arg2->disp < 64 || arg2->type & MDF_STACK)
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, arg2->type, arg2->reg, arg2->disp, rip2);
			t2 = MDF_REG+RT_I64;
			r2 = REG_RCX;
			d2 = 0;
		}
		else
		{
			t2 = arg2->type;
			if (t2 & MDF_IMM && arg2->disp < 64)
				r2 = 0;
			else
				r2 = arg2->reg;
			d2 = arg2->disp;
		}
		if (!(tmpi->ic_flags & ICF_SWAP) && !(arg1->type & MDF_REG) &&
			(!(arg1->type & MDF_IMM) || arg1->disp > 63) ||
			tmpi->ic_flags & ICF_SWAP && arg1->type & MDF_IMM &&
			arg1->disp < 64 || arg1->type & MDF_STACK)
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, arg1->type, arg1->reg, arg1->disp, rip2);
			t1 = MDF_REG+RT_I64;
			r1 = REG_RDX;
			d1 = 0;
		}
		else
		{
			t1 = arg1->type;
			if (t1 & MDF_IMM && arg1->disp < 64)
				r1 = 0;
			else
				r1 = arg1->reg;
			d1 = arg1->disp;
		}
	}
	else
	{
		t1 = MDF_DISP + RT_I64;
		t2 = MDF_DISP + RT_I64;
		d1 = 0;
		d2 = 0;
		if (arg2->type & MDF_REG)
			r2 = arg2->reg;
		else if (!(tmpi->ic_flags & ICF_SWAP) || !(arg2->type & MDF_IMM) || arg2->disp > 63)
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, arg2->type, arg2->reg, arg2->disp, rip2);
			r2 = REG_RCX;
		}
		else
			r2 = 0;
		if (arg1->type & MDF_REG)
			r1 = arg1->reg;
		else if (tmpi->ic_flags & ICF_SWAP || !(arg1->type & MDF_IMM) || arg1->disp > 63)
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, arg1->type, arg1->reg, arg1->disp, rip2);
			r1 = REG_RDX;
		}
		else
			r1 = 0;
	}
	if (tmpi->ic_flags & ICF_LOCK && op != 0xA30F)
		ICU8(tmpi, OC_LOCK_PREFIX);
	if (tmpi->ic_flags & ICF_SWAP)
	{
		if (arg2->type & MDF_IMM && arg2->disp < 32)
		{
			if (op == 0xA30F && arg2->disp < 8)
			{
				t = t1 & MDG_MASK+RT_U8;
				op_imm = 0xF6; //TEST
			}
			else
				t = t1 & MDG_MASK + RT_U32;
		}
		else
			t = t1;
		i = ICModr1(r2, t, r1, d1);
		SwapI64(&arg1, &arg2);
	}
	else
	{
		if (arg1->type & MDF_IMM && arg1->disp < 32)
		{
			if (op == 0xA30F && arg1->disp < 8)
			{
				t = t2 & MDG_MASK + RT_U8;
				op_imm = 0xF6; //TEST
			}
			else
				t = t2 & MDG_MASK + RT_U32;
		}
		else
			t = t2;
		i = ICModr1(r1, t, r2, d2);
	}
	ICRex(tmpi, i.u8[1]);
	if (op_imm == 0xF6)
	{//TEST
		ICU16(tmpi, i.u8[2] << 8 + op_imm);
		ICModr2(tmpi, i,, arg2->disp, rip2 + 1);
		ICU8(tmpi, 1 << arg1->disp);
		if (is == 0x72820F)
			is = 0x75850F;
		else
			is = 0x74840F;
	}
	else if (arg1->type & MDF_IMM && arg1->disp < 64)
	{
		ICU24(tmpi, i.u8[2] << 16 + op_imm);
		ICModr2(tmpi, i,, arg2->disp, rip2 + 1);
		ICU8(tmpi, arg1->disp);
	}
	else
	{
		ICU24(tmpi, i.u8[2] << 16 + op);
		ICModr2(tmpi, i,, arg2->disp, rip2);
	}

	rip += tmpi->ic_count;
	lb = OptLabelFwd(tmpi->ic_data);
	short_jmp = ToBool(tmpi->ic_flags & ICF_SHORT_JMP);
	if (!buf && lb->addr != INVALID_PTR)
	{
		i = lb->addr - (rip + 2);
		if (lb->flags & CMF_POP_CMP)
			i += 8;
		if (I8_MIN <= i <= I8_MAX)
			short_jmp = TRUE;
	}

	if (short_jmp)
	{
		tmpi->ic_flags |= ICF_SHORT_JMP;
		i = lb->addr - (rip + 2);
		if (lb->flags & CMF_POP_CMP)
			i += 8;
		ICU16(tmpi, i << 8 + is.u8[2]);
	}
	else
	{
		tmpi->ic_flags &= ~ICF_SHORT_JMP;
		i = lb->addr - (rip + 6);
		if (lb->flags & CMF_POP_CMP)
			i += 8;
		ICU16(tmpi, is.u16[0]);
		ICU32(tmpi, i);
	}
}

U0 ICQueueInit(CIntermediateCode *tmpi, I64 rip2)
{
	I64 r1;

	if (tmpi->arg1.type == MDF_REG + RT_I64)
		r1 = tmpi->arg1.reg;
	else
	{
		ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
		r1 = REG_RAX;
	}
	ICMov(tmpi, MDF_DISP + RT_I64, r1, 0,			 MDF_REG + RT_I64, r1, 0, rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, r1, sizeof(U8 *), MDF_REG + RT_I64, r1, 0, rip2);
}

U0 ICQueueInsert(CIntermediateCode *tmpi, I64 rip2)
{
	I64 r1, r2;

	if (tmpi->arg2.type == MDF_REG + RT_I64 && tmpi->arg2.reg != REG_RDX)
		r2 = tmpi->arg2.reg;
	else
	{
		ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
		r2 = REG_RAX;
	}
	if (tmpi->arg1.type == MDF_REG + RT_I64)
		r1 = tmpi->arg1.reg;
	else
	{
		ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
		r1 = REG_RDX;
	}
	ICMov(tmpi, MDF_REG  + RT_I64, REG_RBX,	0,				MDF_DISP + RT_I64, r1,		0, rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, r1,		0,				MDF_REG  + RT_I64, r2,		0, rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, r2,		0,				MDF_REG  + RT_I64, REG_RBX,	0, rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, r2,		sizeof(U8 *),	MDF_REG  + RT_I64, r1,		0, rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, REG_RBX,	sizeof(U8 *),	MDF_REG  + RT_I64, r2,		0, rip2);
}

U0 ICQueueInsertRev(CIntermediateCode *tmpi, I64 rip2)
{
	I64 r1, r2;

	if (tmpi->arg2.type == MDF_REG + RT_I64 && tmpi->arg2.reg != REG_RDX)
		r2 = tmpi->arg2.reg;
	else
	{
		ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
		r2 = REG_RAX;
	}
	if (tmpi->arg1.type == MDF_REG + RT_I64)
		r1 = tmpi->arg1.reg;
	else
	{
		ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
		r1 = REG_RDX;
	}
	ICMov(tmpi, MDF_REG  + RT_I64, REG_RBX,	0,				MDF_DISP + RT_I64,	r1,			sizeof(U8 *),	rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, REG_RBX,	0,				MDF_REG  + RT_I64,	r2,			0,				rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, r2,		0,				MDF_REG  + RT_I64,	r1,			0,				rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, r2,		sizeof(U8 *),	MDF_REG  + RT_I64,	REG_RBX,	0,				rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, r1,		sizeof(U8 *),	MDF_REG  + RT_I64,	r2,			0,				rip2);
}

U0 ICQueueRemove(CIntermediateCode *tmpi, I64 rip2)
{
	I64 r1;

	if (tmpi->arg1.type == MDF_REG+RT_I64)
		r1 = tmpi->arg1.reg;
	else
	{
		ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
		r1 = REG_RAX;
	}
	ICMov(tmpi, MDF_REG + RT_I64, REG_RBX, 0, MDF_DISP + RT_I64, r1, 0, rip2);
	ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, MDF_DISP + RT_I64, r1, sizeof(U8 *), rip2);
	ICU24(tmpi, 0x1A8948);
	ICU32(tmpi, sizeof(U8 *) << 24 + 0x538948);
}

U0 ICMinMax(CIntermediateCode *tmpi, I64 op, I64 rip2)
{
	I64 r1, i1 = 0x48;

	if (tmpi->arg2.type == MDF_REG + RT_I64 && tmpi->arg2.reg != REG_RAX)
	{
		r1 = tmpi->arg2.reg;
		if (r1 > 7)
		{
			i1++;
			r1 &= 7;
		}
		ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
	}
	else
	{
		if (tmpi->arg1.reg == REG_RAX && tmpi->arg1.type & MDG_REG_DISP_SIB)
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
			r1 = REG_RDX;
			ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
		}
		else
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
			if (tmpi->arg1.type == MDF_REG + RT_I64)
			{
				r1 = tmpi->arg1.reg;
				if (r1 > 7)
				{
					i1++;
					r1 &= 7;
				}
			}
			else
			{
				r1 = REG_RDX;
				ICMov(tmpi, MDF_REG + RT_I64, REG_RDX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
			}
		}
	}
	ICU24(tmpi, 0xC03B00   + r1 << 16 + i1);
	ICU32(tmpi, 0xC0000F00 + op << 16 + r1 << 24 + i1);
}

U0 ICSqr(CIntermediateCode *tmpi, I64 op, I64 rip2)
{
	ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
	ICSlashOp(tmpi, MDF_REG + RT_I64, REG_RAX, 0, op, rip2);
}

U0 ICModU64(CIntermediateCode *tmpi, I64 rip2)
{
	CICType	t1;
	I64		r1, d1;

	ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
	if (tmpi->arg1.reg != REG_RAX && tmpi->arg1.reg != REG_RDX &&
		tmpi->arg1.type & MDG_REG_DISP_SIB &&
		tmpi->arg1.type.raw_type >= RT_I64)
	{
		t1 = tmpi->arg1.type;
		r1 = tmpi->arg1.reg;
		d1 = tmpi->arg1.disp;
	}
	else
	{
		t1 = MDF_REG + RT_I64;
		r1 = REG_RBX;
		d1 = 0;
		ICMov(tmpi, MDF_REG + RT_I64, REG_RBX, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
	}
	ICMov(tmpi, MDF_REG + RT_I64, REG_RAX, 0, MDF_DISP + RT_I64, REG_RCX, 0, rip2);
	ICZero(tmpi, REG_RDX);
	ICSlashOp(tmpi, t1, r1, d1, SLASH_OP_DIV, rip2);
	ICMov(tmpi, MDF_DISP + RT_I64, REG_RCX, 0, MDF_REG + RT_I64, REG_RAX, 0, rip2);
	ICMov(tmpi, MDF_REG  + RT_I64, REG_RAX, 0, MDF_REG + RT_I64, REG_RDX, 0, rip2);
}

U0 ICSwap(CIntermediateCode *tmpi, I64 rip2)
{
	I64 r1, r2;

	if (tmpi->arg1.type & MDF_REG)
		r1 = tmpi->arg1.reg;
	else
		r1 = REG_RAX;
	if (tmpi->arg2.type & MDF_REG)
		r2 = tmpi->arg2.reg;
	else
		r2 = REG_RAX;
	if (r1 == r2)
	{
		if (r1 == REG_RAX)
			r1 = REG_RBX;
		else
			r2 = REG_RAX;
	}
	ICMov(tmpi, MDF_REG + RT_I64, r2, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
	ICMov(tmpi, MDF_REG + RT_I64, r1, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
	switch (tmpi->ic_code)
	{
		case IC_SWAP_U8:
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX,	0, MDF_DISP + RT_U8,  r1,		0, rip2);
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX,	0, MDF_DISP + RT_U8,  r2,		0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U8,  r2,		0, MDF_REG  + RT_I64, REG_RCX,	0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U8,  r1,		0, MDF_REG  + RT_I64, REG_RDX,	0, rip2);
			break;

		case IC_SWAP_U16:
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX,	0, MDF_DISP + RT_U16, r1,		0, rip2);
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX,	0, MDF_DISP + RT_U16, r2,		0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U16, r2,		0, MDF_REG  + RT_I64, REG_RCX,	0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U16, r1,		0, MDF_REG  + RT_I64, REG_RDX,	0, rip2);
			break;

		case IC_SWAP_U32:
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX,	0, MDF_DISP + RT_U32, r1,		0, rip2);
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX,	0, MDF_DISP + RT_U32, r2,		0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U32, r2,		0, MDF_REG  + RT_I64, REG_RCX,	0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U32, r1,		0, MDF_REG  + RT_I64, REG_RDX,	0, rip2);
			break;

		case IC_SWAP_I64:
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RCX,	0, MDF_DISP + RT_U64, r1,		0, rip2);
			ICMov(tmpi, MDF_REG  + RT_I64, REG_RDX,	0, MDF_DISP + RT_U64, r2,		0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U64, r2,		0, MDF_REG  + RT_I64, REG_RCX,	0, rip2);
			ICMov(tmpi, MDF_DISP + RT_U64, r1,		0, MDF_REG  + RT_I64, REG_RDX,	0, rip2);
			break;
	}
}

U0 ICAndEqu(CIntermediateCode *tmpi, I64 rip2)
{
	I64 i, bit;

	if (tmpi->arg2.type & MDF_IMM && !(tmpi->arg1.type & MDF_STACK) && tmpi->ic_flags & ICF_RES_NOT_USED)
	{
		i = ~tmpi->arg2.disp;
		bit = Bsf(i);
		if (0 <= bit == Bsr(i))
		{
			tmpi->arg2.disp = bit;
			tmpi->arg2.reg = 0;
			tmpi->arg1.type = tmpi->arg1.type & MDG_MASK + RT_I64;
			ICBitOps(tmpi, &tmpi->arg2, &tmpi->arg1, tmpi, 0xB30F, 0x30BA0F, rip2);
			return;
		}
	}
	ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type,tmpi->res.reg, tmpi->res.disp,
				   tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp,
				   tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp,
				   0x210425240423, rip2);
}

U0 ICOrEqu(CIntermediateCode *tmpi, I64 rip2)
{
	I64 i, bit;

	if (tmpi->arg2.type & MDF_IMM && !(tmpi->arg1.type & MDF_STACK) && tmpi->ic_flags & ICF_RES_NOT_USED)
	{
		i = tmpi->arg2.disp;
		bit = Bsf(i);
		if (0 <= bit == Bsr(i) && i > I8_MAX)
		{
			tmpi->arg2.disp = bit;
			tmpi->arg2.reg = 0;
			tmpi->arg1.type = tmpi->arg1.type & MDG_MASK + RT_I64;
			ICBitOps(tmpi, &tmpi->arg2, &tmpi->arg1, tmpi, 0xAB0F, 0x28BA0F, rip2);
			return;
		}
	}
	ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg, tmpi->res.disp,
				   tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp,
				   tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp,
				   0x09010D0C010B, rip2);
}

U0 ICXorEqu(CIntermediateCode *tmpi, I64 rip2)
{
	I64 i, bit;

	if (tmpi->arg2.type & MDF_IMM && !(tmpi->arg1.type & MDF_STACK) && tmpi->ic_flags & ICF_RES_NOT_USED)
	{
		i = tmpi->arg2.disp;
		bit = Bsf(i);
		if (0 <= bit == Bsr(i))
		{
			tmpi->arg2.disp = bit;
			tmpi->arg2.reg = 0;
			tmpi->arg1.type = tmpi->arg1.type & MDG_MASK + RT_I64;
			ICBitOps(tmpi, &tmpi->arg2, &tmpi->arg1, tmpi, 0xBB0F, 0x38BA0F, rip2);
			return;
		}
	}
	ICAddSubEctEqu(tmpi, tmpi->arg1_type_pointed_to, tmpi->res.type, tmpi->res.reg,tmpi->res.disp,
				   tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp,
				   tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp,
				   0x310635340633, rip2);
}

U0 ICSwitch(CIntermediateCode *tmpi, I64 rip, Bool nobound, CCompCtrl *cc, U8 *buf, I64 rip2)
{
	I64			 i, j, count, min, max, begin, r;
	CCodeMisc	*lb;
	Bool		 short_jmp;
	CAOTAbsAddr	*tmpa;

	if (!(tmpi->arg1.type & MDF_REG) || tmpi->arg1.reg & 7 == REG_RSP)
		r = REG_RDX;
	else
		r = tmpi->arg1.reg;
	if (nobound)
		ICMov(tmpi, MDF_REG + RT_I64, r, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
	else
	{
		if (tmpi->arg2.type & MDF_IMM)
		{
			j = tmpi->arg2.disp;
			ICMov(tmpi, MDF_REG + RT_I64, r, 0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
			if (I8_MIN <= j <= I8_MAX)
			{
				i = 0xF88348 + (r & 7) << 16;
				if (r > 7)
					i++;
				ICU24(tmpi, i);
				ICU8(tmpi, j);
			}
			else if (I32_MIN <= j <= I32_MAX)
			{
				i = 0xF88148 + (r & 7) << 16;
				if (r > 7)
					i++;
				ICU24(tmpi, i);
				ICU32(tmpi, j);
			}
			else
			{
				ICMov(tmpi, MDF_REG + RT_I64, REG_RCX, 0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
				i = 0xC13B48 + (r & 7) << 19;
				if (r > 7)
					i += 4;
				ICU24(tmpi, i);
			}
		}
		else
		{
			ICMov(tmpi, MDF_REG + RT_I64, REG_RCX,	0, tmpi->arg2.type, tmpi->arg2.reg, tmpi->arg2.disp, rip2);
			ICMov(tmpi, MDF_REG + RT_I64, r,		0, tmpi->arg1.type, tmpi->arg1.reg, tmpi->arg1.disp, rip2);
			i = 0xC13B48 + (r & 7) << 19;
			if (r > 7)
				i += 4;
			ICU24(tmpi, i);
		}

		rip += tmpi->ic_count;
		lb = tmpi->ic_data(CCodeMisc *)->default;
		short_jmp = ToBool(tmpi->ic_flags & ICF_SHORT_JMP);
		if (!buf && lb->addr != INVALID_PTR)
		{
			i = lb->addr - (rip + 2);
			if (I8_MIN <= i <= I8_MAX)
				short_jmp = TRUE;
		}
		if (short_jmp)
		{
			tmpi->ic_flags |= ICF_SHORT_JMP;
			ICU16(tmpi, (lb->addr - (rip + 2)) << 8 + 0x73);
		}
		else
		{
			tmpi->ic_flags &= ~ICF_SHORT_JMP;
			ICU16(tmpi, 0x830F);
			ICU32(tmpi, lb->addr - (rip + 6));
		}
	}

	lb = tmpi->ic_data;
	begin = lb->begin->addr;
	if (!buf && begin != INVALID_PTR)
	{
		min = I64_MAX;
		max = I64_MIN;
		for (i = 0; i < lb->range; i++)
		{
			if (lb->jmp_table[i]->addr == INVALID_PTR)
			{
				min = I64_MIN;
				max = I64_MAX;
				break;
			}
			else
			{
				j = lb->jmp_table[i]->addr-begin;
				min = MinI64(min, j);
				max = MaxI64(max, j);
			}
		}
		if (I8_MIN <= min <= max <= I8_MAX)
			lb->flags |= CMF_I8_JMP_TABLE;
		else if (U8_MIN <= min <= max <= U8_MAX)
			lb->flags |= CMF_U8_JMP_TABLE;
		else if (I16_MIN <= min <= max <= I16_MAX)
			lb->flags |= CMF_I16_JMP_TABLE;
		else if (U16_MIN <= min <= max <= U16_MAX)
			lb->flags |= CMF_U16_JMP_TABLE;
	}

	if (lb->flags & CMF_I8_JMP_TABLE)
	{
		if (r < 8)
			ICU8(tmpi, 0x48);
		else
			ICU8(tmpi, 0x49);
		ICU24(tmpi, 0x98BE0F + (r & 7) << 16);
		count = 1;
	}
	else if (lb->flags & CMF_U8_JMP_TABLE)
	{
		if (r < 8)
			count = 2;
		else
		{
			ICU8(tmpi, 0x49);
			count = 1;
		}
		ICU24(tmpi, 0x98B60F + (r & 7) << 16);
	}
	else if (lb->flags & CMF_I16_JMP_TABLE)
	{
		if (r < 8)
			ICU8(tmpi, 0x48);
		else
			ICU8(tmpi, 0x4A);
		ICU32(tmpi, 0x451CBF0F + (r & 7) << 27);
		count = 0;
	}
	else if (lb->flags & CMF_U16_JMP_TABLE)
	{
		if (r < 8)
			count = 1;
		else {
			ICU8(tmpi, 0x4A);
			count = 0;
		}
		ICU32(tmpi, 0x451CB70F + (r & 7) << 27);
	}
	else
	{
		if (r < 8)
			count = 2;
		else {
			ICU8(tmpi, 0x42);
			count = 1;
		}
		ICU24(tmpi, 0x851C8B + (r & 7) << 19);
	}
	if (buf && cc->flags & CCF_AOT_COMPILE)
	{
		tmpa = CAlloc(sizeof(CAOTAbsAddr));
		tmpa->next = cc->aotc->abss;
		tmpa->type = AAT_ADD_U32;
		cc->aotc->abss = tmpa;
		tmpa->rip = rip2 + tmpi->ic_count;
		ICU32(tmpi, lb->addr + cc->aotc->rip);
	}
	else
		ICU32(tmpi, lb->addr+buf);

	if (lb->flags & (CMF_I8_JMP_TABLE | CMF_U8_JMP_TABLE | CMF_I16_JMP_TABLE | CMF_U16_JMP_TABLE))
	{
		ICU16(tmpi, 0xC381); //ADD EBX,0x12345678
		if (buf && cc->flags & CCF_AOT_COMPILE)
		{
			tmpa = CAlloc(sizeof(CAOTAbsAddr));
			tmpa->next = cc->aotc->abss;
			tmpa->type = AAT_ADD_U32;
			cc->aotc->abss = tmpa;
			tmpa->rip = rip2 + tmpi->ic_count;
			ICU32(tmpi, begin + cc->aotc->rip);
		}
		else
			ICU32(tmpi, begin + buf);
	}
	else
		count += 6;
	ICU16(tmpi, 0xE3FF); //JMP EBX
	for (i = 0; i < count; i++) //Code must always shrink, not expand
		ICU8(tmpi, OC_NOP);
	tmpi->ic_flags &= ~ICF_CODE_FINAL;
}

U0 ICLocalVarInit(CIntermediateCode *tmpi)
{
	ICU24(tmpi, 0xC48B48);
	ICU16(tmpi, 0x5748);
	ICU24(tmpi, 0xF88B48);
	ICU24(tmpi, 0xC1C748);
	ICU32(tmpi, tmpi->ic_data);
	ICU16(tmpi, sys_var_init_val << 8 + 0xB0);
	ICU24(tmpi, 0xAA48F3);
	ICU16(tmpi, 0x5F48);
}
