ULong arm64g_calculate_flags_nzcv ( ULong cc_op, ULong cc_dep1,
ULong cc_dep2, ULong cc_dep3 );
-//ZZ /* Calculate the C flag from the thunk components, in the lowest bit
-//ZZ of the word (bit 0). */
-//ZZ extern
-//ZZ UInt armg_calculate_flag_c ( UInt cc_op, UInt cc_dep1,
-//ZZ UInt cc_dep2, UInt cc_dep3 );
-//ZZ
+/* Calculate the C flag from the thunk components, in the lowest bit
+ of the word (bit 0). */
+extern
+ULong arm64g_calculate_flag_c ( ULong cc_op, ULong cc_dep1,
+ ULong cc_dep2, ULong cc_dep3 );
+
//ZZ /* Calculate the V flag from the thunk components, in the lowest bit
//ZZ of the word (bit 0). */
//ZZ extern
OP_ADD64 argL argR unused
OP_SUB32 argL argR unused
OP_SUB64 argL argR unused
-//ZZ OP_ADC argL argR 31x0:old_C
-//ZZ OP_SBB argL argR 31x0:old_C
+ OP_ADC32 argL argR 63x0:old_C
+ OP_ADC64 argL argR 63x0:old_C
+ OP_SBC32 argL argR 63x0:old_C
+ OP_SBC64 argL argR 63x0:old_C
OP_LOGIC32 result unused unused
OP_LOGIC64 result unused unused
//ZZ OP_MUL result unused 30x0:old_C:old_V
ARM64G_CC_OP_SUB64, /* DEP1 = argL (Rn), DEP2 = argR (shifter_op),
DEP3 = 0 */
-//ZZ ARMG_CC_OP_ADC, /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
-//ZZ DEP3 = oldC (in LSB) */
-//ZZ
-//ZZ ARMG_CC_OP_SBB, /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
-//ZZ DEP3 = oldC (in LSB) */
+ ARM64G_CC_OP_ADC32, /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
+ DEP3 = oldC (in LSB) */
+
+ ARM64G_CC_OP_ADC64, /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
+ DEP3 = oldC (in LSB) */
+
+ ARM64G_CC_OP_SBC32, /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
+ DEP3 = oldC (in LSB) */
+
+ ARM64G_CC_OP_SBC64, /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
+ DEP3 = oldC (in LSB) */
ARM64G_CC_OP_LOGIC32, /* DEP1 = result, DEP2 = 0, DEP3 = 0 */
ARM64G_CC_OP_LOGIC64, /* DEP1 = result, DEP2 = 0, DEP3 = 0 */
ULong nf = res >> 63;
return nf;
}
-//ZZ case ARMG_CC_OP_ADC: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt res = argL + argR + oldC;
-//ZZ UInt nf = res >> 31;
-//ZZ return nf;
-//ZZ }
-//ZZ case ARMG_CC_OP_SBB: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt res = argL - argR - (oldC ^ 1);
-//ZZ UInt nf = res >> 31;
-//ZZ return nf;
-//ZZ }
+ case ARM64G_CC_OP_ADC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ UInt res = argL + argR + oldC;
+ ULong nf = (ULong)(res >> 31);
+ return nf;
+ }
+ case ARM64G_CC_OP_ADC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong res = argL + argR + oldC;
+ ULong nf = res >> 63;
+ return nf;
+ }
+ case ARM64G_CC_OP_SBC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ UInt res = argL - argR - (oldC ^ 1);
+ ULong nf = (ULong)(res >> 31);
+ return nf;
+ }
+ case ARM64G_CC_OP_SBC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong res = argL - argR - (oldC ^ 1);
+ ULong nf = res >> 63;
+ return nf;
+ }
case ARM64G_CC_OP_LOGIC32: {
/* (res, unused, unused) */
UInt res = (UInt)cc_dep1;
ULong zf = res == 0;
return zf;
}
-//ZZ case ARMG_CC_OP_ADC: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt res = argL + argR + oldC;
-//ZZ UInt zf = res == 0;
-//ZZ return zf;
-//ZZ }
-//ZZ case ARMG_CC_OP_SBB: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt res = argL - argR - (oldC ^ 1);
-//ZZ UInt zf = res == 0;
-//ZZ return zf;
-//ZZ }
+ case ARM64G_CC_OP_ADC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ UInt res = argL + argR + oldC;
+ ULong zf = res == 0;
+ return zf;
+ }
+ case ARM64G_CC_OP_ADC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong res = argL + argR + oldC;
+ ULong zf = res == 0;
+ return zf;
+ }
+ case ARM64G_CC_OP_SBC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ UInt res = argL - argR - (oldC ^ 1);
+ ULong zf = res == 0;
+ return zf;
+ }
+ case ARM64G_CC_OP_SBC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong res = argL - argR - (oldC ^ 1);
+ ULong zf = res == 0;
+ return zf;
+ }
case ARM64G_CC_OP_LOGIC32: {
/* (res, unused, unused) */
UInt res = (UInt)cc_dep1;
/* CALLED FROM GENERATED CODE: CLEAN HELPER */
/* Calculate the C flag from the supplied thunk components, in the
least significant bit of the word. Returned bits 63:1 are zero. */
-static
ULong arm64g_calculate_flag_c ( ULong cc_op, ULong cc_dep1,
ULong cc_dep2, ULong cc_dep3 )
{
ULong cf = argL >= argR;
return cf;
}
-//ZZ case ARMG_CC_OP_ADC: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt res = argL + argR + oldC;
-//ZZ UInt cf = oldC ? (res <= argL) : (res < argL);
-//ZZ return cf;
-//ZZ }
-//ZZ case ARMG_CC_OP_SBB: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt cf = oldC ? (argL >= argR) : (argL > argR);
-//ZZ return cf;
-//ZZ }
+ case ARM64G_CC_OP_ADC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ UInt res = argL + argR + oldC;
+ ULong cf = oldC ? (res <= argL) : (res < argL);
+ return cf;
+ }
+ case ARM64G_CC_OP_ADC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong res = argL + argR + oldC;
+ ULong cf = oldC ? (res <= argL) : (res < argL);
+ return cf;
+ }
+ case ARM64G_CC_OP_SBC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong cf = oldC ? (argL >= argR) : (argL > argR);
+ return cf;
+ }
+ case ARM64G_CC_OP_SBC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong cf = oldC ? (argL >= argR) : (argL > argR);
+ return cf;
+ }
case ARM64G_CC_OP_LOGIC32:
case ARM64G_CC_OP_LOGIC64: {
/* (res, unused, unused) */
ULong vf = (((argL ^ argR) & (argL ^ res))) >> 63;
return vf;
}
-//ZZ case ARMG_CC_OP_ADC: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt res = argL + argR + oldC;
-//ZZ UInt vf = ((res ^ argL) & (res ^ argR)) >> 31;
-//ZZ return vf;
-//ZZ }
-//ZZ case ARMG_CC_OP_SBB: {
-//ZZ /* (argL, argR, oldC) */
-//ZZ UInt argL = cc_dep1;
-//ZZ UInt argR = cc_dep2;
-//ZZ UInt oldC = cc_dep3;
-//ZZ vassert((oldC & ~1) == 0);
-//ZZ UInt res = argL - argR - (oldC ^ 1);
-//ZZ UInt vf = ((argL ^ argR) & (argL ^ res)) >> 31;
-//ZZ return vf;
-//ZZ }
+ case ARM64G_CC_OP_ADC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ UInt res = argL + argR + oldC;
+ ULong vf = (ULong)(((res ^ argL) & (res ^ argR)) >> 31);
+ return vf;
+ }
+ case ARM64G_CC_OP_ADC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong res = argL + argR + oldC;
+ ULong vf = ((res ^ argL) & (res ^ argR)) >> 63;
+ return vf;
+ }
+ case ARM64G_CC_OP_SBC32: {
+ /* (argL, argR, oldC) */
+ UInt argL = cc_dep1;
+ UInt argR = cc_dep2;
+ UInt oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ UInt res = argL - argR - (oldC ^ 1);
+ ULong vf = (ULong)(((argL ^ argR) & (argL ^ res)) >> 31);
+ return vf;
+ }
+ case ARM64G_CC_OP_SBC64: {
+ /* (argL, argR, oldC) */
+ ULong argL = cc_dep1;
+ ULong argR = cc_dep2;
+ ULong oldC = cc_dep3;
+ vassert((oldC & ~1) == 0);
+ ULong res = argL - argR - (oldC ^ 1);
+ ULong vf = ((argL ^ argR) & (argL ^ res)) >> 63;
+ return vf;
+ }
case ARM64G_CC_OP_LOGIC32:
case ARM64G_CC_OP_LOGIC64: {
/* (res, unused, unused) */
}
-//ZZ /* Build IR to calculate just the carry flag from stored
-//ZZ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
-//ZZ Ity_I32. */
-//ZZ static IRExpr* mk_armg_calculate_flag_c ( void )
-//ZZ {
-//ZZ IRExpr** args
-//ZZ = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
-//ZZ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
-//ZZ IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
-//ZZ IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
-//ZZ IRExpr* call
-//ZZ = mkIRExprCCall(
-//ZZ Ity_I32,
-//ZZ 0/*regparm*/,
-//ZZ "armg_calculate_flag_c", &armg_calculate_flag_c,
-//ZZ args
-//ZZ );
-//ZZ /* Exclude OP and NDEP from definedness checking. We're only
-//ZZ interested in DEP1 and DEP2. */
-//ZZ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
-//ZZ return call;
-//ZZ }
-//ZZ
-//ZZ
+/* Build IR to calculate just the carry flag from stored
+ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
+ Ity_I64. */
+static IRExpr* mk_arm64g_calculate_flag_c ( void )
+{
+ IRExpr** args
+ = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I64),
+ IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
+ IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
+ IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
+ IRExpr* call
+ = mkIRExprCCall(
+ Ity_I64,
+ 0/*regparm*/,
+ "arm64g_calculate_flag_c", &arm64g_calculate_flag_c,
+ args
+ );
+ /* Exclude OP and NDEP from definedness checking. We're only
+ interested in DEP1 and DEP2. */
+ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
+ return call;
+}
+
+
//ZZ /* Build IR to calculate just the overflow flag from stored
//ZZ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
//ZZ Ity_I32. */
setFlags_D1_D2_ND(cc_op, argL64, argR64, z64);
}
+/* Build IR to set the flags thunk after ADC or SBC. */
+static
+void setFlags_ADC_SBC ( Bool is64, Bool isSBC,
+ IRTemp argL, IRTemp argR, IRTemp oldC )
+{
+ IRTemp argL64 = IRTemp_INVALID;
+ IRTemp argR64 = IRTemp_INVALID;
+ IRTemp oldC64 = IRTemp_INVALID;
+ if (is64) {
+ argL64 = argL;
+ argR64 = argR;
+ oldC64 = oldC;
+ } else {
+ argL64 = newTemp(Ity_I64);
+ argR64 = newTemp(Ity_I64);
+ oldC64 = newTemp(Ity_I64);
+ assign(argL64, unop(Iop_32Uto64, mkexpr(argL)));
+ assign(argR64, unop(Iop_32Uto64, mkexpr(argR)));
+ assign(oldC64, unop(Iop_32Uto64, mkexpr(oldC)));
+ }
+ UInt cc_op = ARM64G_CC_OP_NUMBER;
+ /**/ if ( isSBC && is64) { cc_op = ARM64G_CC_OP_SBC64; }
+ else if ( isSBC && !is64) { cc_op = ARM64G_CC_OP_SBC32; }
+ else if (!isSBC && is64) { cc_op = ARM64G_CC_OP_ADC64; }
+ else if (!isSBC && !is64) { cc_op = ARM64G_CC_OP_ADC32; }
+ else { vassert(0); }
+ setFlags_D1_D2_ND(cc_op, argL64, argR64, oldC64);
+}
+
/* Build IR to set the flags thunk after ADD or SUB, if the given
condition evaluates to True at run time. If not, the flags are set
to the specified NZCV value. */
}
}
+ /* ------------------- ADC/SBC(reg) ------------------- */
+ /* x==0 => 32 bit op x==1 => 64 bit op
+
+ 31 30 29 28 23 21 20 15 9 4
+ | | | | | | | | | |
+ x 0 0 11010 00 0 Rm 000000 Rn Rd ADC Rd,Rn,Rm
+ x 0 1 11010 00 0 Rm 000000 Rn Rd ADCS Rd,Rn,Rm
+ x 1 0 11010 00 0 Rm 000000 Rn Rd SBC Rd,Rn,Rm
+ x 1 1 11010 00 0 Rm 000000 Rn Rd SBCS Rd,Rn,Rm
+ */
+
+ if (INSN(28,21) == BITS8(1,1,0,1,0,0,0,0) && INSN(15,10) == 0 ) {
+ UInt bX = INSN(31,31);
+ UInt bOP = INSN(30,30); /* 0: ADC, 1: SBC */
+ UInt bS = INSN(29,29); /* set flags */
+ UInt rM = INSN(20,16);
+ UInt rN = INSN(9,5);
+ UInt rD = INSN(4,0);
+
+ Bool isSUB = bOP == 1;
+ Bool is64 = bX == 1;
+ IRType ty = is64 ? Ity_I64 : Ity_I32;
+
+ IRTemp oldC = newTemp(ty);
+ assign(oldC,
+ is64 ? mk_arm64g_calculate_flag_c()
+ : unop(Iop_64to32, mk_arm64g_calculate_flag_c()) );
+
+ IRTemp argL = newTemp(ty);
+ assign(argL, getIRegOrZR(is64, rN));
+ IRTemp argR = newTemp(ty);
+ assign(argR, getIRegOrZR(is64, rM));
+
+ IROp op = isSUB ? mkSUB(ty) : mkADD(ty);
+ IRTemp res = newTemp(ty);
+ if (isSUB) {
+ IRExpr* one = is64 ? mkU64(1) : mkU32(1);
+ IROp xorOp = is64 ? Iop_Xor64 : Iop_Xor32;
+ assign(res,
+ binop(op,
+ binop(op, mkexpr(argL), mkexpr(argR)),
+ binop(xorOp, mkexpr(oldC), one)));
+ } else {
+ assign(res,
+ binop(op,
+ binop(op, mkexpr(argL), mkexpr(argR)),
+ mkexpr(oldC)));
+ }
+
+ if (rD != 31) putIRegOrZR(is64, rD, mkexpr(res));
+
+ if (bS) {
+ setFlags_ADC_SBC(is64, isSUB, argL, argR, oldC);
+ }
+
+ DIP("%s%s %s, %s, %s\n",
+ bOP ? "sbc" : "adc", bS ? "s" : "",
+ nameIRegOrZR(is64, rD), nameIRegOrZR(is64, rN),
+ nameIRegOrZR(is64, rM));
+ return True;
+ }
+
/* -------------------- LOGIC(reg) -------------------- */
/* x==0 => 32 bit op x==1 => 64 bit op
N==0 => inv? is no-op (no inversion)