diff --git a/SMPBasicBlock.cpp b/SMPBasicBlock.cpp index fd1152efe97e22778c1a6a17b05d75df35939b00..35db7cb3de1ae1011e7d359db47445e8502e9347 100644 --- a/SMPBasicBlock.cpp +++ b/SMPBasicBlock.cpp @@ -3763,6 +3763,25 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd } } } + if (benign) { + return benign; + } + + SMPInstr *DefInst = this->GetFunc()->GetInstFromAddr(DefAddr); + ea_t SourceInstAddr = BADADDR; + SMPInstr *SourceInst = NULL; + int UseSSANum = SMP_SSA_UNINIT; + bool SpecialSourceFound = false; + bool LeaDef = DefInst->MDIsLoadEffectiveAddressInstr(); + UseIter = DefInst->FindUse(DefOp); // DEF is also USE in addition, subtraction, etc. + if (MDIsDataFlowOpnd(DefOp, UseFP) && (UseIter != DefInst->GetLastUse())) { + UseSSANum = UseIter->GetSSANum(); + this->GetFunc()->ResetProcessedBlocks(); + SpecialSourceFound = DefInst->IsOpSourceSpecial(DefOp, UseSSANum, false, SourceInstAddr); + if (SpecialSourceFound) { + SourceInst = this->GetFunc()->GetInstFromAddr(SourceInstAddr); + } + } // Second case: Subtraction of two values, each of which is just a condition code. // This can happen in optimized code that tests for which of two condition codes @@ -3781,11 +3800,7 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd // potential underflow or overflow. If eax comes from a condition code (seta eax), the values // will be small and no overflow check is needed. if (!benign) { - SMPInstr *DefInst = this->GetFunc()->GetInstFromAddr(DefAddr); - int UseSSANum; if (UnderflowOpcode && MDIsDataFlowOpnd(DefOp, UseFP)) { - UseIter = DefInst->FindUse(DefOp); // DEF is also USE in subtraction - UseSSANum = UseIter->GetSSANum(); // Prepare for possible recursive traversals through the function blocks. this->GetFunc()->ResetProcessedBlocks(); if (DefInst->IsOpSourceConditionCode(DefOp, UseSSANum)) { @@ -3799,6 +3814,7 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd CanonicalizeOpnd(UseOp); UseIter = DefInst->FindUse(UseOp); int SubtrahendSSANum = UseIter->GetSSANum(); + this->GetFunc()->ResetProcessedBlocks(); benign = DefInst->IsOpSourceConditionCode(UseOp, SubtrahendSSANum); } else if (UseOp.type == o_imm) { @@ -3823,6 +3839,7 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd CanonicalizeOpnd(UseOp); UseIter = DefInst->FindUse(UseOp); UseSSANum = UseIter->GetSSANum(); + this->GetFunc()->ResetProcessedBlocks(); benign = DefInst->IsOpSourceZeroExtendedMove(UseOp, UseSSANum, false); } } @@ -3901,6 +3918,7 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd UseIter = DefInst->FindUse(SearchOp); assert(UseIter != DefInst->GetLastUse()); UseSSANum = UseIter->GetSSANum(); + this->GetFunc()->ResetProcessedBlocks(); SafeBaseReg = DefInst->IsOpSourceConditionCode(SearchOp, UseSSANum); } if (SafeBaseReg && (!SafeIndexReg)) { @@ -3913,6 +3931,7 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd UseIter = DefInst->FindUse(SearchOp); assert(UseIter != DefInst->GetLastUse()); UseSSANum = UseIter->GetSSANum(); + this->GetFunc()->ResetProcessedBlocks(); SafeIndexReg = DefInst->IsOpSourceConditionCode(SearchOp, UseSSANum); } } @@ -3929,7 +3948,6 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd // are applied to a POINTER type. InstIter = this->GetInstIterFromAddr(DefAddr); assert(InstIter != this->GetLastInstr()); - SMPInstr *DefInst = (*InstIter); DefIter = DefInst->FindDef(DefOp); assert(DefIter != DefInst->GetLastDef()); SMPOperandType DefType = DefIter->GetType(); @@ -3961,123 +3979,63 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd if (!benign) { // Bitwise NOT is likely to produce an overflow/underflow for a subsequent add/subtract. - SMPInstr *DefInst = this->GetFunc()->GetInstFromAddr(DefAddr); - int UseSSANum; +#if 0 if (RegDef) { - UseIter = DefInst->FindUse(DefOp); // DEF is also USE in addition or subtraction ... +#endif + // DEF is also USE in addition or subtraction ... if (UseIter != DefInst->GetLastUse()) { // ... but not always on lea opcode - UseSSANum = UseIter->GetSSANum(); -#if 1 - if (DefInst->IsOpSourceBitwiseNot(DefOp, UseSSANum)) { - benign = true; - IdiomCode = 21; - } -#else - ea_t UseDefAddr = this->GetDefAddrFromUseAddr(DefOp, DefAddr, UseSSANum, LocalDefName); - if (UseDefAddr >= this->GetFunc()->GetFirstFuncAddr()) { // inst DEF, not Phi DEF - DefInst = this->GetFunc()->GetInstFromAddr(UseDefAddr); - if (DefInst->MDIsBitwiseNotOpcode()) { - benign = true; - IdiomCode = 21; - } + if (SpecialSourceFound && SourceInst->MDIsBitwiseNotOpcode()) { + benign = true; + IdiomCode = 21; } -#endif } +#if 0 } +#endif +#if 0 else if (MDIsStackAccessOpnd(DefOp, this->GetFunc()->UsesFramePointer())){ // We need the canonicalized stack operand as found in DEFs and USEs. UseOp = DefInst->MDGetMemUseOp(); // DEF is also USE in addition or subtraction ... -#if 1 UseIter = DefInst->FindUse(UseOp); if (UseIter != DefInst->GetLastUse()) { // ... but not always on lea opcode UseSSANum = UseIter->GetSSANum(); - if (DefInst->IsOpSourceBitwiseNot(UseOp, UseSSANum)) { + if (SourceInst->MDIsBitwiseNotOpcode()) { benign = true; IdiomCode = 21; } } -#else - assert(o_void != UseOp.type); - InstIter = this->GetInstIterFromAddr(DefAddr); - assert(InstIter != this->GetLastInstr()); - list<SMPInstr *>::reverse_iterator RevInstIter(InstIter); - op_t NewDefOp; - while (RevInstIter != this->Instrs.rend()) { - SMPInstr *SearchInst = (*RevInstIter); - NewDefOp = SearchInst->MDGetMemDefOp(); // Get canonicalized stack operand - if (IsEqOp(UseOp, NewDefOp)) { - // Found the DEF of the stack operand used in our add or subtract. - if (SearchInst->MDIsBitwiseNotOpcode()) { - benign = true; - IdiomCode = 21; - } - break; // Only look for NOT in previous DEF. - } - ++RevInstIter; - } -#endif } +#endif } if (!benign) { // Look for bitwise NOT idiom on USE-only addend or subtrahend. - SMPInstr *DefInst = this->GetFunc()->GetInstFromAddr(DefAddr); UseOp = DefInst->GetUseOnlyAddSubOp(); - int UseSSANum; if (UseOp.type == o_reg) { CanonicalizeOpnd(UseOp); - UseIter = DefInst->FindUse(UseOp); // DEF is also USE in addition or subtraction ... - if (UseIter != DefInst->GetLastUse()) { // ... but not always on lea opcode + UseIter = DefInst->FindUse(UseOp); + if (UseIter != DefInst->GetLastUse()) { UseSSANum = UseIter->GetSSANum(); bool LocalName = this->IsLocalName(UseOp); -#if 1 + this->GetFunc()->ResetProcessedBlocks(); if (DefInst->IsOpSourceBitwiseNot(UseOp, UseSSANum)) { benign = true; IdiomCode = 21; } -#else - ea_t UseDefAddr = this->GetDefAddrFromUseAddr(UseOp, DefAddr, UseSSANum, LocalName); - if (UseDefAddr >= this->GetFunc()->GetFirstFuncAddr()) { // inst DEF, not Phi DEF - DefInst = this->GetFunc()->GetInstFromAddr(UseDefAddr); - if (DefInst->MDIsBitwiseNotOpcode()) { - benign = true; - IdiomCode = 21; - } - } -#endif } } else if (MDIsStackAccessOpnd(UseOp, this->GetFunc()->UsesFramePointer())) { // We need the canonicalized stack operand as found in DEFs and USEs. UseOp = DefInst->MDGetMemUseOp(); assert(o_void != UseOp.type); -#if 1 UseIter = DefInst->FindUse(UseOp); assert(UseIter != DefInst->GetLastUse()); UseSSANum = UseIter->GetSSANum(); + this->GetFunc()->ResetProcessedBlocks(); if (DefInst->IsOpSourceBitwiseNot(UseOp, UseSSANum)) { benign = true; IdiomCode = 21; } -#else - InstIter = this->GetInstIterFromAddr(DefAddr); - assert(InstIter != this->GetLastInstr()); - list<SMPInstr *>::reverse_iterator RevInstIter(InstIter); - op_t NewDefOp; - while (RevInstIter != this->Instrs.rend()) { - SMPInstr *SearchInst = (*RevInstIter); - NewDefOp = SearchInst->MDGetMemDefOp(); - if (IsEqOp(UseOp, NewDefOp)) { - // Found the DEF of the stack operand used in our add or subtract. - if (SearchInst->MDIsBitwiseNotOpcode()) { - benign = true; - IdiomCode = 21; - } - break; // Only look for NOT in previous DEF. - } - ++RevInstIter; - } -#endif } } diff --git a/SMPInstr.cpp b/SMPInstr.cpp index 8954a2e001607d89dca28e5ded46a2699ea4fc58..9caccd1de053dfdc01dfce49cc501c9ef83f3b79 100644 --- a/SMPInstr.cpp +++ b/SMPInstr.cpp @@ -3955,6 +3955,113 @@ bool SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(op_t UseOp, i return FoundMoveZXCC; } // 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) { + if (UseSSANum == -1) { + return false; + } + + bool FoundMoveNotZXCCSubreg = false; + bool RegDef = (o_reg == UseOp.type); + bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); + 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)) { + // Try to find in the function level. + UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); + } + + if ((!MDIsDataFlowOpnd(UseOp, UseFP)) || (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. + FoundMoveNotZXCCSubreg = 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->IsOpSourceSpecial(UseOp, PhiUseSSANum, TruncationCheck, SourceInstAddr)) { + FoundMoveNotZXCCSubreg = 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)) { + FoundMoveNotZXCCSubreg = ((FG_MASK_UNSIGNED == SignMask) || TruncationCheck); // Truncation chain cares if source was reduced width. + if (FoundMoveNotZXCCSubreg) { + SourceInstAddr = DefInst->GetAddr(); + } + } + else if (DefInst->MDIsAnySetValue() || DefInst->MDIsShiftRight() || DefInst->MDIsBitwiseNotOpcode()) { + FoundMoveNotZXCCSubreg = true; + SourceInstAddr = DefInst->GetAddr(); + } + else if (DefInst->MDIsMoveInstr()) { + op_t MoveUseOp = DefInst->GetMoveSource(); + if (o_reg == MoveUseOp.type) { // pattern is simple; don't try to follow through memory + CanonicalizeOpnd(MoveUseOp); + set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp); + assert(MoveUseIter != DefInst->GetLastUse()); + int MoveUseSSANum = MoveUseIter->GetSSANum(); + FoundMoveNotZXCCSubreg = DefInst->IsOpSourceSpecial(MoveUseOp, MoveUseSSANum, TruncationCheck, SourceInstAddr); // 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(); + FoundMoveNotZXCCSubreg = DefInst->IsOpSourceSpecial(UseOp, BitUseSSANum, true, SourceInstAddr); // recurse up the chain + } + } + else { + FoundMoveNotZXCCSubreg = false; + } + } + + return FoundMoveNotZXCCSubreg; +} // end of SMPInstr::IsOpSourceSpecial() + // Is opcode a shift or rotate? // NOTE: We omit MMX/SSE unit shifts that do not use a general purpose // register as a shift counter, because right now this method is only diff --git a/SMPInstr.h b/SMPInstr.h index 6ff64563302648c02f94453bda45fb690c1592f9..0310d03820312535b2b9eac608984b4720762f72 100644 --- a/SMPInstr.h +++ b/SMPInstr.h @@ -479,6 +479,7 @@ public: bool IsOpSourceConditionCode(op_t UseOp, int UseSSANum); // Does UseOp ultimately come from a set-condition-code instruction? bool IsOpSourceZeroExtendedMove(op_t UseOp, int UseSSANum, bool TruncationCheck); // Does UseOp ultimately come from a move-with-zero-extension instruction? bool IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(op_t UseOp, int UseSSANum, bool TruncationCheck); // Union of two previous methods plus right shifts + bool IsOpSourceSpecial(op_t UseOp, int UseSSANum, bool TruncationCheck, ea_t &SourceInstAddr); // Trace through moves to any of the above cases, return source addr bool MDIsOverflowingOpcode(void) const; // Is non-multiply arithmetic instruction that can possibly overflow? bool MDIsUnderflowingOpcode(void) const; // Is non-multiply arithmetic instruction that can possibly underflow? bool MDIsAddition(void) const;