Newer
Older
// Do all DEFs have DEF_METADATA_UNUSED status?
bool SMPInstr::AllDefMetadataUnused(void) {
bool AllUnused = (this->Defs.GetSize() > 0); // false if no DEFs, true otherwise
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
AllUnused = (AllUnused
&& (DEF_METADATA_UNUSED == CurrDef->GetMetadataStatus()));
}
return AllUnused;
} // end of SMPInstr::AllDefMetadataUnused()
// DEBUG print operands for Inst.
void SMPInstr::PrintOperands(void) const {
op_t Opnd;
for (int i = 0; i < UA_MAXOP; ++i) {
Opnd = SMPcmd.Operands[i];
PrintOneOperand(Opnd, this->features, i);
}
clc5q
committed
SMP_msg(" \n");
return;
} // end of SMPInstr::PrintOperands()
// Complete DEBUG printing.
SMP_msg("%lx %d SMPitype: %d %s\n", (unsigned long) this->address, this->SMPcmd.size, (int) this->type,
DisAsmText.GetDisAsm(this->GetAddr()));
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
#if STARS_DUMP_FG_INFO
SMP_msg("USEs: ");
if (NULL == this->GetBlock()) { // during early improvement of disasm
this->Uses.Dump();
SMP_msg("DEFs: ");
this->Defs.Dump();
}
else {
set<DefOrUse, LessDefUse>::iterator UseIter, DefIter;
op_t UseOp, DefOp;
int UseHashValue, DefHashValue, UseSSANum, DefSSANum;
unsigned short SignMiscInfo, SignMask;
bool LocalName;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
UseIter->Dump();
UseOp = UseIter->GetOp();
if (o_reg == UseOp.type) {
LocalName = this->GetBlock()->IsLocalName(UseOp);
UseSSANum = UseIter->GetSSANum();
UseHashValue = HashGlobalNameAndSSA(UseOp, UseSSANum);
if (LocalName) {
SignMiscInfo = this->GetBlock()->GetUseSignMiscInfo(UseHashValue);
}
else {
SignMiscInfo = this->GetBlock()->GetFunc()->GetUseSignMiscInfo(UseHashValue);
}
SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
if (SignMask == FG_MASK_SIGNED) {
SMP_msg(" Si ");
}
else if (SignMask == FG_MASK_UNSIGNED) {
SMP_msg(" Un ");
}
else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
SMP_msg(" Xs ");
}
}
SMP_msg("\n");
}
SMP_msg("DEFs: ");
for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
DefIter->Dump();
DefOp = DefIter->GetOp();
if (o_reg == DefOp.type) {
LocalName = this->GetBlock()->IsLocalName(DefOp);
DefSSANum = DefIter->GetSSANum();
DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum);
if (LocalName) {
SignMiscInfo = this->GetBlock()->GetDefSignMiscInfo(DefHashValue);
}
else {
SignMiscInfo = this->GetBlock()->GetFunc()->GetDefSignMiscInfo(DefHashValue);
}
SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
if (SignMask == FG_MASK_SIGNED) {
SMP_msg(" Si ");
}
else if (SignMask == FG_MASK_UNSIGNED) {
SMP_msg(" Un ");
}
else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
SMP_msg(" Xs ");
}
}
SMP_msg("\n");
}
}
#else
clc5q
committed
SMP_msg("USEs: ");
this->Uses.Dump();
clc5q
committed
SMP_msg("DEFs: ");
this->Defs.Dump();
this->RTL.Dump();
#if SMP_VERBOSE_DUMP
this->PrintOperands();
#endif
clc5q
committed
SMP_msg("\n");
return;
} // end of SMPInstr::Dump()
// Print out the destination operand list for the instruction, given
// the OptCategory for the instruction as a hint.
char * SMPInstr::DestString(int OptType) {
static char DestList[MAXSTR];
DestList[0] = 'Z'; // Make sure there are no leftovers from last call
DestList[1] = 'Z';
DestList[2] = '\0';
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
op_t DefOpnd = CurrDef->GetOp();
if (DefOpnd.is_reg(X86_FLAGS_REG)) // don't print flags as a destination
continue;
// We want to ignore the stack pointer DEF for pops and just include
// the register DEF for the pop.
if (DefOpnd.is_reg(R_sp) && this->MDIsPopInstr())
continue;
if (o_reg == DefOpnd.type) {
ushort DestReg = DefOpnd.reg;
if (0 == RegDestCount) {
clc5q
committed
SMP_strncpy(DestList, RegNames[DestReg], 1 + strlen(RegNames[DestReg]));
clc5q
committed
SMP_strncat(DestList, " ", MAXSTR);
SMP_strncat(DestList, RegNames[DestReg], MAXSTR);
}
++RegDestCount;
}
}
if (0 >= RegDestCount) {
clc5q
committed
SMP_msg("WARNING: No destination registers: %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
SMP_strncat(DestList, " ZZ ", MAXSTR);
}
return DestList;
} // end of SMPInstr::DestString()
clc5q
committed
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
// print the registers that are dead right before this instruction.
void SMPInstr::PrintDeadRegs(FILE *OutputFile) {
size_t RegNum = (size_t) MD_FLAGS_REG;
// Start with the flags register.
if (this->DeadRegsBitmap[RegNum]) {
SMP_fprintf(OutputFile, "%s ", RegNames[RegNum]);
}
// Do all other registers
for (RegNum = 0; RegNum < MD_FLAGS_REG; ++RegNum) {
if (this->DeadRegsBitmap[RegNum]) {
SMP_fprintf(OutputFile, "%s ", RegNames[RegNum]);
}
}
for (RegNum = 1 + MD_FLAGS_REG; RegNum <= MD_LAST_REG_NO; ++RegNum) {
if (this->DeadRegsBitmap[RegNum]) {
SMP_fprintf(OutputFile, "%s ", RegNames[RegNum]);
}
}
// Print sequence terminator.
SMP_fprintf(OutputFile, "ZZ");
return;
} // end of SMPInstr::PrintDeadRegs()
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
// Equality operator for SMPInstr. Key field is address.
int SMPInstr::operator==(const SMPInstr &rhs) const {
if (this->address != rhs.GetAddr())
return 0;
else
return 1;
}
// Inequality operator for SMPInstr. Key field is address.
int SMPInstr::operator!=(const SMPInstr &rhs) const {
return (this->address != rhs.GetAddr());
}
// Less than operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<(const SMPInstr &rhs) const {
return (this->address < rhs.GetAddr());
}
// Less than or equal operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<=(const SMPInstr &rhs) const {
return (this->address <= rhs.GetAddr());
}
#define MD_FIRST_ENTER_INSTR NN_enterw
#define MD_LAST_ENTER_INSTR NN_enterq
// Is this instruction one that allocates space on the
// stack for the local variables?
bool SMPInstr::MDIsFrameAllocInstr(void) {
// The frame allocating instruction should look like:
// sub esp,48 or add esp,-64 etc.
op_t ESPOp = InitOp;
ESPOp.type = o_reg;
ESPOp.reg = R_sp;
if ((SMPcmd.itype == NN_sub) || (SMPcmd.itype == NN_add)) {
if (this->GetLastDef() != this->Defs.FindRef(ESPOp)) {
// We know that an addition or subtraction is being
// performed on the stack pointer. This should not be
// possible within the prologue except at the stack
// frame allocation instruction, so return true. We
// could be more robust in this analysis in the future. **!!**
// CAUTION: If a compiler allocates 64 bytes for locals
// and 16 bytes for outgoing arguments in a single
// instruction: sub esp,80
// you cannot insist on finding sub esp,LocSize
// To make this more robust, we are going to insist that
// an allocation of stack space is either performed by
// adding a negative immediate value, or by subtracting
// a positive immediate value. We will throw in, free of
// charge, a subtraction of a register, which is how alloca()
// usually allocates stack space.
// PHASE ORDERING: Should we use the Operands[] instead of the USE list? **!!**
set<DefOrUse, LessDefUse>::iterator CurrUse;
for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
if (o_imm == CurrUse->GetOp().type) {
signed long TempImm = (signed long) CurrUse->GetOp().value;
if (((0 > TempImm) && (this->SMPcmd.itype == NN_add))
|| ((0 < TempImm) && (this->SMPcmd.itype == NN_sub))) {
return true;
}
}
else if ((o_reg == CurrUse->GetOp().type)
&& (!CurrUse->GetOp().is_reg(R_sp)) // skip the ESP operand
&& (this->SMPcmd.itype == NN_sub)) { // sub esp,reg: alloca() ?
return true;
}
}
}
}
else if ((this->SMPcmd.itype >= MD_FIRST_ENTER_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_ENTER_INSTR)) {
return true;
}
return false;
} // end of SMPInstr::MDIsFrameAllocInstr()
#define MD_FIRST_LEAVE_INSTR NN_leavew
#define MD_LAST_LEAVE_INSTR NN_leaveq
// Is this instruction in the epilogue the one that deallocates the local
// vars region of the stack frame?
bool SMPInstr::MDIsFrameDeallocInstr(bool UseFP, asize_t LocalVarsSize) {
// The usual compiler idiom for the prologue on x86 is to
// deallocate the local var space with: mov esp,ebp
// It could be add esp,constant. We can be tricked by
// add esp,constant when the constant is just the stack
// adjustment after a call. We will have to insist that
// the immediate operand have at least the value of
// LocalVarsSize for this second form, and that UseFP be true
// for the first form.
set<DefOrUse, LessDefUse>::iterator FirstDef = this->GetFirstDef();
set<DefOrUse, LessDefUse>::iterator FirstUse = this->GetFirstUse();
if ((SMPcmd.itype >= MD_FIRST_LEAVE_INSTR) && (SMPcmd.itype <= MD_LAST_LEAVE_INSTR))
return true;
else if (this->HasDestMemoryOperand() || this->HasSourceMemoryOperand()) {
// Don't get fooled by USE or DEF entries of EBP or ESP that come
// from memory operands, e.g. mov eax,[ebp-20]
return false;
}
else if (UseFP && (this->SMPcmd.itype == NN_mov)
&& (FirstDef->GetOp().is_reg(MD_STACK_POINTER_REG))
&& (FirstUse->GetOp().is_reg(MD_FRAME_POINTER_REG)))
return true;
else if ((this->SMPcmd.itype == NN_add)
&& (FirstDef->GetOp().is_reg(MD_STACK_POINTER_REG))) {
set<DefOrUse, LessDefUse>::iterator SecondUse = ++FirstUse;
if (SecondUse == this->Uses.GetLastRef())
return false; // no more USEs ... strange for ADD instruction
if (SecondUse->GetOp().is_imm((uval_t) LocalVarsSize))
return true;
else if (SecondUse->GetOp().type == o_imm) {
signed long TempImm = (signed long) this->SMPcmd.Operands[1].value;
if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc
return false;
else {
clc5q
committed
SMP_msg("Used imprecise LocalVarsSize to find dealloc instr.\n");
return true;
}
}
else
return false;
}
else
return false;
} // end of SMPInstr::MDIsFrameDeallocInstr()
// Is instruction a no-op? There are 1-byte, 2-byte, etc., versions of no-ops.
bool SMPInstr::MDIsNop(void) const {
bool IsNop = false;
ushort opcode = this->SMPcmd.itype;
// NOTE: More examples have arisen, e.g. xchg reg with itself. !!!!!!
if (NN_nop == opcode)
else if ((NN_mov == opcode) || (NN_xchg == opcode)) {
if ((o_reg == this->SMPcmd.Operands[0].type)
&& this->SMPcmd.Operands[1].is_reg(this->SMPcmd.Operands[0].reg)) {
// We have a register to register move with source == destination,
// or a register exchanged with itself.
IsNop = true;
}
}
else if (NN_lea == opcode) {
if ((o_reg == this->SMPcmd.Operands[0].type)
&& (o_displ == this->SMPcmd.Operands[1].type)
&& (0 == this->SMPcmd.Operands[1].addr)) {
// We are looking for 6-byte no-ops like lea esi,[esi+0]
ushort destreg = this->SMPcmd.Operands[0].reg;
if ((this->SMPcmd.Operands[1].hasSIB)
&& (destreg == (ushort) sib_base(this->SMPcmd.Operands[1]))
&& (R_sp == sib_index(this->SMPcmd.Operands[1]))) {
// R_sp signifies no SIB index register. So, we have
// lea reg,[reg+0] with reg being the same in both place,
// once as Operands[0] and once as the base reg in Operands[1].
IsNop = true;
}
else if (destreg == this->SMPcmd.Operands[1].reg) {
IsNop = true;
}
}
}
return IsNop;
} // end of SMPInstr::MDIsNop()
// Opcode always produces an UNSIGNED DEF.
bool SMPInstr::MDAlwaysUnsignedDEF(void) const {
ushort opcode = this->SMPcmd.itype;
return ((opcode == NN_bsf) || (opcode == NN_bsr) || (opcode == NN_div)
|| (opcode == NN_lahf) || (opcode == NN_lar) || (opcode == NN_lgs)
|| (opcode == NN_lss) || (opcode == NN_lds) || (opcode == NN_les)
|| (opcode == NN_lfs) || (opcode == NN_lsl) || (opcode == NN_movzx)
|| (opcode == NN_rcl) || (opcode == NN_rcr) || (opcode == NN_rol)
|| (opcode == NN_ror) || (opcode == NN_shl) || (opcode == NN_shr)
|| ((opcode >= NN_seta) && (opcode <= NN_setz)) || (opcode == NN_cpuid)
|| (opcode == NN_rdtsc) || (opcode == NN_rdpmc) || (opcode == NN_fstsw)
|| (opcode == NN_setalc) || (opcode == NN_packuswb) || (opcode == NN_paddusb)
|| (opcode == NN_paddusw) || (opcode == NN_psllw) || (opcode == NN_pslld)
|| (opcode == NN_psllq) || (opcode == NN_psrlw) || (opcode == NN_psrld)
|| (opcode == NN_psrlq) || (opcode == NN_psubusb) || (opcode == NN_psubusw)
|| (opcode == NN_pxor) || (opcode == NN_pavgusb) || (opcode == NN_pavgb)
|| (opcode == NN_pavgw) || (opcode == NN_pextrw) || (opcode == NN_pmaxub)
|| ((opcode >= NN_pminub) && (opcode <= NN_psadbw))
|| (opcode == NN_movmskpd) || (opcode == NN_pmuludq) || (opcode == NN_pslldq)
|| (opcode == NN_psrldq) || ((opcode >= NN_pabsb) && (opcode <= NN_pabsd))
|| (opcode == NN_rdtscp) || (opcode == NN_mpsadbw) || (opcode == NN_packusdw)
|| ((opcode >= NN_pcmpeqq) && (opcode <= NN_phminposuw)) || (opcode == NN_pmaxud)
|| (opcode == NN_pmaxuw) || (opcode == NN_pminud) || (opcode == NN_pminuw)
|| ((opcode >= NN_pmovzxbw) && (opcode <= NN_pmovzxdq)) || ((opcode >= NN_crc32)
&& (opcode <= NN_pcmpistrm)) || (opcode == NN_popcnt) || (opcode == NN_lzcnt)
|| ((opcode >= NN_aesenc) && (opcode <= NN_aeskeygenassist)));
} // end of SMPInstr::MDAlwaysUnsignedDEF()
// Opcode always produces a SIGNED DEF.
bool SMPInstr::MDAlwaysSignedDEF(void) const {
ushort opcode = this->SMPcmd.itype;
return ((opcode == NN_cbw) || (opcode == NN_cwde) || (opcode == NN_cdqe)
|| (opcode == NN_cwd) || (opcode == NN_cdq) || (opcode == NN_cqo)
|| (opcode == NN_idiv) || (opcode == NN_movsx) || (opcode == NN_neg)
|| (opcode == NN_sal) || (opcode == NN_sar) || (opcode == NN_fist)
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
|| (opcode == NN_fistp) || (opcode == NN_fbstp) || (opcode == NN_packsswb)
|| (opcode == NN_packssdw) || (opcode == NN_paddsb) || (opcode == NN_paddsw)
|| (opcode == NN_pmaddwd) || (opcode == NN_pmulhw) || (opcode == NN_pmullw)
|| (opcode == NN_psraw) || (opcode == NN_psrad) || (opcode == NN_psubsb)
|| (opcode == NN_psubsw) || (opcode == NN_pfadd) || (opcode == NN_pfsub)
|| (opcode == NN_pfsubr) || (opcode == NN_pfacc) || (opcode == NN_pfmin)
|| (opcode == NN_pfmax) || (opcode == NN_pf2id) || (opcode == NN_pfrcp)
|| (opcode == NN_pfadd) || (opcode == NN_pfrsqrt) || (opcode == NN_pfmul)
|| (opcode == NN_pfrcpit1) || (opcode == NN_pfrsqit1) || (opcode == NN_pfrcpit2)
|| (opcode == NN_pmulhrw) || ((opcode >= NN_addps) && (opcode <= NN_andps))
|| ((opcode >= NN_cvtpi2ps) && (opcode <= NN_divss)) || ((opcode >= NN_maxps)
&& (opcode <= NN_movlps)) || ((opcode >= NN_movss) && (opcode <= NN_sqrtss))
|| (opcode == NN_subps) || (opcode == NN_subss) || (opcode == NN_unpckhps)
|| (opcode == NN_unpcklps) || (opcode == NN_pmaxsw) || (opcode == NN_pminsw)
|| (opcode == NN_movntps) || (opcode == NN_pf2iw) || (opcode == NN_pfnacc)
|| (opcode == NN_pfpnacc) || (opcode == NN_pi2fw) || ((opcode >= NN_addpd)
&& (opcode <= NN_andpd)) || ((opcode >= NN_cvtdq2pd) && (opcode <= NN_divsd))
|| (opcode == NN_maxpd) || (opcode == NN_maxsd) || ((opcode >= NN_minpd)
&& (opcode <= NN_movapd)) || (opcode == NN_movhpd) || (opcode == NN_movlpd)
|| (opcode == NN_movntpd) || ((opcode >= NN_movsd) && (opcode <= NN_orpd))
|| ((opcode >= NN_sqrtpd) && (opcode <= NN_subsd)) && ((opcode >= NN_unpckhpd)
&& (opcode <= NN_xorpd)) || ((opcode >= NN_movddup) && (opcode <= NN_movsxd))
|| ((opcode >= NN_addsubpd) && (opcode <= NN_hsubps)) || (opcode == NN_fisttp)
|| ((opcode >= NN_psignb) && (opcode <= NN_psignd)) || ((opcode >= NN_pmulhrsw)
&& (opcode <= NN_phsubd)) || (opcode == NN_pfrcpv) || (opcode == NN_pfrsqrtv)
|| ((opcode >= NN_blendpd) && (opcode <= NN_insertps)) || (opcode == NN_pmaxsb)
|| (opcode == NN_pmaxsd) || (opcode == NN_pminsb) || (opcode == NN_pminsd)
|| ((opcode >= NN_pmovsxbw) && (opcode <= NN_pmovsxdq)) || (opcode == NN_pmuldq)
|| (opcode == NN_pmulld) || ((opcode >= NN_roundpd) && (opcode <= NN_roundss))
|| (opcode == NN_movntsd) || (opcode == NN_movntss));
} // end of SMPInstr::MDAlwaysSignedDEF()
bool SMPInstr::MDIsAddition(void) const {
unsigned short opcode = this->SMPcmd.itype;
clc5q
committed
bool FoundAddition = ((NN_adc == opcode) || (NN_add == opcode));
clc5q
committed
if (this->MDIsLoadEffectiveAddressInstr()) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if (CurrRT->HasRightSubTree()) {
CurrRT = CurrRT->GetRightTree();
FoundAddition = (SMP_ADD == CurrRT->GetOperator());
}
}
return FoundAddition;
// Is non-multiply arithmetic instruction that can possibly overflow?
bool SMPInstr::MDIsOverflowingOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
|| (NN_neg == opcode) || (NN_xadd == opcode));
}
// Is non-multiply arithmetic instruction that can possibly underflow?
bool SMPInstr::MDIsUnderflowingOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}
clc5q
committed
// Is potentially benign overflow instruction?
bool SMPInstr::MDIsMaybeBenignOverflowOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_adc == opcode) || (NN_add == opcode));
}
// Is potentially benign underflow instruction?
bool SMPInstr::MDIsMaybeBenignUnderflowOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_neg == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}
clc5q
committed
// Is definitely benign underflow instruction?
// NOTE: Overlaps with MDIsMaybeBenignUnderflowOpcode(), so call this one first.
bool SMPInstr::MDIsDefiniteBenignUnderflowOpcode(int &IdiomCode) {
clc5q
committed
unsigned short opcode = this->SMPcmd.itype;
// gcc use: sbb edx,edx as a tricky way to get all zeroes or all ones into edx.
clc5q
committed
// (Some sort of saturation? Often treated as 0 or -1, i.e. it becomes SIGNED
// even if it used to be UNSIGNED.)
clc5q
committed
// The "underflow" on the subtraction is irrelevant and benign.
bool benign = ((NN_sbb == opcode) && (this->SubtractsFromItself()));
if (benign) {
IdiomCode = 4;
}
return benign;
clc5q
committed
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
}
// Does a subtraction operator get applied to same left and right operands?
bool SMPInstr::SubtractsFromItself(void) {
bool SelfSubtract = false;
size_t RTLCount = this->RTL.GetCount();
for (size_t index = 0; index < RTLCount; ++index) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOp = CurrRT->GetOperator();
if ((SMP_SUBTRACT_BORROW == CurrOp) || (SMP_SUBTRACT == CurrOp)) {
if (!(CurrRT->HasRightSubTree())) {
// NOTE: Must change this code when we build more precise SMP_SUBTRACT_BORROW RTL.
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
SelfSubtract = IsEqOp(RightOp, LeftOp);
}
break;
}
}
}
return SelfSubtract;
} // end of SMPInstr::SubtractsFromItself()
// Does instruction subtract an immediate value that is often used in ASCII computations,
// such as the ASCII code for '0', 'a', or 'A' ?
bool SMPInstr::SubtractsImmedASCII(void) {
return (this->MDIsMaybeBenignUnderflowOpcode() && (o_imm == this->AddSubSourceOp.type)
&& (('0' == this->AddSubSourceOp.value) || ('a' == this->AddSubSourceOp.value)
|| ('A' == this->AddSubSourceOp.value)));
}
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
// Does instruction compare a location to an immediate value that is often used in ASCII computations,
// such as the ASCII code for '0' or '9', 'a' or 'A', 'z' or 'Z', or carriage return?
#define SMP_ASCII_CARRIAGE_RETURN 13
bool SMPInstr::MDComparesImmedASCII(void) {
bool ComparesToASCII = false;
if (this->SMPcmd.itype == NN_cmp) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) {
CurrRT = CurrRT->GetRightTree();
if (!(CurrRT->HasRightSubTree())) {
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if ((o_imm == RightOp.type) && ((SMP_ASCII_CARRIAGE_RETURN == RightOp.value)
|| ('0' == RightOp.value) || ('9' == RightOp.value)
|| ('a' == RightOp.value) || ('z' == RightOp.value)
|| ('A' == RightOp.value) || ('Z' == RightOp.value))) {
ComparesToASCII = true;
}
}
}
}
return ComparesToASCII;
} // end of SMPInstr::MDComparesImmedASCII()
// Multiply by large constant; overflow is probably intentional.
#define STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD 0x20000000
#define STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD 0x10000000
#define STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD))
bool SMPInstr::IsMultiplyByLargeConstant(uval_t &ConstValue, unsigned short SignMask) {
bool LargeConstFound = false;
if (this->MDIsMultiply() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
set<DefOrUse, LessDefUse>::iterator UseIter;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
if (this->FindConstantValue(UseIter, ConstValue)) {
if (FG_MASK_UNSIGNED == SignMask) {
if (((uval_t) STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD) <= ConstValue) {
LargeConstFound = true;
break;
}
}
else if (FG_MASK_SIGNED == SignMask) {
int SignedConstValue = (int) ConstValue;
if ( (((int) STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD) <= SignedConstValue)
|| (((int) STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD) >= SignedConstValue)) {
LargeConstFound = true;
break;
}
}
}
}
}
return LargeConstFound;
} // end of SMPInstr::IsMultiplyByLargeConstant()
// Subtraction of large constant; underflow is probably intentional.
#define STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD 0x80000000
#define STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD 0x40000000
#define STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD))
bool SMPInstr::IsSubtractionOfLargeConstant(uval_t &ConstValue, unsigned short SignMask) {
bool LargeConstFound = false;
if (this->MDIsUnderflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
op_t SubtrahendOp = this->AddSubSourceOp;
if (o_void != SubtrahendOp.type) {
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SubtrahendOp);
if (this->FindConstantValue(UseIter, ConstValue)) {
if (FG_MASK_UNSIGNED == SignMask) {
if (((uval_t) STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD) <= ConstValue) {
LargeConstFound = true;
}
}
else if (FG_MASK_SIGNED == SignMask) {
int SignedConstValue = (int) ConstValue;
if ( (((int) STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD) <= SignedConstValue)
|| (((int) STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD) >= SignedConstValue)) {
LargeConstFound = true;
}
}
}
}
}
return LargeConstFound;
} // end of SMPInstr::IsSubtractionOfLargeConstant()
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
// Subtraction of large constant; underflow is probably intentional.
#define STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD 0x80000000
#define STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD 0x40000000
#define STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD))
bool SMPInstr::IsAdditionOfLargeConstant(uval_t &ConstValue, unsigned short SignMask) {
bool LargeConstFound = false;
if (this->MDIsOverflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
op_t AddendOp = this->AddSubSourceOp;
if (o_void != AddendOp.type) {
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(AddendOp);
if (this->FindConstantValue(UseIter, ConstValue)) {
if (FG_MASK_UNSIGNED == SignMask) {
if (((uval_t) STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD) <= ConstValue) {
LargeConstFound = true;
}
}
else if (FG_MASK_SIGNED == SignMask) {
int SignedConstValue = (int) ConstValue;
if ( (((int) STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD) <= SignedConstValue)
|| (((int) STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD) >= SignedConstValue)) {
LargeConstFound = true;
}
}
}
}
}
return LargeConstFound;
} // end of SMPInstr::IsAdditionOfLargeConstant()
// MACHINE DEPENDENT: Is instruction a return instruction?
bool SMPInstr::MDIsReturnInstr(void) const {
return ((this->SMPcmd.itype == NN_retn) || (this->SMPcmd.itype == NN_retf));
}
// MACHINE DEPENDENT: Is instruction a POP instruction?
#define FIRST_POP_INST NN_pop
#define LAST_POP_INST NN_popfq
bool SMPInstr::MDIsPopInstr(void) const {
return ((this->SMPcmd.itype >= FIRST_POP_INST)
&& (this->SMPcmd.itype <= LAST_POP_INST));
}
// MACHINE DEPENDENT: Is instruction a PUSH instruction?
#define FIRST_PUSH_INST NN_push
#define LAST_PUSH_INST NN_pushfq
bool SMPInstr::MDIsPushInstr(void) const {
return ((this->SMPcmd.itype >= FIRST_PUSH_INST)
&& (this->SMPcmd.itype <= LAST_PUSH_INST));
}
// MACHINE DEPENDENT: Is instruction an ENTER instruction?
bool SMPInstr::MDIsEnterInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_ENTER_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_ENTER_INSTR));
}
// MACHINE DEPENDENT: Is instruction a LEAVE instruction?
bool SMPInstr::MDIsLeaveInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_LEAVE_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_LEAVE_INSTR));
// MACHINE DEPENDENT: Is instruction a HALT instruction?
bool SMPInstr::MDIsHaltInstr(void) const {
return (NN_hlt == this->SMPcmd.itype);
}
#define MD_FIRST_COND_MOVE_INSTR NN_cmova
#define MD_LAST_COND_MOVE_INSTR NN_fcmovnu
// MACHINE DEPENDENT: Is instruction a conditional move?
bool SMPInstr::MDIsConditionalMoveInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_COND_MOVE_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_COND_MOVE_INSTR));
}
clc5q
committed
// MACHINE DEPENDENT: Is instruction any kind of move?
bool SMPInstr::MDIsMoveInstr(void) const {
return ((NN_mov == this->SMPcmd.itype) || (NN_movsx == this->SMPcmd.itype)
|| (NN_movzx == this->SMPcmd.itype) || this->MDIsConditionalMoveInstr());
}
// MACHINE DEPENDENT: Do opcode/operands definitely indicate signed arithmetic?
// Generally, this is only true for certain variants of multiplication and division.
bool SMPInstr::MDIsSignedArithmetic(void) const {
unsigned short opcode = this->SMPcmd.itype;
if (NN_idiv == opcode)
return true;
if (NN_imul == opcode) {
// If we discard the upper N bits of the multiplication result, then the
// lower N bits are the same for signed and unsigned multiplication, and
// gcc/g++ often use the IMUL opcode for both signed and unsigned multiplies
// when only N bits of result are retained. Therefore, the SIGNED nature of
// IMUL operands can only be inferred from the case in which 2N bits are kept.
return (!(this->AreMultiplicationBitsDiscarded()));
}
else { // idiv and imul are only possible signed cases
return false;
}
} // end of SMPInstr::MDIsSignedArithmetic()
// MACHINE DEPENDENT: Is instruction a conditional jump based on an unsigned condition?
bool SMPInstr::MDIsUnsignedBranch(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_ja == opcode) || (NN_jae == opcode) || (NN_jb == opcode) || (NN_jbe == opcode)
|| (NN_jna == opcode) || (NN_jnae == opcode) || (NN_jnb == opcode) || (NN_jnbe == opcode));
}
// MACHINE DEPENDENT: Is instruction a conditional jump based on a signed condition?
bool SMPInstr::MDIsSignedBranch(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_jg == opcode) || (NN_jge == opcode) || (NN_jl == opcode) || (NN_jle == opcode)
|| (NN_jng == opcode) || (NN_jnge == opcode) || (NN_jnl == opcode) || (NN_jnle == opcode)
|| (NN_js == opcode) || (NN_jns == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on an unsigned condition?
bool SMPInstr::MDIsUnsignedSetValue(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_seta == opcode) || (NN_setae == opcode) || (NN_setb == opcode) || (NN_setbe == opcode)
|| (NN_setna == opcode) || (NN_setnae == opcode) || (NN_setnb == opcode) || (NN_setnbe == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on a signed condition?
bool SMPInstr::MDIsSignedSetValue(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_setg == opcode) || (NN_setge == opcode) || (NN_setl == opcode) || (NN_setle == opcode)
|| (NN_setng == opcode) || (NN_setnge == opcode) || (NN_setnl == opcode) || (NN_setnle == opcode)
|| (NN_sets == opcode) || (NN_setns == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on any condition?
bool SMPInstr::MDIsAnySetValue(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_seta <= opcode) && (NN_setz >= opcode));
}
// Is kind of shift or rotate that is used in hash functions
#define STARS_HASH_SHIFT_THRESHOLD 4
bool SMPInstr::MDIsHashingArithmetic(void) const {
bool FoundHashShift = false;
unsigned short opcode = this->SMPcmd.itype;
// We are looking for shifts or rotates in the leftward direction.
if ((opcode == NN_rcl) || (opcode == NN_rol) || (opcode == NN_shl) || (opcode == NN_shld)) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
assert(CurrRT->HasRightSubTree());
CurrRT = CurrRT->GetRightTree();
op_t ShiftCountOp = CurrRT->GetRightOperand();
if (o_imm == ShiftCountOp.type) {
uval_t CountValue = ShiftCountOp.value;
FoundHashShift = (CountValue >= STARS_HASH_SHIFT_THRESHOLD);
}
}
return FoundHashShift;
} // end of SMPInstr::MDIsHashingArithmetic()
clc5q
committed
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
// Detect comparison of non-immediate to immediate. Return the two operands if true.
bool SMPInstr::MDIsCompareToPositiveConstant(op_t &NonConstOperand, uval_t &ConstValue) const {
bool CompareToConst = false;
if (NN_cmp == this->SMPcmd.itype) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
assert(CurrRT->HasRightSubTree());
CurrRT = CurrRT->GetRightTree();
assert(!(CurrRT->HasRightSubTree()));
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
CompareToConst = true;
ConstValue = RightOp.value;
NonConstOperand = LeftOp;
}
else if (o_imm == LeftOp.type) { // rare to see immediate first
CompareToConst = true;
ConstValue = LeftOp.value;
NonConstOperand = RightOp;
}
}
return CompareToConst;
} // end of SMPInstr::MDIsCompareToPositiveConstant()
bool SMPInstr::MDIsSubtractionOfConstant(op_t &NonConstOperand, uval_t &ConstValue) const {
bool SubtractOfConst = false;
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if (CurrRT->HasRightSubTree()) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOp = CurrRT->GetOperator();
if (SMP_SUBTRACT == CurrOp) {
assert(!(CurrRT->HasRightSubTree()));
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
SubtractOfConst = true;
ConstValue = RightOp.value;
NonConstOperand = LeftOp;
}
}
clc5q
committed
else if (this->MDIsLoadEffectiveAddressInstr() && (SMP_ADD == CurrOp)) {
// We could have an addition of a negative constant via an lea opcode,
// e.g. lea ecx,[eax-48] will look like ecx := eax+(-48) in the RTL.
if (!(CurrRT->HasRightSubTree())) {
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
ConstValue = RightOp.value;
int SignedConstValue = (int) ConstValue;
if (0 > SignedConstValue) {
SubtractOfConst = true;
NonConstOperand = LeftOp;
ConstValue = (uval_t)(-SignedConstValue); // make +(-x) into -(+x)
}
}
}
}
clc5q
committed
}
return SubtractOfConst;
} // end of SMPInstr::MDIsSubtractionOfConstant()
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
// is AND operation that masks off lower BytesMasked bytes
bool SMPInstr::MDIsSubregMaskInst(size_t &BytesMasked) {
bool MaskingFound = false;
if (this->MDIsBitwiseAndOpcode()) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if (CurrRT->HasRightSubTree()) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOp = CurrRT->GetOperator();
assert(SMP_BITWISE_AND == CurrOp);
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
uval_t MaskValue = RightOp.value;
if (0x01000000 > MaskValue) {
MaskingFound = true;
if (0x100 > MaskValue) {
BytesMasked = 1;
}
else if (0x10000 > MaskValue) {
BytesMasked = 2;
}
else {
BytesMasked = 3;
}
}
}
}
}
return MaskingFound;
}
// MACHINE DEPENDENT: Does instruction use a callee-saved register?
bool SMPInstr::MDUsesCalleeSavedReg(void) {
set<DefOrUse, LessDefUse>::iterator CurrUse;
for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
op_t CurrOp = CurrUse->GetOp();
if (CurrOp.is_reg(MD_FRAME_POINTER_REG) || CurrOp.is_reg(R_si)
|| CurrOp.is_reg(R_di) || CurrOp.is_reg(R_bx)) {
return true;
}
}
return false;
} // end of SMPInstr::MDUsesCalleeSavedReg()
// Is the instruction a register to register copy of a stack pointer or frame pointer
// into a general purpose register (which mmStrata will now need to track as a stack
// relative pointer)?
bool SMPInstr::MDIsStackPointerCopy(bool UseFP) {
// OptType 3 indicates a move instruction
// The lea instruction can perform three operand arithmetic, e.g.
// lea ebx,[esp+12] is just ebx:=esp+12, so it is a stack pointer copy.
if (((this->OptType == 3) || (NN_lea == this->SMPcmd.itype))
&& (this->GetFirstDef()->GetOp().type == o_reg)
&& (!(this->GetFirstDef()->GetOp().is_reg(R_sp)))
&& (!(this->HasSourceMemoryOperand()))) { // reg to reg move
if (this->GetFirstUse()->GetOp().is_reg(MD_FRAME_POINTER_REG))
// Move of base pointer EBP into a general register
return true;
else if ((this->GetFirstUse()->GetOp().is_reg(MD_STACK_POINTER_REG))
&& !(this->GetFirstDef()->GetOp().is_reg(MD_FRAME_POINTER_REG)))
// Move of ESP into something besides a base pointer
return true;
}
else if (this->GetFirstUse()->GetOp().is_reg(MD_STACK_POINTER_REG)) {
// Move of ESP into a register; no base pointer used in this function
return true;
}
}
return false;
} // end of SMPInstr::MDIsStackPointerCopy()
// Does any RTL fit the alloca() pattern: stack_pointer -= non-immediate-operand
bool SMPInstr::HasAllocaRTL(void) {
bool FoundAlloca = false;
size_t RTLCount = this->RTL.GetCount();
size_t RTLIndex;
for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
if (CurrRT->IsAllocaRTL()) {
FoundAlloca = true;
break;
}
}
return FoundAlloca;
} // end of SMPInstr::HasAllocaRTL()
// Determine if the instruction saves or restores a pointer into the stack frame.
// If it saves a stack pointer, set Save to true, set the StackDelta saved, and set
// the operand that received the saved stack pointer into CopyOp. and return true.
// If it restores a stack pointer, set Save to false, set CopyOp to the operand that
// held the value being restored, set RestoreOp to the stack pointer or frame pointer
// register (whichever was restored), leave StackDelta alone for later computation
// based on reaching definitions, and return true.
// For most instructions, no save or restore of a stack pointer, so return false.
bool SMPInstr::MDIsStackPtrSaveOrRestore(bool UseFP, sval_t FPDelta, bool &Save, sval_t &StackDelta, op_t &CopyOp, bool &Error) {
bool StackPointerSaveOrRestore;
size_t RTLCount = this->RTL.GetCount();
size_t RTLIndex;
int BaseReg, IndexReg, CopyReg;
ushort Scale;
ea_t offset;
SMPoperator CurrOper;
bool LookUpStackDelta; // Get stack delta from reaching defs for TempOp
sval_t DeltaAdjust; // add to StackDelta after computing from reaching defs, e.g. lea esp,[ecx-4] get TempOp of ecx
// and DeltaAdjust of -4
Error = false;
for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
bool FPRestore = false; // frame pointer is restored
bool SPRestore = false; // stack pointer is restored
StackPointerSaveOrRestore = false; // default unless we detect a save or restore of the stack or frame pointer
TempOp = InitOp;
LookUpStackDelta = false;
DeltaAdjust = 0;
Save = false; // default unless we detect a stack pointer save
// The stack alignment instructions (SP := SP bitwise_and immediate_value)
// look like something that needs to be processed here, but we always ignore
// these instructions. They have a variable effect on the stack pointer, from zero
// to -15 delta, but we assume that the delta is zero. This works for us because
// no stack accesses will occur into the padding region.
// Also, any instruction that definitely does not restore the stack pointer or
// frame pointer from an arbitrary register or memory location, e.g. a leave instruction
// in x86 CPUs, is already handled in normal stack delta computations and needs
// no lookups from reaching defs, etc.
if (this->IsStackAlignmentInst() || this->MDIsLeaveInstr() || this->MDIsFrameAllocInstr()) {
break; // exit and return false
}
SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
CurrOper = CurrRT->GetOperator();
if (SMP_ASSIGN != CurrOper) {
break; // not a regular RTL
}
op_t LeftOp = CurrRT->GetLeftOperand();
if (LeftOp.is_reg(MD_STACK_POINTER_REG)) {
SPRestore = true; // temporary; might just be a push or pop RTL, etc., in which case we will reset.
}
else if (UseFP && LeftOp.is_reg(MD_FRAME_POINTER_REG)) {
FPRestore = true; // likewise temporary
}
if (!(SPRestore || FPRestore)) {
#if 0
if (LeftOp.is_reg(MD_FLAGS_REG)) {
break; // No point in looking for a save into the flags register
}
#endif
clc5q
committed
Save = true; // Maybe; keep looking for save
// If we are assigning to the stack pointer reg or the frame pointer reg, we need to analyze the right
// hand side of the RTL to see if it is a stack/frame pointer value, and not a simple push, pop, etc.
if (!(CurrRT->HasRightSubTree())) {
// Simple assignment.
op_t RightOp = CurrRT->GetRightOperand();
if ((o_reg <= RightOp.type) && (o_displ >= RightOp.type)) { // register or memory
if (RightOp.is_reg(MD_STACK_POINTER_REG)) {
// Stack pointer reg is being saved.
StackDelta = this->GetStackPtrOffset(); // LeftOp := SP, so saved delta is just current delta
CopyOp = LeftOp;
StackPointerSaveOrRestore = true;
FPRestore = false; // treat FP := SP as a save of SP rather than a restoration of FP
else if (!SPRestore && UseFP && RightOp.is_reg(MD_FRAME_POINTER_REG)) {
// Frame pointer is being saved
StackDelta = FPDelta;
CopyOp = LeftOp;
StackPointerSaveOrRestore = true;
break;
}
else if (SPRestore || FPRestore) {
// stack or frame pointer is being restored; leave Save=false and set other outgoing arguments.
TempOp = RightOp;
CopyOp = RightOp;
StackPointerSaveOrRestore = true;
LookUpStackDelta = true;
}
else { // RightOp is register or non-stack-pointer memory expr; either might hold stack delta
TempOp = RightOp;
CopyOp = LeftOp;
LookUpStackDelta = true; // See if RightOp is holding a stack delta
clc5q
committed
StackPointerSaveOrRestore = true; // Maybe; flag tells us to keep looking
}
}
else {
if (SPRestore || FPRestore) {
SMP_msg("ERROR: Invalid operand type for assignment to stack or frame pointer at %lx\n",
(unsigned long) this->GetAddr());
StackPointerSaveOrRestore = false;