From 0d1e64310f9d6d99d2117683a1d52bb2c103d227 Mon Sep 17 00:00:00 2001
From: clc5q <clc5q@git.zephyr-software.com>
Date: Tue, 25 Jun 2013 16:03:22 +0000
Subject: [PATCH] IsOpSourceSpecial() generalization and redundancy
 elmimination.

---
 SMPBasicBlock.cpp | 118 +++++++++++++++-------------------------------
 SMPInstr.cpp      | 107 +++++++++++++++++++++++++++++++++++++++++
 SMPInstr.h        |   1 +
 3 files changed, 146 insertions(+), 80 deletions(-)

diff --git a/SMPBasicBlock.cpp b/SMPBasicBlock.cpp
index fd1152ef..35db7cb3 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 8954a2e0..9caccd1d 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 6ff64563..0310d038 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;
-- 
GitLab