Skip to content
Snippets Groups Projects
SMPInstr.cpp 396 KiB
Newer Older
		case SMP_ADD_CARRY:   // add with carry
		case SMP_BITWISE_AND:
		case SMP_BITWISE_OR:
clc5q's avatar
clc5q committed
			// Extract the current types of right and left operands and the operator.
clc5q's avatar
clc5q committed
			LeftOp = CurrRT->GetLeftOperand();
			CurrUse = this->Uses.FindRef(LeftOp);
			assert(CurrUse != this->GetLastUse()); // found it
			LeftType = CurrUse->GetType();
			if (CurrRT->HasRightSubTree()) {
				updated |= this->InferOperatorType(CurrRT->GetRightTree());
clc5q's avatar
clc5q committed
				RightType = CurrRT->GetRightTree()->GetOperatorType();
			}
			else {
				RightOp = CurrRT->GetRightOperand();
				if (o_void == RightOp.type) {
					SMP_msg("ERROR: void operand at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
clc5q's avatar
clc5q committed
					CurrUse = this->Uses.FindRef(RightOp);
					if (CurrUse == this->GetLastUse()) {
						SMP_msg("SERIOUS WARNING: Adding missing USE of ");
clc5q's avatar
clc5q committed
						PrintOperand(RightOp);
						SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
clc5q's avatar
clc5q committed
						this->Uses.SetRef(RightOp);
						RightType = CurrUse->GetType();
clc5q's avatar
clc5q committed
				}
			}

			// We have to know both operand types to infer the operator, or know the
			//  operator type and one operand type to infer the other operand type.
			if ((UNINIT == OperType) 
clc5q's avatar
clc5q committed
				&& ((UNINIT == LeftType) || (UNINIT == RightType)))
				break;

			// If both operands are NUMERIC, operator and result are NUMERIC.
			// If one operand is NUMERIC and the other is a pointer type,
			//  then the ADD operator and the result will inherit this second type,
			//  while AND and OR operators will remain UNINIT (we don't know what
			//  type "ptr AND 0xfffffff8" has until we see how it is used).
			LeftNumeric = IsEqType(NUMERIC, LeftType);
			RightNumeric = IsEqType(NUMERIC, RightType);
			LeftPointer = IsDataPtr(LeftType);
			RightPointer = IsDataPtr(RightType);
clc5q's avatar
clc5q committed
				// Infer operator type from left and right operands.
				if (LeftNumeric && RightNumeric) {
					CurrRT->SetOperatorType(NUMERIC, this);
					updated = true;
clc5q's avatar
clc5q committed
					break;
				}
				else if (LeftNumeric || RightNumeric) {
					// ADD of NUMERIC to non-NUMERIC preserves non-NUMERIC type.
					// AND and OR operations should leave the operator UNINIT for now.
					if (LeftNumeric && (UNINIT != RightType) 
						&& ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) {
						CurrRT->SetOperatorType(RightType, this);
						updated = true;
clc5q's avatar
clc5q committed
						break;
					else if (RightNumeric && (UNINIT != LeftType) 
						&& ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) {
						CurrRT->SetOperatorType(LeftType, this);
						updated = true;
clc5q's avatar
clc5q committed
						break;
				else if (LeftPointer && RightPointer) {
					// Arithmetic on two pointers
					if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) {
						CurrRT->SetOperatorType(UNKNOWN, this);
					}
					else { // bitwise AND or OR of two pointers
						SMP_msg("WARNING: hash of two pointers at %x in %s\n",
							this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						// hash operation? leave operator as UNINIT
clc5q's avatar
clc5q committed
					break;
				else if ((LeftPointer && IsEqType(RightType, PTROFFSET))
					|| (RightPointer && IsEqType(LeftType, PTROFFSET))) {
					// Arithmetic on PTR and PTROFFSET
					if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) {
						// We assume (A-B) is being added to B or vice versa **!!**
						CurrRT->SetOperatorType(POINTER, this);
					}
					else { // bitwise AND or OR of pointer and pointer difference
						SMP_msg("WARNING: hash of PTROFFSET and POINTER at %x in %s\n",
							this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						// hash operation? leave operator as UNINIT
clc5q's avatar
clc5q committed
					break;
				else if ((LeftPointer && IsEqType(RightType, NEGATEDPTR))
					|| (RightPointer && IsEqType(LeftType, NEGATEDPTR))) {
					// Compiler optimizations can take a ptr expression such as:
					//  PTR1 - PTR2 + 1
					//  and hoist the loop-invariant subexpression " - PTR2 + 1"
					//  out of the loop as "1 - PTR2", which produces a NEGATEDPTR type.
					//  When PTR1 gets its value determined inside the loop, then the
					//  addition of PTR1 finally happens, producing a PTROFFSET type,
					//  which is what the whole expression is.
					if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) {
						CurrRT->SetOperatorType(PTROFFSET, this);
						updated = true;
					}
					else { // bitwise AND or OR of pointer and pointer difference
						SMP_msg("WARNING: hash of NEGATEDPTR and POINTER at %x in %s\n",
							this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			} // end if UNINIT operator type
			else { // operator has type other than UNINIT
				// We make add-with-carry and subtract-with-borrow exceptions
				//  to the type propagation. LeftOp could have POINTER type
				//  inferred later; these instructions can change the type of
				//  the register from POINTER to NUMERIC, unlike regular
				//  add and subtract opcodes.
				OperNumeric = IsEqType(NUMERIC, OperType);
				OperPointer = IsDataPtr(OperType);
				if (OperNumeric) {
					if ((UNINIT == LeftType)
						&& (SMP_ADD_CARRY != CurrOp)) {
						CurrUse = this->SetUseType(LeftOp, CurrRT->GetOperatorType());
						updated = true;
						assert(CurrUse != this->GetLastUse());
clc5q's avatar
clc5q committed
						break;
					if (CurrRT->HasRightSubTree()) {
						// Must need to iterate through the right tree again, as the operator
						//  has been typed.
						if (UNINIT == RightType) {
							CurrRT->GetRightTree()->SetOperatorType(CurrRT->GetOperatorType(), this);
							updated = true;
							updated |= this->InferOperatorType(CurrRT->GetRightTree());
						}
						break;
					}
					else { // right operand; propagate operator type if needed
						if (UNINIT == RightType) {
							CurrUse = this->SetUseType(RightOp, CurrRT->GetOperatorType());
							updated = true;
							assert(CurrUse != this->GetLastUse());
							break;
						}
					}
		case SMP_SUBTRACT_BORROW:  // subtract with borrow
			// Extract the current types of right and left operands and the operator.
			OperType = CurrRT->GetOperatorType();
			LeftOp = CurrRT->GetLeftOperand();
			LeftUse = this->Uses.FindRef(LeftOp);
			assert(LeftUse != this->GetLastUse()); // found it
			LeftType = LeftUse->GetType();
			if (CurrRT->HasRightSubTree()) {
				updated |= this->InferOperatorType(CurrRT->GetRightTree());
				RightType = CurrRT->GetRightTree()->GetOperatorType();
			}
			else {
				RightOp = CurrRT->GetRightOperand();
				if (o_void == RightOp.type) {
					SMP_msg("ERROR: void operand in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
					return false;
				}
				else {
					RightUse = this->Uses.FindRef(RightOp);
					if (RightUse == this->GetLastUse()) {
						PrintOperand(RightOp);
						SMP_msg(" in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
						this->Uses.SetRef(RightOp);
						updated = true;
						break;
					}
					else {
						RightType = RightUse->GetType();
					}
				}
			}
			// If left operand is NUMERIC, operator is NUMERIC.
			LeftNumeric = IsEqType(NUMERIC, LeftType);
			RightNumeric = IsEqType(NUMERIC, RightType);
			LeftPointer = IsDataPtr(LeftType);
			RightPointer = IsDataPtr(RightType);
				// Subtracting anything from a NUMERIC leaves it NUMERIC or NEGATEDPTR,
				//  in the special case in which a POINTER is subtracted from a NUMERIC.
				//  See NEGATEDPTR comments in the ADD/AND operators case above.
				if (RightPointer) {
					CurrRT->SetOperatorType(NEGATEDPTR, this);
					updated = true;
				}
				else if (UNINIT == OperType) {
					CurrRT->SetOperatorType(NUMERIC, this);
				else if (IsNotEqType(NUMERIC, OperType) && IsNotEqType(NEGATEDPTR, OperType)) {
					SMP_msg("ERROR: SMP_SUBTRACT from NUMERIC should be NUMERIC or NEGATEDPTR operator.");
					SMP_msg(" Operator type is %d in: %s\n", OperType, DisAsmText.GetDisAsm(this->GetAddr()));
				if (!RightNumeric) {
					// Right operand is being used as a NUMERIC, so propagate NUMERIC to it.
					if (CurrRT->HasRightSubTree()) {
						CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
					}
					else {
						RightUse = this->SetUseType(RightOp, NUMERIC);
					}
					updated = true;
				}
			} // end if LeftNumeric
			else if (LeftPointer) {
				if (UNINIT == OperType) {
					// If we subtract another pointer type, we produce PTROFFSET.
					if (RightPointer) {
						CurrRT->SetOperatorType(PTROFFSET, this);
						updated = true;
					}
					else if (RightType == PTROFFSET) {
						// We assume B - (B - A) == A    **!!**
						CurrRT->SetOperatorType(POINTER, this);
						SMP_msg("WARNING: PTR - PTROFFSET produces PTR at %x in %s\n", 
							this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						updated = true;
					}
					else if (RightNumeric) {
						// pointer minus NUMERIC keeps same pointer type
						CurrRT->SetOperatorType(LeftType, this);
						updated = true;
					}
				}
				else { // we have an operator type for the SMP_SUBTRACT
					OperNumeric = IsEqType(NUMERIC, OperType);
					OperPointer = IsDataPtr(OperType);
					if (CurrRT->HasRightSubTree()) {
						// Might need to iterate through the right tree again, if its operator
						//  can be typed.
						if (UNINIT == RightType) {
							if (OperPointer) {
								// PTR := PTR - ?? ==> ?? is NUMERIC  Why? ?? could be PTROFFSET
								CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
								updated |= this->InferOperatorType(CurrRT->GetRightTree());
							}
							else if (OperType == PTROFFSET) {
								CurrRT->GetRightTree()->SetOperatorType(LeftType, this);
								updated |= this->InferOperatorType(CurrRT->GetRightTree());
							}
							else if (OperNumeric) {
								SMP_msg("WARNING: PTR - ?? produces NUMERIC at %x in %s\n", 
									this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
							}
						}
						break;
					}
					else { // right operand; propagate operator type if needed
						if (UNINIT == RightType) {
							if (OperPointer) {
								// PTR := PTR - ?? ==> ?? is NUMERIC  Why? ?? could be PTROFFSET
								RightUse = this->SetUseType(RightOp, NUMERIC);
								updated = true;
								assert(RightUse != this->GetLastUse());
							}
							else if (OperType == PTROFFSET) {
								// PTROFFSET := PTR - ?? ==> ?? is PTR
								RightUse = this->SetUseType(RightOp, LeftType);
								updated = true;
							}
								SMP_msg("WARNING: PTR - ?? produces NUMERIC at %x in %s\n", 
									this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
							break;
						}
					}
				} // end if OperType is UNINIT ... else ...
			} // end if LeftNumeric ... else if LeftPointer ...
			else if (UNINIT == LeftType) {
				// We make add-with-carry and subtract-with-borrow exceptions
				//  to the type propagation. LeftOp could have POINTER type
				//  inferred later; these instructions can change the type of
				//  the register from POINTER to NUMERIC, unlike regular
				//  add and subtract opcodes.
				if ((UNINIT != OperType)
					&& (SMP_SUBTRACT_BORROW != CurrOp)) {
					LeftUse = this->SetUseType(LeftOp, OperType);
					assert(LeftUse != this->GetLastUse());
					updated = true;
				}
			}
			break;

		case SMP_ASSIGN:
clc5q's avatar
clc5q committed
			// Extract the current types of right and left operands and SMP_ASSIGN operator.
			OperType = CurrRT->GetOperatorType();
			DefOp = CurrRT->GetLeftOperand();
			CurrDef = this->Defs.FindRef(DefOp);
			assert(CurrDef != this->GetLastDef()); // found it
clc5q's avatar
clc5q committed
			LeftType = CurrDef->GetType();
			if (CurrRT->HasRightSubTree()) {
				updated |= this->InferOperatorType(CurrRT->GetRightTree());
clc5q's avatar
clc5q committed
				RightType = CurrRT->GetRightTree()->GetOperatorType();
			}
			else {
				UseOp = CurrRT->GetRightOperand();
				if (o_void == UseOp.type) {
					SMP_msg("ERROR: void operand for SMP_ASSIGN in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
					return false;
				}
				else {
					CurrUse = this->Uses.FindRef(UseOp);
					if (CurrUse == this->GetLastUse()) {
						PrintOperand(UseOp);
						SMP_msg(" in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
						this->Uses.SetRef(UseOp);
						updated = true;
clc5q's avatar
clc5q committed
						break;
clc5q's avatar
clc5q committed
						RightType = CurrUse->GetType();
clc5q's avatar
clc5q committed
			}
				SMP_msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->address, LeftType,
clc5q's avatar
clc5q committed
			if ((UNINIT == RightType) && (UNINIT == LeftType)) {
				break;
			}
clc5q's avatar
clc5q committed
				// UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT.
				if (UNINIT != RightType) {
					// We have to special case conditional moves. Only if both operands
					//  (the source and the prior value of the potential destination,
					//  which was added to the USE set by BuildMoveRTL()) agree in type
					//  can we propagate their common type to the operator and ultimately
					//  to the DEF.
					if ((!this->MDIsConditionalMoveInstr()) || this->Uses.TypesAgreeNoFlags()) {
						CurrRT->SetOperatorType(RightType, this);
						OperType = RightType;
						UpdatedOperType = true;
					CurrRT->SetOperatorType(LeftType, this);
					UpdatedOperType = true;
				}
				// Speed up type propagation by passing the RightType/OperType to the Def
				//  on this iteration.
				if (UpdatedOperType) {
					// Propagate the new DEF type unless it is an indirect memory access.
					//  Future: Propagate until re-DEF of addressing register terminates
					//  the propagation. **!!**
					CurrDef = this->SetDefType(DefOp, OperType);
					LeftType = OperType;
					if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
						bool IsMemOp = (o_reg != DefOp.type);
						bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
						;
#else
						// Be conservative and only propagate register DEFs and SAFE stack locs.
						//  We can improve this in the future. **!!**
						MemPropagate = MemPropagate && SafeFunc;
#endif
						if ((o_reg == DefOp.type) || MemPropagate) {
							int SSANum = CurrDef->GetSSANum();
							if (this->BasicBlock->IsLocalName(DefOp)) {
								(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
									this->GetAddr(), SSANum, IsMemOp);
							}
							else { // global name
								this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
								(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
									SSANum, IsMemOp);
							}
						}
					}
clc5q's avatar
clc5q committed
				break;
			}
			else if (UNINIT == LeftType) {
				// SMP_ASSIGN operator has type, so propagate it.
				CurrDef = this->SetDefType(DefOp, OperType);
clc5q's avatar
clc5q committed
				updated = true;
				// Propagate the new DEF type unless it is an indirect memory access.
				//  Future: Propagate until re-DEF of addressing register terminates
				//  the propagation. **!!**
				if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
					bool IsMemOp = (o_reg != DefOp.type);
					bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
					;
#else
					// Be conservative and only propagate register DEFs and SAFE stack locs.
					//  We can improve this in the future. **!!**
					MemPropagate = MemPropagate && SafeFunc;
#endif
					if ((o_reg == DefOp.type) || MemPropagate) {
						if (this->BasicBlock->IsLocalName(DefOp)) {
							(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
								this->GetAddr(), SSANum, IsMemOp);
						}
						else { // global name
							this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
							(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
clc5q's avatar
clc5q committed
				}
				break;
			}
			else if (UNINIT == RightType) {
				// SMP_ASSIGN operator has type, so propagate it.
				if (CurrRT->HasRightSubTree()) {
					CurrRT->GetRightTree()->SetOperatorType(OperType, this);
clc5q's avatar
clc5q committed
					updated |= this->InferOperatorType(CurrRT->GetRightTree());
				}
				else {
					// For conditional moves, propagate to the pseudo-USE of the
					//  destination register as well as the source operand.
					if (this->MDIsConditionalMoveInstr()) {
						CurrUse = this->FindUse(DefOp);
						assert(CurrUse != this->GetLastUse());
						if (UNINIT == CurrUse->GetType())
							CurrUse = this->SetUseType(DefOp, OperType);
						else if (OperType != CurrUse->GetType()) {
							SMP_msg("WARNING: Avoiding lattice oscillation from type %d to %d at %x for: ",
								CurrUse->GetType(), OperType, this->address);
							PrintOperand(CurrUse->GetOp());
						}
					}
					CurrUse = this->SetUseType(UseOp, OperType);
					updated = true;
			SMP_msg("ERROR: Unknown operator %d at %x in %s\n", 
				CurrOp, this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			break;
	} // end switch on operator

clc5q's avatar
clc5q committed
	// Determine if type inference is finished for this register transfer.
	if (updated && (!TypeInferenceFinished)) {
		bool FinishedRight = false;
		bool FinishedLeft = false;
		bool FinishedOperator = (CurrRT->GetOperatorType() != UNINIT);
		if (FinishedOperator) {
			switch (CurrOp) {
				case SMP_INPUT:  // input from port
				case SMP_OUTPUT: // output to port
				case SMP_SIGN_EXTEND:
				case SMP_ZERO_EXTEND:
				case SMP_ADDRESS_OF: // take effective address
				case SMP_SYSTEM_OPERATION:   // for instructions such as CPUID, RDTSC, etc.; NUMERIC
				case SMP_BITWISE_NOT: // unary operator
				case SMP_NEGATE:    // unary negation
				case SMP_DECREMENT:
				case SMP_INCREMENT:
				case SMP_UNARY_NUMERIC_OPERATION:  // miscellaneous; produces NUMERIC result
				case SMP_UNARY_FLOATING_ARITHMETIC:  // all the same to our type system; all NUMERIC
					// Unary operators have no right operand.
					FinishedRight = true;
					break;

				default: // All binary operators come here
					if (CurrRT->HasRightSubTree()) {
						FinishedRight = CurrRT->GetRightTree()->IsTypeInferenceComplete();
					}
					else {
						UseOp = CurrRT->GetRightOperand();
						if (UseOp.type != o_void) {
							CurrUse = this->Uses.FindRef(UseOp);
							assert(CurrUse != this->GetLastUse());
							FinishedRight = (CurrUse->GetType() != UNINIT);
						}
						else { // if o_void, no further type inference on it is possible.
							FinishedRight = true;
						}
					}
					break;
			} // end switch on CurrOp
			if (FinishedRight) { // no point checking left op if right op is not finished
				DefOp = CurrRT->GetLeftOperand();
				if (DefOp.type != o_void) {
					if (SMP_ASSIGN == CurrOp) {
						CurrDef = this->Defs.FindRef(DefOp);
						assert(CurrDef != this->GetLastDef());
						FinishedLeft = (CurrDef->GetType() != UNINIT);
					}
					else { // not ASSIGN, so really a UseOp not DefOp
						CurrUse = this->Uses.FindRef(DefOp);
						assert(CurrUse != this->GetLastUse());
						FinishedLeft = (CurrUse->GetType() != UNINIT);
					}
				}
				else { // if o_void, no further type inference on it is possible.
					FinishedLeft = true;
				}
			}
clc5q's avatar
clc5q committed
			TypeInferenceFinished = (FinishedLeft && FinishedRight);
		} // end if (FinishedOperator)
	} // end if (updated && (!TypeInferenceFinished))
	if (TypeInferenceFinished) {
		CurrRT->SetTypeInferenceComplete();
	}
	return updated;
} // end of SMPInstr::InferOperatorType()

// Transfer function: Does operator propagate signedness of its operands to its result?
bool SMPInstr::DoesOperatorTransferSign(SMPoperator CurrOp) {
	bool transfer = false;

	switch (CurrOp) {
		case SMP_NULL_OPERATOR:
		case SMP_CALL:  // CALL instruction
		case SMP_INPUT:  // input from port
		case SMP_OUTPUT: // output to port
		case SMP_SYSTEM_OPERATION:   // for instructions such as CPUID, RDTSC, etc.; NUMERIC
			// No concept of signedness for some operators
			break;

		case SMP_ADDRESS_OF: // take effective address
		case SMP_U_LEFT_SHIFT: // unsigned left shift
		case SMP_U_RIGHT_SHIFT: // unsigned right shift
		case SMP_ROTATE_LEFT:
		case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
		case SMP_ROTATE_RIGHT:
		case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
		case SMP_U_MULTIPLY:
		case SMP_U_DIVIDE:
		case SMP_U_REMAINDER:
		case SMP_ZERO_EXTEND:
		case SMP_BITWISE_NOT: // unary operator
		case SMP_BITWISE_XOR:
		case SMP_BITWISE_AND_NOT:
		case SMP_U_COMPARE: // unsigned compare (AND-based)
		case SMP_S_LEFT_SHIFT: // signed left shift
		case SMP_S_RIGHT_SHIFT: // signed right shift
		case SMP_S_MULTIPLY:
		case SMP_S_DIVIDE:
		case SMP_SIGN_EXTEND:
		case SMP_NEGATE:    // unary negation
		case SMP_S_COMPARE: // signed compare (subtraction-based)
		case SMP_LESS_THAN: // boolean test operators
		case SMP_GREATER_THAN:
		case SMP_LESS_EQUAL:
		case SMP_GREATER_EQUAL:
			// Inherently unsigned and signed operators force the signedness
			//  of their results, rather than propagating the signedness of
			//  their operands.
			break;

		case SMP_DECREMENT:
		case SMP_INCREMENT:
		case SMP_ADD:
		case SMP_ADD_CARRY:   // add with carry
		case SMP_SUBTRACT:
		case SMP_SUBTRACT_BORROW:  // subtract with borrow
		case SMP_ASSIGN:
		case SMP_BITWISE_AND:
		case SMP_BITWISE_OR:
		case SMP_EQUAL:
		case SMP_NOT_EQUAL:
		case SMP_LOGICAL_AND:
		case SMP_LOGICAL_OR:
		case SMP_UNARY_NUMERIC_OPERATION:  // miscellaneous; produces NUMERIC result
		case SMP_BINARY_NUMERIC_OPERATION:  // miscellaneous; produces NUMERIC result
			transfer = true;
			break;

		case SMP_UNARY_FLOATING_ARITHMETIC:  // all the same to our type system; all NUMERIC
		case SMP_BINARY_FLOATING_ARITHMETIC:  // all the same to our type system; all NUMERIC
		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
		case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
		case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
		case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's
		case SMP_PACK_S:  // Pack operands into extended-precision register, signed saturation for loss of precision
		case SMP_PACK_U:  // Pack operands into extended-precision register, unsigned saturation for loss of precision
		case SMP_AVERAGE_U: // Average of unsigned operands
		case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
		case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
		case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
		case SMP_CONCATENATE:     // extended-precision concatenation; NUMERIC
			transfer = true;
			break;

		default:
			SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
			break;
	} // end switch on operator

	return transfer;
} // end of SMPInstr::DoesOperatorTransferSign()

// Initial inferences (if any) about FG info of operand based solely on the RTL operator type above it in RTL.
bool SMPInstr::InitFGInfoFromOperator(SMPoperator CurrOp, struct FineGrainedInfo &InitFG) {
	bool changed = false;

	switch (CurrOp) {
		case SMP_NULL_OPERATOR:
			break;

		case SMP_CALL:  // CALL instruction
			InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; // target address is unsigned 32-bit
			InitFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_CODEPOINTER);
			break;

		case SMP_INPUT:  // input from port
		case SMP_OUTPUT: // output to port
		case SMP_ADDRESS_OF: // take effective address
		case SMP_U_COMPARE: // unsigned compare (AND-based)
		case SMP_S_COMPARE: // signed compare (subtraction-based)
			// NOTE: The AND-based and subtraction-based comparisons are used
			//  on lots of operands of all types, and the conditional jump that
			//  follows determines signedness, not the operator.
			break;

		case SMP_U_LEFT_SHIFT: // unsigned left shift
		case SMP_U_RIGHT_SHIFT: // unsigned right shift
		case SMP_ROTATE_LEFT:
		case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
		case SMP_ROTATE_RIGHT:
		case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
		case SMP_U_MULTIPLY:
		case SMP_U_DIVIDE:
		case SMP_U_REMAINDER:
		case SMP_ZERO_EXTEND:
		case SMP_BITWISE_NOT: // unary operator
		case SMP_BITWISE_XOR:
		case SMP_BITWISE_AND_NOT:
			InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			break;

		case SMP_S_LEFT_SHIFT: // signed left shift
		case SMP_S_RIGHT_SHIFT: // signed right shift
		case SMP_S_MULTIPLY:
		case SMP_S_DIVIDE:
		case SMP_SIGN_EXTEND:
		case SMP_NEGATE:    // unary negation
		case SMP_LESS_THAN: // boolean test operators
		case SMP_GREATER_THAN:
		case SMP_LESS_EQUAL:
		case SMP_GREATER_EQUAL:
			// Special case: If signed multiply operator, it might sometimes
			//  be used for unsigned operands when upper bits of the result
			//  are discarded, because there is no difference in the result bits
			//  between unsigned and signed multiplcation when only the lower
			//  N bits are retained and the upper N bits are discarded.
			if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) {
				break;
			}
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			break;

		case SMP_DECREMENT:
		case SMP_INCREMENT:
		case SMP_ADD:
		case SMP_ADD_CARRY:   // add with carry
		case SMP_SUBTRACT:
		case SMP_SUBTRACT_BORROW:  // subtract with borrow
		case SMP_ASSIGN:
		case SMP_BITWISE_AND:
		case SMP_BITWISE_OR:
		case SMP_EQUAL:
		case SMP_NOT_EQUAL:
		case SMP_LOGICAL_AND:
		case SMP_LOGICAL_OR:
		case SMP_UNARY_NUMERIC_OPERATION:  // miscellaneous; produces NUMERIC result
		case SMP_BINARY_NUMERIC_OPERATION:  // miscellaneous; produces NUMERIC result
		case SMP_SYSTEM_OPERATION:   // for instructions such as CPUID, RDTSC, etc.; NUMERIC
			break;

		case SMP_UNARY_FLOATING_ARITHMETIC:  // all the same to our type system; all NUMERIC
		case SMP_BINARY_FLOATING_ARITHMETIC:  // all the same to our type system; all NUMERIC
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			InitFG.SizeInfo |= FG_MASK_FLOAT_MMX;
			break;

		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
		case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
		case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
		case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's
		case SMP_PACK_S:  // Pack operands into extended-precision register, signed saturation for loss of precision
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
			changed = true;
			break;

		case SMP_PACK_U:  // Pack operands into extended-precision register, unsigned saturation for loss of precision
		case SMP_AVERAGE_U: // Average of unsigned operands
		case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
		case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
			InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
			changed = true;
			break;

		case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
		case SMP_CONCATENATE:     // extended-precision concatenation; NUMERIC
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
			SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
			break;
	} // end switch on operator

} // end of SMPInstr::InitFGInfoFromOperator()

// Helper to take USE operand, find its SSANum, and return its UseHashValue.
int SMPInstr::GetUseOpHashAndSSA(op_t UseOp, int &SSANum) {
	op_t SearchOp = UseOp;
	SearchOp.reg = MDCanonicalizeSubReg(UseOp.reg);
	set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
	assert(UseIter != this->GetLastUse());
	SSANum = UseIter->GetSSANum();
	int UseHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
	return UseHashValue;
} // end of SMPInstr::GetUseOpHashAndSSA()

// Helper to take DEF operand, find its SSANum, and return its DefHashValue.
int SMPInstr::GetDefOpHashAndSSA(op_t DefOp, int &SSANum) {
	op_t SearchOp = DefOp;
	SearchOp.reg = MDCanonicalizeSubReg(DefOp.reg);
	set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp);
	assert(DefIter != this->GetLastDef());
	SSANum = DefIter->GetSSANum();
	int DefHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
	return DefHashValue;
} // end of SMPInstr::GetDefOpHashAndSSA()

// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
bool SMPInstr::UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	set<DefOrUse, LessDefUse>::iterator DefIter;
	int SSANum;
	int DefHashValue;
	op_t SearchOp;
	bool LocalName;
	struct FineGrainedInfo OldFG, UnionFG;

	// If operator is inherently signed, then we will have 
	//  a sign bit set in NewFG from InitFGInfoFromOperator().
	DefHashValue = this->GetDefOpHashAndSSA(DefOp, SSANum);
	LocalName = this->BasicBlock->IsLocalName(DefOp);
	if (LocalName) {
		// Get old FG info from block level.
		OldFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
	}
	else { // global name
		// Get old FG info from function level.
		OldFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
	}
	UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
	UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
	if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
		// The signs they are a-changin'.
		MapsChanged = true;
		if (LocalName)
			this->BasicBlock->UpdateDefFGInfo(DefHashValue, UnionFG);
			this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, UnionFG);
	}
	return MapsChanged;
} // end of SMPInstr::UpdateDefOpFGInfo()

// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
bool SMPInstr::UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	int SSANum;
	int UseHashValue;
	bool LocalName;
	struct FineGrainedInfo OldFG, UnionFG;

	// If operator is inherently signed, then we will have 
	//  a sign bit set in NewFG from InitFGInfoFromOperator().
	UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
	LocalName = this->BasicBlock->IsLocalName(UseOp);
	if (LocalName) {
		// Get old FG info from block level.
		OldFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
	}
	else { // global name
		// Get old FG info from function level.
		OldFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
	}
	UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
	UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
	if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
		// The signs they are a-changin'.
		MapsChanged = true;
		if (LocalName)
			this->BasicBlock->UpdateUseFGInfo(UseHashValue, UnionFG);
			this->BasicBlock->GetFunc()->UpdateUseFGInfo(UseHashValue, UnionFG);
	}
	return MapsChanged;
} // end of SMPInstr::UpdateUseOpFGInfo()

// Helper to fetch DEF signedness info for UseOp that has none.
unsigned short SMPInstr::GetDefSignInfoFromUseOp(op_t UseOp) {
	int SSANum, UseHashValue;
	bool LocalName;

	UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
	LocalName = this->BasicBlock->IsLocalName(UseOp);
	if (LocalName) {
		// Get old sign info from block level.
		return this->BasicBlock->GetDefSignMiscInfo(UseHashValue);
	}
	else { // global name
		// Get old sign info from function level.
		return this->BasicBlock->GetFunc()->GetDefSignMiscInfo(UseHashValue);
	}
} // end of SMPInstr::GetDefSignInfoFromUseOp()
// infer FG info, + width on FirstIter; pass out FG info for op subtree, return true if change made to any FG info map.
bool SMPInstr::InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter, struct FineGrainedInfo &OpFG) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	bool NewChange = false;  // Bit changes from InitFGInfoFromOperator() ?
	SMPoperator CurrOp = CurrRT->GetOperator();
	struct FineGrainedInfo LeftFG, OldLeftFG;
	struct FineGrainedInfo RightFG, OldRightFG;
	op_t LeftOp, RightOp;
	unsigned short WidthMask, SignMask;
	bool CurrOpTransfersSign = this->DoesOperatorTransferSign(CurrOp);
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
	bool success;
	int DefHashValue, UseHashValue, SSANum;

	// Recurse to the right first, so we can do a depth-first accumulation of FG info.
	RightFG.SignMiscInfo = 0;
	RightFG.SizeInfo = 0;
	if (CurrRT->HasRightSubTree()) {
		if (FirstIter) { // Get width as well as signedness
			NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
		} // end if (FirstIter)
		MapsChanged |= this->InferOperatorFGInfo(CurrRT->GetRightTree(), FirstIter, RightFG);
	}
	else {
		RightOp = CurrRT->GetRightOperand();
		if (RightOp.type == o_imm) {
			// If immediate operand is a data address or code address, we can infer that it is unsigned.
			uval_t ImmVal = RightOp.value;
			if (IsImmedGlobalAddress((ea_t) ImmVal)) {
				// Data address (type GLOBALPTR)
				RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			}
			else if (this->MDIsInterruptCall() || IsImmedCodeAddress((ea_t) ImmVal)) {
				// Code address (type GLOBALPTR)
				RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			}
		}
		else if ((RightOp.type == o_reg) && !RightOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
			if (FirstIter) { // Get width as well as signedness
				NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
				WidthMask = ComputeOperandBitWidthMask(RightOp, 0);
				RightFG.SizeInfo |= WidthMask;
			} // end if (FirstIter)
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1
#if SMP_AGGRESSIVE_SIGN_TRANSFER
			else {
				// On all iterations other than 1st, see if USE has FG info.
				UseHashValue = this->GetUseOpHashAndSSA(RightOp, SSANum);
				if (this->BasicBlock->IsLocalName(RightOp)) {
					// Get FG info from block.
					RightFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
				}
				else {
					// Get FG info from function level.
					RightFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
				}
			}
#endif
			// Propagate signedness on all iterations.
			// If operator is inherently signed, then we will have 
			//  a sign bit set in RightFG from InitFGInfoFromOperator().
			if ((RightFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
				// We have a USE with no sign info. See if we
				//  can get sign info from the DEF of this USE so we can
				//  transfer it up the RTL tree. 
				RightFG.SignMiscInfo = 
					(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(RightOp)));
			}
			if ((RightFG.SignMiscInfo != 0) || (RightFG.SizeInfo != 0))
				MapsChanged |= this->UpdateUseOpFGInfo(RightOp, RightFG);
		} // end if (RightOP is o_reg)
		else if (MDIsStackAccessOpnd(RightOp, UseFP)) {
			// We used to assume that all FG info transfers from stack locations to
			//  the target registers of stack loads happened in SMPInstr::MDSetWidthSignInfo(),
			//  in an early pass that needed no iteration. The FG info was loaded from the
			//  StackFGInfo that was computed in SMPFunction::FindOutgoingArgsSize() based solely
			//  on whether the load was sign-extended or zero-extended. Of course, many stack
			//  locations have neither kind of signed/unsigned load. So, if we see a store to
			//  a stack location with no signedness, we transfer the signedness of the RightFG
			//  to the stack location FGInfo in the code below that processes the LeftOp.
			//  As a result, we now have a need to examine regular loads from the stack to
			//  see if there is signedness info for the stack location.
			success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, RightOp, RightFG);
			if (success) {
				SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
				RightFG.SizeInfo = 0; // only want to transfer signedness
			}
		}
	} // end if (right subtree) else right operand

	LeftFG.SignMiscInfo = 0;
	LeftFG.SizeInfo = 0;
	LeftOp = CurrRT->GetLeftOperand();
	bool OpIsDEF = (SMP_ASSIGN == CurrOp);
	// Skip control-flow assignments to the instruction pointer register.
	if ((LeftOp.type == o_reg) && !LeftOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
		if (FirstIter) { // Get width as well as signedness
			NewChange = this->InitFGInfoFromOperator(CurrOp, LeftFG);
			// Special case: For sign-extended and zero-extended loads,
			//  we don't know whether the DEF will always be USEd as
			//  the smaller or larger size. For example, we could
			//  zero-extend a 16-bit stack location into a 32-bit register
			//  just because the compiler always loads unsigned shorts
			//  that way, but we might never use it as a 32-bit value.
			//  So there is no truncation if we store only 16 bits later.
			//  By setting the target of an extended load to zero width,
			//  we signal that we want the maximum USE width to determine
			//  whether the store is truncated (see EmitIntegerErrorAnnotations).
			WidthMask = ComputeOperandBitWidthMask(LeftOp, 0);
			if (OpIsDEF) {
				if (this->MDIsSignedLoad(SignMask)) {
					WidthMask = 0;
				}
				// DEF inherits sign from right hand side.
				LeftFG.SignMiscInfo |= RightFG.SignMiscInfo; 
			else if ((LeftFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
				// We have a USE, not a DEF, with no sign info. See if we
				//  can get sign info from the DEF of this USE so we can
				//  transfer it up the RTL tree. 
				LeftFG.SignMiscInfo = 
					(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(LeftOp)));
			LeftFG.SizeInfo |= WidthMask;
			if ((LeftFG.SignMiscInfo != 0) || (LeftFG.SizeInfo != 0)) {
				// Either NewChanged or CurrOpTransfersSign is true or we set WidthMask above.
				//  See if we would change the FG map entry.
				if (OpIsDEF) { // Need DEF map info
					MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
				}
				else { // need USE map info
					MapsChanged |= this->UpdateUseOpFGInfo(LeftOp, LeftFG);
				}
			} // end if non-zero LeftFG info
		} // end if (FirstIter)
#if SMP_AGGRESSIVE_SIGN_TRANSFER
		else {
			// On all iterations other than 1st, see if LeftOp has FG info.
			if (!OpIsDEF) { // LeftOp is a USE
				UseHashValue = this->GetUseOpHashAndSSA(LeftOp, SSANum);
				if (this->BasicBlock->IsLocalName(LeftOp)) {
					// Get FG info from block.