Newer
Older
op_t IndexOpnd = Opnd; // Init to current operand field values
IndexOpnd.type = o_reg; // Change type and reg fields
IndexOpnd.reg = (ushort) IndexReg;
IndexOpnd.hasSIB = 0;
IndexOpnd.set_showed();
if (0 == ScaleFactor)
this->Uses.SetRef(IndexOpnd);
else { // scaling == shift ==> NUMERIC
HasIndexReg = true;
this->Uses.SetRef(IndexOpnd, NUMERIC);
if (R_none != BaseReg) {
op_t BaseOpnd = Opnd; // Init to current operand field values
BaseOpnd.type = o_reg; // Change type and reg fields
BaseOpnd.reg = (ushort) BaseReg;
BaseOpnd.set_showed();
RefType = UNINIT;
#if SMP_BASEREG_POINTER_TYPE
// R_sp and R_bp will get type STACKPTR in SMPInstr::SetImmedTypes().
// Other registers used as base registers should get their USEs as
// base registers typed as POINTER, which might get refined later
// to STACKPTR, GLOBALPTR, HEAPPTR, etc.
// NOTE: the NN_lea opcode is often used without a true base register.
// E.g. lea eax,[eax+eax+5] is an x86 idiom for eax:=eax*2+5, which
// could not be done in one instruction without using the addressing
// modes of the machine to do the arithmetic. We don't want to set the
// USE of EAX to POINTER in this case, so we will conservatively skip
// all lea instructions here.
// We cannot be sure that a register is truly a base register unless
// there is also an index register. E.g. with reg+displacement, we
// could have memaddr+indexreg or basereg+offset, depending on what
// the displacement is. The exception is if there is no offset and only
// one addressing register, e.g. mov eax,[ebx].
if (BaseOpnd.is_reg(MD_STACK_POINTER_REG) || (UseFP && BaseOpnd.is_reg(MD_FRAME_POINTER_REG))
|| leaInst || (!HasIndexReg && !SingleAddressReg)) {
#endif
this->Uses.SetRef(BaseOpnd, RefType);
} // end if R_none != BaseReg
} // end if (o_phrase or o_displ operand)
} // end for (all operands)
// The lea (load effective address) instruction looks as if it has
// a memory USE: lea ebx,[edx+esi]
// However, this instruction is really just: ebx := edx+esi
// Now that the above code has inserted the "addressing" registers
// into the USE list, we should remove the "memory USE".
if (leaInst) {
set<DefOrUse, LessDefUse>::iterator CurrUse;
for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
op_t UseOp = CurrUse->GetOp();
if ((o_mem <= UseOp.type) && (o_displ >= UseOp.type)) {
this->EraseUse(CurrUse);
this->USEMemOp = InitOp;
break;
}
}
}
// Next, handle repeat prefices in the instructions. The Intel REPE/REPZ prefix
// is just the text printed for SCAS/CMPS instructions that have a REP prefix.
// Only two distinct prefix codes are actually defined: REP and REPNE/REPNZ, and
// REPNE/REPNZ only applies to SCAS and CMPS instructions.
bool HasRepPrefix = (0 != (this->SMPcmd.auxpref & aux_rep));
bool HasRepnePrefix = (0 != (this->SMPcmd.auxpref & aux_repne));
if (HasRepPrefix && HasRepnePrefix)
clc5q
committed
SMP_msg("REP and REPNE both present at %x %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
if (HasRepPrefix || HasRepnePrefix) {
// All repeating instructions use ECX as the countdown register.
op_t BaseOpnd = InitOp;
BaseOpnd.type = o_reg; // Change type and reg fields
BaseOpnd.reg = R_cx;
BaseOpnd.clr_showed();
this->Defs.SetRef(BaseOpnd, NUMERIC);
this->Uses.SetRef(BaseOpnd, NUMERIC);
if ((opcode == NN_cmps) || (opcode == NN_scas) || (opcode == NN_movs) || (opcode == NN_stos)) {
// ESI and EDI are USEd and DEFed to point to source and dest strings for CMPS/MOVS.
// Only EDI is involved with SCAS/STOS.
op_t BaseOpnd = InitOp;
BaseOpnd.type = o_reg; // Change type and reg fields
BaseOpnd.clr_showed();
if ((opcode == NN_cmps) || (opcode == NN_movs)) {
BaseOpnd.reg = R_si;
this->Defs.SetRef(BaseOpnd, POINTER);
this->Uses.SetRef(BaseOpnd, POINTER);
}
BaseOpnd.reg = R_di;
this->Defs.SetRef(BaseOpnd, POINTER);
this->Uses.SetRef(BaseOpnd, POINTER);
else if ((NN_loopw <= opcode) && (NN_loopqne >= opcode)) {
op_t LoopCounterOp = InitOp;
LoopCounterOp.type = o_reg;
LoopCounterOp.reg = R_cx;
this->Defs.SetRef(LoopCounterOp, NUMERIC);
this->Uses.SetRef(LoopCounterOp, NUMERIC);
}
// Now, handle special instruction categories that have implicit operands.
if (NN_cmpxchg == opcode) {
// x86 Compare and Exchange conditionally sets EAX. We must keep data flow analysis
// sound by declaring that EAX is always a DEF.
this->MDAddRegDef(R_ax, false);
} // end if NN_cmpxchg
else if (this->MDIsPopInstr() || this->MDIsPushInstr() || this->MDIsReturnInstr()) {
// IDA does not include the stack pointer in the DEFs or USEs.
this->MDAddRegDef(R_sp, false);
this->MDAddRegUse(R_sp, false);
// We always reference [esp+0] or [esp-4], so add it to the DEF or USE list.
op_t StackOp = InitOp;
StackOp.type = o_displ;
StackOp.reg = R_sp;
if (this->MDIsPopInstr()) {
StackOp.addr = 0; // [ESP+0]
this->Uses.SetRef(StackOp); // USE
}
else {
StackOp.addr = (ea_t) -4; // [ESP-4]
this->Defs.SetRef(StackOp); // DEF
}
clc5q
committed
else if ((this->type == CALL) || (this->type == INDIR_CALL) || this->IsTailCall()) {
// We want to add the caller-saved registers to the USEs and DEFs lists
this->MDAddRegDef(R_ax, false);
this->MDAddRegDef(R_cx, false);
this->MDAddRegDef(R_dx, false);
this->MDAddRegUse(R_ax, false);
this->MDAddRegUse(R_cx, false);
this->MDAddRegUse(R_dx, false);
#if 1
if (this->MDIsInterruptCall()) {
#endif
this->MDAddRegDef(R_bx, false);
this->MDAddRegUse(R_bx, false);
this->MDAddRegDef(R_si, false);
this->MDAddRegUse(R_si, false);
}
#endif
else if (this->MDIsEnterInstr() || this->MDIsLeaveInstr()) {
// Entire function prologue or epilogue microcoded.
this->MDAddRegDef(MD_STACK_POINTER_REG, false);
this->MDAddRegUse(MD_STACK_POINTER_REG, false);
this->MDAddRegDef(MD_FRAME_POINTER_REG, false);
this->MDAddRegUse(MD_FRAME_POINTER_REG, false);
else if ((opcode == NN_maskmovq) || (opcode == NN_maskmovdqu)) {
else if (8 == this->GetOptType()) {
// This category implicitly writes to EDX:EAX.
this->MDAddRegDef(R_dx, false);
this->MDAddRegDef(R_ax, false);
} // end else if (8 == GetOptType)
else if (7 == this->GetOptType()) {
// Category 7 instructions sometimes write implicitly to EDX:EAX or DX:AX.
// DX is the same as EDX to IDA Pro (and SMP); ditto for EAX and AX.
// DIV, IDIV, and MUL all have hidden EAX or AX operands (hidden in the IDA Pro
// sense, because they are not displayed in the disassembly text). For example:
// mul ebx means EDX:EAX <-- EAX*EBX, and mul bx means DX:AX <-- AX*BX. If the
// source operand is only 8 bits wide, there is room to hold the result in AX
// without using DX: mul bl means AX <-- AL*BL.
// IMUL has forms with a hidden EAX or AX operand and forms with no implicit
// operands: imul ebx means EDX:EAX <-- EAX*EBX, but imul ebx,edx means that
// EBX*EDX gets truncated and the result placed in EBX (no hidden operands).
for (OpNum = 0; OpNum < UA_MAXOP; ++OpNum) {
op_t TempUse = this->SMPcmd.Operands[OpNum];
if (!TempUse.showed()) { // hidden operand
if (TempUse.is_reg(R_ax)) { // not R_al, so it is not 8 bits
if ((NN_div == this->SMPcmd.itype) || (NN_idiv == this->SMPcmd.itype)) {
this->MDAddRegUse(R_dx, false);
}
this->MDAddRegDef(R_ax, false);
this->MDAddRegDef(R_dx, false);
}
}
}
} // end else if (7 == OptType)
#if 0
// The floating point instructions in type categories 14 and 15 often USE and DEF
// the floating point register stack, e.g. pushing a value onto that stack is a
// massive copy downward of stack locations. We don't really care about the USE of
// the stack if the value being pushed came from elsewhere than the stack. For example,
// an "fld" opcode pushes its source onto the stack. We build RTLs with a simple
// move structure, but the RTL building can be fooled by seeing two "source" operands
// in the USE list.
if ((14 == SMPTypeCategory[this->SMPcmd.itype])
|| (15 == SMPTypeCategory[this->SMPcmd.itype])) {
}
#endif
clc5q
committed
#if 0 // Not true for LOOP instructions that use only the ECX counter register.
if (this->type == COND_BRANCH) {
assert(SMPUsesFlags[opcode]);
clc5q
committed
#endif
// The return value register EAX is not quite like a caller-save or callee-save
// register (technically, it is caller-save). Within a callee, it might appear
// that EAX has become dead by the time a return instruction is reached, but
// the USE that would make it not dead is in the caller. To prevent type inference
// from mistakenly thinking that all USEs of EAX have been seen in the callee,
// we add EAX to the USE list for all return instructions, as well as for all
// tail calls, which are essentially returns in terms of data flow analysis.
// This USE of EAX will always be of type UNINIT unless its DEF has a known type
// that propagates to it. Thus, it will prevent an invalid back inference of the
// DEF type from "all" USE types that are visible in the callee; even if they
// were all NUMERIC, this return USE will be UNINIT and inhibit the invalid
// type inference. EAX could be loaded with a pointer from memory, for example,
// and USEd only in a comparison instruction, making it falsely appear to be
// a NUMERIC, without this extra USE at the return instruction.
// Because some of the library functions pass values around in EBX, EDI, etc.,
// we will add these general purpose registers to the USE list for returns
// in order to prevent erroneous analyses of dead registers or unused
// metadata.
if ((this->type == RETURN) || this->IsTailCall()) {
this->MDAddRegUse(R_ax, false);
this->MDAddRegUse(R_bx, false);
this->MDAddRegUse(R_cx, false);
this->MDAddRegUse(R_dx, false);
this->MDAddRegUse(MD_FRAME_POINTER_REG, false);
this->MDAddRegUse(R_si, false);
this->MDAddRegUse(R_di, false);
}
clc5q
committed
// Next, add the flags register to the DEFs and USEs for those instructions that
// are marked as defining or using flags.
if (!this->IsDefsFlags() && SMPDefsFlags[opcode]) {
this->MDAddRegDef(X86_FLAGS_REG, false);
this->SetDefsFlags();
if (!this->IsUsesFlags() && SMPUsesFlags[opcode]) {
this->MDAddRegUse(X86_FLAGS_REG, false);
this->SetUsesFlags();
}
if (this->IsNop()) {
// Clear the DEFs and USEs for no-ops.
// These include machine idioms for no-ops, e.g. mov esi,esi
// or xchg ax,ax or lea esi,[esi].
this->Defs.clear();
this->Uses.clear();
this->MoveSource = InitOp;
this->DEFMemOp = InitOp;
this->USEMemOp = InitOp;
this->OptType = 1;
}
#endif
clc5q
committed
SMP_msg("DEBUG after MDFixupDefUseLists:\n");
return;
} // end of SMPInstr::MDFixupDefUseLists()
// If we can definitely identify which part of the addressing expression
// used in MemOp is the POINTER type, and it is not a STACKPTR or GLOBALPTR
// immediate, set the USE type for that register to POINTER and return true.
// If we can find definite NUMERIC addressing registers that are not already
// typed as NUMERIC, set their USE types to NUMERIC and return true.
bool SMPInstr::MDFindPointerUse(op_t MemOp, bool UseFP) {
bool changed = false;
int BaseReg;
int IndexReg;
op_t BaseOp = InitOp;
op_t IndexOp = InitOp;
SMPOperandType BaseType = UNKNOWN;
SMPOperandType IndexType = UNKNOWN;
ushort ScaleFactor;
ea_t offset;
set<DefOrUse, LessDefUse>::iterator BaseIter;
set<DefOrUse, LessDefUse>::iterator IndexIter;
if (NN_lea == this->SMPcmd.itype)
return false; // lea instruction really has no memory operands
if (NN_fnop == this->SMPcmd.itype)
return false; // SSA marker instruction
MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor, offset);
if (R_none != IndexReg) {
IndexOp.type = o_reg;
IndexOp.reg = MDCanonicalizeSubReg((ushort) IndexReg);
IndexOp.dtyp = dt_dword; // Canonical 32-bit width
IndexIter = this->FindUse(IndexOp);
assert(IndexIter != this->GetLastUse());
IndexType = IndexIter->GetType();
}
if (R_none != BaseReg) {
BaseOp.type = o_reg;
BaseOp.reg = MDCanonicalizeSubReg((ushort) BaseReg);
BaseOp.dtyp = dt_dword; // Canonical 32-bit width
BaseIter = this->FindUse(BaseOp);
assert(BaseIter != this->GetLastUse());
BaseType = BaseIter->GetType();
}
if (MDIsStackPtrReg(BaseReg, UseFP)) {
if ((R_none != IndexReg) && (!IsNumeric(IndexType))) {
// We have an indexed access into the stack frame.
// Set IndexReg USE type to NUMERIC.
changed = true;
IndexIter = this->SetUseType(IndexOp, NUMERIC);
assert(IndexIter != this->GetLastUse());
}
return changed; // stack accesses will get STACKPTR type in SetImmedTypes()
}
if (MDIsStackPtrReg(IndexReg, UseFP)) {
if ((R_none != BaseReg) && (!IsNumeric(BaseType))) {
// We have an indexed access into the stack frame.
// Set BaseReg USE type to NUMERIC.
// Note that BaseReg is really an IndexReg and vice versa.
changed = true;
BaseIter = this->SetUseType(BaseOp, NUMERIC);
assert(BaseIter != this->GetLastUse());
clc5q
committed
SMP_msg("WARNING: BaseReg is index, IndexReg is base: %s\n",
DisAsmText.GetDisAsm(this->GetAddr()));
}
return changed; // stack accesses will get STACKPTR type in SetImmedTypes()
}
if (IsImmedGlobalAddress(offset)) {
if ((R_none != IndexReg) && (!IsNumeric(IndexType))) {
// We have an indexed access into a global.
// Set IndexReg USE type to NUMERIC.
changed = true;
IndexIter = this->SetUseType(IndexOp, NUMERIC);
assert(IndexIter != this->GetLastUse());
}
if ((R_none != BaseReg) && (!IsNumeric(BaseType))) {
// We have an indexed access into a global.
// Set BaseReg USE type to NUMERIC.
// Note that BaseReg is really an index register.
changed = true;
BaseIter = this->SetUseType(BaseOp, NUMERIC);
assert(BaseIter != this->GetLastUse());
clc5q
committed
SMP_msg("WARNING: BaseReg used as index: %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
return changed; // global immediate is handled in SetImmedTypes()
// At this point, we must have a base address in a register, not used
// to directly address the stack or a global.
if ((0 < ScaleFactor) || (R_none == IndexReg)) {
// IndexReg is scaled, meaning it is NUMERIC, so BaseReg must
// be a POINTER; or IndexReg is not present, so BaseReg is the
// only possible holder of an address.
if (R_none != BaseReg) {
if (UNINIT == BaseIter->GetType()) {
changed = true;
BaseIter = this->SetUseType(BaseOp, POINTER);
assert(BaseIter != this->GetLastUse());
}
}
}
else if (R_none == BaseReg) {
// We have an unscaled IndexReg and no BaseReg and offset was
// not a global offset, so IndexReg must be a POINTER.
if (R_none != IndexReg) {
changed = true;
IndexIter = this->SetUseType(IndexOp, POINTER);
assert(IndexIter != this->GetLastUse());
}
}
}
else { // We have BaseReg and an unscaled IndexReg.
// The only hope for typing something like [ebx+edx] is for
// one register to already be typed NUMERIC, in which case
// the other one must be a POINTER, or if one register is
// already POINTER, then the other one must be NUMERIC.
if (IsNumeric(BaseType)) {
if (UNINIT == IndexType) {
// Set to POINTER or PROF_POINTER
changed = true;
IndexIter = this->SetUseType(IndexOp, POINTER);
assert(IndexIter != this->GetLastUse());
}
else if (IsNumeric(IndexType)) {
clc5q
committed
SMP_msg("ERROR: BaseReg and IndexReg both NUMERIC at %x: %s\n",
this->address, DisAsmText.GetDisAsm(this->GetAddr()));
}
}
else { // BaseReg was not NUMERIC
if (UNINIT == BaseType) { // BaseReg is UNINIT
if (IsNumeric(IndexType)) {
changed = true;
BaseIter = this->SetUseType(BaseOp, POINTER);
assert(BaseIter != this->GetLastUse());
}
else if (IsDataPtr(IndexType)) {
// IndexReg is POINTER, so make BaseReg NUMERIC.
changed = true;
BaseIter = this->SetUseType(BaseOp, NUMERIC);
assert(BaseIter != this->GetLastUse());
}
}
else if (IsDataPtr(BaseType)) {
// BaseReg was a pointer type. IndexReg must be NUMERIC.
if (UNINIT == IndexType) {
changed = true;
IndexIter = this->SetUseType(IndexOp, NUMERIC);
assert(IndexIter != this->GetLastUse());
}
else if (IsDataPtr(IndexType)) {
clc5q
committed
SMP_msg("ERROR: BaseReg and IndexReg both POINTER at %x: %s\n",
this->address, DisAsmText.GetDisAsm(this->GetAddr()));
}
}
}
}
return changed;
} // end of SMPInstr::MDFindPointerUse()
clc5q
committed
// Are all DEFs typed to something besides UNINIT?
bool SMPInstr::AllDEFsTyped(void) {
if (this->AreDEFsTyped()) {
return true;
}
clc5q
committed
bool FoundUNINIT = false;
set<DefOrUse, LessDefUse>::iterator DefIter;
for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
if (IsEqType(UNINIT, DefIter->GetType())) {
FoundUNINIT = true;
break;
}
}
if (!FoundUNINIT) {
this->SetDEFsTyped();
}
clc5q
committed
return (!FoundUNINIT);
} // end of SMPInstr::AllDEFsTyped()
// Are all USEs typed to something besides UNINIT?
bool SMPInstr::AllUSEsTyped(void) {
if (this->AreUSEsTyped()) {
return true;
}
clc5q
committed
bool FoundUNINIT = false;
set<DefOrUse, LessDefUse>::iterator UseIter;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
if (IsEqType(UNINIT, UseIter->GetType())) {
FoundUNINIT = true;
break;
}
}
if (!FoundUNINIT) {
this->SetUSEsTyped();
}
clc5q
committed
return (!FoundUNINIT);
} // end of SMPInstr::AllUSEsTyped()
// Return true if UseOp is a USE reg, not just an address reg in a memory USE
clc5q
committed
bool SMPInstr::IsNonAddressReg(op_t UseOp) const {
bool FoundUse = false;
ushort SearchReg = MDCanonicalizeSubReg(UseOp.reg);
for (size_t OpNum = 0; OpNum < UA_MAXOP; ++OpNum) {
op_t Opnd = this->SMPcmd.Operands[OpNum];
if (this->features & UseMacros[OpNum]) { // USE
if (Opnd.type == o_reg) {
ushort TestReg = MDCanonicalizeSubReg(Opnd.reg);
if (TestReg == SearchReg) {
FoundUse = true;
break;
}
}
}
}
return FoundUse;
} // end of SMPInstr::IsNonAddressReg()
uval_t SMPInstr::MDGetShiftCount(void) const {
uval_t ShiftCount = 0;
if (this->MDIsShiftOrRotate()) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
assert(CurrRT->HasRightSubTree());
CurrRT = CurrRT->GetRightTree();
op_t ShiftCountOp = CurrRT->GetRightOperand();
if (o_imm == ShiftCountOp.type) {
ShiftCount = ShiftCountOp.value;
}
}
return ShiftCount;
} // end of SMPInstr::MDGetShiftCount()
clc5q
committed
// RTL shows DEF operand is subreg.
bool SMPInstr::IsReducedWidthDef(void) const {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
op_t DefOp = CurrRT->GetLeftOperand();
return ((o_void != DefOp.type) && (DefOp.dtyp < 2));
}
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
// Is a sub-register of UseOp used as a shift counter in the RTL?
// For example, UseOp could be ECX on an x86 machine, and CL
// could be used as a shift or rotate counter.
bool SMPInstr::IsSubRegUsedAsShiftCount(op_t UseOp) {
bool ShiftCounter = false;
if ((o_reg == UseOp.type) && this->MDIsShiftOrRotate()) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
assert(CurrRT->HasRightSubTree());
CurrRT = CurrRT->GetRightTree();
op_t ShiftCountOp = CurrRT->GetRightOperand();
if (o_reg == ShiftCountOp.type) {
ushort UseReg = UseOp.reg;
ushort ShiftCountReg = ShiftCountOp.reg;
ushort WideUseReg = MDCanonicalizeSubReg(UseReg);
ushort WideShiftCountReg = MDCanonicalizeSubReg(ShiftCountReg);
if ((UseReg != ShiftCountReg) && (WideUseReg == WideShiftCountReg)) {
// Registers were not equal, but their canonical enclosing
// registers are equal. Because shift counters that are not
// immediate are the 8-bit subregister in x86 (MD here !!!!!!)
// it must be that the ShiftCountReg is a subreg of UseReg.
// This is the condition we are looking for.
ShiftCounter = true;
}
}
}
return ShiftCounter;
} // end of SMPInstr::IsSubRegUsedAsShiftCount()
// Does UseOp ultimately come from a small positive constant?
bool SMPInstr::IsOpSourceSmallPositiveConstant(op_t UseOp, int UseSSANum) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
clc5q
committed
return false;
}
clc5q
committed
bool FoundSmallConst = false;
bool RegDef = (o_reg == UseOp.type);
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
clc5q
committed
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
clc5q
committed
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
clc5q
committed
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
clc5q
committed
|| (UseDefAddr == BADADDR) || IndirectMemAccess) {
// Cannot search for general memory DEFs; must be stack or register.
// FirstFuncAddr - 1 signifies the pseudo-inst to hold DEFs of regs
// that are LiveIn to the function; pseudo-inst is not a bitwise not.
// First block addr - 1 is pseudo-location that indicates live-in, UpExposed,
// and LocalName means we will not find a DEF anywhere besides this block.
// AboveStackFrame means an incoming arg, whose DEF will not be seen.
clc5q
committed
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
else if (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
// A block number was returned. That means the DEF is in a Phi Function.
// We could trace all Phi USEs and see if all of them come from small constants
// but we only need one of the Phi USEs to come from
// a small constant to potentially lead to a false positive numeric error. We
// will recurse on all Phi USEs, declaring success if we find a single one of them
// to come from a small constant.
size_t BlockNum = (size_t) UseDefAddr;
assert(!LocalName);
SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum);
assert(NULL != PhiDefBlock);
if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion
set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp);
assert(DefPhiIter != PhiDefBlock->GetLastPhi());
size_t PhiListSize = DefPhiIter->GetPhiListSize();
PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
for (size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
if (this->IsOpSourceSmallPositiveConstant(UseOp, PhiUseSSANum)) {
FoundSmallConst = true; // only one success on all Phi USEs is needed
break;
}
}
}
}
else {
bool ValueFound;
uval_t ConstValue;
SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
if (DefInst->MDIsSimpleAssignment(ValueFound, ConstValue)) {
FoundSmallConst = (ValueFound && (ConstValue <= 2));
if (!FoundSmallConst && !ValueFound && DefInst->MDIsMoveInstr()) {
// We have a non-immediate move. Trace back through move source to find small const.
op_t CopyUseOp = DefInst->GetMoveSource();
CanonicalizeOpnd(CopyUseOp);
set<DefOrUse, LessDefUse>::iterator UseIter = DefInst->FindUse(CopyUseOp);
assert(UseIter != DefInst->GetLastUse());
int CopyUseSSANum = UseIter->GetSSANum();
FoundSmallConst = DefInst->IsOpSourceSmallPositiveConstant(CopyUseOp, CopyUseSSANum);
}
}
}
return FoundSmallConst;
} // end of SMPInstr::IsOpSourceSmallPositiveConstant()
// Does UseOp ultimately come from a bitwise not instruction?
bool SMPInstr::IsOpSourceBitwiseNot(op_t UseOp, int UseSSANum) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
return false;
}
bool FoundBitwiseNotInst = false;
bool RegDef = (o_reg == UseOp.type);
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
clc5q
committed
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
|| (UseDefAddr == BADADDR) || IndirectMemAccess) {
// Cannot search for general memory DEFs; must be stack or register.
// FirstFuncAddr - 1 signifies the pseudo-inst to hold DEFs of regs
// that are LiveIn to the function; pseudo-inst is not a bitwise not.
// First block addr - 1 is pseudo-location that indicates live-in, UpExposed,
// and LocalName means we will not find a DEF anywhere besides this block.
// AboveStackFrame means an incoming arg, whose DEF will not be seen.
FoundBitwiseNotInst = false;
}
else if (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
// A block number was returned. That means the DEF is in a Phi Function.
clc5q
committed
// We could trace all Phi USEs and see if all of them come from bitwise nots
// but we only need one of the Phi USEs to come from
clc5q
committed
// a bitwise not to potentially lead to a false positive numeric error. We
// will recurse on all Phi USEs, declaring success if we find a single one of them
clc5q
committed
// to come from a bitwise not.
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
size_t BlockNum = (size_t) UseDefAddr;
assert(!LocalName);
SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum);
assert(NULL != PhiDefBlock);
if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion
set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp);
assert(DefPhiIter != PhiDefBlock->GetLastPhi());
size_t PhiListSize = DefPhiIter->GetPhiListSize();
PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
for (size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
if (this->IsOpSourceBitwiseNot(UseOp, PhiUseSSANum)) {
FoundBitwiseNotInst = true; // only one success on all Phi USEs is needed
break;
}
}
}
}
else {
SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
if (DefInst->MDIsBitwiseNotOpcode()) {
FoundBitwiseNotInst = true;
}
else if (DefInst->MDIsMoveInstr()) {
op_t MoveUseOp = DefInst->GetMoveSource();
clc5q
committed
if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
CanonicalizeOpnd(MoveUseOp);
set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
assert(MoveUseIter != DefInst->GetLastUse());
int MoveUseSSANum = MoveUseIter->GetSSANum();
FoundBitwiseNotInst = DefInst->IsOpSourceBitwiseNot(MoveUseOp, MoveUseSSANum); // recurse
}
}
else {
// Not a move, not a bitwise not. We must return false.
FoundBitwiseNotInst = false;
}
}
return FoundBitwiseNotInst;
} // end of SMPInstr::IsOpSourceBitwiseNot()
clc5q
committed
// Does UseOp ultimately come from a set-condition-code instruction?
bool SMPInstr::IsOpSourceConditionCode(op_t UseOp, int UseSSANum) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
clc5q
committed
return false;
}
clc5q
committed
bool FoundConditionalSetInst = false;
clc5q
committed
bool RegDef = (o_reg == UseOp.type);
clc5q
committed
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
clc5q
committed
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
clc5q
committed
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
clc5q
committed
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
clc5q
committed
clc5q
committed
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
clc5q
committed
|| (UseDefAddr == BADADDR) || IndirectMemAccess) {
// Cannot search for general memory DEFs; must be stack or register.
// FirstFuncAddr - 1 signifies the pseudo-inst to hold DEFs of regs
clc5q
committed
// that are LiveIn to the function; pseudo-inst is not a bitwise not.
// First block addr - 1 is pseudo-location that indicates live-in, UpExposed,
// and LocalName means we will not find a DEF anywhere besides this block.
// AboveStackFrame means an incoming arg, whose DEF will not be seen.
FoundConditionalSetInst = false;
}
else if (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
// A block number was returned. That means the DEF is in a Phi Function.
// We could trace all Phi USEs and see if all of them come from condition codes
// but we only need one of the Phi USEs to come from
// a condition code to potentially lead to a false positive numeric error. We
// will recurse on all Phi USEs, declaring success if we find a single one of them
// to come from a condition code.
size_t BlockNum = (size_t) UseDefAddr;
assert(!LocalName);
SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum);
assert(NULL != PhiDefBlock);
if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion
set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp);
assert(DefPhiIter != PhiDefBlock->GetLastPhi());
size_t PhiListSize = DefPhiIter->GetPhiListSize();
PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
for (size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
if (this->IsOpSourceConditionCode(UseOp, PhiUseSSANum)) {
FoundConditionalSetInst = true; // only one success on all Phi USEs is needed
break;
}
}
}
}
else {
SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
if (DefInst->MDIsAnySetValue()) {
FoundConditionalSetInst = true;
clc5q
committed
}
else if (DefInst->MDIsMoveInstr()) {
op_t MoveUseOp = DefInst->GetMoveSource();
clc5q
committed
if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
CanonicalizeOpnd(MoveUseOp);
set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
assert(MoveUseIter != DefInst->GetLastUse());
int MoveUseSSANum = MoveUseIter->GetSSANum();
FoundConditionalSetInst = DefInst->IsOpSourceConditionCode(MoveUseOp, MoveUseSSANum); // recurse
clc5q
committed
}
}
else {
// Not a move, not a condition code transfer. We must return false.
FoundConditionalSetInst = false;
}
}
return FoundConditionalSetInst;
} // end of SMPInstr::IsOpSourceConditionCode()
// Does UseOp ultimately come from a move-with-zero-extension instruction?
bool SMPInstr::IsOpSourceZeroExtendedMove(op_t UseOp, int UseSSANum, bool TruncationCheck) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
clc5q
committed
return false;
}
bool FoundMoveZX = false;
clc5q
committed
bool RegDef = (o_reg == UseOp.type);
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
clc5q
committed
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
clc5q
committed
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
clc5q
committed
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
clc5q
committed
|| (UseDefAddr == BADADDR) || IndirectMemAccess) {
// Cannot search for general memory DEFs; must be stack or register.
// FirstFuncAddr - 1 signifies the pseudo-inst to hold DEFs of regs
clc5q
committed
// that are LiveIn to the function; pseudo-inst is not a bitwise not.
// First block addr - 1 is pseudo-location that indicates live-in, UpExposed,
// and LocalName means we will not find a DEF anywhere besides this block.
// AboveStackFrame means an incoming arg, whose DEF will not be seen.
FoundMoveZX = false;
}
else if (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
// A block number was returned. That means the DEF is in a Phi Function.
// We could trace all Phi USEs and see if all of them come from zero-extended
// moves into the UseOp register, but we only need one of the Phi USEs to come from
// a zero-extended move to potentially lead to a false positive numeric error. We
// will recurse on all Phi USEs, declaring success if we find a single one of them
// to come from a zero-extended move.
size_t BlockNum = (size_t) UseDefAddr;
assert(!LocalName);
SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum);
assert(NULL != PhiDefBlock);
if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion
set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp);
assert(DefPhiIter != PhiDefBlock->GetLastPhi());
size_t PhiListSize = DefPhiIter->GetPhiListSize();
PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
for (size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
if (this->IsOpSourceZeroExtendedMove(UseOp, PhiUseSSANum, TruncationCheck)) {
FoundMoveZX = true; // only one success on all Phi USEs is needed
break;
clc5q
committed
}
}
}
}
else {
SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
unsigned short SignMask;
if (DefInst->MDIsSignedLoad(SignMask)) {
FoundMoveZX = (FG_MASK_UNSIGNED == SignMask);
}
else if (DefInst->MDIsMoveInstr()) {
op_t MoveUseOp = DefInst->GetMoveSource();
clc5q
committed
if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
CanonicalizeOpnd(MoveUseOp);
set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
assert(MoveUseIter != DefInst->GetLastUse());
int MoveUseSSANum = MoveUseIter->GetSSANum();
FoundMoveZX = DefInst->IsOpSourceZeroExtendedMove(MoveUseOp, MoveUseSSANum, TruncationCheck); // recurse
}
}
else if (TruncationCheck && DefInst->MDIsNonOverflowingBitManipulation()) {
// Not a move, not a zero-extended move. We must return false for the non-truncation case,
// but we allow non-overflowing bit manipulation instructions in the chain for truncation checks.
// This is because of a benign code pattern:
// reg: = zero-extended move
// reg := reg AND bit pattern
// reg := reg OR bit pattern
// store lower bits of reg
// Compilers like to do 32-bit arithmetic. There was never any good reason otherwise to zero-extend the
// value in the first instruction in the pattern. The lower bits that are stored at the end of the code
// sequence are the only bits that ever mattered, so this is not really a truncation.
set<DefOrUse, LessDefUse>::iterator BitUseIter = DefInst->FindUse(UseOp);
if (BitUseIter != DefInst->GetLastUse()) {
int BitUseSSANum = BitUseIter->GetSSANum();
FoundMoveZX = DefInst->IsOpSourceZeroExtendedMove(UseOp, BitUseSSANum, true); // recurse up the chain
clc5q
committed
}
}
else {
FoundMoveZX = false;
}
clc5q
committed
}
return FoundMoveZX;
} // end of SMPInstr::IsOpSourceZeroExtendedMove()
clc5q
committed
// Does UseOp ultimately come from a move-with-zero-extension instruction OR from a condition code OR from a right shift?
bool SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(op_t UseOp, int UseSSANum, bool TruncationCheck) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
clc5q
committed
return false;
}
bool FoundMoveZXCC = false;
clc5q
committed
bool RegDef = (o_reg == UseOp.type);
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
clc5q
committed
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
clc5q
committed
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
clc5q
committed
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
clc5q
committed
|| (UseDefAddr == BADADDR) || IndirectMemAccess) {
// Cannot search for general memory DEFs; must be stack or register.
// FirstFuncAddr - 1 signifies the pseudo-inst to hold DEFs of regs
clc5q
committed
// that are LiveIn to the function; pseudo-inst is not a bitwise not.
// First block addr - 1 is pseudo-location that indicates live-in, UpExposed,
// and LocalName means we will not find a DEF anywhere besides this block.
// AboveStackFrame means an incoming arg, whose DEF will not be seen.
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
FoundMoveZXCC = false;
}
else if (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
// A block number was returned. That means the DEF is in a Phi Function.
// We could trace all Phi USEs and see if all of them come from zero-extended
// moves into the UseOp register, but we only need one of the Phi USEs to come from
// a zero-extended move to potentially lead to a false positive numeric error. We
// will recurse on all Phi USEs, declaring success if we find a single one of them
// to come from a zero-extended move.
size_t BlockNum = (size_t) UseDefAddr;
assert(!LocalName);
SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum);
assert(NULL != PhiDefBlock);
if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion
set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp);
assert(DefPhiIter != PhiDefBlock->GetLastPhi());
size_t PhiListSize = DefPhiIter->GetPhiListSize();
PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
for (size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
if (this->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(UseOp, PhiUseSSANum, TruncationCheck)) {
FoundMoveZXCC = true; // only one success on all Phi USEs is needed
break;
}
}
}
}
else {
SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
unsigned short SignMask;
if (DefInst->MDIsSignedLoad(SignMask)) {
FoundMoveZXCC = (FG_MASK_UNSIGNED == SignMask);
}
else if (DefInst->MDIsAnySetValue() || DefInst->MDIsShiftRight()) {
FoundMoveZXCC = true;
}
else if (DefInst->MDIsMoveInstr()) {
op_t MoveUseOp = DefInst->GetMoveSource();
clc5q
committed
if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
CanonicalizeOpnd(MoveUseOp);
set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
assert(MoveUseIter != DefInst->GetLastUse());
int MoveUseSSANum = MoveUseIter->GetSSANum();
FoundMoveZXCC = DefInst->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(MoveUseOp, MoveUseSSANum, TruncationCheck); // recurse
}
}
else if (TruncationCheck && (DefInst->MDIsNonOverflowingBitManipulation() || DefInst->MDIsSmallAdditionOrSubtraction())) {
// Not a move, not a zero-extended move. We must return false for the non-truncation case,
// but we allow non-overflowing bit manipulation instructions in the chain for truncation checks.
// This is because of a benign code pattern:
// reg: = zero-extended move
// reg := reg AND bit pattern
// reg := reg OR bit pattern
// store lower bits of reg
// Compilers like to do 32-bit arithmetic. There was never any good reason otherwise to zero-extend the
// value in the first instruction in the pattern. The lower bits that are stored at the end of the code
// sequence are the only bits that ever mattered, so this is not really a truncation.
// NOTE: We combine into this case additions or subtractions of small values, as they only operate on the
// lower bits of the register.
set<DefOrUse, LessDefUse>::iterator BitUseIter = DefInst->FindUse(UseOp);
if (BitUseIter != DefInst->GetLastUse()) {
int BitUseSSANum = BitUseIter->GetSSANum();
FoundMoveZXCC = DefInst->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(UseOp, BitUseSSANum, true); // recurse up the chain
}
}
else {
FoundMoveZXCC = false;
}
}
return FoundMoveZXCC;
clc5q
committed
} // end of SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode()
// Trace through moves to any of the above cases, return source inst
bool SMPInstr::IsOpSourceSpecial(op_t UseOp, int UseSSANum, bool TruncationCheck, ea_t &SourceInstAddr) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
return false;
}
bool FoundMoveNotZXCCSubreg = false;
bool RegDef = (o_reg == UseOp.type);
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {