Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
case SMP_COMPARE_NE_AND_SET: // Compare for not-equal and set fields to all 1's or all 0's
case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's
case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's
case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's
case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's
case SMP_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision
case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision
case SMP_AVERAGE_U: // Average of unsigned operands
case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
case SMP_MAX_S: // dest := signed_max(dest, src)
case SMP_MAX_U: // dest := unsigned_max(dest, src)
case SMP_MIN_S: // dest := signed_min(dest, src)
case SMP_MIN_U: // dest := unsigned_min(dest, src)
case SMP_ABSOLUTE_VALUE: // take absolute value
case SMP_CONVERT_INT_TO_FP: // convert integer to floating point
case SMP_CONVERT_FP_TO_INT: // convert floating point to integer
case SMP_CREATE_MASK: // Create AND-mask from operand and byte/word/dword position # in immediate
case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC
case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length
case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation
case SMP_SIGNAL: // signal or raise exception
break;
default:
SMP_msg("ERROR: SPARK: Cannot translate unknown operator: ");
SMP_msg(" %s \n", OperatorText[this->GetOperator()]);
break;
}
return;
} // end of SMPRegTransfer::EmitSPARKAda()
// Helper for right hand side of statements (i.e. RightOperand or RightTree)
void SMPRegTransfer::EmitSPARKAdaForRHS(void) const {
if (this->HasRightSubTree()) {
SMP_fprintf(ZST_SPARKSourceFile, "(");
SMPRegTransfer *RightRT = this->GetRightTree();
RightRT->EmitSPARKAda();
SMP_fprintf(ZST_SPARKSourceFile, ")");
}
else {
PrintSPARKAdaOperand(this->GetRightOperand(), ZST_SPARKSourceFile);
}
return;
} // end of SMPRegTransfer::EmitSPARKAdaForRHS()
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
// *****************************************************************
// Class SMPRTL
// *****************************************************************
// Constructor
SMPRTL::SMPRTL() {
this->ExtraKills.clear();
this->RTCount = 0;
return;
}
// Destructor
SMPRTL::~SMPRTL() {
for (size_t index = 0; index < this->RTCount; ++index) {
delete (this->RTvector[index]);
}
this->ExtraKills.clear();
return;
}
// Get methods
clc5q
committed
SMPRegTransfer *SMPRTL::GetRT(size_t index) const {
if (index > this->RTCount)
return NULL;
else
return this->RTvector[index];
}
// Set methods
void SMPRTL::push_back(SMPRegTransfer *NewEffect) {
assert(SMP_RT_LIMIT > this->RTCount);
this->RTvector[this->RTCount] = NewEffect;
++(this->RTCount);
return;
}
clc5q
committed
void SMPRTL::Dump(void) const {
size_t index;
if (0 < this->RTCount) {
clc5q
committed
SMP_msg("RTL: ");
for (index = 0; index < this->RTCount; ++index) {
this->RTvector[index]->Dump();
}
for (index = 0; index < this->ExtraKills.size(); ++index) {
clc5q
committed
SMP_msg(" KILL: ");
PrintOperand(this->ExtraKills.at(index));
}
clc5q
committed
SMP_msg("\n");
}
return;
} // end of SMPRTL::Dump()
// Accumulate stack pointer alteration total across all RTs.
clc5q
committed
sval_t SMPRTL::TotalStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
sval_t TotalDelta = 0;
sval_t IncrementalDelta;
for (size_t index = 0; index < this->RTCount; ++index) {
clc5q
committed
IncrementalDelta = this->RTvector[index]->ComputeStackPointerAlteration(IsLeaveInstr, IncomingDelta, FramePtrDelta);
if ((SMP_STACK_DELTA_ERROR_CODE == IncrementalDelta)
|| (SMP_STACK_POINTER_BITWISE_AND_CODE == IncrementalDelta)) {
TotalDelta = IncrementalDelta; // pass code back
break; // exit loop and return coded value
}
else {
TotalDelta += IncrementalDelta;
}
}
return TotalDelta;
} // end of SMPRTL::TotalStackPointerAlteration()
// *****************************************************************
// Class SMPInstr
// *****************************************************************
// Constructor for instruction.
SMPInstr::SMPInstr(ea_t addr) {
this->ResetGoodRTL();
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
this->ResetJumpTarget();
this->ResetBlockTerm();
this->ResetTailCall();
this->ResetCondTailCall();
this->ResetCallUsedAsJump();
this->ResetDirectRecursiveCall();
this->ResetInterrupt();
#else
this->booleans1 = 0;
#endif
#if 0
this->ResetNop();
this->ResetRegClearIdiom();
this->ResetDefsFlags();
this->ResetUsesFlags();
this->ResetFarBranchComputed();
this->ResetBranchesToFarChunk();
this->ResetIndirectMemWrite();
this->ResetIndirectMemRead();
#else
this->booleans2 = 0;
#endif
#if 0
this->ResetLoadFromStack();
this->ResetMultiplicationBitsDiscarded();
this->ResetTypeInferenceComplete();
this->ResetCategoryInferenceComplete();
this->ResetDEFsTyped();
this->ResetUSEsTyped();
#else
this->booleans3 = 0;
#endif
this->booleans4 = 0;
this->CallTarget = BADADDR;
this->FarBranchTarget = BADADDR;
this->AddSubSourceType = UNINIT;
clc5q
committed
this->AddSubSourceOp = InitOp;
this->DEFMemOp = InitOp;
this->USEMemOp = InitOp;
this->MoveSource = InitOp;
this->BasicBlock = NULL;
clc5q
committed
this->features = 0;
this->StackPtrOffset = 0;
clc5q
committed
this->type = DEFAULT;
this->OptType = 0;
this->Defs.clear();
this->Uses.clear();
clc5q
committed
// Destructor.
clc5q
committed
SMPInstr::~SMPInstr() {
this->Defs.clear();
this->Uses.clear();
clc5q
committed
return;
clc5q
committed
}
char *SMPInstr::GetDisasm(void) const {
return DisAsmText.GetDisAsm(this->GetAddr());
}
// Is the instruction the type that terminates a basic block?
bool SMPInstr::IsBasicBlockTerminator() const {
return ((type == JUMP) || (type == COND_BRANCH)
|| (type == INDIR_JUMP) || (type == RETURN));
}
// Get non-flags DEF, usually for arithmetic opcode.
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetFirstNonFlagsDef(void) {
set<DefOrUse, LessDefUse>::iterator DefIter;
op_t DefOp;
for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
DefOp = DefIter->GetOp();
if (!((o_reg == DefOp.type) && DefOp.is_reg(MD_FLAGS_REG)))
break; // found a non-flags-reg DEF.
}
return DefIter;
}
clc5q
committed
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
// Fetch the operands for a shift instruction
void SMPInstr::GetShiftOperands(op_t &ShiftedOp, op_t &ShiftCounterOp) {
bool success = false;
if (this->RTL.GetRT(0)->HasRightSubTree()) {
SMPRegTransfer *RightRT = this->RTL.GetRT(0)->GetRightTree();
SMPoperator RightOper = RightRT->GetOperator();
if ((RightOper == SMP_U_LEFT_SHIFT) || (RightOper == SMP_S_LEFT_SHIFT)
|| (RightOper == SMP_U_RIGHT_SHIFT) || (RightOper == SMP_S_RIGHT_SHIFT)) {
if (!(RightRT->HasRightSubTree())) {
success = true;
ShiftedOp = RightRT->GetLeftOperand();
ShiftCounterOp = RightRT->GetRightOperand();
}
}
}
if (!success) {
ShiftedOp = InitOp;
ShiftCounterOp = InitOp;
}
return;
} // end of SMPInstr::GetShiftOperands()
// Is the destination operand a memory reference?
bool SMPInstr::HasDestMemoryOperand(void) {
} // end of SMPInstr::HasDestMemoryOperand()
// Is a source operand a memory reference?
bool SMPInstr::HasSourceMemoryOperand(void) {
} // end of SMPInstr::HasSourceMemoryOperand()
// Get the first memory operand in the DEF list.
clc5q
committed
op_t SMPInstr::MDGetMemDefOp(void) const {
} // end of SMPInstr::MDGetMemDefOp()
// Get the first memory operand in the USE list.
clc5q
committed
op_t SMPInstr::MDGetMemUseOp(void) const {
} // end of SMPInstr::MDGetMemUseOp()
// return original Lea instruction [pseudo-]memory operand.
op_t SMPInstr::GetLeaMemUseOp(void) {
if (this->BasicBlock == NULL) {
return InitOp;
}
else {
map<ea_t, op_t>::iterator MapIter = this->GetBlock()->GetFunc()->FindLeaOperand(this->GetAddr());
return MapIter->second;
}
}
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
op_t SMPInstr::GetUseOnlyAddSubOp(void) const {
unsigned short opcode = this->SMPcmd.itype;
bool IsAddSubInst = ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
|| (NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
if ((this->RTL.GetCount() < 1) || (!IsAddSubInst))
return InitOp; // no RTL or not an addition or subtraction
assert(this->RTL.GetRT(0)->HasRightSubTree());
SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
op_t RightOp;
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
if ((NN_adc != this->SMPcmd.itype) && (NN_sbb != this->SMPcmd.itype)) {
assert(!(RightTree->HasRightSubTree()));
RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand
}
else {
// Add with carry and subtract with borrow have an extra level
// to the tree RTL, e.g. for add with carry:
// opnd1 := (opnd1 + (opnd2 + carryflag))
assert(RightTree->HasRightSubTree());
RightTree = RightTree->GetRightTree();
RightOp = RightTree->GetLeftOperand();
}
#else
RightOp = RightTree->GetRightOperand(); // Use (also DEF) operand
#endif
return RightOp;
}; // end of SMPInstr::GetUseOnlyAddSubOp()
op_t SMPInstr::GetDefUseAddSubOp(void) const {
unsigned short opcode = this->SMPcmd.itype;
bool IsAddSubInst = ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
|| (NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
if ((this->RTL.GetCount() < 1) || (!IsAddSubInst))
return InitOp; // no RTL or not an addition or subtraction
assert(this->RTL.GetRT(0)->HasRightSubTree());
SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
op_t LeftOp;
LeftOp = RightTree->GetLeftOperand(); // Use (also DEF) operand
return LeftOp;
}; // end of SMPInstr::GetDefUseAddSubOp()
// return BADADDR if not jump, target addr otherwise.
clc5q
committed
ea_t SMPInstr::GetJumpTarget(void) const {
ea_t TargetAddr = BADADDR;
if (this->HasGoodRTL()) {
// We want to find an RTL of the form: inst_ptr_reg := code_addr
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
op_t DefOp = CurrRT->GetLeftOperand();
if (DefOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if ((SMP_ASSIGN == CurrRT->GetOperator()) && (!CurrRT->HasRightSubTree())) {
op_t UseOp = CurrRT->GetRightOperand();
if ((o_near == UseOp.type) || (o_far == UseOp.type)) { // address
TargetAddr = UseOp.addr;
}
}
}
}
return TargetAddr;
} // end SMPInstr::GetJumpTarget()
clc5q
committed
// Does any USE have type NEGATEDPTR?
bool SMPInstr::HasNegatedPtrUSE(void) {
bool UseFound = false;
set<DefOrUse, LessDefUse>::iterator UseIter;
SMPOperandType UseType;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
UseType = UseIter->GetType();
if (IsEqType(UseType, NEGATEDPTR)) {
UseFound = true;
break;
}
}
return UseFound;
} // end of SMPInstr::HasNegatedPtrUSE()
// Detect indirect memory DEFs or USEs
void SMPInstr::AnalyzeIndirectRefs(bool UseFP) {
op_t DefMemOp = this->MDGetMemDefOp();
op_t UseMemOp = this->MDGetMemUseOp();
if (o_void != DefMemOp.type) {
// Found a memory DEF. Is it indirect?
if (MDIsIndirectMemoryOpnd(DefMemOp, UseFP)) {
this->SetIndirectMemWrite();
}
}
if (o_void != UseMemOp.type) {
// Found a memory USE. Is it indirect?
if (MDIsIndirectMemoryOpnd(UseMemOp, UseFP)) {
this->SetIndirectMemRead();
}
}
return;
} // end of SMPInstr::AnalyzeIndirectRefs()
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetPointerAddressReg(op_t MemOp) {
int BaseReg;
int IndexReg;
ushort ScaleFactor;
ea_t displacement;
set<DefOrUse, LessDefUse>::iterator PtrIter;
if ((NULL == this->BasicBlock) || (NULL == this->BasicBlock->GetFunc())) {
SMP_msg("ERROR: NULL member pointers in SMPInstr::GetPointerAddressReg() at %lx \n",
(unsigned long) this->address);
return this->GetLastUse();
}
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor,
displacement);
if ((R_none != BaseReg) && (!MDIsStackPtrReg(BaseReg, UseFP))) {
op_t BaseOp = InitOp;
BaseOp.type = o_reg;
BaseOp.reg = (ushort) BaseReg;
BaseOp.dtyp = this->GetOperandDtypField();
PtrIter = this->FindUse(BaseOp);
assert(PtrIter != this->GetLastUse());
if (IsDataPtr(PtrIter->GetType())) {
return PtrIter;
}
}
if ((R_none != IndexReg) && (!MDIsStackPtrReg(IndexReg, UseFP))) {
op_t IndexOp = InitOp;
IndexOp.type = o_reg;
IndexOp.reg = (ushort) IndexReg;
IndexOp.dtyp = this->GetOperandDtypField();
PtrIter = this->FindUse(IndexOp);
assert(PtrIter != this->GetLastUse());
if (IsDataPtr(PtrIter->GetType())) {
return PtrIter;
}
}
PtrIter = this->GetLastUse();
return PtrIter;
} // end of SMPInstr::GetPointerAddressReg()
// Does the instruction whose flags are in F have a numeric type
// as the second source operand?
// NOTE: We can only analyze immediate values now. When data flow analyses are implemented,
// we will be able to analyze many non-immediate operands.
#define IMMEDNUM_LOWER -8191
#define IMMEDNUM_UPPER 8191
bool SMPInstr::IsSecondSrcOperandNumeric(flags_t F) const {
bool SecondOpImm = (this->SMPcmd.Operands[1].type == o_imm);
uval_t TempImm;
if (SecondOpImm) {
TempImm = this->SMPcmd.Operands[1].value;
return (SecondOpImm && IsImmedNumeric(TempImm));
} // end of SMPInstr::IsSecondSrcOperandNumeric()
// Determine the type of the USE-only operand for add and subtract
// instructions. If it is NUMERIC or PROF_NUMERIC, an optimizing
// annotation will result.
// As a byproduct, find the type of the USE/DEF operand as well.
void SMPInstr::SetAddSubSourceType(void) {
// Walk the RTL and find the operands we care about.
// The RTL should look like: opnd1 := (opnd1 op opnd2), where op is
// and add or subtract operator. Within the parentheses, the type
// of opnd1 is our AddSubUseType and opnd1 is our AddSubUseOp, while
// the type of opnd2 is our AddSubSourceType.
if (this->RTL.GetCount() < 1)
return; // no RTL, no leave types as UNINIT.
assert(this->RTL.GetRT(0)->HasRightSubTree());
SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
op_t LeftOp, RightOp;
LeftOp = RightTree->GetLeftOperand(); // Use (also DEF) operand
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
if ((NN_adc != this->SMPcmd.itype) && (NN_sbb != this->SMPcmd.itype)) {
assert(!(RightTree->HasRightSubTree()));
RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand
}
else {
// Add with carry and subtract with borrow have an extra level
// to the tree RTL, e.g. for add with carry:
// opnd1 := (opnd1 + (opnd2 + carryflag))
assert(RightTree->HasRightSubTree());
RightTree = RightTree->GetRightTree();
RightOp = RightTree->GetLeftOperand();
}
#else
assert(!(RightTree->HasRightSubTree()));
RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand
#endif
set<DefOrUse, LessDefUse>::iterator UseIter, SrcIter;
SrcIter = this->FindUse(RightOp);
assert(SrcIter != this->GetLastUse());
this->AddSubSourceType = SrcIter->GetType();
this->AddSubSourceOp = RightOp;
UseIter = this->FindUse(LeftOp);
assert(UseIter != this->GetLastUse());
this->AddSubDefUseType = UseIter->GetType();
#if 0
this->AddSubDefUseOp = LeftOp;
#endif
return;
} // end of SMPInstr::SetAddSubSourceType()
// Are all DEFs in the DEF set NUMERIC type?
bool AllNumeric = (this->Defs.GetSize() > 0); // false if no DEFs, true otherwise
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
// We ignore the stack pointer for pop instructions and consider only
// the register DEF of the pop.
if (this->MDIsPopInstr() && CurrDef->GetOp().is_reg(R_sp))
continue;
clc5q
committed
AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType()));
}
return AllNumeric;
} // end of SMPInstr::AllDefsNumeric()
// Were the types of any DEFs derived from profiler info?
bool SMPInstr::AnyDefsProfiled(void)
{
bool profd = false;
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
profd = (profd || IsProfDerived(CurrDef->GetType()));
}
return profd;
}
// 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()));
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
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
1611
1612
1613
#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, MDGetRegName(DefOpnd), 1 + strlen(MDGetRegName(DefOpnd)));
clc5q
committed
SMP_strncat(DestList, " ", MAXSTR);
clc5q
committed
SMP_strncat(DestList, MDGetRegName(DefOpnd), 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
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
// 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()
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
// 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;
ESPOp.dtyp = this->GetOperandDtypField();
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;
if ((NN_nop == opcode) || (NN_lock == 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) MD_STARS_sib_base(this->SMPcmd.Operands[1]))
&& (R_sp == MD_STARS_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)
|| (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_pfrsqrt) || (opcode == NN_pfmul)
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
|| (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
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
}
// 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()