From 8ff7959e11c6743ec70b83a72b54c6124875a12d Mon Sep 17 00:00:00 2001
From: clc5q <clc5q@git.zephyr-software.com>
Date: Tue, 25 Jun 2013 18:38:15 +0000
Subject: [PATCH] IDIOM 24 for truncations.

---
 SMPBasicBlock.cpp | 29 ++++++++++++++++++++++++++++-
 SMPBasicBlock.h   |  2 +-
 SMPInstr.cpp      | 23 ++++++++++++++++-------
 SMPInstr.h        |  1 +
 4 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/SMPBasicBlock.cpp b/SMPBasicBlock.cpp
index 35db7cb3..d6ea98cf 100644
--- a/SMPBasicBlock.cpp
+++ b/SMPBasicBlock.cpp
@@ -4084,7 +4084,7 @@ bool SMPBasicBlock::IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAdd
 
 // We don't care if we truncate computing some DEFs, because of how they are used.
 //  Return true when we detect one of these cases.
-bool SMPBasicBlock::IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefAddr) {
+bool SMPBasicBlock::IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefAddr, int &IdiomCode) {
 	bool benign = false;
 	list<SMPInstr *>::iterator InstIter, NextIter;
 	set<DefOrUse, LessDefUse>::iterator UseIter, UseIter2, DefIter;
@@ -4135,6 +4135,7 @@ bool SMPBasicBlock::IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefA
 
 				if (UseIter->DoesNotTruncate()) {
 					benign = true; // already analyzed
+					IdiomCode = 2;
 					break;
 				}
 
@@ -4168,6 +4169,7 @@ bool SMPBasicBlock::IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefA
 						if (CurrInst->ShiftMakesUpperBitsLower(UseBitWidth, false)) {
 							// At least it matches the less restrictive two-inst sequence.
 							benign = true;
+							IdiomCode = 2;
 							// Set the NoTruncate flag in the first instruction for the sub-reg UseOp.
 							TruncationInst->SetUseNoTruncate(SearchOp, true);
 							if (CurrInst->ShiftMakesUpperBitsLower(UseBitWidth, true)) {
@@ -4180,6 +4182,7 @@ bool SMPBasicBlock::IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefA
 						//  less than the full register after the truncation, so the truncation
 						//  is almost certainly benign.
 						benign = true;
+						IdiomCode = 4;
 						break; // Masking inst is redefining SearchOp
 					}
 				} // end if found SearchOp in CurrInst
@@ -4220,6 +4223,30 @@ bool SMPBasicBlock::IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefA
 		} // end if (InstAddr == DefAddr) ... else if (FoundTruncationDef) ...
 	} // end for all insts in block
 
+	if (benign)
+		return true;
+
+	SMPInstr *DefInst = this->GetFunc()->GetInstFromAddr(DefAddr);
+	ea_t SourceInstAddr = BADADDR;
+	SMPInstr *SourceInst = NULL;
+	int DefUseSSANum = SMP_SSA_UNINIT;
+	bool SpecialSourceFound = false;
+	bool LeaDef = DefInst->MDIsLoadEffectiveAddressInstr();
+	bool UseFP = this->GetFunc()->UsesFramePointer();
+	UseIter = DefInst->FindUse(DefOp); // DEF is also USE in addition, subtraction, etc.
+	if (MDIsDataFlowOpnd(DefOp, UseFP) && (UseIter != DefInst->GetLastUse())) {
+		DefUseSSANum = UseIter->GetSSANum();
+		this->GetFunc()->ResetProcessedBlocks();
+		SpecialSourceFound = DefInst->IsOpSourceSpecial(DefOp, DefUseSSANum, true, SourceInstAddr);
+		if (SpecialSourceFound) {
+			SourceInst = this->GetFunc()->GetInstFromAddr(SourceInstAddr);
+			if (SourceInst->IsReducedWidthDef()) {
+				benign = true;
+				IdiomCode = 24;
+			}
+		}
+	}
+
 	if (!benign && (o_reg == SearchOp.type)) {
 		// See if truncation use is a copy of another register that gets subword masked, which
 		//  is a sign that the truncation use is also only valid for the lower bits.
diff --git a/SMPBasicBlock.h b/SMPBasicBlock.h
index 22bb4ba8..5f8ae1dc 100644
--- a/SMPBasicBlock.h
+++ b/SMPBasicBlock.h
@@ -302,7 +302,7 @@ public:
 	
 	bool IsInfiniteSelfLoop(void); // return true if block loops infinitely to itself
 	bool IsBenignOverflowDEF(op_t DefOp, int DefSSANum, size_t DefAddr, bool UnderflowOpcode, int &IdiomCode); // Do we not care if DEF overflowed, due to how it is used?
-	bool IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefAddr); // Do we not care if DEF overflowed, due to how it is used?
+	bool IsBenignTruncationDEF(op_t DefOp, int DefSSANum, size_t DefAddr, int &IdiomCode); // Do we not care if DEF overflowed, due to how it is used?
 	bool IsDefMasked(op_t DefOp, int DefSSANum, ea_t DefAddr); // Does DefOp+DefSSANum get subreg masked before it gets re-DEFined?
 	bool IsCriticalSink(op_t DefOp, int DefSSANum, string &SinkString); // What is ultimate use of DEF that might have integer error?
 	bool IsStackOpNextUsedWithSignedness(op_t StackDefOp, ea_t DefAddr, int SSANum); // Is next use of stack DEF a sign- or zero-extended load?
diff --git a/SMPInstr.cpp b/SMPInstr.cpp
index 9caccd1d..f44a0680 100644
--- a/SMPInstr.cpp
+++ b/SMPInstr.cpp
@@ -3477,6 +3477,7 @@ bool SMPInstr::IsNonAddressReg(op_t UseOp) const {
 	}
 	return FoundUse;
 } // end of SMPInstr::IsNonAddressReg()
+
 uval_t SMPInstr::MDGetShiftCount(void) const {
 	uval_t ShiftCount = 0;
 
@@ -3493,6 +3494,13 @@ uval_t SMPInstr::MDGetShiftCount(void) const {
 	return ShiftCount;
 } // end of SMPInstr::MDGetShiftCount()
 
+// 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));
+}
+
 // 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.
@@ -4054,8 +4062,12 @@ bool SMPInstr::IsOpSourceSpecial(op_t UseOp, int UseSSANum, bool TruncationCheck
 				FoundMoveNotZXCCSubreg = DefInst->IsOpSourceSpecial(UseOp, BitUseSSANum, true, SourceInstAddr); // recurse up the chain
 			}
 		}
-		else {
-			FoundMoveNotZXCCSubreg = false;
+		else if (TruncationCheck) {
+			// Check for reduced-width arithmetic.
+			if (DefInst->IsReducedWidthDef()) { // chain like sub cl,3; mov eax,ecx; then "truncating" move of al
+				FoundMoveNotZXCCSubreg = true;
+				SourceInstAddr = DefInst->GetAddr();
+			}
 		}
 	}
 
@@ -4876,11 +4888,8 @@ bool SMPInstr::IsBenignTruncation(int &IdiomCode) {
 				set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef();
 				assert(DefIter != this->GetLastDef());
 				int DefSSANum = DefIter->GetSSANum();
-				benign = this->GetBlock()->IsBenignTruncationDEF(DefIter->GetOp(), DefSSANum, this->GetAddr());
-				if (benign) {
-					IdiomCode = 2;
-				}
-				else {
+				benign = this->GetBlock()->IsBenignTruncationDEF(DefIter->GetOp(), DefSSANum, this->GetAddr(), IdiomCode);
+				if (!benign) {
 					// Third case: value gets zero-extended, AND/OR instructions manipulate it, then
 					//  the lower bits get written. No adds, subtracts, etc. in the chain of operations.
 					//  This is just the typical unwillingness of compiler to do less than 32-bit arithmetic,
diff --git a/SMPInstr.h b/SMPInstr.h
index 0310d038..136f2c7a 100644
--- a/SMPInstr.h
+++ b/SMPInstr.h
@@ -473,6 +473,7 @@ public:
 	bool AllDEFsTyped(void); // No DEF is UNINIT
 	bool AllUSEsTyped(void); // No USE is UNINIT
 	bool IsNonAddressReg(op_t UseOp) const; // UseOp is a USE reg, not just an address reg in a memory USE
+	bool IsReducedWidthDef(void) const; // RTL shows DEF operand is subreg.
 	bool IsSubRegUsedAsShiftCount(op_t UseOp); // Is a subreg of UseOp used as a shift counter?
 	bool IsOpSourceSmallPositiveConstant(op_t UseOp, int UseSSANum); // Does UseOp ultimately come from a small positive constant?
 	bool IsOpSourceBitwiseNot(op_t UseOp, int UseSSANum); // Does UseOp ultimately come from a bitwise not instruction?
-- 
GitLab