From e72764aafeb966be2537ebff10f7bf5f2a5f4e1a Mon Sep 17 00:00:00 2001
From: clc5q <clc5q@git.zephyr-software.com>
Date: Sun, 18 May 2014 05:20:28 +0000
Subject: [PATCH] Interprocedural propagation of fine-grained numeric type info
 for registers.

---
 SMPDataFlowAnalysis.cpp |  2 +-
 SMPFunction.cpp         | 22 ++++++++++++++++++++++
 SMPFunction.h           |  2 +-
 SMPInstr.cpp            | 20 +++++++++++++++++++-
 SMPInstr.h              |  8 ++++----
 SMPProgram.cpp          |  2 +-
 6 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/SMPDataFlowAnalysis.cpp b/SMPDataFlowAnalysis.cpp
index 4f5c936a..549bd451 100644
--- a/SMPDataFlowAnalysis.cpp
+++ b/SMPDataFlowAnalysis.cpp
@@ -124,7 +124,7 @@ const char *MDGetRegName(op_t RegOp) {
 		return WordRegStrings[RegOp.reg];
 	}
 	else if ((RegOp.dtyp == dt_qword) && (RegOp.reg >= R_ax) && (RegOp.reg <= R_di)) {
-		// 16-bit registers
+		// 64-bit registers
 		return QWordRegStrings[RegOp.reg];
 	}
 	else {
diff --git a/SMPFunction.cpp b/SMPFunction.cpp
index 5c9d281f..3b102d1b 100644
--- a/SMPFunction.cpp
+++ b/SMPFunction.cpp
@@ -2343,6 +2343,19 @@ void SMPFunction::MDFindIncomingTypes(void) {
 					// Note this type meet function is used in an aggressive way here, as
 					//  a mixture of UNINIT and NUMERIC at various call sites will produce NUMERIC, for example.
 					//  We are not demanding that all call sites have a consistent type with no UNINIT instances.
+
+					// Get the FGInfo (from call site in CallerFunc) for each USE as well.
+					int UseSSANum = CallSiteUseIter->GetSSANum();
+					int DefHashIndex = HashGlobalNameAndSSA(MarkerDefOp, UseSSANum);
+					struct FineGrainedInfo RegDefFG;
+					if (CallerFunc->IsGlobalName(MarkerDefOp)) {
+						RegDefFG = CallerFunc->GetDefFGInfo(DefHashIndex);
+					}
+					else {
+						RegDefFG = CallSiteInst->GetBlock()->GetDefFGInfo(DefHashIndex);
+					}
+					// Meet function for FGInfo is a simple bitwise OR operation.
+					(void) MarkerInst->UpdateDefOpFGInfo(MarkerDefOp, RegDefFG);
 				}
 			}
 		}
@@ -7217,7 +7230,16 @@ bool SMPFunction::InferInterproceduralTypes(void) {
 	// If that produced new incoming types, then see if new type inference can happen.
 	if (change) {
 		this->InferTypes(false);
+		for (list<SMPBasicBlock *>::iterator BlockIter = this->Blocks.begin(); BlockIter != this->Blocks.end(); ++BlockIter) {
+			SMPBasicBlock *CurrBlock = (*BlockIter);
+			CurrBlock->PropagatePhiFGInfo();
+		}
 	}
+#if STARS_AGGRESSIVE_SIGNEDNESS_PROPAGATION
+	else {
+		change = this->PropagateSignedness();
+	}
+#endif
 
 	return change;
 } // end of SMPFunction::InferInterproceduralTypes()
diff --git a/SMPFunction.h b/SMPFunction.h
index 22c1a40e..97c06713 100644
--- a/SMPFunction.h
+++ b/SMPFunction.h
@@ -168,7 +168,7 @@ public:
 	inline int GetReturnRegType(uint16 RegNum) const { return ((RegNum < ReturnRegTypes.size()) ? (int) ReturnRegTypes[RegNum] : 0); };
 	inline struct FineGrainedInfo GetReturnRegFGInfo(uint16 RegNum) const { return ReturnRegFGInfo.at(RegNum); };
 	inline size_t GetReturnRegFGInfoSize(void) const { return ReturnRegFGInfo.size(); };
-	SMPOperandType GetIncomingRegType(uint16 RegNum); // Get reg type from all call sites; compute if called for the first time.
+	SMPOperandType GetIncomingRegType(uint16 RegNum); // Get reg type from all call sites.
 	inline map<ea_t, op_t>::iterator FindLeaOperand(ea_t addr) { return LeaInstOpMap.find(addr); };
 	inline map<int, struct STARS_SCCP_Const_Struct>::iterator FindConstValue(int DefHashValue) { return ConstantDefs.find(DefHashValue); };
 	inline map<int, struct STARS_SCCP_Const_Struct>::iterator GetLastConstValueIter(void) { return ConstantDefs.end(); };
diff --git a/SMPInstr.cpp b/SMPInstr.cpp
index b1f63a08..241ff558 100644
--- a/SMPInstr.cpp
+++ b/SMPInstr.cpp
@@ -9921,7 +9921,8 @@ void SMPInstr::EmitIntegerErrorAnnotations(FILE *InfoAnnotFile, list<size_t> &Lo
 		op_t SearchOp = UseOp;
 		// Canonicalize sub-regs for searching DEFs and USEs.
 		CanonicalizeOpnd(SearchOp);
-		UseHashValue = HashGlobalNameAndSSA(SearchOp, UseIter->GetSSANum());
+		UseSSANum = UseIter->GetSSANum();
+		UseHashValue = HashGlobalNameAndSSA(SearchOp, UseSSANum);
 
 		if (this->BasicBlock->IsLocalName(SearchOp)) {
 			// Local name, find in basic block maps.
@@ -9941,6 +9942,17 @@ void SMPInstr::EmitIntegerErrorAnnotations(FILE *InfoAnnotFile, list<size_t> &Lo
 		SourceDefSignInfo = SourceDefFGInfo.SignMiscInfo;
 		SourceDefSignMask = (SourceDefSignInfo & FG_MASK_SIGNEDNESS_BITS);
 
+		// If the DEF is in the SSA marker instruction at the top of the function,
+		//  then the register was live into the function. The register is canonicalized
+		//  to full width in the DEF in the marker instruction, making it appear that it
+		//  is now being truncated. In fact, what is more likely is that a subword reg
+		//  was passed in to the function, zero-extended. We should detect this case and suppress 
+		//  truncation annotations, else they will increase when we pass interprocedural
+		//  types and FG info into the marker instruction.
+		if (!SuppressTruncation && (0 == UseSSANum) && (this->GetBlock()->GetFunc()->IsLiveIn(SearchOp))) {
+			SuppressTruncation = true;
+			TruncationIdiomCode = 26;
+		}
 #if 1
 		// If we have no signedness info at all for the UseSignMask, but
 		//  the SourceDefSignMask has info, then we want to use the
@@ -10057,6 +10069,12 @@ void SMPInstr::EmitIntegerErrorAnnotations(FILE *InfoAnnotFile, list<size_t> &Lo
 			if (SourceDefBitWidth == 0) { // Convert for printing annotation.
 				SourceDefBitWidth = 8 * GetOpDataSize(SearchOp);
 			}
+			if ((SourceDefBitWidth == 64) && (SearchOp.dtyp < dt_qword)) {
+				// Unlike overflows, we don't have the original DefOp that is 64 bits;
+				//  it is in a previous instruction. We don't want to print ESI instead of RSI,
+				//  for example, so we fix the width field of SearchOp.
+				SearchOp.dtyp = dt_qword;
+			}
 
 			// OK, we need to check for possible truncation. But, how we check depends on the
 			//  signedness combinations of the source and destination operands of the move.
diff --git a/SMPInstr.h b/SMPInstr.h
index 34169bed..e24513a6 100644
--- a/SMPInstr.h
+++ b/SMPInstr.h
@@ -438,6 +438,10 @@ public:
 	inline void EraseUse(set<DefOrUse, LessDefUse>::iterator UseIter)  { Uses.EraseRef(UseIter); };
 	void SetRegDead(size_t RegNum); // Set the DeadRegsBitmap entry for Regnum.
 	inline void SetStackPtrOffset(sval_t Delta) { StackPtrOffset = Delta; };
+	bool UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG);
+		// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
+	bool UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG);
+		// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
 
 	// Query methods
 	bool HasDestMemoryOperand(void); // Does instruction write to memory?
@@ -827,10 +831,6 @@ private:
 	bool InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter,  struct FineGrainedInfo &OpFG);
 		// infer FG info, + width on FirstIter; pass out FG info, return true if changes to FG info maps
 
-	bool UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG);
-		// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
-	bool UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG);
-		// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
 	unsigned short GetDefSignInfoFromUseOp(op_t UseOp);
 		// Helper to fetch DEF signedness info for UseOp that has none.
 
diff --git a/SMPProgram.cpp b/SMPProgram.cpp
index 97a29ed1..5561409f 100644
--- a/SMPProgram.cpp
+++ b/SMPProgram.cpp
@@ -78,7 +78,7 @@
 
 // Perform interprocedural type inference and propagation?
 #define STARS_INTERPROCEDURAL_TYPE_INFERENCE 1
-#define STARS_INTERPROCEDURAL_ITERATION_LIMIT 5
+#define STARS_INTERPROCEDURAL_ITERATION_LIMIT 7
 
 ea_t LowestGlobalVarAddress;
 ea_t HighestGlobalVarAddress;
-- 
GitLab