Skip to content
Snippets Groups Projects
SMPInstr.cpp 640 KiB
Newer Older
		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_NE_AND_SET: // Compare for not-equal 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_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's
		case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's
		case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal 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_MAX_S: // dest := signed_max(dest, src)
		case SMP_MAX_U: // dest := unsigned_max(dest, src)
		case SMP_MIN_S: // dest := signed_min(dest, src)
		case SMP_MIN_U: // dest := unsigned_min(dest, src)
		case SMP_ABSOLUTE_VALUE: // take absolute value
		case SMP_CONVERT_INT_TO_FP: // convert integer to floating point
		case SMP_CONVERT_FP_TO_INT: // convert floating point to integer
		case SMP_CREATE_MASK: // Create AND-mask from operand and byte/word/dword position # in immediate
		case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
		case SMP_CONCATENATE:     // extended-precision concatenation; NUMERIC
		case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length
		case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation
		case SMP_SIGNAL:   // signal or raise exception
			break;

		default:
			SMP_msg("ERROR: SPARK: Cannot translate unknown operator: ");
			SMP_msg(" %s \n", OperatorText[this->GetOperator()]);
			break;
	}
	return;
} // end of SMPRegTransfer::EmitSPARKAda()

// Helper for right hand side of statements (i.e. RightOperand or RightTree)
void SMPRegTransfer::EmitSPARKAdaForRHS(void) const {
	if (this->HasRightSubTree()) {
		SMP_fprintf(ZST_SPARKSourceFile, "(");
		SMPRegTransfer *RightRT = this->GetRightTree();
		RightRT->EmitSPARKAda();
		SMP_fprintf(ZST_SPARKSourceFile, ")");
	}
	else {
		PrintSPARKAdaOperand(this->GetRightOperand(), ZST_SPARKSourceFile);
	}
	return;
} // end of SMPRegTransfer::EmitSPARKAdaForRHS()

// *****************************************************************
// Class SMPRTL
// *****************************************************************

// Constructor
SMPRTL::SMPRTL() {
	this->ExtraKills.clear();
	this->RTCount = 0;
	return;
}

// Destructor
SMPRTL::~SMPRTL() {
	for (size_t index = 0; index < this->RTCount; ++index) {
		delete (this->RTvector[index]);
	}
	this->ExtraKills.clear();
	return;
}

// Get methods
SMPRegTransfer *SMPRTL::GetRT(size_t index) const {
	if (index > this->RTCount)
		return NULL;
	else
		return this->RTvector[index];
}

// Set methods
void SMPRTL::push_back(SMPRegTransfer *NewEffect) {
	assert(SMP_RT_LIMIT > this->RTCount);
	this->RTvector[this->RTCount] = NewEffect;
	++(this->RTCount);
	return;
}

// Printing methods
	size_t index;
	if (0 < this->RTCount) {
		for (index = 0; index < this->RTCount; ++index) {
			this->RTvector[index]->Dump();
		}
		for (index = 0; index < this->ExtraKills.size(); ++index) {
			PrintOperand(this->ExtraKills.at(index));
		}
	}
	return;
} // end of SMPRTL::Dump()

// Accumulate stack pointer alteration total across all RTs.
sval_t SMPRTL::TotalStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
	sval_t TotalDelta = 0;
	sval_t IncrementalDelta;

	for (size_t index = 0; index < this->RTCount; ++index) {
		IncrementalDelta = this->RTvector[index]->ComputeStackPointerAlteration(IsLeaveInstr, IncomingDelta, FramePtrDelta);
		if ((SMP_STACK_DELTA_ERROR_CODE == IncrementalDelta) 
			|| (SMP_STACK_POINTER_BITWISE_AND_CODE == IncrementalDelta)) {
			TotalDelta = IncrementalDelta;  // pass code back
			break; // exit loop and return coded value
		}
		else {
			TotalDelta += IncrementalDelta;
		}
	}

	return TotalDelta;
} // end of SMPRTL::TotalStackPointerAlteration()
// *****************************************************************
// Class SMPInstr
// *****************************************************************

// Constructor for instruction.
SMPInstr::SMPInstr(ea_t addr) {
	this->SMPcmd.size = 0;
	this->address = addr;
	this->ResetJumpTarget();
	this->ResetBlockTerm();
	this->ResetTailCall();
	this->ResetCondTailCall();
	this->ResetCallUsedAsJump();
	this->ResetDirectRecursiveCall();
	this->ResetInterrupt();
#else
	this->booleans1 = 0;
#endif
#if 0
	this->ResetNop();
	this->ResetRegClearIdiom();
	this->ResetDefsFlags();
	this->ResetUsesFlags();
	this->ResetFarBranchComputed();
	this->ResetBranchesToFarChunk();
	this->ResetIndirectMemWrite();
	this->ResetIndirectMemRead();
#else
	this->booleans2 = 0;
#endif
#if 0
	this->ResetLoadFromStack();
	this->ResetMultiplicationBitsDiscarded();
	this->ResetTypeInferenceComplete();
	this->ResetCategoryInferenceComplete();
	this->ResetDEFsTyped();
	this->ResetUSEsTyped();
#else
	this->booleans3 = 0;
#endif
	this->FarBranchTarget = BADADDR;
	this->AddSubSourceType = UNINIT;
clc5q's avatar
clc5q committed
	this->AddSubDefUseType = UNINIT;
#if 0
clc5q's avatar
clc5q committed
	this->AddSubDefUseOp = InitOp;
#endif
	this->DEFMemOp = InitOp;
	this->USEMemOp = InitOp;
	this->MoveSource = InitOp;
	this->BasicBlock = NULL;
	this->type = DEFAULT;
	this->OptType = 0;
	this->Defs.clear();
	this->Uses.clear();
SMPInstr::~SMPInstr() {
	this->Defs.clear();
	this->Uses.clear();
char *SMPInstr::GetDisasm(void) const {
	return DisAsmText.GetDisAsm(this->GetAddr());
}

// Is the instruction the type that terminates a basic block?
bool SMPInstr::IsBasicBlockTerminator() const {
	return ((type == JUMP) || (type == COND_BRANCH)
			|| (type == INDIR_JUMP) || (type == RETURN));
}

// Get non-flags DEF, usually for arithmetic opcode.
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetFirstNonFlagsDef(void) {
	set<DefOrUse, LessDefUse>::iterator DefIter;
	op_t DefOp;

	for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		DefOp = DefIter->GetOp();
		if (!((o_reg == DefOp.type) && DefOp.is_reg(MD_FLAGS_REG)))
			break; // found a non-flags-reg DEF.
	}
	return DefIter;
}

// Fetch the operands for a shift instruction
void SMPInstr::GetShiftOperands(op_t &ShiftedOp, op_t &ShiftCounterOp) {
	bool success = false;
	if (this->RTL.GetRT(0)->HasRightSubTree()) {
		SMPRegTransfer *RightRT = this->RTL.GetRT(0)->GetRightTree();
		SMPoperator RightOper = RightRT->GetOperator();
		if ((RightOper == SMP_U_LEFT_SHIFT) || (RightOper == SMP_S_LEFT_SHIFT)
			|| (RightOper == SMP_U_RIGHT_SHIFT) || (RightOper == SMP_S_RIGHT_SHIFT)) {
			if (!(RightRT->HasRightSubTree())) {
				success = true;
				ShiftedOp = RightRT->GetLeftOperand();
				ShiftCounterOp = RightRT->GetRightOperand();
			}
		}
	}

	if (!success) {
		ShiftedOp = InitOp;
		ShiftCounterOp = InitOp;
	}
	return;
} // end of SMPInstr::GetShiftOperands()

// Is the destination operand a memory reference?
bool SMPInstr::HasDestMemoryOperand(void) {
	return (o_void != this->DEFMemOp.type);
} // end of SMPInstr::HasDestMemoryOperand()

// Is a source operand a memory reference?
bool SMPInstr::HasSourceMemoryOperand(void) {
	return (o_void != this->USEMemOp.type);
} // end of SMPInstr::HasSourceMemoryOperand()

// Get the first memory operand in the DEF list.
op_t SMPInstr::MDGetMemDefOp(void) const {
	return this->DEFMemOp; // cached value
} // end of SMPInstr::MDGetMemDefOp()

// Get the first memory operand in the USE list.
op_t SMPInstr::MDGetMemUseOp(void) const {
	return this->USEMemOp; // cached value
// return original Lea instruction [pseudo-]memory operand.
op_t SMPInstr::GetLeaMemUseOp(void) {
	if (this->BasicBlock == NULL) {
		return InitOp;
	}
	else {
		map<ea_t, op_t>::iterator MapIter = this->GetBlock()->GetFunc()->FindLeaOperand(this->GetAddr());
		return MapIter->second;
	}
}

clc5q's avatar
clc5q committed
op_t SMPInstr::GetUseOnlyAddSubOp(void) const { 
	unsigned short opcode = this->SMPcmd.itype;

	bool IsAddSubInst = ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
		|| (NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
	if ((this->RTL.GetCount() < 1) || (!IsAddSubInst))
		return InitOp;  // no RTL or not an addition or subtraction

	assert(this->RTL.GetRT(0)->HasRightSubTree());
	SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
	op_t RightOp;

#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
	if ((NN_adc != this->SMPcmd.itype) && (NN_sbb != this->SMPcmd.itype)) {
		assert(!(RightTree->HasRightSubTree()));
		RightOp = RightTree->GetRightOperand();  // Src (non-DEF) operand
	}
	else {
		// Add with carry and subtract with borrow have an extra level
		//  to the tree RTL, e.g. for add with carry:
		//  opnd1 := (opnd1 + (opnd2 + carryflag))
		assert(RightTree->HasRightSubTree());
		RightTree = RightTree->GetRightTree();
		RightOp = RightTree->GetLeftOperand();
	}
#else
	RightOp = RightTree->GetRightOperand();    // Use (also DEF) operand
#endif

	return RightOp;
}; // end of SMPInstr::GetUseOnlyAddSubOp()

op_t SMPInstr::GetDefUseAddSubOp(void) const { 
	unsigned short opcode = this->SMPcmd.itype;

	bool IsAddSubInst = ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
		|| (NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
	if ((this->RTL.GetCount() < 1) || (!IsAddSubInst))
		return InitOp;  // no RTL or not an addition or subtraction

	assert(this->RTL.GetRT(0)->HasRightSubTree());
	SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
	op_t LeftOp;
	LeftOp = RightTree->GetLeftOperand();    // Use (also DEF) operand

	return LeftOp;
}; // end of SMPInstr::GetDefUseAddSubOp()

// return BADADDR if not jump, target addr otherwise.
ea_t SMPInstr::GetJumpTarget(void) const {
	ea_t TargetAddr = BADADDR;
	if (this->HasGoodRTL()) {
		// We want to find an RTL of the form: inst_ptr_reg := code_addr
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		op_t DefOp = CurrRT->GetLeftOperand();
		if (DefOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
			if ((SMP_ASSIGN == CurrRT->GetOperator()) && (!CurrRT->HasRightSubTree())) {
				op_t UseOp = CurrRT->GetRightOperand();
				if ((o_near == UseOp.type) || (o_far == UseOp.type)) { // address
					TargetAddr = UseOp.addr;
				}
			}
		}
	}
	return TargetAddr;
} // end SMPInstr::GetJumpTarget()

// Does any USE have type NEGATEDPTR?
bool SMPInstr::HasNegatedPtrUSE(void) {
	bool UseFound = false;
	set<DefOrUse, LessDefUse>::iterator UseIter;
	SMPOperandType UseType;

	for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
		UseType = UseIter->GetType();
		if (IsEqType(UseType, NEGATEDPTR)) {
			UseFound = true;
			break;
		}
	}

	return UseFound;
} // end of SMPInstr::HasNegatedPtrUSE()

// Detect indirect memory DEFs or USEs
void SMPInstr::AnalyzeIndirectRefs(bool UseFP) {
	op_t DefMemOp = this->MDGetMemDefOp();
	op_t UseMemOp = this->MDGetMemUseOp();

	if (o_void != DefMemOp.type) {
		// Found a memory DEF. Is it indirect?
		if (MDIsIndirectMemoryOpnd(DefMemOp, UseFP)) {
			this->SetIndirectMemWrite();
		}
	}

	if (o_void != UseMemOp.type) {
		// Found a memory USE. Is it indirect?
		if (MDIsIndirectMemoryOpnd(UseMemOp, UseFP)) {
			this->SetIndirectMemRead();
		}
	}

	return;
} // end of SMPInstr::AnalyzeIndirectRefs()

set<DefOrUse, LessDefUse>::iterator SMPInstr::GetPointerAddressReg(op_t MemOp) {
	int BaseReg;
	int IndexReg;
	ushort ScaleFactor;
	ea_t displacement;
	set<DefOrUse, LessDefUse>::iterator PtrIter;

	if ((NULL == this->BasicBlock) || (NULL == this->BasicBlock->GetFunc())) {
		SMP_msg("ERROR: NULL member pointers in SMPInstr::GetPointerAddressReg() at %lx \n",
			(unsigned long) this->address);
		return this->GetLastUse();
	}
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();

	MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor,
		displacement);

	if ((R_none != BaseReg) && (!MDIsStackPtrReg(BaseReg, UseFP))) {
		op_t BaseOp = InitOp;
		BaseOp.type = o_reg;
		BaseOp.reg = (ushort) BaseReg;
		BaseOp.dtyp = this->GetOperandDtypField();
		PtrIter = this->FindUse(BaseOp);
		assert(PtrIter != this->GetLastUse());
		if (IsDataPtr(PtrIter->GetType())) {
			return PtrIter;
		}
	}
	if ((R_none != IndexReg) && (!MDIsStackPtrReg(IndexReg, UseFP))) {
		op_t IndexOp = InitOp;
		IndexOp.type = o_reg;
		IndexOp.reg = (ushort) IndexReg;
		IndexOp.dtyp = this->GetOperandDtypField();
		PtrIter = this->FindUse(IndexOp);
		assert(PtrIter != this->GetLastUse());
		if (IsDataPtr(PtrIter->GetType())) {
			return PtrIter;
		}
	}
	PtrIter = this->GetLastUse();
	return PtrIter;
} // end of SMPInstr::GetPointerAddressReg()

// Does the instruction whose flags are in F have a numeric type
//   as the second source operand?
// NOTE: We can only analyze immediate values now. When data flow analyses are implemented,
//   we will be able to analyze many non-immediate operands.
#define IMMEDNUM_LOWER -8191
#define IMMEDNUM_UPPER 8191
bool SMPInstr::IsSecondSrcOperandNumeric(flags_t F) const {
	bool SecondOpImm = (this->SMPcmd.Operands[1].type == o_imm);
		TempImm = this->SMPcmd.Operands[1].value;
	return (SecondOpImm && IsImmedNumeric(TempImm));
} // end of SMPInstr::IsSecondSrcOperandNumeric()

// Determine the type of the USE-only operand for add and subtract
//  instructions. If it is NUMERIC or PROF_NUMERIC, an optimizing
//  annotation will result.
// As a byproduct, find the type of the USE/DEF operand as well.
void SMPInstr::SetAddSubSourceType(void) {
	// Walk the RTL and find the operands we care about.
	// The RTL should look like: opnd1 := (opnd1 op opnd2), where op is
	//  and add or subtract operator. Within the parentheses, the type
	//  of opnd1 is our AddSubUseType and opnd1 is our AddSubUseOp, while
	//  the type of opnd2 is our AddSubSourceType.
	if (this->RTL.GetCount() < 1)
		return;  // no RTL, no leave types as UNINIT.

	assert(this->RTL.GetRT(0)->HasRightSubTree());
	SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
	op_t LeftOp, RightOp;
	LeftOp = RightTree->GetLeftOperand();    // Use (also DEF) operand
	if ((NN_adc != this->SMPcmd.itype) && (NN_sbb != this->SMPcmd.itype)) {
		assert(!(RightTree->HasRightSubTree()));
		RightOp = RightTree->GetRightOperand();  // Src (non-DEF) operand
	else {
		// Add with carry and subtract with borrow have an extra level
		//  to the tree RTL, e.g. for add with carry:
		//  opnd1 := (opnd1 + (opnd2 + carryflag))
		assert(RightTree->HasRightSubTree());
		RightTree = RightTree->GetRightTree();
		RightOp = RightTree->GetLeftOperand();
#else
	assert(!(RightTree->HasRightSubTree()));
	RightOp = RightTree->GetRightOperand();  // Src (non-DEF) operand
#endif

	set<DefOrUse, LessDefUse>::iterator UseIter, SrcIter;

	SrcIter = this->FindUse(RightOp);
	assert(SrcIter != this->GetLastUse());
	this->AddSubSourceType = SrcIter->GetType();
clc5q's avatar
clc5q committed
#if 0
	this->AddSubSourceOp = RightOp;
clc5q's avatar
clc5q committed
#endif

	UseIter = this->FindUse(LeftOp);
	assert(UseIter != this->GetLastUse());
clc5q's avatar
clc5q committed
	this->AddSubDefUseType = UseIter->GetType();
#if 0
	this->AddSubDefUseOp = LeftOp;
#endif
	return;
} // end of SMPInstr::SetAddSubSourceType()

// Are all DEFs in the DEF set NUMERIC type?
jdh8d's avatar
jdh8d committed
bool SMPInstr::AllDefsNumeric(void) 
{
	bool AllNumeric = (this->Defs.GetSize() > 0);  // false if no DEFs, true otherwise
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		// We ignore the stack pointer for pop instructions and consider only
		//  the register DEF of the pop.
		if (this->MDIsPopInstr() && CurrDef->GetOp().is_reg(R_sp))
			continue;
		AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType()));
	}
	return AllNumeric;
} // end of SMPInstr::AllDefsNumeric()

// Were the types of any DEFs derived from profiler info?
jdh8d's avatar
jdh8d committed
bool SMPInstr::AnyDefsProfiled(void) 
{
	bool profd = false;
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
jdh8d's avatar
jdh8d committed
		profd = (profd || IsProfDerived(CurrDef->GetType()));
	}
	return profd;
} 

// Do all DEFs have DEF_METADATA_UNUSED status?
bool SMPInstr::AllDefMetadataUnused(void) {
	bool AllUnused = (this->Defs.GetSize() > 0);  // false if no DEFs, true otherwise
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		AllUnused = (AllUnused 
			&& (DEF_METADATA_UNUSED == CurrDef->GetMetadataStatus()));
	}
	return AllUnused;
} // end of SMPInstr::AllDefMetadataUnused()

// DEBUG print operands for Inst.
void SMPInstr::PrintOperands(void) const {
	op_t Opnd;
	for (int i = 0; i < UA_MAXOP; ++i) {
		Opnd = SMPcmd.Operands[i];
		PrintOneOperand(Opnd, this->features, i);
	}
	return;
} // end of SMPInstr::PrintOperands()

// Complete DEBUG printing.
void SMPInstr::Dump(void) {
	SMP_msg("%lx %d SMPitype: %d %s\n", (unsigned long) this->address, this->SMPcmd.size, (int) this->type, 
		DisAsmText.GetDisAsm(this->GetAddr()));
#if STARS_DUMP_FG_INFO
	SMP_msg("USEs: ");
	if (NULL == this->GetBlock()) { // during early improvement of disasm
		this->Uses.Dump();
		SMP_msg("DEFs: ");
		this->Defs.Dump();
	}
	else {
		set<DefOrUse, LessDefUse>::iterator UseIter, DefIter;
		op_t UseOp, DefOp;
		int UseHashValue, DefHashValue, UseSSANum, DefSSANum;
		unsigned short SignMiscInfo, SignMask;
		bool LocalName;
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			UseIter->Dump();
			UseOp = UseIter->GetOp();
			if (o_reg == UseOp.type) {
				LocalName = this->GetBlock()->IsLocalName(UseOp);
				UseSSANum = UseIter->GetSSANum();
				UseHashValue = HashGlobalNameAndSSA(UseOp, UseSSANum);
				if (LocalName) {
					SignMiscInfo = this->GetBlock()->GetUseSignMiscInfo(UseHashValue);
				}
				else {
					SignMiscInfo = this->GetBlock()->GetFunc()->GetUseSignMiscInfo(UseHashValue);
				}
				SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
				if (SignMask == FG_MASK_SIGNED) {
					SMP_msg(" Si ");
				}
				else if (SignMask == FG_MASK_UNSIGNED) {
					SMP_msg(" Un ");
				}
				else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
					SMP_msg(" Xs ");
				}
			}
			SMP_msg("\n");
		}
		SMP_msg("DEFs: ");
		for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
			DefIter->Dump();
			DefOp = DefIter->GetOp();
			if (o_reg == DefOp.type) {
				LocalName = this->GetBlock()->IsLocalName(DefOp);
				DefSSANum = DefIter->GetSSANum();
				DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum);
				if (LocalName) {
					SignMiscInfo = this->GetBlock()->GetDefSignMiscInfo(DefHashValue);
				}
				else {
					SignMiscInfo = this->GetBlock()->GetFunc()->GetDefSignMiscInfo(DefHashValue);
				}
				SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS;
				if (SignMask == FG_MASK_SIGNED) {
					SMP_msg(" Si ");
				}
				else if (SignMask == FG_MASK_UNSIGNED) {
					SMP_msg(" Un ");
				}
				else if (SignMask == FG_MASK_INCONSISTENT_SIGN) {
					SMP_msg(" Xs ");
				}
			}
			SMP_msg("\n");
		}
	}
#else
	this->RTL.Dump();
#if SMP_VERBOSE_DUMP
	this->PrintOperands();
#endif
	return;
} // end of SMPInstr::Dump()

// Print out the destination operand list for the instruction, given
//  the OptCategory for the instruction as a hint.
char * SMPInstr::DestString(int OptType) {
	int RegDestCount = 0;
	DestList[0] = 'Z';  // Make sure there are no leftovers from last call
	DestList[1] = 'Z';
	DestList[2] = '\0';
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		op_t DefOpnd = CurrDef->GetOp();
		if (DefOpnd.is_reg(X86_FLAGS_REG))  // don't print flags as a destination
			continue;
		// We want to ignore the stack pointer DEF for pops and just include
		//  the register DEF for the pop.
		if (DefOpnd.is_reg(R_sp) && this->MDIsPopInstr())
			continue;
		if (o_reg == DefOpnd.type) {
			ushort DestReg = DefOpnd.reg;
			if (0 == RegDestCount) {
				SMP_strncpy(DestList, MDGetRegName(DefOpnd), 1 + strlen(MDGetRegName(DefOpnd)));
				SMP_strncat(DestList, MDGetRegName(DefOpnd), MAXSTR);
			}
			++RegDestCount;
		}
	}
	if (0 >= RegDestCount) {
		SMP_msg("WARNING: No destination registers: %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
	}
	return DestList;
} // end of SMPInstr::DestString()

// print the registers that are dead right before this instruction.
void SMPInstr::PrintDeadRegs(FILE *OutputFile) {
	size_t RegNum = (size_t) MD_FLAGS_REG;
	// Start with the flags register.
	if (this->DeadRegsBitmap[RegNum]) {
		SMP_fprintf(OutputFile, "%s ", RegNames[RegNum]);
	}
	// Do all other registers
	for (RegNum = 0; RegNum < MD_FLAGS_REG; ++RegNum) {
		if (this->DeadRegsBitmap[RegNum]) {
			SMP_fprintf(OutputFile, "%s ", RegNames[RegNum]);
		}
	}
	for (RegNum = 1 + MD_FLAGS_REG; RegNum <= MD_LAST_REG_NO; ++RegNum) {
		if (this->DeadRegsBitmap[RegNum]) {
			SMP_fprintf(OutputFile, "%s ", RegNames[RegNum]);
		}
	}
	// Print sequence terminator.
	SMP_fprintf(OutputFile, "ZZ");

	return;
} // end of SMPInstr::PrintDeadRegs()

// Equality operator for SMPInstr. Key field is address.
int SMPInstr::operator==(const SMPInstr &rhs) const {
	if (this->address != rhs.GetAddr())
		return 0;
	else
		return 1;
}

// Inequality operator for SMPInstr. Key field is address.
int SMPInstr::operator!=(const SMPInstr &rhs) const {
	return (this->address != rhs.GetAddr());
}

// Less than operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<(const SMPInstr &rhs) const {
	return (this->address < rhs.GetAddr());
}

// Less than or equal operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<=(const SMPInstr &rhs) const {
	return (this->address <= rhs.GetAddr());
}

#define MD_FIRST_ENTER_INSTR  NN_enterw
#define MD_LAST_ENTER_INSTR NN_enterq
// Is this instruction one that allocates space on the
//  stack for the local variables?
bool SMPInstr::MDIsFrameAllocInstr(void) {
	// The frame allocating instruction should look like:
	//   sub esp,48   or   add esp,-64   etc.
	ESPOp.type = o_reg;
	ESPOp.reg = R_sp;
	ESPOp.dtyp = this->GetOperandDtypField();
	if ((SMPcmd.itype == NN_sub) || (SMPcmd.itype == NN_add)) {
		if (this->GetLastDef() != this->Defs.FindRef(ESPOp)) {
			// We know that an addition or subtraction is being
			//  performed on the stack pointer. This should not be
			//  possible within the prologue except at the stack
			//  frame allocation instruction, so return true. We
			//  could be more robust in this analysis in the future. **!!**
			// CAUTION: If a compiler allocates 64 bytes for locals
			//  and 16 bytes for outgoing arguments in a single
			//  instruction:  sub esp,80
			//  you cannot insist on finding sub esp,LocSize
			// To make this more robust, we are going to insist that
			//  an allocation of stack space is either performed by
			//  adding a negative immediate value, or by subtracting
			//  a positive immediate value. We will throw in, free of
			//  charge, a subtraction of a register, which is how alloca()
			//  usually allocates stack space.
			// PHASE ORDERING: Should we use the Operands[] instead of the USE list? **!!**
			set<DefOrUse, LessDefUse>::iterator CurrUse;
			for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
				if (o_imm == CurrUse->GetOp().type) {
					signed long TempImm = (signed long) CurrUse->GetOp().value;
					if (((0 > TempImm) && (this->SMPcmd.itype == NN_add))
						|| ((0 < TempImm) && (this->SMPcmd.itype == NN_sub))) {
						return true;
					}
				}
				else if ((o_reg == CurrUse->GetOp().type)
						&& (!CurrUse->GetOp().is_reg(R_sp)) // skip the ESP operand
						&& (this->SMPcmd.itype == NN_sub)) { // sub esp,reg: alloca() ?
	else if ((this->SMPcmd.itype >= MD_FIRST_ENTER_INSTR) 
		&& (this->SMPcmd.itype <= MD_LAST_ENTER_INSTR)) {
		return true;
	}
	return false;
} // end of SMPInstr::MDIsFrameAllocInstr()

#define MD_FIRST_LEAVE_INSTR  NN_leavew
#define MD_LAST_LEAVE_INSTR NN_leaveq
// Is this instruction in the epilogue the one that deallocates the local
//  vars region of the stack frame?
bool SMPInstr::MDIsFrameDeallocInstr(bool UseFP, asize_t LocalVarsSize) {
	// The usual compiler idiom for the prologue on x86 is to
	//  deallocate the local var space with:   mov esp,ebp
	//  It could be  add esp,constant.  We can be tricked by
	//  add esp,constant when the constant is just the stack
	//  adjustment after a call. We will have to insist that
	//  the immediate operand have at least the value of
	//  LocalVarsSize for this second form, and that UseFP be true
	//  for the first form.
	set<DefOrUse, LessDefUse>::iterator FirstDef = this->GetFirstDef();
	set<DefOrUse, LessDefUse>::iterator FirstUse = this->GetFirstUse();
	if ((SMPcmd.itype >= MD_FIRST_LEAVE_INSTR) && (SMPcmd.itype <= MD_LAST_LEAVE_INSTR))
		return true;
	else if (this->HasDestMemoryOperand() || this->HasSourceMemoryOperand()) {
		// Don't get fooled by USE or DEF entries of EBP or ESP that come
		//  from memory operands, e.g. mov eax,[ebp-20]
		return false;
	}
	else if (UseFP && (this->SMPcmd.itype == NN_mov)
		&& (FirstDef->GetOp().is_reg(MD_STACK_POINTER_REG))
		&& (FirstUse->GetOp().is_reg(MD_FRAME_POINTER_REG)))
		return true;
	else if ((this->SMPcmd.itype == NN_add)
		&& (FirstDef->GetOp().is_reg(MD_STACK_POINTER_REG))) {
		set<DefOrUse, LessDefUse>::iterator SecondUse = ++FirstUse;
		if (SecondUse == this->Uses.GetLastRef())
			return false;  // no more USEs ... strange for ADD instruction
		if (SecondUse->GetOp().is_imm((uval_t) LocalVarsSize))
			return true;
		else if (SecondUse->GetOp().type == o_imm) {
			signed long	TempImm = (signed long) this->SMPcmd.Operands[1].value;
			if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc
				return false;
			else {
				SMP_msg("Used imprecise LocalVarsSize to find dealloc instr.\n");
	}
	else
		return false;
} // end of SMPInstr::MDIsFrameDeallocInstr()

// Is instruction a no-op? There are 1-byte, 2-byte, etc., versions of no-ops.
bool SMPInstr::MDIsNop(void) const {
	bool IsNop = false;
	ushort opcode = this->SMPcmd.itype;
	if ((NN_nop == opcode) || (NN_lock == opcode))
	else if ((NN_mov == opcode) || (NN_xchg == opcode))  {
		if ((o_reg == this->SMPcmd.Operands[0].type) 
			&& this->SMPcmd.Operands[1].is_reg(this->SMPcmd.Operands[0].reg)) {
			// We have a register to register move with source == destination,
			//  or a register exchanged with itself.
			IsNop = true;
		}
	}
	else if (NN_lea == opcode) {
		if ((o_reg == this->SMPcmd.Operands[0].type)
			&& (o_displ == this->SMPcmd.Operands[1].type)
			&& (0 == this->SMPcmd.Operands[1].addr)) {
			// We are looking for 6-byte no-ops like lea esi,[esi+0]
				ushort destreg = this->SMPcmd.Operands[0].reg;
				if ((this->SMPcmd.Operands[1].hasSIB)
					&& (destreg == (ushort) MD_STARS_sib_base(this->SMPcmd.Operands[1]))
					&& (R_sp == MD_STARS_sib_index(this->SMPcmd.Operands[1]))) {
					// R_sp signifies no SIB index register. So, we have
					//  lea reg,[reg+0] with reg being the same in both place,
					//  once as Operands[0] and once as the base reg in Operands[1].
					IsNop = true;
				}
				else if (destreg == this->SMPcmd.Operands[1].reg) {
					IsNop = true;
				}
		}
	}
	return IsNop;
} // end of SMPInstr::MDIsNop()

// Opcode always produces an UNSIGNED DEF.
bool SMPInstr::MDAlwaysUnsignedDEF(void) const {
	ushort opcode = this->SMPcmd.itype;
	return ((opcode == NN_bsf) || (opcode == NN_bsr) || (opcode == NN_div)
		|| (opcode == NN_lahf) || (opcode == NN_lar) || (opcode == NN_lgs)
		|| (opcode == NN_lss) || (opcode == NN_lds) || (opcode == NN_les)
		|| (opcode == NN_lfs) || (opcode == NN_lsl) || (opcode == NN_movzx)
		|| (opcode == NN_rcl) || (opcode == NN_rcr) || (opcode == NN_rol)
		|| (opcode == NN_ror) || (opcode == NN_shl) || (opcode == NN_shr)
		|| ((opcode >= NN_seta) && (opcode <= NN_setz)) || (opcode == NN_cpuid)
		|| (opcode == NN_rdtsc) || (opcode == NN_rdpmc) || (opcode == NN_fstsw)
		|| (opcode == NN_setalc) || (opcode == NN_packuswb) || (opcode == NN_paddusb)
		|| (opcode == NN_paddusw) || (opcode == NN_psllw) || (opcode == NN_pslld)
		|| (opcode == NN_psllq) || (opcode == NN_psrlw) || (opcode == NN_psrld)
		|| (opcode == NN_psrlq) || (opcode == NN_psubusb) || (opcode == NN_psubusw)
		|| (opcode == NN_pxor) || (opcode == NN_pavgusb) || (opcode == NN_pavgb)
		|| (opcode == NN_pavgw) || (opcode == NN_pextrw) || (opcode == NN_pmaxub) 
		|| ((opcode >= NN_pminub) && (opcode <= NN_psadbw))
		|| (opcode == NN_movmskpd) || (opcode == NN_pmuludq) || (opcode == NN_pslldq)
		|| (opcode == NN_psrldq) || ((opcode >= NN_pabsb) && (opcode <= NN_pabsd))
		|| (opcode == NN_rdtscp) || (opcode == NN_mpsadbw) || (opcode == NN_packusdw)
		|| ((opcode >= NN_pcmpeqq) && (opcode <= NN_phminposuw)) || (opcode == NN_pmaxud)
		|| (opcode == NN_pmaxuw) || (opcode == NN_pminud) || (opcode == NN_pminuw)
		|| ((opcode >= NN_pmovzxbw) && (opcode <= NN_pmovzxdq)) || ((opcode >= NN_crc32)
		&& (opcode <= NN_pcmpistrm)) || (opcode == NN_popcnt) || (opcode == NN_lzcnt)
		|| ((opcode >= NN_aesenc) && (opcode <= NN_aeskeygenassist)));
} // end of SMPInstr::MDAlwaysUnsignedDEF()

// Opcode always produces a SIGNED DEF.
bool SMPInstr::MDAlwaysSignedDEF(void) const {
	ushort opcode = this->SMPcmd.itype;
	return ((opcode == NN_cbw) || (opcode == NN_cwde) || (opcode == NN_cdqe)
		|| (opcode == NN_cwd) || (opcode == NN_cdq) || (opcode == NN_cqo)
		|| (opcode == NN_idiv) || (opcode == NN_movsx) || (opcode == NN_neg)
		|| (opcode == NN_sal) || (opcode == NN_sar) || (opcode == NN_fist)
		|| (opcode == NN_fistp) || (opcode == NN_fbstp) || (opcode == NN_packsswb)
		|| (opcode == NN_packssdw) || (opcode == NN_paddsb) || (opcode == NN_paddsw)
		|| (opcode == NN_pmaddwd) || (opcode == NN_pmulhw) || (opcode == NN_pmullw)
		|| (opcode == NN_psraw) || (opcode == NN_psrad) || (opcode == NN_psubsb)
		|| (opcode == NN_psubsw) || (opcode == NN_pfadd) || (opcode == NN_pfsub)
		|| (opcode == NN_pfsubr) || (opcode == NN_pfacc) || (opcode == NN_pfmin)
		|| (opcode == NN_pfmax) || (opcode == NN_pf2id) || (opcode == NN_pfrcp)
		|| (opcode == NN_pfrsqrt) || (opcode == NN_pfmul)
		|| (opcode == NN_pfrcpit1) || (opcode == NN_pfrsqit1) || (opcode == NN_pfrcpit2)
		|| (opcode == NN_pmulhrw) || ((opcode >= NN_addps) && (opcode <= NN_andps))
		|| ((opcode >= NN_cvtpi2ps)	&& (opcode <= NN_divss)) || ((opcode >= NN_maxps)
		&& (opcode <= NN_movlps)) || ((opcode >= NN_movss) && (opcode <= NN_sqrtss))
		|| (opcode == NN_subps) || (opcode == NN_subss) || (opcode == NN_unpckhps)
		|| (opcode == NN_unpcklps) || (opcode == NN_pmaxsw) || (opcode == NN_pminsw)
		|| (opcode == NN_movntps) || (opcode == NN_pf2iw) || (opcode == NN_pfnacc) 
		|| (opcode == NN_pfpnacc) || (opcode == NN_pi2fw) || ((opcode >= NN_addpd)
		&& (opcode <= NN_andpd)) || ((opcode >= NN_cvtdq2pd) && (opcode <= NN_divsd))
		|| (opcode == NN_maxpd) || (opcode == NN_maxsd) || ((opcode >= NN_minpd)
		&& (opcode <= NN_movapd)) || (opcode == NN_movhpd) || (opcode == NN_movlpd)
		|| (opcode == NN_movntpd) || ((opcode >= NN_movsd) && (opcode <= NN_orpd))
		|| ((opcode >= NN_sqrtpd) && (opcode <= NN_subsd)) && ((opcode >= NN_unpckhpd)
		&& (opcode <= NN_xorpd)) || ((opcode >= NN_movddup) && (opcode <= NN_movsxd))
		|| ((opcode >= NN_addsubpd) && (opcode <= NN_hsubps)) || (opcode == NN_fisttp)
		|| ((opcode >= NN_psignb) && (opcode <= NN_psignd)) || ((opcode >= NN_pmulhrsw)
		&& (opcode <= NN_phsubd)) || (opcode == NN_pfrcpv) || (opcode == NN_pfrsqrtv)
		|| ((opcode >= NN_blendpd) && (opcode <= NN_insertps)) || (opcode == NN_pmaxsb)
		|| (opcode == NN_pmaxsd) || (opcode == NN_pminsb) || (opcode == NN_pminsd)
		|| ((opcode >= NN_pmovsxbw) && (opcode <= NN_pmovsxdq)) || (opcode == NN_pmuldq)
		|| (opcode == NN_pmulld) || ((opcode >= NN_roundpd) && (opcode <= NN_roundss))
		|| (opcode == NN_movntsd) || (opcode == NN_movntss));
} // end of SMPInstr::MDAlwaysSignedDEF()

bool SMPInstr::MDIsAddition(void) const {
	unsigned short opcode = this->SMPcmd.itype;
	bool FoundAddition = ((NN_adc == opcode) || (NN_add == opcode));
	if (this->MDIsLoadEffectiveAddressInstr()) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		if (CurrRT->HasRightSubTree()) {
			CurrRT = CurrRT->GetRightTree();
			FoundAddition = (SMP_ADD == CurrRT->GetOperator());
		}
	}

	return FoundAddition;
// Is non-multiply arithmetic instruction that can possibly overflow?
bool SMPInstr::MDIsOverflowingOpcode(void) const {
	unsigned short opcode = this->SMPcmd.itype;

	return ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
		|| (NN_neg == opcode) || (NN_xadd == opcode));
}

// Is non-multiply arithmetic instruction that can possibly underflow?
bool SMPInstr::MDIsUnderflowingOpcode(void) const {
	unsigned short opcode = this->SMPcmd.itype;

	return ((NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}

// Is potentially benign overflow instruction?
bool SMPInstr::MDIsMaybeBenignOverflowOpcode(void) const {
	unsigned short opcode = this->SMPcmd.itype;

	return ((NN_adc == opcode) || (NN_add == opcode));
}

// Is potentially benign underflow instruction?
bool SMPInstr::MDIsMaybeBenignUnderflowOpcode(void) const {
	unsigned short opcode = this->SMPcmd.itype;

	return ((NN_neg == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}

// Is definitely benign underflow instruction?
//  NOTE: Overlaps with MDIsMaybeBenignUnderflowOpcode(), so call this one first.
bool SMPInstr::MDIsDefiniteBenignUnderflowOpcode(int &IdiomCode) {
	unsigned short opcode = this->SMPcmd.itype;

	// gcc use:  sbb edx,edx as a tricky way to get all zeroes or all ones into edx.
	//  (Some sort of saturation? Often treated as 0 or -1, i.e. it becomes SIGNED
	//   even if it used to be UNSIGNED.)
	//  The "underflow" on the subtraction is irrelevant and benign.
	bool benign = ((NN_sbb == opcode) && (this->SubtractsFromItself()));
	if (benign) {
		IdiomCode = 4;
	}
	return benign;
}

// Does a subtraction operator get applied to same left and right operands?
bool SMPInstr::SubtractsFromItself(void) {
	bool SelfSubtract = false;
	size_t RTLCount = this->RTL.GetCount();
	for (size_t index = 0; index < RTLCount; ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) {
			CurrRT = CurrRT->GetRightTree();
			SMPoperator CurrOp = CurrRT->GetOperator();
			if ((SMP_SUBTRACT_BORROW == CurrOp) || (SMP_SUBTRACT == CurrOp)) {
				if (!(CurrRT->HasRightSubTree())) {
					// NOTE: Must change this code when we build more precise SMP_SUBTRACT_BORROW RTL.
					op_t LeftOp = CurrRT->GetLeftOperand();
					op_t RightOp = CurrRT->GetRightOperand();
					SelfSubtract = IsEqOp(RightOp, LeftOp);
				}
				break;
			}
		}
	}
	return SelfSubtract;
} // end of SMPInstr::SubtractsFromItself()