/* SMPInstr.cpp - <see below>.
 *
 * Copyright (c) 2000, 2001, 2010 - University of Virginia 
 *
 * This file is part of the Memory Error Detection System (MEDS) infrastructure.
 * This file may be used and modified for non-commercial purposes as long as 
 * all copyright, permission, and nonwarranty notices are preserved.  
 * Redistribution is prohibited without prior written consent from the University 
 * of Virginia.
 *
 * Please contact the authors for restrictions applying to commercial use.
 *
 * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Author: University of Virginia
 * e-mail: jwd@virginia.com
 * URL   : http://www.cs.virginia.edu/
 *
 * Additional copyrights 2010, 2011, 2012, 2013, 2014, 2015 by Zephyr Software LLC
 * e-mail: {clc,jwd}@zephyr-software.com
 * URL   : http://www.zephyr-software.com/
 *
 */

//
// SMPInstr.cpp
//
// This module performs the instruction level analyses needed for the
//   SMP project (Software Memory Protection).
//

using namespace std;

#include <memory>
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>

#include <cstring>
#include <cstddef>
#include <cassert>

#include "interfaces/STARSTypes.h"
#include "interfaces/SMPDBInterface.h"
#include "base/SMPDataFlowAnalysis.h"
#include "base/SMPInstr.h"
#include "base/SMPProgram.h"
#include "base/ProfilerInformation.h"

#include "interfaces/abstract/STARSInstruction.h"
#include "interfaces/abstract/STARSOp.h"

// Set to 1 for debugging output
#define SMP_DEBUG 1
#define SMP_DEBUG2 0   // verbose
#define SMP_DEBUG_XOR 0
#define SMP_DEBUG_BUILD_RTL  1   // should be left on, serious errors!
#define SMP_VERBOSE_DEBUG_BUILD_RTL  0
#define SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE 0
#define SMP_VERBOSE_DEBUG_INFER_TYPES 0
#define SMP_VERBOSE_DUMP 0
#define SMP_VERBOSE_FIND_POINTERS 0
#define STARS_DUMP_FG_INFO 1  // show signedness of DEFs and USEs in dump
#define STARS_DEBUG_STATIC_MEM_OPS 0

#define SMP_BASEREG_POINTER_TYPE 1  // Initialize Base Register USEs to type POINTER?
#define SMP_OPTIMIZE_ADD_TO_NUMERIC 0 // optimizing annotation type -5
#define SMP_IDENTIFY_POINTER_ADDRESS_REG 0 // optimizing annotation POINTER
#define SMP_CHILDACCESS_ALL_CODE 0 // CHILDACCESS annotations for all funcs, or just analyzed funcs?
#define SPECIAL_CASE_CARRY_BORROW 0 // Treat sbb/adc different from sub/add annotations?
#define SMP_BUILD_SPECIAL_ADC_SBB_RTL 0 // Explicit RTL subtree for carry flag?
#define SMP_AGGRESSIVE_TYPE_INFERENCE 1  // Shorten iterations by quick propagation in InferOperatorType()
#define SMP_ANNOTATE_ALL_MEMORY_OPERANDS 0 // Info annotation for all memory read and write operands?
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1  // More transfer of signedness across instructions
#define STARS_NO_SHIFT_SIGNEDNESS_IN_SCALEFACTOR 1  // unsigned left shift for scale factors is really unknownsign multiply
#define STARS_USE_NUMERIC_ERROR_BLACKLISTING 1  // Only instrument for numeric errors if DEF leads to a blacklisted (important) sink
#define STARS_CONSERVATIVE_DEADREGS 1  // debug DEADREGS annotations by being ultra-conservative at call sites

#define STARS_EXPR_CALL_DEPTH_LIMIT 50 // Limit on number of invocations of ExpandExpr(), ExpandOperand(), and ExpandOperandHelper()

// Text to be printed in each optimizing annotation explaining why
//  the annotation was emitted.
#define LAST_TYPE_CATEGORY 15
static const char *OptExplanation[LAST_TYPE_CATEGORY + 1] =
	{ "NoOpt", "NoMetaUpdate", "AlwaysNUM", "NUMVia2ndSrcIMMEDNUM",
	  "Always1stSrc", "1stSrcVia2ndSrcIMMEDNUM", "AlwaysPtr",
	  "AlwaysNUM", "AlwaysNUM", "NUMViaFPRegDest", "NumericSources",
	  "StackMemoryTracking", "NumericSources", "NumericMemDest",
	  "NeverMemDest", "SafeIfNoIndexing"
	};

const char *OperatorText[LAST_SMP_OPERATOR + 1] = 
{ 	"SMP_NULL_OPERATOR", "SMP_CALL", "SMP_INPUT", "SMP_OUTPUT", "SMP_ADDRESS_OF",
	"SMP_U_LEFT_SHIFT", "SMP_S_LEFT_SHIFT", "SMP_U_RIGHT_SHIFT", "SMP_S_RIGHT_SHIFT",
	"SMP_ROTATE_LEFT", "SMP_ROTATE_LEFT_CARRY", "SMP_ROTATE_RIGHT", "SMP_ROTATE_RIGHT_CARRY",
	"SMP_DECREMENT", "SMP_INCREMENT",
	"SMP_ADD", "SMP_ADD_CARRY", "SMP_SUBTRACT", "SMP_SUBTRACT_BORROW", "SMP_U_MULTIPLY",
	"SMP_S_MULTIPLY", "SMP_U_DIVIDE", "SMP_S_DIVIDE", "SMP_U_REMAINDER",
	"SMP_SIGN_EXTEND", "SMP_ZERO_EXTEND", "SMP_ASSIGN", "SMP_BITWISE_AND",
	"SMP_BITWISE_OR", "SMP_BITWISE_NOT", "SMP_BITWISE_XOR", "SMP_BITWISE_AND_NOT", "SMP_NEGATE", 
	"SMP_S_COMPARE", "SMP_U_COMPARE", "SMP_GENERAL_COMPARE", "SMP_LESS_THAN", "SMP_GREATER_THAN",
	"SMP_LESS_EQUAL", "SMP_GREATER_EQUAL", "SMP_EQUAL", "SMP_NOT_EQUAL",
	"SMP_BELOW", "SMP_BELOW_EQUAL", "SMP_ABOVE", "SMP_ABOVE_EQUAL",
	"SMP_CARRY", "SMP_NOT_CARRY", "SMP_PARITY", "SMP_NOT_PARITY",
	"SMP_OVERFLOW", "SMP_NOT_OVERFLOW", "SMP_SIGN_BIT_SET", "SMP_NOT_SIGN_BIT_SET",
	"SMP_LOGICAL_AND", "SMP_LOGICAL_OR", "SMP_UNARY_NUMERIC_OPERATION",
	"SMP_BINARY_NUMERIC_OPERATION", "SMP_SYSTEM_OPERATION",
	"SMP_UNARY_FLOATING_ARITHMETIC", "SMP_BINARY_FLOATING_ARITHMETIC",
	"SMP_FLOATING_ADD", "SMP_FLOATING_SUBTRACT",
	"SMP_FLOATING_MULTIPLY", "SMP_FLOATING_DIVIDE", "SMP_FLOATING_NEGATE_AND_ADD",
	"SMP_REVERSE_SHIFT_U", "SMP_SHUFFLE", "SMP_COMPARE_EQ_AND_SET",
	"SMP_COMPARE_NE_AND_SET", "SMP_COMPARE_GT_AND_SET", 
	"SMP_COMPARE_GE_AND_SET", "SMP_COMPARE_LT_AND_SET", "SMP_COMPARE_LE_AND_SET",
	"SMP_PACK_SIGNED", "SMP_PACK_UNSIGNED",
	"SMP_AVERAGE_UNSIGNED", "SMP_MULTIPLY_AND_ADD", "SMP_SUM_OF_DIFFS",
	"SMP_MAX_S", "SMP_MAX_U", "SMP_MIN_S", "SMP_MIN_U", "SMP_ABS_VALUE",
	"SMP_CONVERT_INT_TO_FP", "SMP_CONVERT_FP_TO_INT", "SMP_CREATE_MASK",
	"SMP_INTERLEAVE", "SMP_CONCATENATE", "SMP_EXTRACT_ZERO_EXTEND", 
	"SMP_ENCRYPTION_OPERATION", "SMP_UNARY_POINTER_OPERATION", "X86.ReadMem64", "SMP_SIGNAL"
};

// Take RelationalOperator from a comparison instruction, as determined by its matching jump,
//  and convert it to the operator needed if the comparison operands are swapped.
//  E.g.: cmp rax,rbx followed by ja label1 produces SMP_GREATER_THAN operator.
//  If we did cmp rbx,rax then the operator would logically be SMP_LESS_THAN.
//  Used in STARSExpression tree flips.
SMPoperator InvertRelationalOperator(SMPoperator RelationalOperator) {
	switch (RelationalOperator) {
	case SMP_LESS_THAN:
		RelationalOperator = SMP_GREATER_THAN;
		break;

	case SMP_GREATER_THAN:
		RelationalOperator = SMP_LESS_THAN;
		break;

	case SMP_LESS_EQUAL:
		RelationalOperator = SMP_GREATER_EQUAL;
		break;

	case SMP_GREATER_EQUAL:
		RelationalOperator = SMP_LESS_EQUAL;
		break;

	case SMP_EQUAL:
		RelationalOperator = SMP_EQUAL;
		break;

	case SMP_NOT_EQUAL:
		RelationalOperator = SMP_NOT_EQUAL;
		break;

	case SMP_BELOW:   // unsigned comparison operators BELOW, BELOW_EQUAL, ABOVE, ABOVE_EQUAL
		RelationalOperator = SMP_ABOVE;
		break;

	case SMP_BELOW_EQUAL:
		RelationalOperator = SMP_ABOVE_EQUAL;
		break;

	case SMP_ABOVE:
		RelationalOperator = SMP_BELOW;
		break;

	case SMP_ABOVE_EQUAL:
		RelationalOperator = SMP_BELOW_EQUAL;
		break;

	case SMP_CARRY:  // should only be used in Guard RTLs
		RelationalOperator = SMP_NOT_CARRY;
		break;

	case SMP_NOT_CARRY:  // should only be used in Guard RTLs
		RelationalOperator = SMP_CARRY;
		break;

	case SMP_PARITY:  // should only be used in Guard RTLs
		RelationalOperator = SMP_NOT_PARITY;
		break;

	case SMP_NOT_PARITY:  // should only be used in Guard RTLs
		RelationalOperator = SMP_PARITY;
		break;

	case SMP_OVERFLOW:  // should only be used in Guard RTLs
		RelationalOperator = SMP_NOT_OVERFLOW;
		break;

	case SMP_NOT_OVERFLOW:  // should only be used in Guard RTLs
		RelationalOperator = SMP_OVERFLOW;
		break;

	case SMP_SIGN_BIT_SET:  // should only be used in Guard RTLs
		RelationalOperator = SMP_NOT_SIGN_BIT_SET;
		break;

	case SMP_NOT_SIGN_BIT_SET:  // should only be used in Guard RTLs
		RelationalOperator = SMP_SIGN_BIT_SET;
		break;

	default:
		SMP_msg("ERROR: Non-relational operator %d in call to InvertRelationalOperator()\n", RelationalOperator);
		break;
	}

	return RelationalOperator;
} // end of InvertRelationalOperator()

// Is the given memory range just a local frame write?
bool IsLocalStackFrameExprPair(const STARSExpression *LowerExpr, const STARSExpression *UpperExpr) {
	bool StackFrameAccess = false;
	if ((nullptr != LowerExpr) && (nullptr != UpperExpr)) {
		STARS_sval_t CurrentStackOffset = LowerExpr->GetOriginalParentInst()->GetStackPtrOffset();
		STARS_sval_t FinalStackOffset;
		if (UpperExpr->IsStackPtrOffset(CurrentStackOffset, FinalStackOffset)) {
			StackFrameAccess = (0 > FinalStackOffset);
		}
	}
	return StackFrameAccess;
} // end of IsLocalStackFrameExprPair()


#if 0
// Does the CurrOperator definitely indicate a signed or unsigned operation?
bool OperatorHasSignedness(SMPoperator CurrOperator) {
	bool DetectedSignedness;

	switch (CurrOperator) {
		case SMP_NULL_OPERATOR:
			DetectedSignedness = false;
			break;

		case SMP_CALL:  // CALL instruction
			DetectedSignedness = true;
			break;

		case SMP_INPUT:  // input from port
		case SMP_OUTPUT: // output to port
		case SMP_ADDRESS_OF: // take effective address
		case SMP_GENERAL_COMPARE:
			DetectedSignedness = false;
			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:
		case SMP_U_COMPARE: // unsigned compare (AND-based)
		case SMP_UNARY_POINTER_OPERATION:
			DetectedSignedness = true;
			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_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:
		case SMP_BELOW:
		case SMP_BELOW_EQUAL:
		case SMP_ABOVE:
		case SMP_ABOVE_EQUAL:
			DetectedSignedness = true;
			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
		case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
		case SMP_SIGNAL: // signal or raise exception
			DetectedSignedness = false;
			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_FLOATING_ADD:
		case SMP_FLOATING_SUBTRACT:
		case SMP_FLOATING_MULTIPLY:   // floating-point multiplication of any precision; all NUMERIC
		case SMP_FLOATING_DIVIDE:     // floating-point division of any precision; all NUMERIC
		case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; NUMERIC
			DetectedSignedness = true;
			break;

		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
		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 inequality 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_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
		case SMP_CONCATENATE:     // extended-precision concatenation; NUMERIC
			DetectedSignedness = true;
			break;

		default:
			DetectedSignedness = false;
			SMP_msg("ERROR: Unknown operator in OperatorHasSignedness: %d\n", CurrOperator);
			break;
	} // end switch on operator

	return DetectedSignedness;
} // end of OperatorHasSignedness()
#endif

// Print the SPARK Ada procedure suffix for the operand, e.g. reg32 or mem16 or const32
void PrintOperandSPARKAdaSuffix(const STARSOpndTypePtr &Opnd, FILE *OutFile) {
	bool ErrorFlag = false;
	if (Opnd->IsRegOp()) {
		SMP_fprintf(OutFile, "_reg");
	}
	else if (IsMemOperand(Opnd)) {
		SMP_fprintf(OutFile, "_mem");
	}
	else if (Opnd->IsImmedOp()) {
		SMP_fprintf(OutFile, "_const");
	}
	else {
		ErrorFlag = true;
		SMP_fprintf(OutFile, "_ERROR");
	}

	// Append the bit width.
	if (!ErrorFlag) {
		std::size_t ByteWidth = Opnd->GetByteWidth();
		std::size_t BitWidth = ByteWidth * 8;
		char WidthStr[12];
		SMP_snprintf(WidthStr, 5, "%z", BitWidth);
		SMP_fprintf(OutFile, "%s", WidthStr);
	}

	return;
} // end of PrintOperandSPARKAdaSuffix()

// Construct SPARK memory write procedure call, including open parenthesis for arg list.
void GetSPARKMemWriteProcString(std::size_t OpndByteWidth, char *MemWriteString) {
	if (OpndByteWidth == 8) {
		SMP_snprintf(MemWriteString, 30, "X86.WriteMem64((");
	}
	else if (OpndByteWidth == 4) {
		SMP_snprintf(MemWriteString, 30, "X86.WriteMem32(Unsigned64(");
	}
	else if (OpndByteWidth == 2) {
		SMP_snprintf(MemWriteString, 30, "X86.WriteMem16(Unsigned64(");
	}
	else if (OpndByteWidth == 1) {
		SMP_snprintf(MemWriteString, 30, "X86.WriteMem8(Unsigned64(");
	}
	else if (OpndByteWidth == 10) {
		SMP_snprintf(MemWriteString, 30, "X86.WriteMem80(Unsigned64(");
	}

	return;
} // end of GetSPARKMemWriteProcString()

// Construct SPARK memory read procedure call, including open parenthesis for arg list.
void GetSPARKMemReadProcString(std::size_t OpndByteWidth, char *MemReadString) {
	if (OpndByteWidth == 8) {
		SMP_snprintf(MemReadString, 30, "X86.ReadMem64((");
	}
	else if (OpndByteWidth == 4) {
		SMP_snprintf(MemReadString, 30, "X86.ReadMem32(Unsigned64(");
	}
	else if (OpndByteWidth == 2) {
		SMP_snprintf(MemReadString, 30, "X86.ReadMem16(Unsigned64(");
	}
	else if (OpndByteWidth == 1) {
		SMP_snprintf(MemReadString, 30, "X86.ReadMem8(Unsigned64(");
	}
	else if (OpndByteWidth == 10) {
		SMP_snprintf(MemReadString, 30, "X86.ReadMem80(Unsigned64(");
	}

	return;
} // end of GetSPARKMemReadProcString()

// Construct SPARK bitwidth cast string. e.g. Unsigned32.
void GetSPARKWidthCastString(std::size_t OpndByteWidth, char *CastString) {
	if (OpndByteWidth == 8) {
		SMP_snprintf(CastString, 15, "Unsigned64");
	}
	else if (OpndByteWidth == 4) {
		SMP_snprintf(CastString, 15, "Unsigned32");
	}
	else if (OpndByteWidth == 2) {
		SMP_snprintf(CastString, 15, "Unsigned16");
	}
	else if (OpndByteWidth == 1) {
		SMP_snprintf(CastString, 15, "Unsigned8");
	}
	else if (OpndByteWidth == 10) {
		SMP_snprintf(CastString, 15, "Unsigned80");
	}


	return;
} // end of GetSPARKWidthCastString()

void PrintSPARKIndentTabs(FILE *OutFile) {
#define DEBUG_STARS_TABS 1
#if DEBUG_STARS_TABS
	if (STARS_SPARK_IndentCount > 8) {
		SMP_msg("ERROR: Indentation level out of range: %u\n", STARS_SPARK_IndentCount);
		STARS_SPARK_IndentCount = 8;
	}
#endif

	for (std::size_t Counter = 0; Counter < STARS_SPARK_IndentCount; ++Counter) {
		SMP_fprintf(OutFile, "\t");
	}
	return;
}

// Print an operand in SPARK-Ada form.
void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace, bool UseSavedStackPtr) {
#if 1
	std::string OutString;
	this->SPARKAdaOperandToString(Opnd, OutString, LeftHandSide, UseFP, UseMachinePrefix, OmitTrailingSpace, UseSavedStackPtr);
	SMP_fprintf(OutFile, "%s", OutString.c_str());
#else
	std::size_t OpndByteWidth = Opnd->GetByteWidth();
	bool MemOpnd = IsMemOperand(Opnd);
	bool SubwordWidth = (global_STARS_program->GetSTARS_ISA_Bytewidth() > OpndByteWidth);
	bool MemWrite = LeftHandSide && MemOpnd;
	bool MemRead = MemOpnd && (!LeftHandSide);
	char MemWriteString[40] = { '\0' };

	++SPARKOperandCount;

	if (MemWrite) {
		GetSPARKMemWriteProcString(OpndByteWidth, MemWriteString);
	}
	else if (MemRead) {
		GetSPARKMemReadProcString(OpndByteWidth, MemWriteString);
	}

	if (Opnd->IsStaticMemOp()) {
		if (Opnd->HasSIBByte()) {
			SMP_fprintf(OutFile, " %s ", MemWriteString);
			SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr);
			SMP_fprintf(OutFile, " + 16#%llx# )", (uint64_t) Opnd->GetAddr());
		}
		else {
			SMP_fprintf(OutFile, " %s 16#%llx# ", MemWriteString, (uint64_t) Opnd->GetAddr());
		}
		if (SubwordWidth) {
			++SubwordMemCount;
		}
	}
	else if (Opnd->IsMemNoDisplacementOp()) {
		if (Opnd->HasSIBByte()) { // has SIB info
			SMP_fprintf(OutFile, " %s ", MemWriteString);
			SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr);
		}
		else { // no SIB info
			STARS_regnum_t BaseReg = Opnd->GetReg();
			STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg);
			if (this->MDIsAddressing64bit()) {
				BaseOp->SetByteWidth(8);
			}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) {
				// We have a segment selector that is not just a redundant SS: selector for an RSP-relative access.
				STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg());
				SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp));
			}
			else {
#endif
				if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) {
					SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp));
				}
				else {
					SMP_fprintf(OutFile, " %s SaveStackPtr ", MemWriteString);
				}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			}
#endif
			if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) {
				++SubwordAddressRegCount;
			}
		}
		if (Opnd->GetAddr() != 0) {
			SMP_msg(" \n WARNING: addr for o_phrase type: %llx\n", (unsigned long long) Opnd->GetAddr());
		}
		if (SubwordWidth) {
			++SubwordMemCount;
		}
	}
	else if (Opnd->IsMemDisplacementOp()) {
		STARS_ea_t offset = Opnd->GetAddr();
		int SignedOffset = (int) offset;
		if (Opnd->HasSIBByte()) {
			SMP_fprintf(OutFile, " %s ", MemWriteString);
			SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), false);
			if (SignedOffset > 0) // print plus sign
				SMP_fprintf(OutFile, "+ 16#%x# )", (unsigned int) SignedOffset);
			else if (SignedOffset < 0) {
				SMP_fprintf(OutFile, "- 16#%x# )", (unsigned int) (0 - SignedOffset));
			}
		}
		else {
			STARS_regnum_t BaseReg = Opnd->GetReg();
			STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg);
			if (this->MDIsAddressing64bit()) {
				BaseOp->SetByteWidth(8);
			}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) {
				// We have a segment selector that is not just a redundant SS: selector for an RSP-relative access.
				STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg());
				SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp));
			}
			else {
#endif
				if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) {
					SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp));
				}
				else {
					SMP_fprintf(OutFile, " %s SaveStackPtr ", MemWriteString);
				}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			}
#endif
			if (SignedOffset >= 0) // print plus sign
				SMP_fprintf(OutFile, "+ 16#%x# ", (unsigned int) SignedOffset);
			else {
				SMP_fprintf(OutFile, "- 16#%x# ", (unsigned int) (0 - SignedOffset));
			}
			if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) {
				++SubwordAddressRegCount;
			}
		}
		if (SubwordWidth) {
			++SubwordMemCount;
		}
	}
	else if (Opnd->IsRegOp()) {
		if (UseSavedStackPtr && Opnd->MatchesReg(MD_STACK_POINTER_REG)) {
			assert(!LeftHandSide);
			SMP_fprintf(OutFile, " SaveStackPtr");
		}
		else if (SubwordWidth && LeftHandSide) {
			// Subword reg writes are procedure calls, e.g. Write_EDI(...
			SMP_fprintf(OutFile, " X86.Write_%s(", MDGetRegName(Opnd));
		}
		else if (UseMachinePrefix) {
			SMP_fprintf(OutFile, " X86.%s", MDGetRegName(Opnd));
		}
		else {
			SMP_fprintf(OutFile, " %s", MDGetRegName(Opnd));
		}
		if (!OmitTrailingSpace) { // parameters to loop functions will get a suffix; all others need a space now
			SMP_fprintf(OutFile, " ");
		}
		if (SubwordWidth) {
			++SubwordRegCount;
		}
	}
	else if (Opnd->IsFloatingPointRegOp()) {
		bool FPStackTop = (STARS_x86_R_st0 == Opnd->GetReg());
		if (UseMachinePrefix) {
			if (FPStackTop)
				SMP_fprintf(OutFile, " X86.FloatingPointStackDummy ");
			else
				SMP_fprintf(OutFile, " X86.FloatingPointStackDummy1 ");
		}
		else {
			if (FPStackTop)
				SMP_fprintf(OutFile, " FloatingPointStackDummy ");
			else
				SMP_fprintf(OutFile, " FloatingPointStackDummy1 ");
		}
	}
	else if (Opnd->IsImmedOp()) {
		STARS_sval_t SignedImmedValue = (STARS_sval_t) Opnd->GetImmedValue();
		if (0 > SignedImmedValue) { // enclose unary minus in parentheses for Ada
			SMP_fprintf(OutFile, " (%lld) ", (long long) SignedImmedValue);
		}
		else {
			SMP_fprintf(OutFile, " 16#%llx# ", (unsigned long long) SignedImmedValue);
		}
	}
	else if (Opnd->IsFarPointer() || Opnd->IsNearPointer()) {
		SMP_fprintf(OutFile, " 16#%llx# ", (unsigned long long) Opnd->GetAddr());
	}
	else if (Opnd->IsVoidOp()) {
		; // nothing to print
	}
	else {
		SMP_fprintf(OutFile, " ERROROP");
	}

	if (MemWrite) { // close the procedure call address arg cast parentheses
		SMP_fprintf(OutFile, "), "); // e.g. MemWrite32(Unsigned64(Opnd),  
	}
	else if (MemRead) {
		SMP_fprintf(OutFile, ")) "); // e.g. MemRead8(Unsigned64(Opnd))
	}
#endif
	return;
} // end of PrintSPARKAdaOperand()

void SMPInstr::SPARKAdaOperandToString(const STARSOpndTypePtr &Opnd, std::string &OutString, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace, bool UseSavedStackPtr) {
	std::size_t OpndByteWidth = Opnd->GetByteWidth();
	bool MemOpnd = IsMemOperand(Opnd);
	bool SubwordWidth = (global_STARS_program->GetSTARS_ISA_Bytewidth() > OpndByteWidth);
	bool MemWrite = LeftHandSide && MemOpnd;
	bool MemRead = MemOpnd && (!LeftHandSide);
	char MemWriteString[40] = { '\0' };
	char TempString[40] = { '\0' };
	string SIBString;

	++SPARKOperandCount;

	if (MemWrite) {
		GetSPARKMemWriteProcString(OpndByteWidth, MemWriteString);
	}
	else if (MemRead) {
		GetSPARKMemReadProcString(OpndByteWidth, MemWriteString);
	}

	if (Opnd->IsStaticMemOp()) {
		OutString.append(" ");
		OutString.append(MemWriteString);
		if (Opnd->HasSIBByte()) {
			SPARKAnnotSIBToString(Opnd, true, SIBString, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr);
			OutString.append(" ");
			OutString.append(SIBString);
			(void) SMP_snprintf(TempString, 20, " + 16#%llx# )", (unsigned long long) Opnd->GetAddr());
		}
		else {
			(void) SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) Opnd->GetAddr());
		}
		OutString.append(" ");
		OutString.append(TempString);

		if (SubwordWidth) {
			++SubwordMemCount;
//			OutString.append(")"); // close cast parenthesis
		}
	}
	else if (Opnd->IsMemNoDisplacementOp()) {
		OutString.append(" ");
		OutString.append(MemWriteString);
		if (Opnd->HasSIBByte()) {
			SPARKAnnotSIBToString(Opnd, false, SIBString, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr);
			OutString.append(" ");
			OutString.append(SIBString);
		}
		else { // no SIB info
			STARS_regnum_t BaseReg = Opnd->GetReg();
			STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg);
			if (this->MDIsAddressing64bit()) {
				BaseOp->SetByteWidth(8);
			}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) {
				// We have a segment selector that is not just a redundant SS: selector for an RSP-relative access.
				STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg());
				SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp));
			}
			else {
#endif
				if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) {
					OutString.append(" X86.");
					OutString.append(MDGetRegName(BaseOp));
					OutString.append(" ");
				}
				else {
					OutString.append(" SaveStackPtr ");
				}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			}
#endif
			if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) {
				++SubwordAddressRegCount;
			}
		}
		if (Opnd->GetAddr() != 0) {
			SMP_msg(" \n WARNING: addr for o_phrase type: %llx\n", (unsigned long long) Opnd->GetAddr());
		}
		if (SubwordWidth) {
			++SubwordMemCount;
//			OutString.append(")"); // close cast parenthesis
		}
	}
	else if (Opnd->IsMemDisplacementOp()) {
		STARS_ea_t offset = Opnd->GetAddr();
		int SignedOffset = (int) offset;
		OutString.append(" ");
		OutString.append(MemWriteString);
		if (Opnd->HasSIBByte()) {
			SPARKAnnotSIBToString(Opnd, true, SIBString, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), false);
			OutString.append(" ");
			OutString.append(SIBString);
			if (SignedOffset > 0) // print plus sign
				SMP_snprintf(TempString, 20, "+ 16#%x# )", (unsigned int) SignedOffset);
			else if (SignedOffset < 0) 
				SMP_snprintf(TempString, 20, "- 16#%x# )", (unsigned int) (0 - SignedOffset));
			OutString.append(TempString);
		}
		else {
			STARS_regnum_t BaseReg = Opnd->GetReg();
			STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg);
			if (this->MDIsAddressing64bit()) {
				BaseOp->SetByteWidth(8);
			}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) {
				// We have a segment selector that is not just a redundant SS: selector for an RSP-relative access.
				STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg());
				SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp));
			}
			else {
#endif
				if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) {
					OutString.append(" X86.");
					OutString.append(MDGetRegName(BaseOp));
					OutString.append(" ");
				}
				else {
					OutString.append(" SaveStackPtr ");
				}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			}
#endif
			if (SignedOffset > 0) // print plus sign
				SMP_snprintf(TempString, 20, "+ 16#%x# ", (unsigned int) SignedOffset);
			else if (SignedOffset < 0)
				SMP_snprintf(TempString, 20, "- 16#%x# ", (unsigned int) (0 - SignedOffset));
			OutString.append(TempString);
			if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) {
				++SubwordAddressRegCount;
			}
		}
		if (SubwordWidth) {
			++SubwordMemCount;
//			OutString.append(")"); // close cast parenthesis
		}
	}
	else if (Opnd->IsRegOp()) {
		if (UseSavedStackPtr && Opnd->MatchesReg(MD_STACK_POINTER_REG)) {
			assert(!LeftHandSide);
			SMP_snprintf(TempString, 20, " SaveStackPtr");
		}
		else if (SubwordWidth && LeftHandSide) {
			// Subword reg writes are procedure calls, e.g. Write_EDI(...
			SMP_snprintf(TempString, 20, " X86.Write_%s(", MDGetRegName(Opnd));
		}
		else if (UseMachinePrefix) {
			SMP_snprintf(TempString, 20, " X86.%s", MDGetRegName(Opnd));
		}
		else {
			SMP_snprintf(TempString, 20, " %s", MDGetRegName(Opnd));
		}
		OutString.append(TempString);
		if (!OmitTrailingSpace) { // parameters to loop functions will get a suffix; all others need a space now
			OutString.append(" ");
		}
		if (SubwordWidth) {
			++SubwordRegCount;
		}
	}
	else if (Opnd->IsFloatingPointRegOp()) {
		bool FPStackTop = (STARS_x86_R_st0 == Opnd->GetReg());
		if (UseMachinePrefix) {
			if (FPStackTop)
				OutString.append(" X86.FloatingPointStackDummy ");
			else
				OutString.append(" X86.FloatingPointStackDummy1 ");
		}
		else {
			if (FPStackTop)
				OutString.append(" X86.FloatingPointStackDummy ");
			else
				OutString.append(" X86.FloatingPointStackDummy1 ");
		}
	}
	else if (Opnd->IsImmedOp()) {
		STARS_sval_t SignedImmedValue = (STARS_sval_t)Opnd->GetImmedValue();
		if (0 > SignedImmedValue) { // enclose unary minus in parentheses for Ada
			SMP_snprintf(TempString, 20, " (%lld) ", (long long) SignedImmedValue);
		}
		else {
			SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) SignedImmedValue);
		}
		OutString.append(TempString);
	}
	else if (Opnd->IsFarPointer() || Opnd->IsNearPointer()) {
		SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) Opnd->GetAddr());
		OutString.append(TempString);
	}
	else if (Opnd->IsVoidOp()) {
		; // nothing to print
	}
	else {
		OutString.append(" ERROROP");
	}

	if (MemWrite) { // close the procedure call address arg cast parentheses
		OutString.append("), "); // e.g. MemWrite32(Unsigned64(Opnd),  
	}
	else if (MemRead) {
		OutString.append(")) "); // e.g. MemRead8(Unsigned64(Opnd))
	}
	return;
} // end of SMPInstr::SPARKAdaOperandToString()

// Print just the addressing expression for a memory operand in SPARK-Ada form.
void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool UseFP, bool UseSavedStackPtr) {
	bool MemOpnd = IsMemOperand(Opnd);

	assert(MemOpnd);

	if (Opnd->IsStaticMemOp()) {
		if (Opnd->HasSIBByte()) {
			SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr);
			SMP_fprintf(OutFile, " + 16#%llx# )", (uint64_t) Opnd->GetAddr());
		}
		else {
			SMP_fprintf(OutFile, " 16#%llx# ", (uint64_t) Opnd->GetAddr());
		}
	}
	else if (Opnd->IsMemNoDisplacementOp()) {
		if (Opnd->HasSIBByte()) { // has SIB info
			SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr);
		}
		else { // no SIB info
			STARS_regnum_t BaseReg = Opnd->GetReg();
			STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg);
			if (this->MDIsAddressing64bit()) {
				BaseOp->SetByteWidth(8);
			}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) {
				// We have a segment selector that is not just a redundant SS: selector for an RSP-relative access.
				STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg());
				SMP_fprintf(OutFile, " X86.%s + X86.%s ", MDGetRegName(SegRegOp), MDGetRegName(BaseOp));
			}
			else {
#endif
				if (!(UseSavedStackPtr && BaseOp->MatchesReg(MD_STACK_POINTER_REG))) {
					SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp));
				}
				else {
					SMP_fprintf(OutFile, " SaveStackPtr ");
				}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			}
#endif
		}
		if (Opnd->GetAddr() != 0) {
			SMP_msg(" \n WARNING: addr for o_phrase type: %llx\n", (uint64_t) Opnd->GetAddr());
		}
	}
	else if (Opnd->IsMemDisplacementOp()) {
		STARS_ea_t offset = Opnd->GetAddr();
		int SignedOffset = (int) offset;
		if (Opnd->HasSIBByte()) {
			SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr);
			if (SignedOffset > 0) // print plus sign
				SMP_fprintf(OutFile, "+ 16#%x# )", (unsigned int) SignedOffset);
			else if (SignedOffset < 0) // minus sign will print automatically
				SMP_fprintf(OutFile, "%d )", SignedOffset);
		}
		else {
			STARS_regnum_t BaseReg = Opnd->GetReg();
			STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg);
			if (this->MDIsAddressing64bit()) {
				BaseOp->SetByteWidth(8);
			}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) {
				// We have a segment selector that is not just a redundant SS: selector for an RSP-relative access.
				STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg());
				SMP_fprintf(OutFile, " X86.%s + X86.%s ", MDGetRegName(SegRegOp), MDGetRegName(BaseOp));
			}
			else {
#endif
				if (!(UseSavedStackPtr && BaseOp->MatchesReg(MD_STACK_POINTER_REG))) {
					SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp));
				}
				else {
					SMP_fprintf(OutFile, " SaveStackPtr ");
				}
#if STARS_SPARK_EMIT_SEGMENT_REGS
			}
#endif
			if (SignedOffset >= 0) // print plus sign
				SMP_fprintf(OutFile, "+ 16#%x# ", (unsigned int) SignedOffset);
			else // minus sign will print automatically
				SMP_fprintf(OutFile, "%d ", SignedOffset);
		}
	}
	else {
		SMP_fprintf(OutFile, " ERROROP");
	}

	return;
} // end of PrintSPARKAdaAddressExpr()

// Print an operator in SPARK-Ada form.
void PrintSPARKAdaOperator(SMPoperator Oper, string &OutString, bool &PrefixProcCall, bool &PrefixUnary, bool ConstFollows) {
	PrefixProcCall = false;
	PrefixUnary = false;

	switch (Oper) {
		case SMP_NULL_OPERATOR: 
		case SMP_INPUT:  // input from port
		case SMP_OUTPUT: // output to port
		case SMP_ADDRESS_OF: // take effective address
		case SMP_S_LEFT_SHIFT: // signed left shift
		case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
		case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
			SMP_msg("ERROR: SPARK: Cannot translate operator: ");
			SMP_msg(" %s \n", OperatorText[Oper]);
			OutString = "ERROR";
			break;

		case SMP_ADD_CARRY:   // add with carry
			OutString = " X86.adc";
			PrefixProcCall = true;
			break;

		case SMP_SUBTRACT_BORROW:  // subtract with borrow
			OutString = " X86.sbb";
			PrefixProcCall = true;
			break;

		case SMP_CALL:  // CALL instruction
			break;

		case SMP_U_LEFT_SHIFT: // unsigned left shift
		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
			OutString = " Interfaces.Shift_Left";
			PrefixProcCall = true;
			break;

		case SMP_U_RIGHT_SHIFT: // unsigned right shift
			OutString = " Interfaces.Shift_Right";
			PrefixProcCall = true;
			break;

		case SMP_S_RIGHT_SHIFT: // signed right shift
			OutString = " Interfaces.Shift_Right_Arithmetic";
			PrefixProcCall = true;
			break;

		case SMP_ROTATE_LEFT:
			OutString = " Interfaces.Rotate_Left";
			PrefixProcCall = true;
			break;

		case SMP_ROTATE_RIGHT:
			OutString = " Interfaces.Rotate_Right";
			PrefixProcCall = true;
			break;

		case SMP_DECREMENT:
			OutString = " - 1";  // we print LeftOp first, then - 1, then RightOp will be void
			break;

		case SMP_INCREMENT:
			OutString = " + 1";  // we print LeftOp first, then + 1, then RightOp will be void
			break;

		case SMP_ADD:
		case SMP_FLOATING_ADD:
			OutString = " + ";
			break;

		case SMP_SUBTRACT:
		case SMP_FLOATING_SUBTRACT:
			OutString = " - ";
			break;

		case SMP_U_MULTIPLY:
		case SMP_S_MULTIPLY:
		case SMP_FLOATING_MULTIPLY:   // floating-point multiplication of any precision; all NUMERIC
			OutString = " * ";
			break;

		case SMP_U_DIVIDE:
		case SMP_S_DIVIDE:
			if (ConstFollows) {
				OutString = " / ";
			}
			else {
				OutString = " X86.SafeDivision64";
				PrefixProcCall = true;
			}
			break;

		case SMP_FLOATING_DIVIDE:     // floating-point division of any precision; all NUMERIC
			if (ConstFollows) {
				OutString = " / ";
			}
			else {
				OutString = " X86.SafeDivision64";
				PrefixProcCall = true;
			}
			break;

		case SMP_U_REMAINDER:
			OutString = " rem ";
			break;

		case SMP_SIGN_EXTEND:
			OutString = "";
			PrefixUnary = true;
			break;

		case SMP_ZERO_EXTEND:
			OutString = "";
			PrefixUnary = true;
			break;

		case SMP_ASSIGN:
			OutString = ":= ";
			break;

		case SMP_BITWISE_AND:
			OutString = " and ";
			break;

		case SMP_BITWISE_OR:
			OutString = " or ";
			break;

		case SMP_BITWISE_NOT: // unary operator
			OutString = " not ";
			PrefixUnary = true;
			break;

		case SMP_BITWISE_XOR:
			OutString = " xor ";
			break;

		case SMP_BITWISE_AND_NOT:
			OutString = " andnot ";
			break;

		case SMP_NEGATE:    // unary negation
			OutString = "-";
			PrefixUnary = true;
			break;

		case SMP_LESS_THAN: // boolean test operators
		case SMP_BELOW:
			OutString = " < ";
			break;

		case SMP_GREATER_THAN:
		case SMP_ABOVE:
			OutString = " > ";
			break;

		case SMP_LESS_EQUAL:
		case SMP_BELOW_EQUAL:
			OutString = " <= ";
			break;

		case SMP_GREATER_EQUAL:
		case SMP_ABOVE_EQUAL:
			OutString = " >= ";
			break;

		case SMP_EQUAL:
			OutString = " = ";
			break;

		case SMP_NOT_EQUAL:
			OutString = " /= ";
			break;

		case SMP_LOGICAL_AND:
#if ZST_EMIT_SPARK_ADA_SHORT_CIRCUIT_OPERATORS
			OutString = " and then "; // short circuit operator is accurate representation
#else
			OutString = " and "; // faster proofs without short circuit operator
#endif
			break;

		case SMP_LOGICAL_OR:
#if ZST_EMIT_SPARK_ADA_SHORT_CIRCUIT_OPERATORS
			OutString = " or else "; // short circuit operator is accurate representation
#else
			OutString = " or "; // faster proofs without short circuit operator
#endif
			break;

		case SMP_S_COMPARE: // signed compare (subtraction-based)
		case SMP_U_COMPARE: // unsigned compare (AND-based)
			SMP_msg("WARNING: SPARK: Translating comparison operator: ");
			SMP_msg(" %s \n", OperatorText[Oper]);
			OutString = ", ";  // assume this is part of Write_EFLAGS(opnd1, opnd2);
			break;

		case SMP_CONVERT_INT_TO_FP: // convert integer to floating point
		case SMP_CONVERT_FP_TO_INT: // convert floating point to integer
			SMP_msg("WARNING: SPARK: Translating conversion operator: ");
			SMP_msg(" %s \n", OperatorText[Oper]);
			OutString = " + "; // just move between int and FP regs, as they are all treated as ints in SPARK X86 package
			break;

		case SMP_SYMBOLIC_READ_MEMORY:
			OutString = " X86.ReadMem64";
			PrefixUnary = true;
			break;

		case SMP_GENERAL_COMPARE: // comparisons of packed data, strings, signed, unsigned depending on control words
		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
		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_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_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_UNARY_POINTER_OPERATION: 
		case SMP_SIGNAL:   // signal or raise exception
		default:
			SMP_msg("ERROR: SPARK: Cannot translate unknown operator: ");
			SMP_msg(" %s \n", OperatorText[Oper]);
			OutString = "ERROR";
			break;
	}
	return;
} // end of PrintSPARKAdaOperator()

// *****************************************************************
// Class SMPGuard
// *****************************************************************
// Constructor
SMPGuard::SMPGuard(void) {
	this->LeftOperand = nullptr;
	this->RightOperand = nullptr;
	this->GuardOp = SMP_NULL_OPERATOR;
	return;
}

// Debug print
void SMPGuard::Dump(void) const {
	SMP_msg("GUARD: ");
	PrintOperand(this->LeftOperand);
	SMP_msg(" %s ", OperatorText[this->GuardOp]);
	PrintOperand(this->RightOperand);
	SMP_msg(":");
	return;
} // end of SMPGuard::Dump()

// *****************************************************************
// Class SMPRegTransfer
// *****************************************************************
// Constructors
SMPRegTransfer::SMPRegTransfer(void) {
	this->Guard = NULL;
	this->LeftOperand = nullptr;
	this->RightOperand = nullptr;
	this->RTop.oper = SMP_NULL_OPERATOR;
	this->RTop.type = UNINIT;
#if SMP_TRACK_NONSPEC_OPER_TYPE
	this->RTop.NonSpeculativeType = UNINIT;
#endif
	this->RightRT = NULL;
	this->ParentInst = NULL;
	this->booleans1 = 0;
	return;
}

// Destructor
SMPRegTransfer::~SMPRegTransfer() {
#if 0
	SMP_msg("Destroying SMPRegTransfer.\n");
#endif
	if (NULL != this->RightRT)
		delete this->RightRT;
	if (NULL != this->Guard)
		delete this->Guard;
	return;
}

// Get the left operand, and normalize it if it is a stack operand.
STARSOpndTypePtr SMPRegTransfer::GetLeftOperand(void) const {
	STARSOpndTypePtr TempOp = this->LeftOperand;
#if 0
	if (this->ParentInst->AreDefsNormalized() && (0 != this->ParentInst->GetStackPtrOffset())) {
#else
	if (this->ParentInst->AreDefsNormalized()) {
#endif
		STARS_ea_t InstAddr = this->ParentInst->GetAddr();
		TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
	}
	return TempOp;
} // end of SMPRegTransfer::GetLeftOperand()

// Get the right operand, and normalize it if it is a stack operand.
STARSOpndTypePtr SMPRegTransfer::GetRightOperand(void) const {
	STARSOpndTypePtr TempOp = this->RightOperand;
#if 0
	if (this->ParentInst->AreDefsNormalized() && (0 != this->ParentInst->GetStackPtrOffset())) {
#else
	if (this->ParentInst->AreDefsNormalized()) {
#endif
		STARS_ea_t InstAddr = this->ParentInst->GetAddr();
		TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
	}
	return TempOp;
} // end of SMPRegTransfer::GetRightOperand()

// Does RTL subtract a non-immediate value from the stack pointer?
bool SMPRegTransfer::IsAllocaRTL(void) {
	bool AllocaFound = false;
	// Search for the pattern: stack_pointer := stack_pointer minus non-immediate
	if ((SMP_ASSIGN == this->GetOperator()) && (this->HasRightSubTree())) {
		STARSOpndTypePtr DefOp = this->GetLeftOperand();
		if (DefOp->MatchesReg(MD_STACK_POINTER_REG)) {
			// We have the code pattern stack_pointer := ...
			SMPRegTransfer *RightRT = this->GetRightTree();
			SMPoperator RightOperator = RightRT->GetOperator();
			STARSOpndTypePtr RightDefOp = RightRT->GetLeftOperand();
			if ((RightDefOp->MatchesReg(MD_STACK_POINTER_REG)) && (SMP_SUBTRACT == RightOperator)) {
				// We have the code pattern stack_pointer := stack_pointer minus ...
				if (RightRT->HasRightSubTree()) {
					AllocaFound = true; // not an immediate rightop, whatever it is
				}
				else {
					STARSOpndTypePtr RightUseOp = RightRT->GetRightOperand();
					if (! RightUseOp->IsImmedOp()) {
						AllocaFound = true;
					}
				}
			}
		}
	}
	return AllocaFound;
} // end of SMPRegTransfer::IsAllocaRTL()

// SetOperatorType - set the type of the operator, take into account the speculative (profiler) status
void SMPRegTransfer::SetOperatorType(SMPOperandType OpType, const SMPInstr* Instr) { 
	SMPOperandType NewType = OpType;
	if (Instr->GetBlock()->GetFunc()->GetIsSpeculative()) {
		NewType = (SMPOperandType) (((int)NewType) | PROF_BASE);
#if SMP_TRACK_NONSPEC_OPER_TYPE
		SMPOperandType OldType = RTop.type;
		if (!IsProfDerived(OldType))
			RTop.NonSpeculativeType = OldType;
#endif
	}

	RTop.type = NewType; 
} // end of SMPRegTransfer::SetOperatorType

// Does UseOp arithmetically affect the value of the NonFlagsDef for this RTL?
bool SMPRegTransfer::OperandTransfersValueToDef(const STARSOpndTypePtr &UseOp) const {
	bool FoundTransfer = false;
	STARSOpndTypePtr DefOp = this->GetLeftOperand();
	SMPoperator CurrOp = this->GetOperator();
	if ((SMP_ASSIGN == CurrOp) && (! DefOp->IsVoidOp()) && (! DefOp->MatchesReg(MD_FLAGS_REG))) {
		// We have an assignment to a non-flag DefOp. The only remaining question is whether
		//  UseOp appears in the right hand side of the RT as something besides an address register
		//  inside a memory operand.
		if (this->HasRightSubTree()) {
			FoundTransfer = this->GetRightTree()->OperandTransfersHelper(UseOp);
		}
		else {
			STARSOpndTypePtr RightOp = this->GetRightOperand();
			if (IsEqOpIgnoreBitwidth(UseOp, RightOp)) {
				// Found UseOp.
				FoundTransfer = true;
			}
		}
	}
	return FoundTransfer;
} // end of SMPRegTransfer::OperandTransfersValueToDef()

// Does UseOp arithmetically affect the value of the NonFlagsDef for this RT?
//  Recursive helper for OperandTransfersValueToDef().
bool SMPRegTransfer::OperandTransfersHelper(const STARSOpndTypePtr &UseOp) const {
	bool FoundTransfer = false;
	STARSOpndTypePtr LeftOp = this->GetLeftOperand();
	// Have to check left and right operands to see if they are UseOp.
	if (IsEqOpIgnoreBitwidth(UseOp, LeftOp)) {
		FoundTransfer = true; // Found UseOp.
	}
	else if (this->HasRightSubTree()) { // recurse
		FoundTransfer = this->GetRightTree()->OperandTransfersHelper(UseOp);
	}
	else {
		STARSOpndTypePtr RightOp = this->GetRightOperand();
		if (IsEqOpIgnoreBitwidth(UseOp, RightOp)) {
			// Found UseOp.
			FoundTransfer = true;
		}
	}

	return FoundTransfer;
} // end of SMPRegTransfer::OperandTransfersHelper()

// Does RTL show LeftOp has smaller bitwidth than the right hand side operands?
bool SMPRegTransfer::IsTruncatedWidthRTL(std::size_t &LeftBitWidth, std::size_t &RightBitWidth) const {
	bool TruncatedWidth = false;
	const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm();
	std::size_t LeftOpByteWidth = (std::size_t) LeftOp->GetByteWidth();
	std::size_t RightOpByteWidth = 0;
	const STARSOpndTypePtr RightOp = (this->HasRightSubTree()) ? this->GetRightTree()->GetConstLeftOperandNoNorm()
		: this->GetConstRightOperandNoNorm();
	if (nullptr != RightOp) {
		RightOpByteWidth = RightOp->GetByteWidth();
	}
	size_t DefaultByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
	if ((LeftOpByteWidth < DefaultByteWidth) || (RightOpByteWidth > DefaultByteWidth)) { // Forget it unless LeftOp is reduced width.
		// Search right hand side for wider operands.
		LeftBitWidth = 8 * LeftOpByteWidth;
		RightBitWidth = 8 * RightOpByteWidth;
		TruncatedWidth = ((RightOpByteWidth > LeftOpByteWidth) && (RightOp->IsRegOp() || RightOp->IsMemOp() || RightOp->IsFloatingPointRegOp()));
	}

	return TruncatedWidth;
} // end of SMPRegTransfer::IsTruncatedWidthRTL()

// Does RTL show LeftOp has larger bitwidth than the right hand side operands?
bool SMPRegTransfer::IsExpandedWidthRTL(std::size_t &LeftBitWidth, std::size_t &RightBitWidth) const {
	bool ExpandedWidth = false;
	const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm();
	std::size_t LeftOpByteWidth = (std::size_t) LeftOp->GetByteWidth();
	if (LeftOpByteWidth > global_STARS_program->GetSTARS_ISA_Bytewidth()) { // Forget it unless LeftOp is wide, e.g. FP stack.
		// Search right hand side for narrower operands.
		const STARSOpndTypePtr RightOp = (this->HasRightSubTree()) ? this->GetRightTree()->GetConstLeftOperandNoNorm() 
																	: this->GetConstRightOperandNoNorm();
		size_t RightOpByteWidth = RightOp->GetByteWidth();
		if (nullptr != RightOp) {
			ExpandedWidth = ((RightOpByteWidth < LeftOpByteWidth) && (RightOp->IsRegOp() || RightOp->IsMemOp() || RightOp->IsFloatingPointRegOp()));
			LeftBitWidth = 8 * LeftOpByteWidth;
			RightBitWidth = 8 * RightOpByteWidth;
		}
	}

	return ExpandedWidth;
} // end of SMPRegTransfer::IsExpandedWidthRTL()

// fix machine-specific FP reg encodings
void SMPRegTransfer::MDFixFloatingPointRTL(void) {
	const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm();
	if ((nullptr != LeftOp) && LeftOp->IsFloatingPointRegOp()) {
		STARS_regnum_t FPRegNum = LeftOp->GetReg();
		if (FPRegNum < STARS_x86_R_st0) {
			// X86 encodes STARS_x86_R_st0 as register 0, STARS_x86_R_st1 as register 1, with o_fpreg flag indicating adjustment.
			//  We want to encode using the STARS_regnum_t enumeration alone.
			STARSOpndTypePtr NewLeftOp = this->GetParentInst()->MakeFloatingPointRegOpnd(FPRegNum);
			this->SetLeftOperand(NewLeftOp);
		}
	}
	if (this->HasRightSubTree()) {
		this->GetRightTree()->MDFixFloatingPointRTL(); // recurse into right tree
	}
	else {
		const STARSOpndTypePtr RightOp = this->GetConstRightOperandNoNorm();
		if ((nullptr != RightOp) && RightOp->IsFloatingPointRegOp()) {
			STARS_regnum_t FPRegNum = RightOp->GetReg();
			if (FPRegNum < STARS_x86_R_st0) {
				// X86 encodes STARS_x86_R_st0 as register 0, STARS_x86_R_st1 as register 1, with o_fpreg flag indicating adjustment.
				//  We want to encode using the STARS_regnum_t enumeration alone.
				STARSOpndTypePtr NewRightOp = this->GetParentInst()->MakeFloatingPointRegOpnd(FPRegNum);
				this->SetRightOperand(NewRightOp);
			}
		}
	}

	return;
} // end of SMPRegTransfer::MDFixFloatingPointRTL()

// If we see add esp,immediate and the immediate value is large, then
//  some stupid hand-coded ASM is probably counting on an overflow, and
//  this is actually a subtraction from the stack pointer (i.e. it is an
//  addition of a negative number). We have to detect the signedness error
//  because IDA Pro treats the immediate operands as unsigned at all times.
#define STARS_ESP_ADDITION_OVERFLOW_THRESHOLD 0xf0000000

// Compute operand-dependent change in stack pointer value.
STARS_sval_t SMPRegTransfer::ComputeStackPointerAlteration(bool IsLeaveInstr, STARS_sval_t IncomingDelta, STARS_sval_t FramePtrDelta) {
	STARS_sval_t delta = 0;

	// Search for the pattern: stack_pointer := ...
	if (SMP_ASSIGN == this->GetOperator()) {
		STARSOpndTypePtr DefOp = this->GetLeftOperand();
		if (DefOp->MatchesReg(MD_STACK_POINTER_REG)) {
			// We have the code pattern stack_pointer := ...
			// We expect to find an overall RT structure of:
			//   stack_pointer := stack_pointer binaryoperator constant
			//  If the binaryoperator is addition or subtraction, then
			//   we use the constant to determine our return value.
			//  If the binaryoperator is a bitwise AND, then we return
			//   a special code. Delta is unknown but can probably be treated
			//   as zero, assuming that no stack-pointer-relative accesses to
			//   the stack region above the current stack pointer occur later.
			//  If we have a non-constant operand, we return an error code
			//   to indicate that we cannot compute the delta.
			//  If we don't have a binary operator, we return an error code,
			//   unless we find a stack frame deallocation:  esp := ebp
			if (!this->HasRightSubTree()) {
				STARSOpndTypePtr UseOp = this->GetRightOperand();
				if (UseOp->MatchesReg(MD_FRAME_POINTER_REG)) { // !!!!****!!!! Should validate that frame pointer reg is used as frame pointer
					// Found esp := ebp (deallocation of stack frame)
					delta = FramePtrDelta - IncomingDelta;
					assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
				}
				else {
					// !!!!****!!!!**** Need to look up deltas for registers that
					//  were used to hold a copy of the stack pointer.
					// For now, just consider it an error.
					delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE;
				}
			}
			else {
				SMPRegTransfer *RightRT = this->GetRightTree();
				SMPoperator RightOperator = RightRT->GetOperator();
				STARSOpndTypePtr RightDefOp = RightRT->GetLeftOperand();
				if (IsLeaveInstr) {
					// Found the RT esp := ebp + wordsize that adjusts the stack pointer
					//  for an x86 LEAVE instruction. esp := ebp is equivalent
					//  to esp := <esp when frame ptr was set up>, so delta becomes
					//  <esp delta when frame ptr was set up> - IncomingDelta + wordsize.
					assert(SMP_ADD == RightOperator);
					assert(!RightRT->HasRightSubTree());
					assert(RightDefOp->MatchesReg(X86_FRAME_POINTER_REG));
					delta = global_STARS_program->GetSTARS_ISA_Bytewidth() + FramePtrDelta - IncomingDelta;
				}
				else if (RightRT->HasRightSubTree()) {
					// Not the right code pattern; unknown effect on stack pointer.
					delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE;
				}
				else if (!RightDefOp->MatchesReg(MD_STACK_POINTER_REG)) {
					// We have stack_pointer := something1 operator something2
					//  where something1 is not the stack_pointer. It might be
					//  the frame pointer, e.g. SP := FP-12. We can compute this
					//  stack delta because we know the delta when the FP was set up.
					STARSOpndTypePtr RightUseOp = RightRT->GetRightOperand();
					if (RightDefOp->MatchesReg(MD_FRAME_POINTER_REG) && RightUseOp->IsImmedOp()) {
						// We have SP := FP operator immediate
						delta = FramePtrDelta - IncomingDelta; // partial computation: SP := BP
						assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
						if (SMP_ADD == RightOperator) {
							delta += RightUseOp->GetImmedValue();
						}
						else if (SMP_SUBTRACT == RightOperator) {
							delta -= RightUseOp->GetImmedValue();
						}
						else {
							// Not the right code pattern; unknown effect on stack pointer.
							delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE;
						}
					}
					else {
						// !!!!****!!!!**** Need to look up deltas for registers that
						//  were used to hold a copy of the stack pointer.
						// For now, just consider it an error.
						delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE;
					}
				}
				else {
					// We have stack_pointer := stack_pointer operator ...
					STARSOpndTypePtr RightUseOp = RightRT->GetRightOperand();
					// Check the operator
					if (SMP_BITWISE_AND == RightOperator) {
						delta = (STARS_sval_t) SMP_STACK_POINTER_BITWISE_AND_CODE;
					}
					else {
						if (! RightUseOp->IsImmedOp()) {
							// Don't know how to deal with adding non-constant to stack pointer
							delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE;
						}
						else if (SMP_ADD == RightOperator) {
							delta = (STARS_sval_t) RightUseOp->GetImmedValue();
							if (((STARS_uval_t) delta) > STARS_ESP_ADDITION_OVERFLOW_THRESHOLD) {
								// Really a subtraction via addition of a negative.
								//  E.g. add esp, 0xfffffff0 is sub esp,16
								int32_t TempDelta = (int32_t) (delta & 0xffffffff);
								delta = (STARS_sval_t) TempDelta;
							}
						}
						else if (SMP_SUBTRACT == RightOperator) {
							if (RightUseOp->GetImmedValue() > STARS_ESP_ADDITION_OVERFLOW_THRESHOLD) {
								// Really a subtraction via addition of a negative.
								//  E.g. add esp, 0xfffffff0 is sub esp,16
								int32_t TempDelta = (int32_t) (RightUseOp->GetImmedValue() & 0xffffffff);
								delta = (0 - ((STARS_sval_t) TempDelta));
							}
							else {
								delta = (0 - ((STARS_sval_t) RightUseOp->GetImmedValue()));
							}
						}
						else {
							delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE;
						}
					}
				}
			}
		}
	}
	return delta;
} // end of SMPRegTransfer::ComputeStackPointerAlteration()

// Evaluate constant expressions for SCCP algorithm
struct STARS_SCCP_Const_Struct SMPRegTransfer::SCCPEvaluateRTLConsts(list<pair<int, int> > &SSAWorkList) {
	struct STARS_SCCP_Const_Struct ReturnConstStruct;
	ReturnConstStruct.ConstType = STARS_CONST_TOP; // default value

	SMPoperator CurrOper = this->GetOperator();
	switch (CurrOper) {
		case SMP_ASSIGN:
		{
			STARSOpndTypePtr LeftOp = this->GetLeftOperand();
			if (! LeftOp->IsRegOp()) {
				break; // Only looking to update registers now
			}
			bool NewValueAvailable;
			if (NULL != this->GetGuard()) { // TODO: Evaluate guard expressions.
				ReturnConstStruct.ConstType = STARS_CONST_BOTTOM; // Don't know value until we can evaluate guards
			}
			else if (this->HasRightSubTree()) {
				ReturnConstStruct = this->GetRightTree()->SCCPEvaluateRTLConsts(SSAWorkList); // recurse into right subtree
			}
			else {
				STARSOpndTypePtr RightOp = this->GetRightOperand();
				this->ParentInst->SCCPFetchConstUseValue(RightOp, ReturnConstStruct);
			}
			NewValueAvailable = (STARS_CONST_TOP != ReturnConstStruct.ConstType);
			// Update const map entry for DEF
			if (NewValueAvailable) {
				STARSOpndTypePtr SearchLeftOp = CloneIfSubwordReg(LeftOp);
				CanonicalizeOpnd(SearchLeftOp);
				struct STARS_SCCP_Const_Struct OldConstStruct;
				OldConstStruct.ConstType = STARS_CONST_TOP;
				set<DefOrUse, LessDefUse>::iterator DefIter = this->ParentInst->FindDef(SearchLeftOp);
				if (DefIter != this->ParentInst->GetLastDef()) {
					int DefSSANum = DefIter->GetSSANum();
					int DefHashValue = HashGlobalNameAndSSA(SearchLeftOp, DefSSANum);
					bool LocalName = this->ParentInst->GetBlock()->IsLocalName(SearchLeftOp);
					this->ParentInst->SCCPFetchConstDefValue(LeftOp, OldConstStruct);
					bool HasOldValue = (STARS_CONST_TOP != OldConstStruct.ConstType);

					if (HasOldValue) { // must perform type lattice meet operation to update ReturnConstStruct
						STARSConstantTypeMeet(OldConstStruct, ReturnConstStruct);
					}
					if (ReturnConstStruct.ConstType != OldConstStruct.ConstType) { // type change
						map<int, struct STARS_SCCP_Const_Struct>::iterator NewConstIter;
						if (LocalName) {
							NewConstIter = this->ParentInst->GetBlock()->InsertLocalConstValue(DefHashValue, ReturnConstStruct);
						}
						else {
							NewConstIter = this->ParentInst->GetBlock()->GetFunc()->InsertGlobalConstValue(DefHashValue, ReturnConstStruct);
						}
						// Propagate along SSA edges.
						int BlockNum = this->ParentInst->GetBlock()->GetNumber();
						pair<int, int> SSAEdge(BlockNum, DefHashValue);
						SSAWorkList.push_back(SSAEdge);
					}
				}
			}
			break; // end case for SMP_ASSIGN
		}

		case SMP_ADD:
		case SMP_SUBTRACT:
		case SMP_U_MULTIPLY:
		case SMP_S_MULTIPLY:
		case SMP_BITWISE_AND:
		case SMP_BITWISE_OR:
		case SMP_BITWISE_XOR:
		case SMP_BITWISE_AND_NOT:
		case SMP_S_COMPARE:
		case SMP_U_COMPARE:
			// binary arithmetic operators
			// We will initially deal with the simple case: The comparison is of a LeftOp register to a RightOp register or immediate.
			//  If the result is definitely zero, we return zero as the const value (presumably to be put into the zero flag).
			if (!(this->HasRightSubTree())) {
				STARSOpndTypePtr LeftOp = this->GetLeftOperand();
				STARSOpndTypePtr RightOp = this->GetRightOperand();
				if ((LeftOp->IsRegOp()) && ((RightOp->IsRegOp()) || (RightOp->IsImmedOp()))) {
					size_t LeftByteWidth = LeftOp->GetByteWidth();
					size_t RightByteWidth = RightOp->GetByteWidth();
					STARSOpndTypePtr SearchLeftOp = CloneIfSubwordReg(LeftOp);
					STARSOpndTypePtr SearchRightOp = CloneIfSubwordReg(RightOp);
					CanonicalizeOpnd(SearchLeftOp);
					CanonicalizeOpnd(SearchRightOp);
					struct STARS_SCCP_Const_Struct LeftValue, RightValue;

					this->ParentInst->SCCPFetchConstUseValue(SearchLeftOp, LeftValue);
					bool LeftValueAvailable = (STARS_CONST_TOP != LeftValue.ConstType);
					if (STARS_CONST_BOTTOM == LeftValue.ConstType) {
						ReturnConstStruct = LeftValue;
						break; // right operand is irrelevant if left is BOTTOM
					}

					bool RightValueAvailable = false;
					if (SearchRightOp->IsImmedOp()) {
						RightValueAvailable = true;
						RightValue.ConstType = STARS_CONST_HAS_VALUE;
						RightValue.ConstValue = SearchRightOp->GetImmedValue();
					}
					else {
						this->ParentInst->SCCPFetchConstUseValue(SearchRightOp, RightValue);
						RightValueAvailable = (STARS_CONST_TOP != RightValue.ConstType);
						if (STARS_CONST_BOTTOM == RightValue.ConstType) {
							ReturnConstStruct = RightValue;
							break; // left operand is irrelevant if right is BOTTOM
						}
					}

					if (LeftValueAvailable && RightValueAvailable) {
						// Apply the operator to the values.
						HandleConstStructWidths(LeftByteWidth, RightByteWidth, LeftValue, RightValue);
						ReturnConstStruct.ConstType = STARS_CONST_HAS_VALUE;
						STARS_uval_t TestValue;
						bool CompareFlag = ((CurrOper == SMP_S_COMPARE) || (CurrOper == SMP_U_COMPARE));
						if (CurrOper == SMP_ADD) {
							TestValue = (LeftValue.ConstValue + RightValue.ConstValue);
						}
						else if ((CurrOper == SMP_U_MULTIPLY) || (CurrOper == SMP_S_MULTIPLY)) {
							TestValue = (LeftValue.ConstValue * RightValue.ConstValue);
						}
						else if ((CurrOper == SMP_SUBTRACT) || (CurrOper == SMP_S_COMPARE)) {
							// Signed compare is a subtraction operation
							TestValue = (LeftValue.ConstValue - RightValue.ConstValue);
						}
						else if ((CurrOper == SMP_U_COMPARE) || (CurrOper == SMP_BITWISE_AND)) {
							// Unsigned compare is a bitwise AND operation
							TestValue = (LeftValue.ConstValue & RightValue.ConstValue);
						}
						else if (CurrOper == SMP_BITWISE_OR) {
							TestValue = (LeftValue.ConstValue | RightValue.ConstValue);
						}
						else if (CurrOper == SMP_BITWISE_XOR) {
							TestValue = (LeftValue.ConstValue ^ RightValue.ConstValue);
						}
						else if (CurrOper == SMP_BITWISE_AND_NOT) {
							TestValue = (LeftValue.ConstValue & (~(RightValue.ConstValue)));
						}
						else {
							break; // should be unreachable
						}
						if ((0 != TestValue) && CompareFlag) {
							TestValue = 1; // i.e. zero flag will be set to false
						}
						ReturnConstStruct.ConstValue = TestValue;
					}
				} // end if two regs, or one reg and one immediate
			} // end if no right subtree
			break; // end of signed and unsigned compare operators case

		case SMP_ZERO_EXTEND:
		{	STARSOpndTypePtr LeftOp = this->GetLeftOperand();
			if (LeftOp->IsImmedOp()) {
				ReturnConstStruct.ConstType = STARS_CONST_HAS_VALUE;
				ReturnConstStruct.ConstValue = LeftOp->GetImmedValue();
			}
			else if (LeftOp->IsRegOp()) {
				size_t LeftByteWidth = LeftOp->GetByteWidth();
				STARSOpndTypePtr SearchLeftOp = CloneIfSubwordReg(LeftOp);
				CanonicalizeOpnd(SearchLeftOp);
				struct STARS_SCCP_Const_Struct LeftValue;

				this->ParentInst->SCCPFetchConstUseValue(SearchLeftOp, LeftValue);
				bool LeftValueAvailable = (STARS_CONST_TOP != LeftValue.ConstType);
				if (STARS_CONST_BOTTOM == LeftValue.ConstType) {
					ReturnConstStruct = LeftValue; // return the STARS_CONST_BOTTOM value
				}
				else if (STARS_CONST_HAS_VALUE == LeftValue.ConstType) {
					ReturnConstStruct = LeftValue; // zero-extend does not change it
				}
			}
		}
		break;

		default:
			break; // ignore
	} // end switch(CurrOper)

	return ReturnConstStruct;
} // end of SMPRegTransfer::SCCPEvaluateRTLConsts()

// Is stack ptr (or frame ptr) reg in RT?
bool SMPRegTransfer::IsStackPtrUsedInRT(bool UseFP) const {
	bool StackPtrUsed = false;
	if (this->GetLeftOperand()->IsRegOp()) {
		if (this->GetLeftOperand()->MatchesReg(MD_STACK_POINTER_REG)
			|| (UseFP && this->GetLeftOperand()->MatchesReg(MD_FRAME_POINTER_REG))) {
			StackPtrUsed = true;
		}
	}
	if (!StackPtrUsed) {
		if (this->HasRightSubTree()) {
			StackPtrUsed = this->GetRightTree()->IsStackPtrUsedInRT(UseFP);
		}
		else if (this->GetRightOperand()->IsRegOp()) {
			if (this->GetRightOperand()->MatchesReg(MD_STACK_POINTER_REG)
				|| (UseFP && this->GetRightOperand()->MatchesReg(MD_FRAME_POINTER_REG))) {
				StackPtrUsed = true;
			}
		}
	}
	return StackPtrUsed;
} // end of SMPRegTransfer::IsStackPtrUsedInRT()

// Is RT a move of a const or subreg into a subreg?
bool SMPRegTransfer::IsSubregMove(void) const {
	bool SubregMove = false;
	const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm();
	if ((nullptr != LeftOp) && (LeftOp->IsRegOp())) {
		bool SubregDest = (LeftOp->GetByteWidth() < 4); // move into EAX zeroes out upper RAX, but move into AX does not.
		SubregMove = (SubregDest && (!this->HasRightSubTree()) && (SMP_ASSIGN == this->GetOperator()));
	}
	return SubregMove;
}

// sign-extend RightOperand if it needs to become 64 bit operand
size_t SMPRegTransfer::MDSignExtend64RightOpIfNeeded(void) {
	size_t OriginalByteWidth = this->RightOperand->GetByteWidth();
	size_t FinalByteWidth = OriginalByteWidth;
	if (this->ParentInst->MDHas64BitOperands() && (this->RightOperand->IsImmedOp() || this->RightOperand->IsMemOp())
		&& (4 >= OriginalByteWidth)) {
		// On x86-64, less than 64-bit immediate and memory operands are sign-extended in the hardware on opcodes that
		//  have 64-bit operands. For example, "pushq  0x1234" looks like a 32-bit immediate push, but the pushq opcode
		//  as printed by objdump indicates that it will be sign-extended to 64 bits. Ditto for "pushq [rbp-4]" where the 
		//  memory operand is 32 bit in the IRDB view. In both cases, the operand has been sign-extended behind the scenes
		//  by IDA Pro so no action will be needed, as the RightOperand->GetByteWidth() above will return 8 in IDA Pro.
		SMPRegTransfer *ExtendedRT = new SMPRegTransfer;
		ExtendedRT->SetOperator(SMP_SIGN_EXTEND);
		ExtendedRT->SetLeftOperand(this->RightOperand);
		ExtendedRT->SetRightOperand(this->ParentInst->MakeVoidOpnd());
		ExtendedRT->SetParentInst(this->ParentInst);
		this->SetRightTree(ExtendedRT);
		FinalByteWidth = 8;
		SMP_msg("INFO: Sign-extending right RTL operand to 64 bits at %llx\n", 
			(unsigned long long) this->ParentInst->GetAddr());
	}

	return FinalByteWidth;
} // end of SMPRegTransfer::MDSignExtend64RightOpIfNeeded()

// for SPARK Ada translation
bool SMPRegTransfer::RightTreeNeedsWidthCast(FILE *OutFile, std::size_t LeftBitWidth, std::size_t &RightBitWidth) const {
	RightBitWidth = LeftBitWidth;
	if (!this->HasRightSubTree())
		return false;
	SMPRegTransfer *RightRT = this->GetRightTree();
	assert(NULL != RightRT);
	// Initial cases: zero-extension and sign-extension; add more cases as required
	if (SMP_ZERO_EXTEND == RightRT->GetOperator()) {
		const STARSOpndTypePtr RightLeftOp = RightRT->GetConstLeftOperandNoNorm();
		RightBitWidth = RightLeftOp->GetByteWidth() * 8;
		if (LeftBitWidth != RightBitWidth) {
			SMP_fprintf(OutFile, "Unsigned%u(", LeftBitWidth);
		}
	}
	else if (SMP_SIGN_EXTEND == RightRT->GetOperator()) {
		const STARSOpndTypePtr RightLeftOp = RightRT->GetConstLeftOperandNoNorm();
		RightBitWidth = RightLeftOp->GetByteWidth() * 8;
		if (LeftBitWidth != RightBitWidth) {
			SMP_fprintf(OutFile, "X86.SignExtend%uTo%u(", RightBitWidth, LeftBitWidth);
		}
	}


	return (LeftBitWidth != RightBitWidth);
} // end of SMPRegTransfer::RightTreeNeedsWidthCast()

// Is RT irrelevant for SPARK, e.g. floating-point operations that the SPARK provers will not model
bool SMPRegTransfer::IsSPARKAdaNop(void) const {
	SMPoperator CurrOperator = this->GetOperator();
	bool SPARKNop = ((CurrOperator == SMP_NULL_OPERATOR) || (CurrOperator == SMP_UNARY_NUMERIC_OPERATION)
		|| (CurrOperator == SMP_BINARY_NUMERIC_OPERATION) || (CurrOperator == SMP_UNARY_FLOATING_ARITHMETIC)
		|| (CurrOperator == SMP_BINARY_FLOATING_ARITHMETIC) || (CurrOperator == SMP_UNARY_POINTER_OPERATION));

	if (!SPARKNop && this->HasRightSubTree()) {
		SPARKNop = this->GetRightTree()->IsSPARKAdaNop();
	}
	if (!SPARKNop && (SMP_ASSIGN == CurrOperator)) {
		const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm();
		const STARSOpndTypePtr RightOp = this->GetConstRightOperandNoNorm();
		if ((nullptr != LeftOp) && (nullptr != RightOp) && LeftOp->IsFloatingPointRegOp() && RightOp->IsFloatingPointRegOp()) {
			SPARKNop = (LeftOp->GetReg() == RightOp->GetReg()); // e.g. fld st just duplicates top of stack
		}
	}
	return SPARKNop;
} // end of SMPRegTransfer::IsSPARKAdaNop()

// Debug print
void SMPRegTransfer::Dump(void) const {
	if (NULL != this->Guard)
		this->Guard->Dump();
	// Left operand
	if ((nullptr != this->LeftOperand) && (! this->LeftOperand->IsVoidOp()))
		PrintOperand(this->LeftOperand);
	// Then the operator
	SMP_msg(" %s ", OperatorText[this->GetOperator()]);
	// then the right operand or subtree
	if (this->HasRightSubTree())
		this->GetRightTree()->Dump();
	else if ((nullptr != this->RightOperand) && (!this->RightOperand->IsVoidOp()))
		PrintOperand(this->RightOperand);
	SMP_msg("\n");
	return;
} // end of SMPRegTransfer::Dump()

// emit SPARK-Ada procedure suffix, e.g. _reg32_reg32( for the add_reg32_reg32() case
void SMPRegTransfer::EmitSPARKAdaProcSuffix(FILE *OutFile) const {
	PrintOperandSPARKAdaSuffix(this->GetLeftOperand(), OutFile);
	if (!this->HasRightSubTree()) {
		PrintOperandSPARKAdaSuffix(this->GetRightOperand(), OutFile);
	}
	else {
		PrintOperandSPARKAdaSuffix(this->GetRightTree()->GetRightOperand(), OutFile);
	}
	return;

} // end of SMPRegTransfer::EmitSPARKAdaProcSuffix()

// Helper for right hand side of statements (i.e. RightOperand or RightTree)
void SMPRegTransfer::EmitSPARKAdaForRHS(FILE *OutFile, bool RecursiveCall) const {
#if 1
	std::size_t LeftOpBitWidth, RightOpBitWidth;
	bool Truncated = false;
	bool UseFP = this->ParentInst->GetBlock()->GetFunc()->UsesFramePointer();
	bool X86ProcCall = this->GetParentInst()->MDIsArithmeticUsingCarryFlag();
	size_t ISA_ByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();

	if (!RecursiveCall && (this->IsTruncatedWidthRTL(LeftOpBitWidth, RightOpBitWidth) || this->IsExpandedWidthRTL(LeftOpBitWidth, RightOpBitWidth))) {
		// We don't want to cast to 128 bits or more for XMM, YMM et al. registers. In many cases,
		//  the opcode really means to write only the lowest 64 bits and IDA Pro says the reg is 128 bits.
		if (LeftOpBitWidth > 80)
			LeftOpBitWidth = 64;
		if (LeftOpBitWidth != RightOpBitWidth) {
			Truncated = true;
			SMP_fprintf(OutFile, "Unsigned%d(", LeftOpBitWidth);
		}
	}
	if (this->HasRightSubTree()) {  // NOTE: Handle operators like Shift_right() !!!!****!!!!
		SMPRegTransfer *RightRT = this->GetRightTree();
		size_t LeftByteWidth = this->GetConstLeftOperandNoNorm()->GetByteWidth();
		LeftOpBitWidth = LeftByteWidth * 8;
		bool ShortLeftWidth = (ISA_ByteWidth > LeftByteWidth);

		size_t RightTreeBitWidth;
		bool NeedWidthCast = this->RightTreeNeedsWidthCast(OutFile, LeftOpBitWidth, RightTreeBitWidth);
		string OperatorString;
		bool OperatorIsProcCall = false;
		bool PrefixUnaryOperator = false;
		SMP_fprintf(OutFile, "(");
		SMPoperator CurrOper = RightRT->GetOperator();
		bool ConstFollows = (!RightRT->HasRightSubTree()) && RightRT->GetConstRightOperandNoNorm()->IsImmedOp();
		PrintSPARKAdaOperator(CurrOper, OperatorString, OperatorIsProcCall, PrefixUnaryOperator, ConstFollows);
		const STARSOpndTypePtr LeftOp = RightRT->GetConstLeftOperandNoNorm();
		if (!OperatorIsProcCall) {
			if (!PrefixUnaryOperator) {
				this->ParentInst->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
				SMP_fprintf(OutFile, "%s", OperatorString.c_str());
				RightRT->EmitSPARKAdaForRHS(OutFile, true); // recurse on right tree or operand
			}
			else { // unary prefix operator, such as unary negation
				SMP_fprintf(OutFile, "%s", OperatorString.c_str());
				this->ParentInst->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
			}
		}
		else {  // printing something like Interfaces.Shift_Right(LeftOp, RightOp)
			STARSOpndTypePtr LeftOp2 = LeftOp->clone();
			if (X86ProcCall && ShortLeftWidth) {
				// We have to pass the 64-bit register even for 32-bit add-with-carry and subtract-with-borrow.
				LeftOp2->SetByteWidth(ISA_ByteWidth);
			}
			SMP_fprintf(OutFile, "%s(", OperatorString.c_str()); // proc call name + open parenthesis for arguments
			this->ParentInst->PrintSPARKAdaOperand(LeftOp2, OutFile, false, UseFP, true, false); // LeftOp is first argument
			SMP_fprintf(OutFile, " , ");   // separate args with a comma
			RightRT->EmitSPARKAdaForRHS(OutFile, true); // recurse on right tree or operand
			SMP_fprintf(OutFile, ")"); // close parenthesis for procedure call arguments
		}
		if (NeedWidthCast) {
			SMP_fprintf(OutFile, ")");  // close parenthesis printed within RightTreeNeedsWidthCast()
		}
		SMP_fprintf(OutFile, ")");
	}
	else {
		const STARSOpndTypePtr RightOp = this->GetConstRightOperandNoNorm();
		this->ParentInst->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
	}
	if (!RecursiveCall && Truncated) {
		SMP_fprintf(OutFile, ")"); // close cast of right hand side
	}
#endif
	return;
} // end of SMPRegTransfer::EmitSPARKAdaForRHS()

// Emit SPARK-Ada translation of RT
void SMPRegTransfer::EmitSPARKAda(FILE *OutFile) {
	const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm();
	if ((nullptr == LeftOp) || this->IsSPARKAdaNop()) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, "null;\n"); // Ada no-op
		return;
	}

	SMPoperator CurrOper = this->GetOperator();
	assert(CurrOper == SMP_ASSIGN);
	bool X86ProcCall = this->GetParentInst()->MDIsArithmeticUsingCarryFlag();
	uint16_t LeftByteWidth = LeftOp->GetByteWidth();
	size_t ISA_ByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
	bool MemWrite = LeftOp->IsMemOp();
	bool ShortLeftWidth = (ISA_ByteWidth > LeftByteWidth);
	bool LongLeftWidth = (ISA_ByteWidth < LeftByteWidth);
	bool SubregWrite = (LeftOp->IsRegOp() && ShortLeftWidth);
	bool OperatorIsProcCall = false;
	bool PrefixUnaryOperator = false;
	bool UseFP = this->ParentInst->GetBlock()->GetFunc()->UsesFramePointer();

	PrintSPARKIndentTabs(OutFile);
	if (X86ProcCall) {
		// We don't emit X := X + Y; we emit ProcName(X, Y);
		this->EmitSPARKAdaForRHS(OutFile, false);
	}
	else {

		this->ParentInst->PrintSPARKAdaOperand(LeftOp, OutFile, true, UseFP, true, false);

		if (MemWrite) {
			// We have printed X86.WriteMem##((Unsigned64(LeftOpnd), 
			//  Now we need to print Unsigned##(right-hand-side))
			if (ShortLeftWidth || LongLeftWidth) {
				char CastString[25];
				GetSPARKWidthCastString(LeftByteWidth, CastString);
				SMP_fprintf(OutFile, "%s(", CastString);
			}
			this->EmitSPARKAdaForRHS(OutFile, false);
			if (ShortLeftWidth || LongLeftWidth) {
				// Close cast parentheses and MemWrite parentheses.
				SMP_fprintf(OutFile, "))");
			}
			else { // no cast; just close MemWrite parenthesis.
				SMP_fprintf(OutFile, ")");
			}
		}
		else {
			if (!SubregWrite) {
				// Print := operator unless we are assigning with a procedure call.
				string OutString;
				PrintSPARKAdaOperator(CurrOper, OutString, OperatorIsProcCall, PrefixUnaryOperator, false);
				assert(!OperatorIsProcCall);
				assert(!PrefixUnaryOperator);
				SMP_fprintf(OutFile, "%s", OutString.c_str());
			}
			this->EmitSPARKAdaForRHS(OutFile, false);
			if (SubregWrite) { // Have to write with a procedure call, e.g. Write_AX(Right-Hand-Side).
				// Close the procedure call parenthesis.
				SMP_fprintf(OutFile, ")");
			}
		}
	}
	SMP_fprintf(OutFile, ";\n");

	return;
} // end of SMPRegTransfer::EmitSPARKAda()

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

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

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

// Get methods
SMPRegTransfer *SMPRTL::GetRT(std::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
void SMPRTL::Dump(void) const {
	std::size_t index;
	if (0 < this->RTCount) {
		SMP_msg("RTL: ");
		for (index = 0; index < this->RTCount; ++index) {
			this->RTvector[index]->Dump();
		}
		if (!this->ExtraKills.empty()) {
			for (index = 0; index < this->ExtraKills.size(); ++index) {
				SMP_msg(" KILL: ");
				PrintOperand(this->ExtraKills.at(index));
			}
			SMP_msg("\n");
		}
	}
	return;
} // end of SMPRTL::Dump()

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

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

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

// *****************************************************************
// Class STARSExpression
// *****************************************************************
// Constructors
STARSExpression::STARSExpression(void) {
	this->LeftOperand = nullptr;
	this->LeftUseAddr = STARS_BADADDR;
	this->LeftSSANum = SMP_SSA_UNINIT;
	this->RightOperand = nullptr;
	this->RightUseAddr = STARS_BADADDR;
	this->RightSSANum = SMP_SSA_UNINIT;
	this->ExprOperator = SMP_NULL_OPERATOR;
	this->LeftExpr = nullptr;
	this->RightExpr = nullptr;
	this->ParentInst = nullptr;
	this->OriginalParentInst = nullptr;
	this->ParentFunc = nullptr;
	this->LeftPreLoopDefAddr = STARS_BADADDR;
	this->RightPreLoopDefAddr = STARS_BADADDR;
	this->booleans1 = 0;
	return;
}

// Construct from an RTL subtree.
STARSExpression::STARSExpression(SMPRegTransfer *RTExpr) {
	this->SetOperator(RTExpr->GetOperator());
	this->booleans1 = 0;
	this->ParentInst = RTExpr->GetParentInst();
	this->OriginalParentInst = this->GetParentInst();
	this->LeftPreLoopDefAddr = STARS_BADADDR;
	this->RightPreLoopDefAddr = STARS_BADADDR;
	STARS_ea_t InstAddr = this->ParentInst->GetAddr();
	this->SetParentFunc(this->ParentInst->GetBlock()->GetFunc());
	bool UseFP = this->GetParentFunc()->UsesFramePointer();
	STARSOpndTypePtr LeftOp = RTExpr->GetLeftOperand();
	this->SetLeftOperand(LeftOp);
	this->SetLeftUseAddr(InstAddr);
	this->SetLeftTree(nullptr);  // RTL subtrees never have left subtrees
	if (this->GetConstLeftOperand() != nullptr) {
		if (MDIsDataFlowOpnd(LeftOp, UseFP)) {
			STARSDefUseIter LeftIter;
			bool GoodIter = false;
			if (this->GetOperator() == SMP_ASSIGN) {
				LeftIter = RTExpr->GetParentInst()->FindDef(LeftOp);
				GoodIter = (LeftIter != RTExpr->GetParentInst()->GetLastDef());
			}
			else {
				LeftIter = RTExpr->GetParentInst()->FindUse(LeftOp);
				GoodIter = (LeftIter != RTExpr->GetParentInst()->GetLastUse());
			}
			if (GoodIter) {
				this->SetLeftSSANum(LeftIter->GetSSANum());
			}
			else {
				SMP_msg("ERROR: Bad DefOrUseIter in STARSExpression from RTL at %llx\n",
					(uint64_t) InstAddr);
				this->SetLeftSSANum(SMP_SSA_UNINIT);
			}
		}
		else {
			this->SetLeftSSANum(SMP_SSA_UNINIT);
		}
	}

	if (RTExpr->HasRightSubTree()) {
		this->SetRightOperand(nullptr);
		SMPRegTransfer *RightRTExpr = RTExpr->GetRightTree();
		STARSExpression *RightSubExpr = new STARSExpression(RightRTExpr);  // recurse
		this->SetRightTree(RightSubExpr);
	}
	else {
		this->SetRightTree(nullptr);
		STARSOpndTypePtr RightOp = RTExpr->GetRightOperand();
		this->SetRightOperand(RightOp);
		this->SetRightUseAddr(RTExpr->GetParentInst()->GetAddr());
		if (this->GetConstRightOperand() != nullptr) {
			if (MDIsDataFlowOpnd(RightOp, UseFP)) {
				STARSDefUseIter RightUseIter = RTExpr->GetParentInst()->FindUse(RightOp);
				if (RightUseIter != RTExpr->GetParentInst()->GetLastUse()) {
					this->SetRightSSANum(RightUseIter->GetSSANum());
				}
				else {
					this->SetRightSSANum(SMP_SSA_UNINIT);
				}
			}
			else {
				this->SetRightSSANum(SMP_SSA_UNINIT);
			}
		}
	}
	return;
}

// build from a DEF or USE
STARSExpression::STARSExpression(const STARSDefUseIter Ref, SMPInstr *CurrInst) {
	this->SetParentFunc(CurrInst->GetBlock()->GetFunc());
	this->SetParentInst(CurrInst);
	this->OriginalParentInst = CurrInst;
	this->SetRightOperand(nullptr);
	this->RightExpr = nullptr;
	this->SetRightPreLoopDefAddr(STARS_BADADDR);
	this->SetRightSSANum(SMP_SSA_UNINIT);
	this->SetLeftPreLoopDefAddr(STARS_BADADDR);
	this->booleans1 = 0;

	if (MDIsDataFlowOpnd(Ref->GetOp(), this->GetParentFunc()->UsesFramePointer())) {
		this->SetLeftOperand(Ref->GetOp());
		this->SetLeftUseAddr(CurrInst->GetAddr());
		this->SetLeftSSANum(Ref->GetSSANum());
		this->SetOperator(SMP_ASSIGN);
	}
	else if (Ref->GetOp()->IsMemOp()) { // must be indirect memory access
		this->SetOperator(SMP_SYMBOLIC_READ_MEMORY);
		STARSExpression *MemAddrExpr = this->GetParentFunc()->CreateMemoryAddressExpr(Ref->GetOp(), CurrInst);
		assert(nullptr != MemAddrExpr);
		this->SetLeftTree(MemAddrExpr);
	}
	return;
}

// Destructor
STARSExpression::~STARSExpression() {
	if (this->HasRightSubTree() && (nullptr != this->RightExpr))
		delete this->RightExpr;
	if (this->HasLeftSubTree() && (nullptr != this->LeftExpr))
		delete this->LeftExpr;
	return;
}

// Allocate a new tree, recursively copy in subtrees
STARSExpression* STARSExpression::Clone(void) const {
	STARSExpression *ClonedExpr = new STARSExpression();
	ClonedExpr->SetOperator(this->GetOperator());
	ClonedExpr->SetParentInst(this->GetParentInst());
	ClonedExpr->OriginalParentInst = this->OriginalParentInst;
	ClonedExpr->SetParentFunc(this->GetParentFunc());
	if (this->HasLeftSubTree()) {
		ClonedExpr->SetLeftTree(this->GetLeftTree()->Clone());  // recurse
	}
	else {
		ClonedExpr->SetLeftOperand(this->GetLeftOperand());
		ClonedExpr->SetLeftUseAddr(this->GetLeftUseAddr());
		ClonedExpr->SetLeftSSANum(this->GetLeftSSANum());
		ClonedExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
	}
	if (this->HasRightSubTree()) {
		ClonedExpr->SetRightTree(this->GetRightTree()->Clone()); // recurse
	}
	else {
		ClonedExpr->SetRightOperand(this->GetRightOperand());
		ClonedExpr->SetRightUseAddr(this->GetRightUseAddr());
		ClonedExpr->SetRightSSANum(this->GetRightSSANum());
		ClonedExpr->SetRightPreLoopDefAddr(this->GetRightPreLoopDefAddr());
	}

	return ClonedExpr;
} // end of STARSExpression::Clone()

// Allocate a new tree, make it a copy of left-hand-side of this tree.
STARSExpression *STARSExpression::CloneLHS(void) const {
	if (this->HasLeftSubTree()) {
		STARSExpression *LeftExpr = this->GetLeftTree()->Clone();
		return LeftExpr;
	}
	else {
		STARSOpndTypePtr LeftOp = this->GetLeftOperand();
		assert(nullptr != LeftOp);
		STARSExpression *LeftExpr = new STARSExpression();
		LeftExpr->SetParentFunc(this->GetParentFunc());
		LeftExpr->SetParentInst(this->GetParentInst());
		LeftExpr->OriginalParentInst = this->OriginalParentInst;
		LeftExpr->SetOperator(SMP_ASSIGN);
		LeftExpr->SetLeftOperand(LeftOp);
		LeftExpr->SetLeftUseAddr(this->GetLeftUseAddr());
		LeftExpr->SetLeftSSANum(this->GetLeftSSANum());
		LeftExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
		return LeftExpr;
	}
} // end of STARSExpression::CloneLHS()

// Allocate a new tree, make it a copy of right-hand-side of this tree.
STARSExpression *STARSExpression::CloneRHS(void) const {
	if (this->HasRightSubTree()) {
		STARSExpression *RightExpr = this->GetRightTree()->Clone();
		return RightExpr;
	}
	else {
		STARSOpndTypePtr RightOp = this->GetConstRightOperand();
		assert(nullptr != RightOp);
		STARSExpression *RightExpr = new STARSExpression();
		RightExpr->SetParentFunc(this->GetParentFunc());
		RightExpr->SetParentInst(this->GetParentInst());
		RightExpr->OriginalParentInst = this->OriginalParentInst;
		RightExpr->SetOperator(SMP_ASSIGN);
		RightExpr->SetLeftOperand(RightOp);
		RightExpr->SetLeftUseAddr(this->GetRightUseAddr());
		RightExpr->SetLeftSSANum(this->GetRightSSANum());
		RightExpr->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr());
		return RightExpr;
	}
} // end of STARSExpression::CloneRHS()

// LessThan operator for ordered containers, such as sets.
bool STARSExpression::operator<(const STARSExpression &rExpr) const {
	bool LessThan = false;
	bool GreaterThan = false;
	if (this->GetOperator() < rExpr.GetOperator()) {
		return true;
	}
	else if (this->GetOperator() != rExpr.GetOperator()) {
		return false;
	}

	if (this->HasLeftSubTree()) {
		if (!rExpr.HasLeftSubTree()) {
			return false;  // operand is less than tree
		}
		else { // both exprs have left trees
#if 1
			// Speed up by checking instruction IDs of OrigParentInst before recursing.
			STARS_ea_t ThisParentAddr = this->GetOriginalParentInst()->GetAddr();
			STARS_ea_t OtherParentAddr = rExpr.GetOriginalParentInst()->GetAddr();
			if (ThisParentAddr != OtherParentAddr)
				return (ThisParentAddr < OtherParentAddr);
#endif
			LessThan = (*(this->GetLeftTree()) < (*(rExpr.GetLeftTree()))); // recurse
			if (LessThan) {
				return true;
			}
			else {
				GreaterThan = (*(rExpr.GetLeftTree()) < (*(this->GetLeftTree()))); // recurse
				if (GreaterThan)
					return false;
			}
		}
	}
	else if (rExpr.HasLeftSubTree()) {
		return true; // operand is less than tree
	}
	else { // both have LeftOperand
		if (nullptr == this->GetConstLeftOperand()) {
			return (nullptr != rExpr.GetConstLeftOperand()); // nullptr < operand
		}
		else if (nullptr == rExpr.GetConstLeftOperand()) {
			return false; // operand is greater than nullptr
		}

#if 1
		// Make SSANum a priority key value because it is faster to compare than operands.
		if (this->GetLeftSSANum() != rExpr.GetLeftSSANum())
			return (this->GetLeftSSANum() < rExpr.GetLeftSSANum());
#endif

		LessThan = (*(this->GetConstLeftOperand()) < (*(rExpr.GetConstLeftOperand()))); // use STARS_op_t < operator
		if (LessThan) {
			return true;
		}
		else {
			GreaterThan = (*(rExpr.GetConstLeftOperand()) < (*(this->GetConstLeftOperand()))); // use STARS_op_t < operator
			if (GreaterThan)
				return false;
		}
	}

	// At this point, the left hand sides did not answer the question and we look at the right hand sides.
	if (this->HasRightSubTree()) {
		if (!rExpr.HasRightSubTree()) {
			return false;  // operand is less than tree
		}
		else {
#if 1
			// Speed up by checking instruction IDs of OrigParentInst before recursing.
			STARS_ea_t ThisParentAddr = this->GetOriginalParentInst()->GetAddr();
			STARS_ea_t OtherParentAddr = rExpr.GetOriginalParentInst()->GetAddr();
			if (ThisParentAddr != OtherParentAddr)
				return (ThisParentAddr < OtherParentAddr);
#endif
			LessThan = (*(this->GetRightTree()) < (*(rExpr.GetRightTree()))); // recurse
			if (LessThan) {
				return true;
			}
		}
	}
	else if (rExpr.HasRightSubTree()) {
		return true; // operand is less than tree
	}
	else { // both have RightOperand
		if (nullptr == this->GetConstRightOperand()) {
			return (nullptr != rExpr.GetConstRightOperand()); // nullptr < operand
		}
		else if (nullptr == rExpr.GetConstRightOperand()) {
			return false; // operand is greater than nullptr
		}

#if 1
		// Make SSANum a priority key value because it is faster to compare than operands.
		if (this->GetRightSSANum() != rExpr.GetRightSSANum())
			return (this->GetRightSSANum() < rExpr.GetRightSSANum());
#endif

		LessThan = (*(this->GetConstRightOperand()) < (*(rExpr.GetConstRightOperand()))); // use STARS_op_t < operator
		if (LessThan) {
			return true;
		}
		else {
			GreaterThan = (*(rExpr.GetConstRightOperand()) < (*(this->GetConstRightOperand()))); // use STARS_op_t < operator
			if (GreaterThan)
				return false;
		}
	}

	return LessThan;
} // end of STARSExpression::operator<()

// are exprs identical in operands and operators?
bool STARSExpression::IsEqualExpr(const STARSExpression *OtherExpr) const {
	bool Identical = true;
	if ((this->GetOperator() == OtherExpr->GetOperator())
		&& (this->HasLeftSubTree() == OtherExpr->HasLeftSubTree())
		&& (this->HasRightSubTree() == OtherExpr->HasRightSubTree())) {
		// Compare operands, if any, or recurse into subtrees.
		if (!this->HasLeftSubTree()) {
			if ((this->GetLeftSSANum() != OtherExpr->GetLeftSSANum())
				|| (!IsEqOp(this->GetConstLeftOperand(), OtherExpr->GetConstLeftOperand()))) {
				return false;
			}
		}
		else if (!this->GetLeftTree()->IsEqualExpr(OtherExpr->GetLeftTree())) {
			return false;
		}
		if (!this->HasRightSubTree()) {
			if ((this->GetRightSSANum() != OtherExpr->GetRightSSANum())
				|| (!IsEqOp(this->GetConstRightOperand(), OtherExpr->GetConstRightOperand()))) {
				return false;
			}
		}
		else if (!this->GetRightTree()->IsEqualExpr(OtherExpr->GetRightTree())) {
			return false;
		}
	}
	else {
		Identical = false;
	}

	return Identical;
} // end of STARSExpression::IsEqualExpr()

// are exprs identical except for ImmedOp values?
bool STARSExpression::IsEqualExprExceptingImmedOpnds(const STARSExpression *OtherExpr) const {
	bool Identical = true;
	if ((this->GetOperator() == OtherExpr->GetOperator())
		&& (this->HasLeftSubTree() == OtherExpr->HasLeftSubTree())
		&& (this->HasRightSubTree() == OtherExpr->HasRightSubTree())) {
		// Compare operands, if any, or recurse into subtrees.
		if (!this->HasLeftSubTree()) {
			if ((this->GetLeftSSANum() != OtherExpr->GetLeftSSANum())
				|| (!IsEqOpIgnoreImmedValues(this->GetConstLeftOperand(), OtherExpr->GetConstLeftOperand()))) {
				return false;
			}
		}
		else if (!this->GetLeftTree()->IsEqualExprExceptingImmedOpnds(OtherExpr->GetLeftTree())) {
			return false;
		}
		if (!this->HasRightSubTree()) {
			if ((this->GetRightSSANum() != OtherExpr->GetRightSSANum())
				|| (!IsEqOpIgnoreImmedValues(this->GetConstRightOperand(), OtherExpr->GetConstRightOperand()))) {
				return false;
			}
		}
		else if (!this->GetRightTree()->IsEqualExprExceptingImmedOpnds(OtherExpr->GetRightTree())) {
			return false;
		}
	}
	else {
		Identical = false;
	}

	return Identical;
} // end of STARSExpression::IsEqualExprExceptingImmedOpnds()

// Print the stack pointer plus optional offset constant to the AnnotFile.
void STARSExpression::AnnotPrintStackPtrPlusOffset(FILE *AnnotFile) const {
	SMPoperator CurrOper = this->GetOperator();
	bool LeftSPOpnd = (!this->HasLeftSubTree()) && this->GetConstLeftOperand()->IsRegOp() && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG);
	bool SPPlusOffset = false;
	bool JustStackPtr = (CurrOper == SMP_ASSIGN) && LeftSPOpnd; // SMP_ASSIGN in expr means no RHS
	if (!JustStackPtr && LeftSPOpnd && IsIntegerAddOrSubOperator(CurrOper)) {
		const STARSOpndTypePtr RightOp = this->GetConstRightOperand();
		bool HasRightTree = this->HasRightSubTree();
		bool ImmedRightOp = (nullptr != RightOp) && (!HasRightTree) && RightOp->IsImmedOp();
		SPPlusOffset = ImmedRightOp;
	}
	if (JustStackPtr) {
		SMP_fprintf(AnnotFile, "RSP ");
	}
	else if (SPPlusOffset) {
		SMP_fprintf(AnnotFile, "RSP ");
		bool UnaryOper = false;
		switch (CurrOper) {
		case SMP_DECREMENT:
			UnaryOper = true;
			SMP_fprintf(AnnotFile, "- 1");
			break;
		case SMP_INCREMENT:
			UnaryOper = true;
			SMP_fprintf(AnnotFile, "+ 1");
			break;
		case SMP_ADD:
		case SMP_ADD_CARRY:
			SMP_fprintf(AnnotFile, "+");
			break;
		case SMP_SUBTRACT:
		case SMP_SUBTRACT_BORROW:
			SMP_fprintf(AnnotFile, "-");
			break;
		default:
			SMP_msg("FATAL ERROR: Invalid operator in AnnotPrintStackPtrPlusOffset.\n");
			this->Dump();
			assert(false);
		}
		if (!UnaryOper) { // Print the immediate offset
			AnnotPrintOperand(this->GetConstRightOperand(), AnnotFile, true, true);
		}
	}
	return;
} // end of STARSExpression::AnnotPrintStackPtrPlusOffset()

// Print the stack pointer plus optional offset constant to the AnnotString
void STARSExpression::StringPrintStackPtrPlusOffset(string &AnnotString) const {
	SMPoperator CurrOper = this->GetOperator();
	bool LeftSPOpnd = (!this->HasLeftSubTree()) && this->GetConstLeftOperand()->IsRegOp() && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG);
	bool SPPlusOffset = false;
	bool JustStackPtr = (CurrOper == SMP_ASSIGN) && LeftSPOpnd; // SMP_ASSIGN in expr means no RHS
	if (!JustStackPtr && LeftSPOpnd && IsIntegerAddOrSubOperator(CurrOper)) {
		const STARSOpndTypePtr RightOp = this->GetConstRightOperand();
		bool HasRightTree = this->HasRightSubTree();
		bool ImmedRightOp = (nullptr != RightOp) && (!HasRightTree) && RightOp->IsImmedOp();
		SPPlusOffset = ImmedRightOp;
	}
	if (JustStackPtr) {
		AnnotString += "RSP ";
	}
	else if (SPPlusOffset) {
		AnnotString += "RSP";
		bool UnaryOper = false;
		switch (CurrOper) {
		case SMP_DECREMENT:
			UnaryOper = true;
			AnnotString += "-1";
			break;
		case SMP_INCREMENT:
			UnaryOper = true;
			AnnotString += "+1";
			break;
		case SMP_ADD:
		case SMP_ADD_CARRY:
			AnnotString += "+";
			break;
		case SMP_SUBTRACT:
		case SMP_SUBTRACT_BORROW:
			AnnotString += "-";
			break;
		default:
			SMP_msg("FATAL ERROR: Invalid operator in AnnotPrintStackPtrPlusOffset.\n");
			this->Dump();
			assert(false);
		}
		if (!UnaryOper) { // Print the immediate offset
			StringPrintOperand(this->GetConstRightOperand(), AnnotString, true, true);
		}
	}
	return;
} // end of STARSExpression::StringPrintStackPtrPlusOffset()

void STARSExpression::Dump(const std::size_t TabCount) const {
	SMP_msg("\n");
	for (size_t count = 0; count < TabCount; ++count) {
		SMP_msg("\t");
	}

	bool AssignOperator = (SMP_ASSIGN == this->GetOperator());  // RHS is unused for SMP_ASSIGN expressions
	bool SymbolicMemoryOperator = (SMP_SYMBOLIC_READ_MEMORY == this->GetOperator());
	SMP_msg(" OrigParentInst : %llx ParentInst: %llx %s \n", (uint64_t) this->GetOriginalParentInst()->GetAddr(), 
		(uint64_t) this->GetParentInst()->GetAddr(), OperatorText[this->GetOperator()]);

	for (size_t count = 0; count < TabCount; ++count) {
		SMP_msg("\t");
	}
	SMP_msg("(\n"); // open parenthesis

	// Left operand or subtree
	if (this->HasLeftSubTree()) {
		this->GetLeftTree()->Dump(1 + TabCount);
	}
	else if ((nullptr != this->LeftOperand) && (!this->LeftOperand->IsVoidOp())) {
		for (size_t count = 0; count < (1 + TabCount); ++count) {
			SMP_msg("\t");
		}
		PrintOperand(this->GetConstLeftOperand());
		if (!this->GetConstLeftOperand()->IsImmedOp()) {
			SMP_msg(" SSA: %d UseAddr: %llx PreLoopAddr: %llx", this->GetLeftSSANum(), 
				(uint64_t) this->GetLeftUseAddr(), (uint64_t) this->GetLeftPreLoopDefAddr());
		}
	}
	if (!(AssignOperator || SymbolicMemoryOperator)) {
		SMP_msg(" ,\n");
		// then the right operand or subtree
		if (this->HasRightSubTree()) {
			this->GetRightTree()->Dump(1 + TabCount);
		}
		else if ((nullptr != this->RightOperand) && (!this->RightOperand->IsVoidOp())) {
			for (size_t count = 0; count < (1 + TabCount); ++count) {
				SMP_msg("\t");
			}
			PrintOperand(this->GetConstRightOperand());
			if (!this->GetConstRightOperand()->IsImmedOp()) {
				SMP_msg(" SSA: %d UseAddr: %llx PreLoopAddr: %llx", this->GetRightSSANum(), 
					(uint64_t) this->GetRightUseAddr(), (uint64_t) this->GetRightPreLoopDefAddr());
			}
		}
	}
	SMP_msg("\n");
	for (size_t count = 0; count < TabCount; ++count) {
		SMP_msg("\t");
	}
	SMP_msg(");\n"); // close the open parenthesis

	return;
} // end of STARSExpression::Dump()

// Emit SPARK Ada translation of expression to OutputFile, perhaps with Reg'Old suffix.
// OffByOne should never be true for subtrees, only certain parent trees.
void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs, bool UseSavedStackPtr, bool NoLHSArgs) const {
#if 1
	std::string OutString;
	this->EmitSPARKAdaString(OutString, ProcessingLoop, OldSuffix, OffByOne, HasLoopArgs, UseSavedStackPtr, NoLHSArgs);
	SMP_fprintf(OutputFile, "%s", OutString.c_str());
#else
	bool UseFP = this->GetParentFunc()->UsesFramePointer();
	bool PrefixProcCall = false;
	bool UnaryPrefix = false;
	string OperatorString;
	SMPoperator CurrOperator = this->GetOperator();
	bool IsRelational = IsRelationalOperator(CurrOperator);
	bool IsSymbolicReadMem = (SMP_SYMBOLIC_READ_MEMORY == CurrOperator);
	bool ConstFollows = (!this->HasRightSubTree() && (SMP_ASSIGN != CurrOperator) && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp());

	// If we can convert the OffByOne+IsRelational case from > to >=, or from < to <=, then we can avoid adding one to the limit.
	if (IsRelational && OffByOne) {
		if (CurrOperator == SMP_GREATER_THAN) {
			CurrOperator = SMP_GREATER_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
		else if (CurrOperator == SMP_LESS_THAN) {
			CurrOperator = SMP_LESS_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
		else if (CurrOperator == SMP_ABOVE) {
			CurrOperator = SMP_ABOVE_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
		else if (CurrOperator == SMP_BELOW) {
			CurrOperator = SMP_BELOW_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
	}

	if (SMP_ASSIGN != CurrOperator) {
		PrintSPARKAdaOperator(CurrOperator, OperatorString, PrefixProcCall, UnaryPrefix, ConstFollows);
		if (PrefixProcCall) { // operator comes first, as a procedure call
			SMP_fprintf(OutputFile, "%s(", OperatorString.c_str());
		}
		else if (UnaryPrefix) {  // operator comes first
			SMP_fprintf(OutputFile, "%s", OperatorString.c_str());
			if (IsSymbolicReadMem)
				SMP_fprintf(OutputFile, "(");
		}
	}

	// Left operand or subtree
	if (this->HasLeftSubTree()) {
		SMP_fprintf(OutputFile, "(");
		this->GetLeftTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, NoLHSArgs);
		SMP_fprintf(OutputFile, ")");
	}
	else if ((nullptr != this->GetConstLeftOperand()) && (!this->GetConstLeftOperand()->IsVoidOp())) {
		bool IsRegOp = this->GetConstLeftOperand()->IsRegOp();
		bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix);
		STARSOpndTypePtr LeftOp = CloneIfNecessary(this->GetConstLeftOperand(), UseFP);
		if (MDIsDirectStackAccessOpnd(LeftOp, UseFP)) {
			this->GetParentInst()->MDGetUnnormalizedOp(LeftOp);
		}
		bool InArgOp = false;
		if (IsRegOp) {
			STARS_regnum_t RegNum = LeftOp->GetReg();
			InArgOp = global_STARS_program->IsArgumentReg(RegNum);
		}
		bool ArgSuffix = ProcessingLoop && InArgOp && (!NoLHSArgs && HasLoopArgs) && (STARS_BADADDR != this->GetLeftPreLoopDefAddr());
		this->GetParentInst()->PrintSPARKAdaOperand(LeftOp, OutputFile, false, UseFP, !ArgSuffix, OmitTrailingSpace, UseSavedStackPtr);
		if (ArgSuffix) { // LiveIn to loop, traced back to InArg
			std::ostringstream AddrString;
			AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
			SMP_fprintf(OutputFile, "_%s", AddrString.str().c_str());
		}
		else {
			if (OldSuffix && IsRegOp) {
				SMP_fprintf(OutputFile, "'Old");
			}
		}
	}

	if (SMP_ASSIGN != CurrOperator) {
		if (PrefixProcCall) { // need comma in middle to separate parameters
			SMP_fprintf(OutputFile, ", ");
		}
		else if (!UnaryPrefix) {  // operator comes in middle
			SMP_fprintf(OutputFile, "%s", OperatorString.c_str());
			if (IsRelational && OffByOne) {
				// Instead of printing x < y, we will print x < (y + 1)
				SMP_fprintf(OutputFile, "(");
			}
		}

		// then the right operand or subtree
		if (this->HasRightSubTree()) {
			SMP_fprintf(OutputFile, "(");
			this->GetRightTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, false);
			SMP_fprintf(OutputFile, ")");
		}
		else if ((nullptr != this->GetConstRightOperand()) && (!this->GetConstRightOperand()->IsVoidOp())) {
			bool IsRegOp = this->GetConstRightOperand()->IsRegOp();
			bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix);
			STARSOpndTypePtr RightOp = CloneIfNecessary(this->GetConstRightOperand(), UseFP);
			if (MDIsDirectStackAccessOpnd(RightOp, UseFP)) {
				this->GetParentInst()->MDGetUnnormalizedOp(RightOp);
			}
			this->GetParentInst()->PrintSPARKAdaOperand(RightOp, OutputFile, false, UseFP, !(ProcessingLoop && HasLoopArgs), OmitTrailingSpace, UseSavedStackPtr);
			if (ProcessingLoop && IsRegOp && HasLoopArgs && (STARS_BADADDR != this->GetRightPreLoopDefAddr())) { // LiveIn to loop, traced back to InArg
				std::ostringstream AddrString;
				AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
				SMP_fprintf(OutputFile, "_%s", AddrString.str().c_str());
			}
			else {
				if (OldSuffix && IsRegOp) {
					SMP_fprintf(OutputFile, "'Old");
				}
			}
		}

		if (PrefixProcCall || IsSymbolicReadMem) { // operator comes first, as a procedure call; close parenthesis
			SMP_fprintf(OutputFile, ")");
		}
		else if (IsRelational && OffByOne) {
			// Instead of printing x < y, we will print x < (y + 1)
			SMP_fprintf(OutputFile, " + 1)");
		}

	} // end if (SMP_ASSIGN != operator)
#endif
	return;
} // end of STARSExpression::EmitSPARKAda()

// Emit SPARK Ada translation of expression to OutString, perhaps with Reg'Old suffix.
void STARSExpression::EmitSPARKAdaString(std::string &OutString, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs, bool UseSavedStackPtr, bool NoLHSArgs) const {
	bool UseFP = this->GetParentFunc()->UsesFramePointer();

	bool PrefixProcCall = false;
	bool UnaryPrefix = false;
	string OperatorString;
	SMPoperator CurrOperator = this->GetOperator();
	bool IsRelational = IsRelationalOperator(CurrOperator);
	bool IsSymbolicReadMem = (SMP_SYMBOLIC_READ_MEMORY == CurrOperator);
	bool ConstFollows = (!this->HasRightSubTree() && (SMP_ASSIGN != CurrOperator) && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp());

	// If we can convert the OffByOne+IsRelational case from > to >=, or from < to <=, then we can avoid adding one to the limit.
	if (IsRelational && OffByOne) {
		if (CurrOperator == SMP_GREATER_THAN) {
			CurrOperator = SMP_GREATER_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
		else if (CurrOperator == SMP_LESS_THAN) {
			CurrOperator = SMP_LESS_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
		else if (CurrOperator == SMP_ABOVE) {
			CurrOperator = SMP_ABOVE_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
		else if (CurrOperator == SMP_BELOW) {
			CurrOperator = SMP_BELOW_EQUAL;
			OffByOne = false; // no more adjustment needed
		}
	}

	if (SMP_ASSIGN != CurrOperator) {
		PrintSPARKAdaOperator(CurrOperator, OperatorString, PrefixProcCall, UnaryPrefix, ConstFollows);
		if (PrefixProcCall) { // operator comes first, as a procedure call
			OutString.append(OperatorString);
			OutString.append("(");
		}
		else if (UnaryPrefix) {  // operator comes first
			OutString.append(OperatorString);
			if (IsSymbolicReadMem)
				OutString.append("(");
		}
	}

	// Left operand or subtree
	if (this->HasLeftSubTree()) {
		OutString.append("(");
		this->GetLeftTree()->EmitSPARKAdaString(OutString, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, NoLHSArgs);
		OutString.append(")");
	}
	else if ((nullptr != this->GetConstLeftOperand()) && (!this->GetConstLeftOperand()->IsVoidOp())) {
		bool IsRegOp = this->GetConstLeftOperand()->IsRegOp();
		bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix);
		STARSOpndTypePtr LeftOp = CloneIfNecessary(this->GetConstLeftOperand(), UseFP);
		if (MDIsDirectStackAccessOpnd(LeftOp, UseFP)) {
			this->GetParentInst()->MDGetUnnormalizedOp(LeftOp);
		}

		bool InArgOp = false;
		if (IsRegOp) {
			STARS_regnum_t RegNum = LeftOp->GetReg();
			InArgOp = global_STARS_program->IsArgumentReg(RegNum);
		}
		bool ArgSuffix = ProcessingLoop && InArgOp && (!NoLHSArgs && HasLoopArgs) && (STARS_BADADDR != this->GetLeftPreLoopDefAddr());
		this->GetParentInst()->SPARKAdaOperandToString(LeftOp, OutString, false, UseFP, !ArgSuffix, OmitTrailingSpace, UseSavedStackPtr);
		if (ArgSuffix) { // LiveIn to loop, traced back to InArg
			std::ostringstream AddrString;
			AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
			OutString.append("_");
			OutString.append(AddrString.str().c_str());
		}
		else {
			if (OldSuffix && IsRegOp) {
				OutString.append("'Old");
			}
		}
	}

	if (SMP_ASSIGN != CurrOperator) {
		if (PrefixProcCall) { // need comma in middle to separate parameters
			OutString.append(", ");
		}
		else if (!UnaryPrefix) {  // operator comes in middle
			OutString.append(OperatorString.c_str());
			if (IsRelational && OffByOne) {
				// Instead of printing x < y, we will print x < (y + 1)
				OutString.append("(");
			}
		}

		// then the right operand or subtree
		if (this->HasRightSubTree()) {
			OutString.append("(");
			this->GetRightTree()->EmitSPARKAdaString(OutString, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, false);
			OutString.append(")");
		}
		else if ((nullptr != this->GetConstRightOperand()) && (!this->GetConstRightOperand()->IsVoidOp())) {
			bool IsRegOp = this->GetConstRightOperand()->IsRegOp();
			bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix);
			STARSOpndTypePtr RightOp = CloneIfNecessary(this->GetConstRightOperand(), UseFP);
			if (MDIsDirectStackAccessOpnd(RightOp, UseFP)) {
				this->GetParentInst()->MDGetUnnormalizedOp(RightOp);
			}
			bool InArgOp = false;
			if (IsRegOp) {
				STARS_regnum_t RegNum = RightOp->GetReg();
				InArgOp = global_STARS_program->IsArgumentReg(RegNum);
			}
			bool ArgSuffix = ProcessingLoop && InArgOp && HasLoopArgs && (STARS_BADADDR != this->GetRightPreLoopDefAddr());
			this->GetParentInst()->SPARKAdaOperandToString(RightOp, OutString, false, UseFP, !ArgSuffix, OmitTrailingSpace, UseSavedStackPtr);
			if (ArgSuffix) { // LiveIn to loop, traced back to InArg
				std::ostringstream AddrString;
				AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
				OutString.append("_");
				OutString.append(AddrString.str().c_str());
			}
			else {
				if (OldSuffix && IsRegOp) {
					OutString.append("'Old");
				}
			}
		}

		if (PrefixProcCall || IsSymbolicReadMem) { // operator comes first, as a procedure call; close parenthesis
			OutString.append(")");
		}
		else if (IsRelational && OffByOne) {
			// Instead of printing x < y, we will print x < (y + 1)
			OutString.append(" + 1)");
		}

	} // end if (SMP_ASSIGN != operator)

	return;
} // end of STARSExpression::EmitSPARKAdaString()

// Emit X86InSafeRegion64(..., X86.RSP) for each byte in memory expr
void STARSExpression::EmitSPARKInSafeRegion64(FILE *OutputFile, size_t MemWidth) const {
	bool UseFP = this->GetParentFunc()->UsesFramePointer();
	SMPoperator CurrOperator = this->GetOperator();
	string OutString;

	this->EmitSPARKAdaString(OutString, false, false, false, false, false, false);

	for (size_t byte = 0; byte < MemWidth; ++byte) {
		SMP_fprintf(OutputFile, "\n\t\tX86.InSafeRegion64(%s", OutString.c_str());
		if (byte > 0)
			SMP_fprintf(OutputFile, " + %u", byte);
		if ((byte + 1) < MemWidth) {
			SMP_fprintf(OutputFile, ", X86.RSP) and");
		}
		else {
			SMP_fprintf(OutputFile, ", X86.RSP)");
		}
	}

	return;
} // end of STARSExpression::EmitSPARKInSafeRegion64()

// create and print vector of strings matching loop-function parameters to their incoming locations
void STARSExpression::PrintSPARKArgLocationStrings(FILE *OutputFile, bool LoopInvariant, size_t LoopIndex, size_t &OutputCount, bitset<1 + MD_LAST_REG_NO> &RegsPrinted) {
	// Walk the expression tree and find non-constant leaves. These must be incoming arguments or basic induction variables (BIVs).
	//  This method should not be called on expressions that were expanded with the StopOnIV option flag, so we will assume that
	//  any non-constant leaf operand is an incoming argument. EXCEPTION: The stack ptr reg is never made into an incoming arg.
	if (this->HasLeftSubTree()) {
		this->GetLeftTree()->PrintSPARKArgLocationStrings(OutputFile, LoopInvariant, LoopIndex, OutputCount, RegsPrinted);
	}
	else if (nullptr != this->GetConstLeftOperand()) { // leaf operand
		STARSOpndTypePtr LeafOp = this->GetLeftOperand();
		STARS_ea_t PreLoopDefAddr = this->GetLeftPreLoopDefAddr();
		if (LeafOp->IsRegOp()) {
			STARS_regnum_t LeafReg = LeafOp->GetReg();
			if (!RegsPrinted[(size_t) LeafReg]) {
				STARSInductionVarFamilyList::iterator ListIter; 
				size_t FamilyIndex;
				// Don't print Loop_Invariant assertions about induction variables, basic or derived.
				if (!(LoopInvariant && this->GetParentFunc()->IsLoopInductionVarForAnySSANum(LoopIndex, LeafOp, ListIter, FamilyIndex))) {
					this->PrintSPARKArgLocationStringsHelper(OutputFile, LoopInvariant, OutputCount, LeafOp, PreLoopDefAddr);
				}
				RegsPrinted.set((size_t) LeafReg);
			}
		}
	}

	if ((SMP_ASSIGN != this->GetOperator()) && (SMP_SYMBOLIC_READ_MEMORY != this->GetOperator())) {  // right hand side is valid
		if (this->HasRightSubTree()) {
			this->GetRightTree()->PrintSPARKArgLocationStrings(OutputFile, LoopInvariant, LoopIndex, OutputCount, RegsPrinted);
		}
		else if ((nullptr != this->GetConstRightOperand()) && !this->GetConstRightOperand()->IsVoidOp()) { // leaf operand
			STARSOpndTypePtr LeafOp = this->GetRightOperand();
			STARS_ea_t PreLoopDefAddr = this->GetRightPreLoopDefAddr();
			if (LeafOp->IsRegOp()) {
				STARS_regnum_t LeafReg = LeafOp->GetReg();
				if (!RegsPrinted[(size_t) LeafReg]) {
					STARSInductionVarFamilyList::iterator ListIter;
					size_t FamilyIndex;
					// Don't print Loop_Invariant assertions about induction variables, basic or derived.
					if (!(LoopInvariant && this->GetParentFunc()->IsLoopInductionVarForAnySSANum(LoopIndex, LeafOp, ListIter, FamilyIndex))) {
						this->PrintSPARKArgLocationStringsHelper(OutputFile, LoopInvariant, OutputCount, LeafOp, PreLoopDefAddr);
					}
					RegsPrinted.set((size_t)LeafReg);
				}
			}
		}
	}

	return;
} // end of STARSExpression::PrintSPARKArgLocationStrings()

void STARSExpression::PrintSPARKArgLocationStringsHelper(FILE *OutputFile, bool LoopInvariant, size_t &OutputCount, const STARSOpndTypePtr &LeafOp, STARS_ea_t PreLoopDefAddr) {
	if (!(LeafOp->IsRegOp() && LeafOp->MatchesReg(MD_STACK_POINTER_REG))) {
		bool UseFP = this->GetParentFunc()->UsesFramePointer();
		std::ostringstream AddrString;
		AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
		if ((STARS_BADADDR != PreLoopDefAddr) && (!STARS_IsBlockNumPseudoID(PreLoopDefAddr))) {
			assert(LeafOp->IsRegOp());
			STARS_regnum_t RegNo = LeafOp->GetReg();
			bool ArgSuffixNeeded = global_STARS_program->IsArgumentReg(RegNo);
			if (STARS_IsSSAMarkerPseudoID(PreLoopDefAddr)) {
				// InArg from calling function was unchanged and LiveIn to loop.
				// We want a string like:  "RDI_400586 = X86.RDI"
				if (LoopInvariant) {
					PrintSPARKIndentTabs(OutputFile);
					SMP_fprintf(OutputFile, "pragma Loop_Invariant(");
					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true, false);
					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false, false);
					SMP_fprintf(OutputFile, ");\n");
				}
				else {
					if (0 < OutputCount) {
						SMP_fprintf(OutputFile, " and\n\t(");
					}
					else {
						SMP_fprintf(OutputFile, "(");
					}
					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false);
					SMP_fprintf(OutputFile, ")");
				}
				++OutputCount;
			}
			else { // A regular instruction is at PreLoopDefAddr
				// We want a string like:  "RDI_400586 = X86.ReadMem64(X86.RBP-8)"
				SMPInstr *PreLoopInst = this->GetParentFunc()->GetInstFromAddr(PreLoopDefAddr);
				assert(nullptr != PreLoopInst);
				STARSOpndTypePtr PreLoopDefOp = PreLoopInst->GetFirstLeftOperandNoNorm();
				assert((nullptr != PreLoopDefOp) && (!PreLoopDefOp->IsVoidOp()));
				if (LoopInvariant) {
					PrintSPARKIndentTabs(OutputFile);
					SMP_fprintf(OutputFile, "pragma Loop_Invariant(");
					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
					this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false);
					SMP_fprintf(OutputFile, ");\n");
				}
				else {
					if (0 < OutputCount) {
						SMP_fprintf(OutputFile, " and\n\t(");
					}
					else {
						SMP_fprintf(OutputFile, "(");
					}
					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
					this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false);
					SMP_fprintf(OutputFile, ")");
				}
				++OutputCount;
			}
		}
	}
	return;
} // end of STARSExpression::PrintSPARKArgLocationStringsHelper()

// swap left and right sides
void STARSExpression::SwapSides(void) {
	STARSExpression *LeftTreeTemp = nullptr;
	if (this->HasLeftSubTree()) {
		LeftTreeTemp = this->GetLeftTree();
		if (this->HasRightSubTree()) {
			this->SetLeftTree(this->GetRightTree());
			this->SetRightTree(LeftTreeTemp);
		}
		else { // Right operand only
			this->SetLeftOperand(this->GetRightOperand());
			this->SetLeftUseAddr(this->GetRightUseAddr());
			this->SetLeftSSANum(this->GetRightSSANum());
			this->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr());
			this->SetRightTree(LeftTreeTemp);
			this->SetLeftTree(nullptr);
		}
	}
	else { // Left operand only
		STARSOpndTypePtr LeftOpTemp = this->GetLeftOperand();
		int LeftOpSSATemp = this->GetLeftSSANum();
		STARS_ea_t LeftOpAddrTemp = this->GetLeftPreLoopDefAddr();
		STARS_ea_t LeftUseAddrTemp = this->GetLeftUseAddr();
		if (this->HasRightSubTree()) {
			this->SetLeftTree(this->GetRightTree());
			this->SetRightTree(nullptr);
			this->SetRightOperand(LeftOpTemp);
			this->SetRightUseAddr(LeftUseAddrTemp);
			this->SetRightSSANum(LeftOpSSATemp);
			this->SetRightPreLoopDefAddr(LeftOpAddrTemp);
			this->SetLeftOperand(nullptr);
		}
		else { // Right operand only
			this->SetLeftOperand(this->GetRightOperand());
			this->SetLeftUseAddr(this->GetRightUseAddr());
			this->SetLeftSSANum(this->GetRightSSANum());
			this->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr());
			this->SetRightOperand(LeftOpTemp);
			this->SetRightUseAddr(LeftUseAddrTemp);
			this->SetRightSSANum(LeftOpSSATemp);
			this->SetRightPreLoopDefAddr(LeftOpAddrTemp);
		}
	}

	return;
} // end of STARSExpression::SwapSides()

// Search OriginalParentInst for MemOp and return its byte width
uint16_t STARSExpression::FindOrigMemOpByteWidth(void) const {
	uint16_t MemOpByteWidth = 0;
	STARSOpndTypePtr MemOp = this->GetOriginalParentInst()->GetMemDef();
	if ((nullptr == MemOp) || (!MemOp->IsMemOp())) {
		MemOp = this->GetOriginalParentInst()->GetMemUse();
	}
	if ((nullptr != MemOp) && MemOp->IsMemOp()) {
		MemOpByteWidth = MemOp->GetByteWidth();
	}

	return MemOpByteWidth;
} // end of STARSExpression::FindOrigMemOpByteWidth()

// Substitute SCCP constants for operands
void STARSExpression::EvaluateConsts(void) {
	STARS_ea_t ConstDefAddr;
	if (this->HasLeftSubTree()) {
		// Recurse into LeftExpr
		this->GetLeftTree()->EvaluateConsts();
	}
	else {
		// Search for SCCP constant for LeftOperand.
		STARSOpndTypePtr LeftOp = this->GetLeftOperand();
		if ((nullptr != LeftOp) && LeftOp->IsRegOp()) {
			STARS_uval_t LeftConstValue;
			bool FoundConst = this->FindConstForOperand(true, LeftConstValue, ConstDefAddr);
			if (FoundConst) {
				// Replace LeftOperand with an immediate operand.
				STARSOpndTypePtr NewLeftOp = this->GetParentInst()->MakeImmediateOpnd(LeftConstValue);
				this->SetLeftOperand(NewLeftOp); // SSANum is irrelevant, just reset LeftOperand
				if (STARS_PSEUDO_ID_MIN > ConstDefAddr) { // real inst addr
					SMPInstr *ConstDefInst = this->GetParentFunc()->GetInstFromAddr(ConstDefAddr);
					assert(nullptr != ConstDefInst);
					this->SetParentInst(ConstDefInst);
				}
			}
		}
	}

	if ((SMP_ASSIGN == this->GetOperator()) || (SMP_SYMBOLIC_READ_MEMORY == this->GetOperator())) {
		// Only the left hand side exists. Nothing more to do.
		return;
	}

	if (nullptr != this->GetRightTree()) {
		// Recurse into RightExpr
		this->GetRightTree()->EvaluateConsts();
	}
	else {
		// Search for SCCP constant for RightOperand.
		STARSOpndTypePtr RightOp = this->GetRightOperand();
		if ((nullptr != RightOp) && RightOp->IsRegOp()) {
			STARS_uval_t RightConstValue;
			bool FoundConst = this->FindConstForOperand(false, RightConstValue, ConstDefAddr);
			if (FoundConst) {
				// Replace RightOperand with an immediate operand.
				STARSOpndTypePtr NewRightOp = this->GetParentInst()->MakeImmediateOpnd(RightConstValue);
				this->SetRightOperand(NewRightOp); // SSANum is irrelevant, just reset RightOperand
				if (STARS_PSEUDO_ID_MIN > ConstDefAddr) { // real inst addr
					SMPInstr *ConstDefInst = this->GetParentFunc()->GetInstFromAddr(ConstDefAddr);
					assert(nullptr != ConstDefInst);
					this->SetParentInst(ConstDefInst);
				}
			}
		}
	}

	return;
} // end of STARSExpression::EvaluateConsts()

// search for SCCP constant value for LeftOperand or RightOperand
bool STARSExpression::FindConstForOperand(bool Left, STARS_uval_t &ConstValue, STARS_ea_t &ConstDefAddr) {
	STARSOpndTypePtr SearchOp = (Left) ? CloneIfSubwordReg(this->GetConstLeftOperand()) : CloneIfSubwordReg(this->GetConstRightOperand());
	CanonicalizeOpnd(SearchOp);
	int SSANum = (Left) ? this->GetLeftSSANum() : this->GetRightSSANum();
	SMPBasicBlock *CurrBlock = this->GetParentInst()->GetBlock();
	int HashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
	bool LocalName = CurrBlock->IsLocalName(SearchOp);
	STARSSCCPMapIter ConstIter;
	bool FoundConst = CurrBlock->GetFunc()->FindSCCPConstIter(CurrBlock, HashValue, LocalName, ConstIter);
	if (FoundConst) {
		ConstValue = ConstIter->second.ConstValue;
		if (LocalName) {
			// Can't const DEF be global prior to block even if HashValue op is inside the block?
			ConstDefAddr = CurrBlock->GetLocalDefAddrForRegHash(HashValue);
		}
		else {
			ConstDefAddr = CurrBlock->GetFunc()->GetGlobalDefAddrForRegHash(HashValue);
		}
	}

	return FoundConst;
} // end of STARSExpression::FindConstForOperand()

// Widen register operands that are narrower than ByteWidth
bool STARSExpression::WidenRegOperands(std::size_t ByteWidth) {
	bool Widened = false;
	if (this->HasLeftSubTree()) {
		Widened = this->GetLeftTree()->WidenRegOperands(ByteWidth); // recurse
	}
	else if (nullptr != this->GetConstLeftOperand()) {
		if (this->GetConstLeftOperand()->IsRegOp() && (ByteWidth > this->GetConstLeftOperand()->GetByteWidth())) {
			STARSOpndTypePtr NewLeftOp = this->GetParentInst()->MakeRegOpnd(this->GetConstLeftOperand()->GetReg());
			NewLeftOp->SetByteWidth((uint16_t)global_STARS_program->GetSTARS_ISA_Bytewidth());
			this->SetLeftOperand(NewLeftOp);
			Widened = true;
		}
		else if (this->GetConstLeftOperand()->IsImmedOp() && ((SMP_ZERO_EXTEND == this->GetOperator()) || (SMP_SIGN_EXTEND == this->GetOperator()))) {
			// Replace extension operator with simple assignment for immediate operands.
			this->SetOperator(SMP_ASSIGN);
			Widened = true;
		}
	}

	if (this->HasRightSubTree()) {
		Widened = (this->GetRightTree()->WidenRegOperands(ByteWidth) || Widened); // recurse
	}
	else if (nullptr != this->GetConstRightOperand()) {
		if (this->GetConstRightOperand()->IsRegOp() && (ByteWidth > this->GetConstRightOperand()->GetByteWidth())) {
			STARSOpndTypePtr NewRightOp = this->GetParentInst()->MakeRegOpnd(this->GetConstRightOperand()->GetReg());
			NewRightOp->SetByteWidth((uint16_t) global_STARS_program->GetSTARS_ISA_Bytewidth());
			this->SetRightOperand(NewRightOp);
			Widened = true;
		}
	}

	return Widened;
} // end of STARSExpression::WidenOperands()

// Lots of compiler-generated x86-64 code has needless sign-extend or zero-extend opcodes because
//  quick arithmetic is performed on 32-bit regs and the compiler extends it later before using the 64-bit reg.
//  Expressions get hard to analyze; the prover can balk as a double-check on unsound simplifications, but
//  get rid of these extensions for our purposes so we can produce simple exprs.
#define STARS_SPARK_DISCARD_BIT_EXTENSIONS 1

// Remove sign-extension and zero-extension operators after widening
bool STARSExpression::SimplifyExtensions(STARSExpression *ParentExpr) {
	bool Simplified = false;
	if (this->HasLeftSubTree())
		Simplified = this->GetLeftTree()->SimplifyExtensions(this);
	if (this->HasRightSubTree())
		Simplified = (this->GetRightTree()->SimplifyExtensions(this) || Simplified);
#if STARS_SPARK_DISCARD_BIT_EXTENSIONS
	if (SMP_ZERO_EXTEND == this->GetOperator() || (SMP_SIGN_EXTEND == this->GetOperator())) {
		Simplified = (this->ElevateLeftSide(ParentExpr) || Simplified); // eliminate the extension operator
	}
#else
	if (SMP_ZERO_EXTEND == this->GetOperator() && (nullptr != this->GetConstLeftOperand()) && (!this->HasLeftSubTree())) {
		// See if we are zero-extending a constant, and transform to just assigning the constant.
		if (this->GetConstLeftOperand()->IsImmedOp()) {
			Simplified = this->ElevateLeftSide(ParentExpr); // eliminate the extension operator
			assert(Simplified);  // now fall through to further simplifications
		}
	}
#endif
	return Simplified;
} // end of STARSExpression::SimplifyExtensions()

// Remove SMP_ASSIGN operators below the root level
bool STARSExpression::SimplifyAssigns(STARSExpression *ParentExpr) {
	bool Simplified = false;
	// Depth-first tree traversal via recursion.
	if (this->HasLeftSubTree())
		Simplified = this->GetLeftTree()->SimplifyAssigns(this);
	if (this->HasRightSubTree())
		Simplified = (this->GetRightTree()->SimplifyAssigns(this) || Simplified);
	if ((nullptr != ParentExpr) && (SMP_ASSIGN == this->GetOperator())) {
		bool LeftOperandLifted = this->ElevateLeftSide(ParentExpr);
		Simplified = true;
		this->SetLeftTree(nullptr); // Nothing left of this expression
		this->SetRightTree(nullptr);
	}
	return Simplified;
} // end of STARSExpression::SimplifyAssigns()

// Call WidenRegOperands, SimplifyExtensions, and SimplifyExpr
bool STARSExpression::SimplifyDriver(void) {
	bool AssignsRemoved = this->SimplifyAssigns(nullptr);
	// Widen the register operands in the expr.
	bool Widened = this->WidenRegOperands(global_STARS_program->GetSTARS_ISA_Bytewidth());
	bool ExtSimplified = this->SimplifyExtensions(nullptr);
	bool Simplified = this->SimplifyExpr(nullptr);
	
	return (AssignsRemoved || Widened || ExtSimplified || Simplified);
} // end of STARSExpression::SimplifyDriver()

// Simplify operations with operands of zero or one, etc. Return true if expr was raised to parent.
bool STARSExpression::SimplifyExpr(STARSExpression *ParentExpr) {
	bool RootLeftExprLifted = false;
	if (SMP_SYMBOLIC_READ_MEMORY == this->GetOperator()) {
		// Nothing to do besides recurse into the memory address.
		if (this->HasLeftSubTree())
			return this->GetLeftTree()->SimplifyExpr(this);
		else
			return false; // no changes made
	}

	if (this->HasLeftSubTree()) {
		bool LeftExprLifted = this->GetLeftTree()->SimplifyExpr(this);
		if (LeftExprLifted && (nullptr != this->GetConstLeftOperand()) && (!this->HasLeftSubTree())) {  
			// nothing remains of left tree.; FALSE if internal SMP_ASSIGN was lifted
			if (nullptr != this->GetLeftTree()) {
				delete this->GetLeftTree();
				this->SetLeftTree(nullptr);
			}
		}
	}

	if (this->HasRightSubTree()) {
		bool RightExprLifted = this->GetRightTree()->SimplifyExpr(this);
		if (RightExprLifted && (!this->HasRightSubTree())) {
			// nothing remains of left tree.; FALSE if internal SMP_ASSIGN was lifted
			if (nullptr != this->GetRightTree()) {
				delete this->GetRightTree();
				this->SetRightTree(nullptr);
			}
		}
	}

	bool LeftNullTree = (!this->HasLeftSubTree());
	bool RightNullTree = (!this->HasRightSubTree());
	bool RightOperandLifted = false; // was RightOperand lifted up into ParentExpr?
	bool LeftOperandLifted = false; // was LeftOperand lifted up into ParentExpr?
	bool NegativeAddendSimplified = false; // Left + (-k) became Left - k

	// A left or right tree might be merely an operand after recursive simplification, so test from scratch.
	if (LeftNullTree || RightNullTree) {
		bool ConstLeftOperand = (LeftNullTree && (nullptr != this->GetConstLeftOperand()) && this->GetConstLeftOperand()->IsImmedOp());
		bool ConstRightOperand = (RightNullTree && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp());
		bool TwoConstOperands = (ConstLeftOperand && ConstRightOperand);
		bool NegativeRightOperand = ConstRightOperand && (((STARS_sval_t) this->GetConstRightOperand()->GetImmedValue()) < 0);

		// Simplify (Left + (-k)) to be (Left - k)
		if (NegativeRightOperand && (SMP_ADD == this->GetOperator())) {
			STARS_sval_t NewImmedVal = 0 - ((STARS_sval_t) this->GetConstRightOperand()->GetImmedValue());
			if (0 < NewImmedVal) { // if not signedness error involving MIN_INT
				STARSOpndTypePtr NewImmedOp = this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t)NewImmedVal);
				this->SetRightOperand(NewImmedOp);
				this->SetOperator(SMP_SUBTRACT);
				NegativeAddendSimplified = true;
			}
		}

		// Handle the case of arithmetic on two constant operands.
		if (TwoConstOperands) {
			SMPoperator CurrOperator = this->GetOperator();
			STARS_uval_t LeftValue = this->GetConstLeftOperand()->GetImmedValue();
			STARS_uval_t RightValue = this->GetConstRightOperand()->GetImmedValue();
			bool Simplified = true;
			STARS_uval_t FinalValue;
			if (SMP_ADD == CurrOperator) {
				FinalValue = LeftValue + RightValue;
			}
			else if (SMP_SUBTRACT == CurrOperator) {
				FinalValue = LeftValue - RightValue;
			}
			else if ((SMP_U_MULTIPLY == CurrOperator) || (SMP_S_MULTIPLY == CurrOperator)) {
				FinalValue = LeftValue * RightValue;
			}
			else if ((SMP_U_DIVIDE == CurrOperator) || (SMP_S_DIVIDE == CurrOperator)) {
				if (RightValue == 0) {
					SMP_msg("SERIOUS WARNING: Divide by zero avoided in SimplifyExpr for expr:\n");
					this->Dump(0);
					this->GetParentFunc()->Dump();
					Simplified = false;
				}
				else {
					FinalValue = LeftValue / RightValue;
				}
			}
			else if ((SMP_U_LEFT_SHIFT == CurrOperator) || (SMP_S_LEFT_SHIFT == CurrOperator)) {
				FinalValue = LeftValue << RightValue;
			}
			else if ((SMP_U_RIGHT_SHIFT == CurrOperator) || (SMP_S_RIGHT_SHIFT == CurrOperator)) {
				FinalValue = LeftValue >> RightValue;
			}
			else if (SMP_BITWISE_AND == CurrOperator) {
				FinalValue = LeftValue & RightValue;
			}
			else if (SMP_BITWISE_OR == CurrOperator) {
				FinalValue = LeftValue | RightValue;
			}
			else if (SMP_BITWISE_XOR == CurrOperator) {
				FinalValue = LeftValue ^ RightValue;
			}
			else {
				Simplified = false;
			}
			if (Simplified) {
				STARSOpndTypePtr FinalOp = this->GetParentInst()->MakeImmediateOpnd(FinalValue);
				if (nullptr == ParentExpr) {
					// This is the highest level expr.
					this->SetOperator(SMP_ASSIGN);
					this->SetLeftOperand(FinalOp);
				}
				else {
					// Are we the left tree of the ParentExpr?
					if (this == ParentExpr->GetLeftTree()) {
						ParentExpr->SetLeftOperand(FinalOp);
						ParentExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
					}
					else {
						assert(this == ParentExpr->GetRightTree());
						ParentExpr->SetRightOperand(FinalOp);
						ParentExpr->SetRightPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
					}
				}
				return true; // Nothing more can be done at this level of the expr.
			}
		}
		if (LeftNullTree) {
			if (ConstLeftOperand) {
				STARS_uval_t LeftValue = this->GetConstLeftOperand()->GetImmedValue();
				SMPoperator CurrOperator = this->GetOperator();
				// Simplify multiplication by 0 or 1, division by 1, addition or subtraction of 0.
				if (1 == LeftValue) {
					if ((SMP_U_MULTIPLY == CurrOperator) || (SMP_S_MULTIPLY == CurrOperator)) {
						// Multiply by 1, produces right tree as result.
						// We can simplify the current expr by making it just be the RightTree or RightOperand.
						RightOperandLifted = this->ElevateRightSide(ParentExpr);
					}
				}
				else if (0 == LeftValue) {
					if ((SMP_U_MULTIPLY <= CurrOperator) && (SMP_S_DIVIDE >= CurrOperator)) {
						// Multiply by 0, or 0 divided by something, produces zero as result.
						// We can simplify the current expr by making it just be the LeftOperand, zero.
						LeftOperandLifted = this->ElevateLeftSide(ParentExpr);
						assert(LeftOperandLifted || (SMP_ASSIGN == this->GetOperator())); // not lifted => we assign zero instead of mul/div
						LeftNullTree = (!this->HasLeftSubTree());
						// Delete the right tree if it exists.
						ConstRightOperand = false;
						if (nullptr != this->GetRightTree()) {
							delete this->GetRightTree();
							this->SetRightTree(nullptr);
						}
						return true;
					}
					else if (SMP_ADD == CurrOperator) {
						// Addition of 0, produces right tree as result.
						// We can simplify the current expr by making it just be the RightTree or RightOperand.
						RightOperandLifted = this->ElevateRightSide(ParentExpr);
					}
				}
			}
		}
		if (!RightOperandLifted && RightNullTree && !LeftOperandLifted) {
			if (ConstRightOperand) {
				STARS_uval_t RightValue = this->GetConstRightOperand()->GetImmedValue();
				SMPoperator CurrOperator = this->GetOperator();
				// Simplify multiplication by 0 or 1, division by 1, addition or subtraction of 0,
				//  and transform shifts into multiplies or divides.
				if (0 == RightValue) {
					if ((SMP_U_MULTIPLY == CurrOperator) && (SMP_S_MULTIPLY == CurrOperator)) {
						// Multiply by 0, produces zero as result.
						// We can simplify the current expr by making it just be the RightOperand, zero.
						RightOperandLifted = this->ElevateRightSide(ParentExpr);
					}
					else if ((SMP_ADD == CurrOperator) || (SMP_SUBTRACT == CurrOperator)) {
						// Addition or subtraction of 0, produces left tree as result.
						// We can simplify the current expr by making it just be the LeftTree or LeftOperand.
						LeftOperandLifted = this->ElevateLeftSide(ParentExpr);
						LeftNullTree = (!this->HasLeftSubTree());
					}
					else if ((SMP_U_DIVIDE == CurrOperator) || (SMP_S_DIVIDE == CurrOperator)) {
						// Divide by 0. Emit error message.
						SMP_msg("ERROR: Divide by zero after constant propagation at %llx\n", (uint64_t) this->GetParentInst()->GetAddr());
					}
				}
				else if ((SMP_U_LEFT_SHIFT <= CurrOperator) && (SMP_S_RIGHT_SHIFT >= CurrOperator)) {
					// Convert constant shift counts into multiply or divide operations.
					if (RightValue < (8 * sizeof(STARS_uval_t))) { // don't overflow
						int ShiftCount = (int) RightValue;
						RightValue = 1;
						while (ShiftCount > 16) { // C/C++ limit on shifting
							RightValue = (RightValue << 16);
							ShiftCount -= 16;
						}
						RightValue = (RightValue << ShiftCount);
						if (SMP_U_LEFT_SHIFT == CurrOperator)
							CurrOperator = SMP_U_MULTIPLY;
						else if (SMP_S_LEFT_SHIFT == CurrOperator)
							CurrOperator = SMP_S_MULTIPLY;
						else if (SMP_U_RIGHT_SHIFT == CurrOperator)
							CurrOperator = SMP_U_DIVIDE;
						else {
							assert(SMP_S_RIGHT_SHIFT == CurrOperator);
							CurrOperator = SMP_S_DIVIDE;
						}
						STARSOpndTypePtr NewRightOperand = this->GetParentInst()->MakeImmediateOpnd(RightValue);
						this->SetRightOperand(NewRightOperand);
						this->SetOperator(CurrOperator);
					}
				}
				else if (1 == RightValue) {
					if ((SMP_U_MULTIPLY <= CurrOperator) && (SMP_S_DIVIDE >= CurrOperator)) {
						// Multiply or divide by 1, produces left tree as result.
						// We can simplify the current expr by making it just be the RightTree or RightOperand.
						LeftOperandLifted = this->ElevateLeftSide(ParentExpr);
						LeftNullTree = (!this->HasLeftSubTree());
					}
				}
				// Handle the multiply by stride and then divide by stride, or vice versa, that are common
				//  in loop iteration count and memory range analyses, e.g. (x / 8) * 8.
				if (!LeftNullTree && (RightValue > 1) && ((SMP_U_MULTIPLY <= CurrOperator) && (SMP_S_DIVIDE >= CurrOperator))) {
					SMPoperator LeftOperator = this->GetLeftTree()->GetOperator();
					if ((SMP_U_MULTIPLY <= LeftOperator) && (SMP_S_DIVIDE >= LeftOperator)) {
						STARSOpndTypePtr LeftRightOp = this->GetLeftTree()->GetConstRightOperand();
						if ((nullptr != LeftRightOp) && (!this->GetLeftTree()->HasRightSubTree()) && LeftRightOp->IsImmedOp()) {
							// We have (x oper1 const1) oper2 const2 where oper1 and oper2 are multiply or divide.
							STARS_uval_t LeftRightValue = LeftRightOp->GetImmedValue();
							if (LeftRightValue == RightValue) {
								// We have (x oper1 const1) oper2 const1 (same consts) where oper1 and oper2 are multiply or divide.
								bool LeftMultiply = ((SMP_U_MULTIPLY == LeftOperator) || (SMP_S_MULTIPLY == LeftOperator));
								bool RightMultiply = ((SMP_U_MULTIPLY == CurrOperator) || (SMP_S_MULTIPLY == CurrOperator));
								if (LeftMultiply != RightMultiply) { // Inverse operations on equal constants.
									if (this->GetLeftTree()->HasLeftSubTree()) {
										// We need to elevate the left child of the left child to our parent location (two levels up).
										//  See drawing and comment for left operand case.
										LeftOperandLifted = this->GetLeftTree()->ElevateLeftSide(this);
										// assert(LeftOperandLifted); // Could lift a tree, not an operand
										LeftOperandLifted = this->ElevateLeftSide(ParentExpr);
										// assert(LeftOperandLifted); // Could lift a tree, not an operand
										LeftNullTree = (!this->HasLeftSubTree());
									}
									else {
										// We need to elevate the left operand of the left child to our parent location (two levels up).
										// We have something like:
										//       MULTIPLY
										//          |
										//      +---+----+
										//      |        |
										//     DIV       8
										//      |
										//    +----+
										//    |    |
										//   Reg   8
										//
										//  We want to elevate Reg to replace the entire Expr that "this" points to.
										//  This can be done with two consecutive ElevateLeftSide calls, the first of which
										//  replaces (Reg DIV 8) by Reg, and the second of which replaces (Reg * 8) with Reg.
										LeftOperandLifted = this->GetLeftTree()->ElevateLeftSide(this);
										// assert(LeftOperandLifted); // Could lift a tree, not an operand
										LeftOperandLifted = this->ElevateLeftSide(ParentExpr);
										// assert(LeftOperandLifted); // Could lift a tree, not an operand
										LeftNullTree = true;   // NOTE: Need to destroy subtrees in Elevate methods to avoid leaks.
									}
								}
							}
						}
					}
				} // end of multiply/divide pairs simplification
				
				// Handle cascading additions and subtractions
				if (!LeftNullTree && ((SMP_SUBTRACT == CurrOperator) || (SMP_ADD == CurrOperator))) {
					SMPoperator LeftOperator = this->GetLeftTree()->GetOperator();
					if ((SMP_ADD == LeftOperator) || (SMP_SUBTRACT == LeftOperator)) {
						STARSOpndTypePtr LeftRightOp = this->GetLeftTree()->GetConstRightOperand();
						if ((nullptr != LeftRightOp) && (!this->GetLeftTree()->HasRightSubTree()) && LeftRightOp->IsImmedOp()) {
							// We have (x oper1 const1) oper2 const2 where oper1 and oper2 are add or subtract.
							STARS_uval_t LeftRightValue = LeftRightOp->GetImmedValue();
							STARS_uval_t SumValue = 0;
							if (SMP_ADD == LeftOperator) {
								SumValue = LeftRightValue;
							}
							else { // SMP_SUBTRACT
								SumValue -= LeftRightValue;
							}
							if (SMP_ADD == CurrOperator) {
								SumValue += RightValue;
							}
							else { // SMP_SUBTRACT
								SumValue -= RightValue;
							}
							STARS_sval_t SignedSumValue = (STARS_sval_t)SumValue;
							if (SignedSumValue < 0) {
								// Negative result. Make CurrOperator SMP_SUBTRACT of a positive value.
								SignedSumValue = (0 - SignedSumValue);
								this->SetOperator(SMP_SUBTRACT);
							}
							else {
								// Positive result. Make CurrOperator SMP_ADD of the positive value.
								this->SetOperator(SMP_ADD);
							}
							this->SetLeftUseAddr(this->GetLeftTree()->GetLeftUseAddr());
							this->SetLeftSSANum(this->GetLeftTree()->GetLeftSSANum());
							if (this->GetLeftTree()->HasLeftSubTree()) {
								LeftOperandLifted = this->GetLeftTree()->ElevateLeftSide(this);
							}
							else {
								this->SetLeftOperand(this->GetLeftTree()->GetConstLeftOperand());
								LeftNullTree = true;
							}
							SumValue = (STARS_uval_t)SignedSumValue;
							this->SetRightOperand(this->GetParentInst()->MakeImmediateOpnd(SumValue));
						}
					}
				} // end of cascading additions and subtractions
			}
		}
	} // end if (LeftNullTree || RightNullTree)
	else {
		// Look for the special case of simplifying address ranges, e.g. if we loop from
		//  RDI + 4 up to RDI + 128, then the iteration count expr will be ((RDI + 128) - (RDI + 4)).
		//  The address register drops out of the expr and the final answer is 124.
		if (SMP_SUBTRACT == this->GetOperator() && (!this->GetLeftTree()->HasRightSubTree()) && (!this->GetRightTree()->HasRightSubTree())) {
			// Check for the LeftTree and RightTree having the same LeftOperand register.
			bool LeftTreeHasLeftOperand = (!(this->GetLeftTree()->HasLeftSubTree()));
			bool RightTreeHasLeftOperand = (!(this->GetRightTree()->HasLeftSubTree()));
			bool HasLeftRegOps = (LeftTreeHasLeftOperand && this->GetLeftTree()->GetConstLeftOperand()->IsRegOp())
				&& (RightTreeHasLeftOperand && this->GetRightTree()->GetConstLeftOperand()->IsRegOp());
			if (HasLeftRegOps) {
				STARS_regnum_t LeftReg = this->GetLeftTree()->GetConstLeftOperand()->GetReg();
				STARS_regnum_t RightReg = this->GetRightTree()->GetConstLeftOperand()->GetReg();
				if (LeftReg == RightReg) {
					// The registers will drop out of the expression.
					//  We have ((Reg op RightOp1) - (Reg op RightOp2))
					//  What to do next depends on the operators and whether we have immediate RightOps
					SMPoperator LeftOperator = this->GetLeftTree()->GetOperator();
					SMPoperator RightOperator = this->GetRightTree()->GetOperator();
					if (SMP_ADD == LeftOperator) {
						// We need RightOp1 - RightOp2 if RightOperator is addition,
						//  and RightOp1 + RightOp2 if RightOperator is subtraction.
						if ((SMP_ADD == RightOperator) || (SMP_SUBTRACT == RightOperator)) {
							// Make the LeftTree->RightOperand into the new left tree,
							//  and the RightTree->RightOperand into the new right tree,
							//  leaving SMP_SUBTRACT as the parent operator.
							LeftOperandLifted = this->GetLeftTree()->ElevateRightSide(this);
							RightOperandLifted = this->GetRightTree()->ElevateRightSide(this);
							assert(LeftOperandLifted && RightOperandLifted);
							if (SMP_SUBTRACT == RightOperator) {
								// We simplified ((Reg + RightOp1) - (Reg - RightOp2))
								//  so the answer is (RightOp1 + RightOp2). Change parent operator
								//  to SMP_ADD.
								this->SetOperator(SMP_ADD);
							}
						}						
					}
					else if (SMP_SUBTRACT == LeftOperator) {
						// We need (-RightOp1) - RightOp2 if RightOperator is addition,
						//  and RightOp2 - RightOp1 if RightOperator is subtraction.
						// We will only deal with the negation case if we have a constant RightOp1.
						if (SMP_SUBTRACT == RightOperator) {
							// Make the LeftTree->RightOperand into the new right operand,
							//  and the RightTree->RightOperand into the new left operand,
							//  leaving SMP_SUBTRACT as the parent operator.
							STARSOpndTypePtr LeftRightOp = this->GetLeftTree()->GetConstRightOperand()->clone();
							STARSOpndTypePtr RightRightOp = this->GetRightTree()->GetConstRightOperand()->clone();
							this->SetLeftOperand(RightRightOp);
							this->SetLeftUseAddr(this->GetRightTree()->GetRightUseAddr());
							this->SetRightOperand(LeftRightOp);
							this->SetRightUseAddr(this->GetLeftTree()->GetRightUseAddr());
							LeftOperandLifted = RightOperandLifted = true;
						}
						else if ((SMP_ADD == RightOperator) && this->GetLeftTree()->GetConstRightOperand()->IsImmedOp()) {
							// Take ((Reg - immed) - (Reg + operand)) and produce (-immed - operand) by negating the
							//  left immediate value, substituting it for the left tree, and raising the right tree's
							//  right operand and leaving the parent operator as SMP_SUBTRACT.
							STARS_uval_t LeftRightValue = this->GetLeftTree()->GetConstRightOperand()->GetImmedValue();
							LeftRightValue = (0 - LeftRightValue); // negate RightOp1
							STARSOpndTypePtr NewLeftOp = this->GetLeftTree()->GetParentInst()->MakeImmediateOpnd(LeftRightValue);
							STARS_ea_t NewLeftUseAddr = this->GetLeftTree()->GetParentInst()->GetAddr();
							RightOperandLifted = this->GetRightTree()->ElevateRightSide(this);
							assert(RightOperandLifted);
							this->SetLeftOperand(NewLeftOp);
							this->SetLeftUseAddr(NewLeftUseAddr);
							LeftOperandLifted = true;
						}
					}
				}
			}
			if (LeftOperandLifted || RightOperandLifted) {
				// See if our simplifications left us with constants.
				if (!this->HasLeftSubTree() && (!this->HasRightSubTree())) {
					if (this->GetConstLeftOperand()->IsImmedOp() && this->GetConstRightOperand()->IsImmedOp()) {
						bool success = this->SimplifyExpr(ParentExpr);
						assert(success);
					}
				}
			}
		}
	}

	if (SMP_ASSIGN == this->GetOperator()) {
		if (this->HasLeftSubTree()) {
#if 0  // might have copied RightExpr to LeftExpr and have a dead RightExpr
			assert(!this->HasRightSubTree());
#endif
			RootLeftExprLifted = this->ElevateLeftSide(nullptr);
			assert(RootLeftExprLifted);  // now fall through to further simplifications
			RootLeftExprLifted = false; // reset so that we don't delete the new LeftTree as if it has been lifted and discarded
		}
		else {
			// Only the LeftOperand is valid. This is an InitExpr or an Expr that has been reduced to one operand.
			// If the current expr has a parent expr, then we can elevate our LeftOperand.
			if (nullptr == ParentExpr) {
				return false; // nothing to simplify
			}
			else {
				// Are we the left tree of the ParentExpr?
				if (this == ParentExpr->GetLeftTree()) {
					// ParentExpr should have our LeftOperand (our only valid operand) as its LeftOperand, no left tree.
					ParentExpr->SetLeftOperand(this->GetLeftOperand());
					ParentExpr->SetLeftUseAddr(this->GetLeftUseAddr());
					ParentExpr->SetLeftSSANum(this->GetLeftSSANum());
					ParentExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
				}
				else {
					assert(this == ParentExpr->GetRightTree());
					// ParentExpr should have our LeftOperand (our only valid operand) as its RightOperand, no right tree.
					ParentExpr->SetRightOperand(this->GetLeftOperand());
					ParentExpr->SetRightUseAddr(this->GetLeftUseAddr());
					ParentExpr->SetRightSSANum(this->GetLeftSSANum());
					ParentExpr->SetRightPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
				}
				return true; // No further simplifications to make
			}
		}
	}

	return (LeftOperandLifted || RightOperandLifted || RootLeftExprLifted || NegativeAddendSimplified);
} // end of STARSExpression::SimplifyExpr()

// Expr simplifies to RightExpr or RightOperand, so raise it into ParentExpr.
bool STARSExpression::ElevateRightSide(STARSExpression *ParentExpr) {
	bool RightOperandLifted = false; // was RightOperand lifted up into ParentExpr?
	if (nullptr != ParentExpr) {
		// Is this the left or right subtree of ParentExpr?
		if (ParentExpr->HasLeftSubTree() && (this == ParentExpr->GetLeftTree())) {
			// New LeftTree of ParentExpr is our RightTree, or new LeftOperand of
			//  ParentExpr is our RightOperand.
			if (this->HasRightSubTree()) {
				ParentExpr->SetLeftTree(this->GetRightTree());
			}
			else { // we have only a RightOperand
				ParentExpr->SetLeftOperand(this->GetRightOperand());
				ParentExpr->SetLeftUseAddr(this->GetRightUseAddr());
				ParentExpr->SetLeftSSANum(this->GetRightSSANum());
				ParentExpr->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr());
				RightOperandLifted = true;
			}
		}
		else if (ParentExpr->HasRightSubTree() && (this == ParentExpr->GetRightTree())) {
			// New RightTree of ParentExpr is our RightTree, or new RightOperand of
			//  ParentExpr is our RightOperand.
			if (this->HasRightSubTree()) {
				ParentExpr->SetRightTree(this->GetRightTree());
			}
			else { // we have only a RightOperand
				ParentExpr->SetRightOperand(this->GetRightOperand());
				ParentExpr->SetRightUseAddr(this->GetRightUseAddr());
				ParentExpr->SetRightSSANum(this->GetRightSSANum());
				ParentExpr->SetRightPreLoopDefAddr(this->GetRightPreLoopDefAddr());
				RightOperandLifted = true;
			}
		}
		else {
			assert(false);
		}
	}
	else { // this is the root expression
		// We no longer have an expression, just an operand. SMP_ASSIGN will mean to use the LeftOperand.
		if (!this->HasRightSubTree()) {
			// We no longer have an expression, just an operand. SMP_ASSIGN will mean to use the LeftOperand.
			this->SetOperator(SMP_ASSIGN);
			this->SetLeftOperand(this->GetRightOperand());
			this->SetLeftUseAddr(this->GetRightUseAddr());
			this->SetLeftSSANum(this->GetRightSSANum());
			this->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr());
			this->SetRightOperand(nullptr);
		}
		else {
			// Copy our RightSubTree into *this.
			STARSExpression *RightHandSide = this->GetRightTree();
			assert(nullptr != RightHandSide);
			this->SetOperator(RightHandSide->GetOperator());
			if (RightHandSide->HasLeftSubTree()) {
				this->SetLeftTree(RightHandSide->GetLeftTree());
			}
			else {
				this->SetLeftOperand(RightHandSide->GetLeftOperand());
				this->SetLeftUseAddr(RightHandSide->GetLeftUseAddr());
				this->SetLeftSSANum(RightHandSide->GetLeftSSANum());
				this->SetLeftPreLoopDefAddr(RightHandSide->GetLeftPreLoopDefAddr());
			}
			if (RightHandSide->HasRightSubTree()) {
				this->SetRightTree(RightHandSide->GetRightTree());
			}
			else {
				this->SetRightOperand(RightHandSide->GetRightOperand());
				this->SetRightUseAddr(RightHandSide->GetRightUseAddr());
				this->SetRightSSANum(RightHandSide->GetRightSSANum());
				this->SetRightPreLoopDefAddr(RightHandSide->GetRightPreLoopDefAddr());
				RightOperandLifted = true;
			}
		}
	}
	return RightOperandLifted;
} // end of STARSExpression::ElevateRightSide()

// Expr simplifies to LeftExpr or LeftOperand, so raise it into ParentExpr.
bool STARSExpression::ElevateLeftSide(STARSExpression *ParentExpr) {
	bool LeftOperandLifted = false; // was LeftOperand lifted up into ParentExpr?
	if (nullptr != ParentExpr) {
		// Is this the left or right subtree of ParentExpr?
		if (ParentExpr->HasLeftSubTree() && (this == ParentExpr->GetLeftTree())) {
			// New LeftTree of ParentExpr is our LeftTree, or new LeftOperand of
			//  ParentExpr is our LeftOperand.
			if (this->HasLeftSubTree()) {
				ParentExpr->SetLeftTree(this->GetLeftTree());
			}
			else { // we have only a LeftOperand
				ParentExpr->SetLeftTree(nullptr);
				ParentExpr->SetLeftOperand(this->GetLeftOperand());
				ParentExpr->SetLeftUseAddr(this->GetLeftUseAddr());
				ParentExpr->SetLeftSSANum(this->GetLeftSSANum());
				ParentExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
				LeftOperandLifted = true;
			}
		}
		else if (ParentExpr->HasRightSubTree() && (this == ParentExpr->GetRightTree())) {
			// New RightTree of ParentExpr is our LeftTree, or new RightOperand of
			//  ParentExpr is our LeftOperand.
			if (this->HasLeftSubTree()) {
				ParentExpr->SetRightTree(this->GetLeftTree());
			}
			else { // we have only a LeftOperand
				ParentExpr->SetRightTree(nullptr);
				ParentExpr->SetRightOperand(this->GetLeftOperand());
				ParentExpr->SetRightUseAddr(this->GetLeftUseAddr());
				ParentExpr->SetRightSSANum(this->GetLeftSSANum());
				ParentExpr->SetRightPreLoopDefAddr(this->GetLeftPreLoopDefAddr());
				LeftOperandLifted = true;
			}
		}
		else {
			assert(false);
		}
		if (LeftOperandLifted) {
			ParentExpr->SetParentInst(this->GetParentInst());
		}
	}
	else { // this is the root expression
		if (!this->HasLeftSubTree()) {
			// We no longer have an expression, just an operand. SMP_ASSIGN will mean to use the LeftOperand.
			this->SetOperator(SMP_ASSIGN);
		}
		else {
			// Copy our LeftSubTree into *this.
			STARSExpression *LeftHandSide = this->GetLeftTree();
			assert(nullptr != LeftHandSide);
			this->SetOperator(LeftHandSide->GetOperator());
			if (LeftHandSide->HasRightSubTree()) {
				this->SetRightTree(LeftHandSide->GetRightTree());
			}
			else {
				this->SetRightOperand(LeftHandSide->GetRightOperand());
				this->SetRightUseAddr(LeftHandSide->GetRightUseAddr());
				this->SetRightSSANum(LeftHandSide->GetRightSSANum());
				this->SetRightPreLoopDefAddr(LeftHandSide->GetRightPreLoopDefAddr());
			}
			if (LeftHandSide->HasLeftSubTree()) {
				this->SetLeftTree(LeftHandSide->GetLeftTree());
			}
			else {
				this->SetLeftOperand(LeftHandSide->GetLeftOperand());
				this->SetLeftUseAddr(LeftHandSide->GetLeftUseAddr());
				this->SetLeftSSANum(LeftHandSide->GetLeftSSANum());
				this->SetLeftPreLoopDefAddr(LeftHandSide->GetLeftPreLoopDefAddr());
			}
			LeftOperandLifted = true;
		}
	}
	return LeftOperandLifted;
} // end of STARSExpression::ElevateLeftSide()

// Replace operands with their definitions, which might be sub-expressions
//  Stop each expansion at incoming arg definition, or
//  at DEFs of the form name := immediate value. If we must stop before that point,
//  e.g. at a Phi function or a non-stack memory read (name := memory value), return false.
//  Otherwise, return true.
// Argument "changed" should be initialized to false before the first call to ExpandExpr(),
//  and it will be left unchanged or set to true but never reset to false.
// When the induction var is the LeftOperand, we expand the RightSideOnly.
bool STARSExpression::ExpandExpr(STARS_ea_t UseAddr, size_t LoopIndex, bool RightSideOnly, bool StopOnIV, bool StopOnLoopBoundary, bool RecordLoopRegs, bool InitCase, 
	set<int> &LoopRegHashes, bool &StoppedOnIV, bool &changed, set<STARS_ea_t> &StackPtrCopySet, int &DepthCounter) {
	bool success = true;
	StoppedOnIV = false;
	++DepthCounter;
	if (STARS_EXPR_CALL_DEPTH_LIMIT < DepthCounter) {
		success = false;
		--DepthCounter;
		SMP_msg("INFO: ExpandExpr() stopped at DepthCounter %d UseAddr %llx\n", DepthCounter, (uint64_t) UseAddr);
		return success;
	}

	if (!RightSideOnly) {
		if (this->HasLeftSubTree()) {
			STARS_ea_t CurrUseAddr = this->GetLeftTree()->GetParentInst()->GetAddr();
			success = this->GetLeftTree()->ExpandExpr(CurrUseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
		}
		else {
			// Expand LeftOperand.
			success = this->ExpandOperand(LoopIndex, true, StopOnIV, this->GetLeftUseAddr(), StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
		}
	}

	if (success) {
		if (this->HasRightSubTree()) {
			STARS_ea_t CurrUseAddr = this->GetRightTree()->GetParentInst()->GetAddr();
			success = this->GetRightTree()->ExpandExpr(CurrUseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
		}
		else {
			// Expand RightOperand.
			success = this->ExpandOperand(LoopIndex, false, StopOnIV, this->GetRightUseAddr(), StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
		}
	}

	--DepthCounter;
	return success;
} // end of STARSExpression::ExpandExpr()

// Expand LeftOperand (if Left == true) or RightOperand into a new subtree using its DEF.
// return false if expansion is forced to stop before constant DEF or SSA #0 DEF.
bool STARSExpression::ExpandOperand(std::size_t LoopIndex, bool Left, bool StopOnIV, STARS_ea_t UseAddr, bool StopOnLoopBoundary, bool RecordLoopRegs, bool InitCase, 
	set<int> &LoopRegHashes, bool &StoppedOnIV, bool &changed, set<STARS_ea_t> &StackPtrCopySet, int &DepthCounter) {
	bool success = true;
	bool UseFP = this->GetParentFunc()->UsesFramePointer();
	STARSOpndTypePtr SearchOp = (Left) ? CloneIfSubwordReg(this->GetConstLeftOperand()) : CloneIfSubwordReg(this->GetConstRightOperand());
	if (SearchOp == nullptr) {
		--DepthCounter;
		return true; // expansion ends cleanly with no operand to expand
	}

	++DepthCounter;
	if (STARS_EXPR_CALL_DEPTH_LIMIT < DepthCounter) {
		success = false;
		--DepthCounter;
		SMP_msg("INFO: ExpandOperand() stopped at DepthCounter %d UseAddr %llx\n", DepthCounter, (uint64_t)UseAddr);
		return success;
	}

	STARSInductionVarFamilyList::iterator IVFamilyIter;
	size_t FamilyIndex;

	// Check if operand meets criteria for ending the expansion.
	if (SearchOp->IsVoidOp()) {
		success = true;
	}
	else if (SearchOp->IsImmedOp()) {
		success = true;
		STARS_uval_t ImmedVal = SearchOp->GetImmedValue();
		bool GlobalStaticRange = IsImmedGlobalAddress((STARS_ea_t) ImmedVal);
		if (GlobalStaticRange) {
			StackPtrCopySet.insert(UseAddr); // add global static mem ops to stack ptr copies
			SMP_msg("INFO: GLOBAL mem def found at %llx in ExpandOperand()\n", (uint64_t) UseAddr);
		}
	}
	else if (SearchOp->IsMemOp() && (SearchOp->GetSegReg() == STARS_x86_R_cs)) {
		// Cannot go further with CS-relative mem read. !!!!****!!!! Could we fetch a constant value?
		StackPtrCopySet.insert(UseAddr); // add global static mem ops to stack ptr copies
		SMP_msg("INFO: GLOBAL CS-relative mem def found at %llx in ExpandOperand()\n", (uint64_t) UseAddr);
		success = true;
	}
	else if (SearchOp->IsMemOp() && (!MDIsDirectStackAccessOpnd(SearchOp, UseFP))) {
		if (SearchOp->IsStaticMemOp()) {
			StackPtrCopySet.insert(UseAddr); // add global static mem ops to stack ptr copies
			SMP_msg("INFO: GLOBAL mem def found at %llx in ExpandOperand()\n", (uint64_t)UseAddr);
		}
		list<STARS_ea_t> MemDefAddrs;
		this->GetParentFunc()->ResetProcessedBlocks();
		set<STARS_regnum_t> AddressRegs;
		SearchOp->GetAddressRegs(AddressRegs);
		set<int> IntAddressRegs; // convert to int to help g++ allocator problem on packed enum types
		for (set<STARS_regnum_t>::const_iterator RegIter = AddressRegs.cbegin(); RegIter != AddressRegs.cend(); ++RegIter) {
			pair<set<int>::iterator, bool> InsertResult = IntAddressRegs.insert((int) (*RegIter));
		}
		SMPBasicBlock *UseAddrBlock = this->GetParentFunc()->GetBlockFromInstAddr(UseAddr);
		assert(nullptr != UseAddrBlock);
		this->GetParentFunc()->FindMatchingMemDEFAddrs(UseAddr, UseAddrBlock, SearchOp, MemDefAddrs, IntAddressRegs);
		IntAddressRegs.clear();
		success = (1 >= MemDefAddrs.size());  // reached top of function (size == 0), or found a single MemDef (size == 1)
		SMP_msg("INFO: SPARK: MemDefAddrs set is of size %zu at %llx\n", MemDefAddrs.size(), (uint64_t) UseAddr);
		bool UniqueMemDefAddr = (1 == MemDefAddrs.size());
		bool ReplaceMemOpndWithMoveSource = (UniqueMemDefAddr && global_STARS_program->ShouldSTARSTranslateToSPARKAda());
#if 0
		if (!success) { // Replace with symbolic mem use and expand.
#else
		if (!ReplaceMemOpndWithMoveSource) { // in either case, replace with symbolic mem use and expand.
#endif
#if 1
			success = true; // traced as far as we can go

#else	// Tracing mem address registers can explode run time.

			// Replace the MemDefOp with a ReadMem64 expr based on the address regs.
			// First, we need a UseIter for the SearchOp, but only stack memory ops are in the Use set,
			//  so add this operand to a special SymbolicMemUse set.
			SMPInstr *UseInst = this->GetParentFunc()->GetInstFromAddr(UseAddr);
			assert(nullptr != UseInst);
			UseInst->AddSymbolicMemUse(SearchOp, UNINIT, SMP_SSA_UNINIT);
			STARSDefUseIter MemUseIter = UseInst->FindSymbolicMemUse(SearchOp);
			assert(UseInst->GetLastSymbolicMemUse() != MemUseIter);
			// Now, use the MemUseIter to create a symbolic memory expression.
			STARSExpression *ReadMemExpr = new STARSExpression(MemUseIter, UseInst);
			// Replace this->LeftOperand or this->RightOperand with a subtree.
			if (Left) {
				this->SetLeftOperand(nullptr);
				this->SetLeftTree(ReadMemExpr);
				success = this->GetLeftTree()->ExpandExpr(UseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
			}
			else {
				this->SetRightOperand(nullptr);
				this->SetRightTree(ReadMemExpr);
				success = this->GetRightTree()->ExpandExpr(UseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
			}
			changed = true;
#endif
		}
		else {
			// Replace the current operand with the MemDefAddr right-hand-side move source operand and recurse.
			STARS_ea_t NewDefAddr = MemDefAddrs.front();
			SMPInstr *NewDefInst = this->GetParentFunc()->GetInstFromAddr(NewDefAddr);
			STARSOpndTypePtr RHSOperand;
			success = NewDefInst->IsSimpleCopy(RHSOperand);
			if (success) {
				int NewBlockNum = this->GetParentFunc()->GetBlockNumFromInstAddr(NewDefAddr);
				bool WentBeforeLoop = !this->GetParentFunc()->IsBlockInLoop(NewBlockNum, LoopIndex);
				if (WentBeforeLoop && StopOnLoopBoundary) {
					// Do not replace USE with its DEF, as DEF precedes the loop. Stop
					//  inside the loop and declare victory.
					// !!!!****!!!! Do we need to replace the MemDefOp with a symbolic ReadMem64?
					return true;
				}
				STARSOpndTypePtr NewSearchOp = CloneIfSubwordReg(RHSOperand);
				STARSDefUseIter UseIter = NewDefInst->FindUse(NewSearchOp);
				assert(UseIter != NewDefInst->GetLastUse());
				int UseSSANum = UseIter->GetSSANum();
				if (Left)
					this->SetLeftSSANum(UseSSANum);
				else
					this->SetRightSSANum(UseSSANum);
				this->SetParentInst(NewDefInst);
				// Replace current operand with new operand.
				if (Left) {
					this->SetLeftOperand(RHSOperand);
					this->SetLeftUseAddr(NewDefAddr);
				}
				else {
					this->SetRightOperand(RHSOperand);
					this->SetRightUseAddr(NewDefAddr);
				}
				changed = true;

				// Recurse into new operand at NewDefAddr.
				success = this->ExpandOperand(LoopIndex, Left, StopOnIV, NewDefAddr, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
			}
		}
	}
	else if (!MDIsDataFlowOpnd(SearchOp, UseFP)) {
		success = false;
		SMP_msg("SPARK: Non-DataFlowOpnd: ");
		PrintOperand(SearchOp);
		SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at non-DataFlowOpnd at %llx\n", (uint64_t) UseAddr);
	}
	else { // we found a reg or direct stack access operand
		// Find DEF instruction for operand.
		CanonicalizeOpnd(SearchOp);
		int SSANum = (Left) ? this->GetLeftSSANum() : this->GetRightSSANum();
		SMPBasicBlock *CurrBlock = this->GetParentFunc()->GetBlockFromInstAddr(UseAddr);
		bool LocalName = CurrBlock->IsLocalName(SearchOp);
		STARS_ea_t DefAddr = CurrBlock->GetDefAddrFromUseAddr(SearchOp, UseAddr, SSANum, LocalName);

		success = this->ExpandOperandHelper(DefAddr, SearchOp, LoopIndex, Left, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
	}

	if (success) {
		// Inherit PreLoopDefAddr.
		if (Left && (STARS_BADADDR == this->GetLeftPreLoopDefAddr()) && this->HasLeftSubTree()) {
			// We expanded our left operand into an expr. Our PreLoopDefAddr is not informative.
			//  Inherit the LeftPreLoopDefAddr of the LeftTree we expanded our LeftOperand into.
			this->SetLeftPreLoopDefAddr(this->GetLeftTree()->GetLeftPreLoopDefAddr());
		}
		else if (!Left && (STARS_BADADDR == this->GetRightPreLoopDefAddr()) && this->HasRightSubTree()) {
			// We expanded our right operand into an expr. Our PreLoopDefAddr is not informative.
			//  Inherit the LeftPreLoopDefAddr of the RightTree we expanded our RightOperand into.
			this->SetRightPreLoopDefAddr(this->GetRightTree()->GetLeftPreLoopDefAddr());
		}
	}
	--DepthCounter;
	return success;
} // end of STARSExpression::ExpandOperand()

// recursive helper for ExpandOperand()
bool STARSExpression::ExpandOperandHelper(STARS_ea_t DefAddr, const STARSOpndTypePtr &SearchOp, size_t LoopIndex, bool Left, bool StopOnIV, bool StopOnLoopBoundary, bool RecordLoopRegs, bool InitCase, 
	set<int> &LoopRegHashes, bool &StoppedOnIV, bool &changed, set<STARS_ea_t> &StackPtrCopySet, int &DepthCounter) {
	bool success = true;
	bool UseFP = this->GetParentFunc()->UsesFramePointer();
	// See if we have crossed the beginning-of-loop boundary for the first time.
	STARS_ea_t CurrLoopDefAddr = Left ? this->GetLeftPreLoopDefAddr() : this->GetRightPreLoopDefAddr();
	STARSInductionVarFamilyList::iterator IVFamilyIter;
	size_t FamilyIndex;

	++DepthCounter;
	if (STARS_EXPR_CALL_DEPTH_LIMIT < DepthCounter) {
		success = false;
		--DepthCounter;
		SMP_msg("INFO: ExpandOperandHelper() stopped at DepthCounter %d DefAddr %llx\n", DepthCounter, (uint64_t) DefAddr);
		return success;
	}

	if (STARS_IsSSAMarkerPseudoID(DefAddr)) {
		success = true;  // DEF is in SSA marker, such as an incoming arg; expansion terminates successfully.
		if (STARS_BADADDR == CurrLoopDefAddr) {
			// Crossed from within the loop to the SSA Marker.
			if (Left)
				this->SetLeftPreLoopDefAddr(DefAddr);
			else
				this->SetRightPreLoopDefAddr(DefAddr);
		}
	}
	else if ((STARS_BADADDR == DefAddr) || STARS_IsLiveInPseudoID(DefAddr)) {
		success = false;  // bad addr, or other non-instruction address.
		SMP_msg("SPARK: Bad DefAddr SearchOp:");
		PrintOperand(SearchOp);
		SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at bad DefAddr: %llx\n", (uint64_t) DefAddr);
	}
	else if (STARS_IsBlockNumPseudoID(DefAddr)) {
		// Hitting a Phi function is only acceptable for induction variables when StopOnIV is our mode,
		//  or for a Phi function at a loop header block if InitCase, because we can resume expansion
		//  before the loop; or for a Phi function at the loop header block for current LoopIndex.
		int LoopIndex = -1;
		success = (StopOnIV && this->GetParentFunc()->IsLoopNestInductionVar(SearchOp, this->GetParentInst(), IVFamilyIter, FamilyIndex, LoopIndex));
		if (success) {
			StoppedOnIV = true;
			SMP_msg("INFO: StoppedOnIV at DefAddr %llx for ParentInst at %llx\n", (uint64_t) DefAddr, (uint64_t) this->GetParentInst()->GetAddr());
			SMP_msg("INFO: StoppedOnIV SearchOp was: ");
			PrintOperand(SearchOp);
			SMP_msg("\n");
		}
		if (success && (STARS_BADADDR == CurrLoopDefAddr)) {
#if 0
			// Did we cross loop boundary?
			int NewBlockNum = (int) STARS_GetBlockNumFromPseudoID(DefAddr);
			if (!this->GetParentFunc()->IsBlockInLoop(NewBlockNum, LoopIndex)) {
				// Crossed from within the loop to a Phi function before the loop.
				if (Left)
					this->SetLeftPreLoopDefAddr(DefAddr);
				else
					this->SetRightPreLoopDefAddr(DefAddr);
			}
#else
			// Even the Phi at the top of the loop represents a pre-loop address that is better than STARS_BADADDR
			if (Left)
				this->SetLeftPreLoopDefAddr(DefAddr);
			else
				this->SetRightPreLoopDefAddr(DefAddr);
#endif
		}
		else if (!success) {
			// Check for loop header block phi function special cases.
			int PhiBlockNum = STARS_GetBlockNumFromPseudoID(DefAddr);
			SMPBasicBlock *PhiBlock = this->GetParentFunc()->GetBlockByNum((size_t) PhiBlockNum);
			int PreLoopSSANum = PhiBlock->GetLoopLiveInSSANum(SearchOp);
			if ((SMP_SSA_UNINIT == PreLoopSSANum) || (!PhiBlock->IsLoopHeaderBlock())) { // failure
				SMP_msg("SPARK: Phi function SearchOp:");
				PrintOperand(SearchOp);
				SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at phi function at %llx\n", (uint64_t)DefAddr);
			}
			else { // Have good PreLoopSSANum at a loop header block.
				bool AtLoopIndexHeader = false;
				if (PhiBlock->GetFunc()->IsBlockInLoop(PhiBlockNum, LoopIndex)) {
					int CurrLoopNum = PhiBlock->GetFunc()->GetLoopNumFromHeaderBlockNum(PhiBlockNum);
					AtLoopIndexHeader = (CurrLoopNum == (int) LoopIndex);
				}
				if (!StopOnLoopBoundary || InitCase) {
					// Use the PreLoopSSANum to continue before the loop.
					STARS_ea_t NewDefAddr = PhiBlock->GetFunc()->GetGlobalDefAddr(SearchOp, PreLoopSSANum);
					success = this->ExpandOperandHelper(NewDefAddr, SearchOp, LoopIndex, Left, StopOnIV,
						StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
				}
				else if (AtLoopIndexHeader) {
					// We are right where we are supposed to stop.
					success = true;
				}
				else { // failure
					SMP_msg("SPARK: Phi function SearchOp:");
					PrintOperand(SearchOp);
					SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at phi function at %llx InitCase: %d\n", (uint64_t) DefAddr, InitCase);
				}
			}
		}
	}
	else { // found DEF inst.
		// 3. Get DEF right-hand-side SMPRegTransfer and create expression from it.
		SMPInstr *DefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr);
		int NewBlockNum = this->GetParentFunc()->GetBlockNumFromInstAddr(DefAddr);
		bool WentBeforeLoop = !this->GetParentFunc()->IsBlockInLoop(NewBlockNum, LoopIndex);
		bool StackPointerReg = SearchOp->MatchesReg(MD_STACK_POINTER_REG);
		if (WentBeforeLoop && StopOnLoopBoundary && (!StackPointerReg)) {
			// Do not replace USE with its DEF, as DEF precedes the loop. Stop
			//  inside the loop and declare victory. Exception for stack pointer reg,
			//  which we want to expand to its func entry value if possible.
			--DepthCounter;
			return true;
		}

		if (DEFAULT != DefInst->GetDataFlowType()) {
			SMP_msg("SPARK: Bad control flow type SearchOp:");
			PrintOperand(SearchOp);
			SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at bad control flow type %d at %llx\n", 
				DefInst->GetDataFlowType(), (uint64_t) DefAddr);
			--DepthCounter;
			return false; // don't want CALL DEFs, etc.
		}

		SMPRegTransfer *DefRT = DefInst->GetDefRT(SearchOp);
		if (nullptr == DefRT) {
			SMP_msg("SPARK: Bad DefRT SearchOp:");
			PrintOperand(SearchOp);
			SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at bad DefRT at %llx\n", (uint64_t) DefAddr);
			--DepthCounter;
			return false;  // some odd opcodes might have a DEF but no normal RT, e.g. "fnstsw ax"
		}

		if ((STARS_BADADDR == CurrLoopDefAddr) && (this->GetParentFunc()->GetNumLoops() > LoopIndex)) {
			// Did we cross loop boundary?
			if (WentBeforeLoop) {
				// Crossed from within the loop to a DefInst before the loop.
				if (Left)
					this->SetLeftPreLoopDefAddr(DefAddr);
				else
					this->SetRightPreLoopDefAddr(DefAddr);
			}
		}

		// See if we have encountered a lea of stack or static memory address expr; record it if so.
		if (DefInst->IsStackBasedLoadEffectiveAddress(UseFP) || DefInst->IsGlobalStaticLoadEffectiveAddress()) {
			StackPtrCopySet.insert(DefAddr);
		}

		// If an SMP_ASSIGN RT was returned, it means that RT was DEF := USE and
		//  we should use only the USE, i.e. the RightOperand, else use the whole RT.
		// If we have a stack alignment instruction (RSP := RSP AND bitmask), treat it
		//  as RSP := RSP with only the SSANum being replaced. Alignment might be a no-op,
		//  and we cannot statically analyze its effect, regardless.
		STARSOpndTypePtr UseOp;
		if (DefInst->IsStackAlignmentInst() || (SMP_ASSIGN == DefRT->GetOperator())) {
			// 4. Replace current operand with the USE operand.
			if (DefInst->IsStackAlignmentInst()) {
				assert(SMP_BITWISE_AND == DefRT->GetOperator());
				UseOp = DefRT->GetLeftOperand();
				assert(UseOp->MatchesReg(MD_STACK_POINTER_REG));
			}
			else {
				assert(!DefRT->HasRightSubTree());
				UseOp = DefRT->GetRightOperand();
			}
			bool ConstUse = UseOp->IsImmedOp();
			if (!(ConstUse || UseOp->IsRegOp() || UseOp->IsMemOp())) {
				SMP_msg("SPARK: Non-DataFlowOpnd: ");
				PrintOperand(UseOp);
				SMP_msg("\nINFO: SPARK: ExpandOperandHelper() hit non-DataFlow UseOp at %llx\n", (uint64_t) DefAddr);
			}
			else {
				STARSOpndTypePtr SearchOp2 = CloneIfSubwordReg(UseOp);
				CanonicalizeOpnd(SearchOp2);
				if (!ConstUse) {
					STARSDefUseIter UseIter = DefInst->FindUse(SearchOp2);
					assert(UseIter != DefInst->GetLastUse());
					int UseSSANum = UseIter->GetSSANum();
					// Until we have alias analysis, cannot trace non-stack memory
					//  operands, which will not be SSA numbered.
					if (SearchOp2->IsMemOp() && (-1 == UseSSANum)) {
						--DepthCounter;
						return true;
					}

					if (Left)
						this->SetLeftSSANum(UseSSANum);
					else
						this->SetRightSSANum(UseSSANum);
					this->ParentInst = DefInst;
					if (!WentBeforeLoop && RecordLoopRegs && UseOp->IsRegOp()) {
						int RegHash = HashGlobalNameAndSSA(SearchOp2, UseSSANum);
						pair<set<int>::iterator, bool> InsertResult = LoopRegHashes.insert(RegHash);
#if 1
						if (InsertResult.second) {
							SMP_msg("INFO: SPARK: New LoopRegHash found at %llx\n", (uint64_t) DefAddr);
						}
#endif
					}
				}
				// Replace current operand with new operand.
				if (Left) {
					this->SetLeftOperand(UseOp);
					this->SetLeftUseAddr(DefAddr);
				}
				else {
					this->SetRightOperand(UseOp);
					this->SetRightUseAddr(DefAddr);
				}
				changed = true;

				if (!ConstUse) {
					// 5. Recurse into new operand at DefAddr.
					success = this->ExpandOperand(LoopIndex, Left, StopOnIV, DefAddr, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
				}
				else {
					success = true;
				}
			}
		}
		else { // not just leftop := rightop
			STARSExpression *DefExpr = new STARSExpression(DefRT);

			// 4. Make new expression the sub-tree that replaces the operand.
			// 5. Recurse into new sub-tree.
			if (Left) {
				this->SetLeftTree(DefExpr);
				success = this->GetLeftTree()->ExpandExpr(DefAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
			}
			else {
				this->SetRightTree(DefExpr);
				int DepthCounter = 0;
				success = this->GetRightTree()->ExpandExpr(DefAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter);
			}
			changed = true;
		}
	}

	--DepthCounter;
	return success;
} // end of STARSExpression::ExpandOperandHelper()

// list incoming argument register numbers encountered (SSA #0 in an InArg reg)
void STARSExpression::ListInArgRegsUsed(std::bitset<1 + MD_LAST_REG_NO> &RegNums) {
	if (this->HasLeftSubTree()) {
		this->GetLeftTree()->ListInArgRegsUsed(RegNums);
	}
	else if ((nullptr != this->GetConstLeftOperand()) && (0 == this->GetLeftSSANum()) && this->GetConstLeftOperand()->IsRegOp()) {
		STARS_regnum_t CurrRegNum = this->GetLeftOperand()->GetReg();
		if (global_STARS_program->IsArgumentReg(CurrRegNum)) {
			RegNums.set((size_t) CurrRegNum);
		}
	}
	if (this->HasRightSubTree()) {
		this->GetRightTree()->ListInArgRegsUsed(RegNums);
	}
	else if ((nullptr != this->GetConstRightOperand()) && (0 == this->GetRightSSANum()) && this->GetConstRightOperand()->IsRegOp()) {
		STARS_regnum_t CurrRegNum = this->GetConstRightOperand()->GetReg();
		if (global_STARS_program->IsArgumentReg(CurrRegNum)) {
			RegNums.set((size_t) CurrRegNum);
		}
	}

	return;
} // end of STARSExpression::ListInArgRegsUsed()

// Is any incoming argument register encountered? (SSA #0 in an InArg reg)
bool STARSExpression::UsesInArgReg(void) const {
	if (this->HasLeftSubTree()) {
		if (this->GetLeftTree()->UsesInArgReg())
			return true;
	}
	else if ((nullptr != this->GetConstLeftOperand()) && (0 == this->GetLeftSSANum()) && this->GetConstLeftOperand()->IsRegOp()) {
		STARS_regnum_t CurrRegNum = this->GetConstLeftOperand()->GetReg();
		if (global_STARS_program->IsArgumentReg(CurrRegNum)) {
			return true;
		}
	}
	if (this->HasRightSubTree()) {
		if (this->GetRightTree()->UsesInArgReg())
			return true;
	}
	else if ((nullptr != this->GetConstRightOperand()) && (0 == this->GetRightSSANum()) && this->GetConstRightOperand()->IsRegOp()) {
		STARS_regnum_t CurrRegNum = this->GetConstRightOperand()->GetReg();
		if (global_STARS_program->IsArgumentReg(CurrRegNum)) {
			return true;
		}
	}

	return false;
} // end of STARSExpression::UsesInArgReg()

// Is Expr just the stack pointer plus optional offset constant?
bool STARSExpression::IsStackPtrPlusOffset(void) const {
	SMPoperator CurrOper = this->GetOperator();
	bool LeftSPOpnd = (!this->HasLeftSubTree()) && this->GetConstLeftOperand()->IsRegOp() && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG);
	bool SPPlusOffset = false;
	bool JustStackPtr = (CurrOper == SMP_ASSIGN) && LeftSPOpnd; // SMP_ASSIGN in expr means no RHS
	if (!JustStackPtr && LeftSPOpnd && IsIntegerAddOrSubOperator(CurrOper)) {
		const STARSOpndTypePtr RightOp = this->GetConstRightOperand();
		bool HasRightTree = this->HasRightSubTree();
		bool ImmedRightOp = (nullptr != RightOp) && (!HasRightTree) && RightOp->IsImmedOp();
		SPPlusOffset = ImmedRightOp;
	}
	return (JustStackPtr || SPPlusOffset);
} // end of STARSExpression::IsStackPtrPlusOffset()

// Is stack pointer reg found in the expr?
bool STARSExpression::IsStackPtrRegUsed(void) const {
	bool SPFound = false;
	if (this->HasLeftSubTree())
		SPFound = this->GetLeftTree()->IsStackPtrRegUsed();
	else {
		assert(nullptr != this->GetConstLeftOperand());
		if (this->GetConstLeftOperand()->IsRegOp())
			SPFound = this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG);
	}

	if (!SPFound) {
		if (this->HasRightSubTree())
			SPFound = this->GetRightTree()->IsStackPtrRegUsed();
		else if (nullptr != this->GetConstRightOperand()) {
			if (this->GetConstRightOperand()->IsRegOp())
				SPFound = this->GetConstRightOperand()->MatchesReg(MD_STACK_POINTER_REG);
		}
	}

	return SPFound;
} // end of STARSExpression::IsStackPtrRegUsed()

// If expr is SP+offset, add offset to CurrentStackPtrOffset to get FinalStackPtrOffset and return true.
//  CurrentStackPtrOffset should be relative to function entry and will generally be negative.
bool STARSExpression::IsStackPtrOffset(const STARS_sval_t CurrentStackPtrOffset, STARS_sval_t &FinalStackPtrOffset) const {
	bool StackPtrExpr = false;
	bool Addition = (SMP_ADD == this->GetOperator());
	if (Addition || (SMP_SUBTRACT == this->GetOperator())) {
		if (!this->HasLeftSubTree() && (nullptr != this->GetConstLeftOperand()) && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG)) {
			// Definitely adding or subtracting from the stack pointer reg.
			if (!this->HasRightSubTree() && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp()) {
				// We are adding or subtracting an immediate value.
				StackPtrExpr = true;
				STARS_uval_t ImmedValue = this->GetConstRightOperand()->GetImmedValue();
				if (Addition) {
					FinalStackPtrOffset = ((STARS_sval_t) ImmedValue) + CurrentStackPtrOffset;
				}
				else {
					FinalStackPtrOffset = CurrentStackPtrOffset - ((STARS_sval_t) ImmedValue);
				}
			}
		}
	}

	return StackPtrExpr;
} // end of STARSExpression::IsStackPtrOffset()

// Is top-level operator relational?
bool STARSExpression::IsRelationalExpr(void) const {
	SMPoperator TopLevelOperator = this->GetOperator();
	return IsRelationalOperator(TopLevelOperator);
} // end of STARSExpression::IsRelationalExpr()

// Is expr just a constant value?
bool STARSExpression::IsConstExpr(void) const {
	bool AssignOnly = (!this->HasRightSubTree() && (!this->HasLeftSubTree()) && (SMP_ASSIGN == this->GetOperator()));
	bool ConstOnly = (AssignOnly && (this->GetConstLeftOperand() != nullptr) && (this->GetConstLeftOperand()->IsImmedOp()));
	return ConstOnly;
} // end of STARSExpression::IsConstExpr()

// Find all uses of InArgOp, SSANum == 0, and give it NewSSANum; replace all ParentInsts with CallInst
void STARSExpression::SubstituteSSANum(SMPInstr *CallInst, const int NewSSANum, const STARSOpndTypePtr &InArgOp) {
	STARS_ea_t CallAddr = CallInst->GetAddr();
	this->SetParentInst(CallInst);
	this->SetParentFunc(CallInst->GetBlock()->GetFunc());
	if (this->HasLeftSubTree()) {
		this->GetLeftTree()->SubstituteSSANum(CallInst, NewSSANum, InArgOp); // recurse
	}
	else if (0 == this->GetLeftSSANum()) { // InArgs will have SSANum of zero
		if (IsEqOp(InArgOp, this->GetConstLeftOperand())) {
			this->SetLeftSSANum(NewSSANum);
			this->SetLeftUseAddr(CallAddr);
		}
	}
	this->SetLeftPreLoopDefAddr(STARS_BADADDR);

	if (this->HasRightSubTree()) {
		this->GetRightTree()->SubstituteSSANum(CallInst, NewSSANum, InArgOp); // recurse
	}
	else if (0 == this->GetRightSSANum()) { // InArgs will have SSANum of zero
		if (IsEqOp(InArgOp, this->GetConstRightOperand())) {
			this->SetRightSSANum(NewSSANum);
			this->SetRightUseAddr(CallAddr);
		}
	}
	this->SetRightPreLoopDefAddr(STARS_BADADDR);

	return;
} // end of STARSExpression::SubstituteSSANum()

// For loop exprs, find the DefOp at LeftPreLoopDefAddr
STARSOpndTypePtr STARSExpression::FindLeftPreLoopDefOp(void) const {
	STARS_ea_t DefAddr = this->GetLeftPreLoopDefAddr();
	STARSOpndTypePtr LeftPreLoopDefOp = nullptr;
	if ((STARS_BADADDR == DefAddr) || STARS_IsSSAMarkerPseudoID(DefAddr) || STARS_IsBlockNumPseudoID(DefAddr) || STARS_IsLiveInPseudoID(DefAddr)) {
		// Nothing to trace back.
		LeftPreLoopDefOp = this->GetLeftOperand();
	}
	else {
		SMPInstr *PreLoopDefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr);
		LeftPreLoopDefOp = PreLoopDefInst->GetFirstLeftOperandNoNorm();
	}
	return LeftPreLoopDefOp;
} // end of STARSExpression::FindLeftPreLoopDefOp()

// Detect loop-invariant exprs, which can occur inside loops.
bool STARSExpression::AreAllRegsLoopInvariant(void) const {
	bool LoopInvariantExpr = true;
	bool UseFP = this->GetParentFunc()->UsesFramePointer();

	if (this->HasLeftSubTree()) {
		LoopInvariantExpr = this->GetLeftTree()->AreAllRegsLoopInvariant();
	}
	else {
		SMPBasicBlock *CurrBlock = this->GetParentInst()->GetBlock();
		STARS_ea_t UseAddr = this->GetLeftUseAddr();
		STARSOpndTypePtr CurrOp = CloneIfSubwordReg(this->GetConstLeftOperand());
		CanonicalizeOpnd(CurrOp);
		if (MDIsDataFlowOpnd(CurrOp, UseFP)) {
			bool LocalName = CurrBlock->IsLocalName(CurrOp);
			int SSANum = this->GetLeftSSANum();
			STARS_ea_t DefAddr = CurrBlock->GetDefAddrFromUseAddr(CurrOp, UseAddr, SSANum, LocalName);
			if (STARS_IsBlockNumPseudoID(DefAddr)) {
				SMP_msg("INFO: Phi DEF termination in STARSExpression::AreAllRegsLoopInvariant() at UseAddr %llx DefAddr %llx\n",
					(uint64_t)UseAddr, (uint64_t)DefAddr);
				LoopInvariantExpr = false;
			}
			else if (STARS_BADADDR == DefAddr) {
				SMP_msg("ERROR: Bad DefAddr termination in STARSExpression::AreAllRegsLoopInvariant() at UseAddr %llx SSANum: %d CurrOp: ",
					(uint64_t)UseAddr, (uint64_t)SSANum);
				PrintOperand(CurrOp);
				SMP_msg("\n");
				LoopInvariantExpr = false;
			}
			else {
				SMPInstr *DefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr);
				STARSDefUseIter DefIter = DefInst->FindDef(CurrOp);
				if (DefIter != DefInst->GetLastDef()) {
					if (DefIter->GetSSANum() == SSANum) {
						LoopInvariantExpr = DefIter->IsInvariantForAllLoops();
					}
					else {
						SMP_msg("ERROR: SSANum mismatch in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr);
						LoopInvariantExpr = false;
					}
				}
				else {
					SMP_msg("ERROR: FindDef failure in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr);
					PrintOperand(this->GetConstRightOperand());
					SMP_msg("\n");
					LoopInvariantExpr = false;
				}
			}
		}
	}

	if (LoopInvariantExpr) {
		if (this->HasRightSubTree()) {
			LoopInvariantExpr = this->GetRightTree()->AreAllRegsLoopInvariant();
		}
		else {
			SMPBasicBlock *CurrBlock = this->GetParentInst()->GetBlock();
			STARS_ea_t UseAddr = this->GetRightUseAddr();
			STARSOpndTypePtr CurrOp = CloneIfSubwordReg(this->GetConstRightOperand());
			CanonicalizeOpnd(CurrOp);
			if (MDIsDataFlowOpnd(CurrOp, UseFP)) {
				bool LocalName = CurrBlock->IsLocalName(CurrOp);
				int SSANum = this->GetRightSSANum();
				STARS_ea_t DefAddr = CurrBlock->GetDefAddrFromUseAddr(CurrOp, UseAddr, SSANum, LocalName);
				if (STARS_IsBlockNumPseudoID(DefAddr)) {
					SMP_msg("INFO: Phi DEF termination in STARSExpression::AreAllRegsLoopInvariant() at UseAddr %llx DefAddr %llx\n",
						(uint64_t)UseAddr, (uint64_t)DefAddr);
					LoopInvariantExpr = false;
				}
				else {
					SMPInstr *DefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr);
					assert(nullptr != DefInst);
					STARSDefUseIter DefIter = DefInst->FindDef(CurrOp);
					if (DefIter != DefInst->GetLastDef()) {
						if (DefIter->GetSSANum() == SSANum) {
							LoopInvariantExpr = DefIter->IsInvariantForAllLoops();
						}
						else {
							SMP_msg("ERROR: SSANum mismatch in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr);
							LoopInvariantExpr = false;
						}
					}
					else {
						SMP_msg("ERROR: FindDef failure in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr);
						PrintOperand(this->GetConstRightOperand());
						SMP_msg("\n");
						LoopInvariantExpr = false;
					}
				}
			}
		}
	}

	return LoopInvariantExpr;
} // end of STARSExpression::AreAllRegsLoopInvariant()

// If this is a relational range expr, produce the lower and limit exprs
void STARSExpression::SplitMemoryRangeExpr(bool PositiveIncrement, STARSExpression *&InitExpr, STARSExpression *&LimitExpr) {
	assert(this->IsRelationalExpr());
	SMPoperator CurrOper = this->GetOperator();

	// Different cases: < or <=; > or >=; == or !=
	bool LessThanCase = ((SMP_LESS_THAN == CurrOper) || (SMP_LESS_EQUAL == CurrOper) || (SMP_BELOW == CurrOper) || (SMP_BELOW_EQUAL == CurrOper));
	bool GreaterThanCase = ((SMP_GREATER_THAN == CurrOper) || (SMP_GREATER_EQUAL == CurrOper) || (SMP_ABOVE == CurrOper) || (SMP_ABOVE_EQUAL == CurrOper));
	if (!LessThanCase && !GreaterThanCase) {
		assert((SMP_EQUAL == CurrOper) || (SMP_NOT_EQUAL == CurrOper));
		LessThanCase = PositiveIncrement;
		GreaterThanCase = (!PositiveIncrement);
	}
	if (LessThanCase) {
		assert(PositiveIncrement);
		// InitExpr will be the LHS of this expr.
		InitExpr = this->CloneLHS();

		// LimitExpr will be the RHS of this expr.
		LimitExpr = this->CloneRHS();
	}
	else if (GreaterThanCase) {
		assert(!PositiveIncrement);
		// InitExpr will be the RHS of this expr.
		InitExpr = this->CloneRHS();

		// LimitExpr will be the LHS of this expr.
		LimitExpr = this->CloneLHS();
	}
	return;
} // end of STARSExpression::SplitMemoryRangeExpr()

// Assuming simple address regs +/- immediate, extract the immediate operand value & return true.
bool STARSExpression::ExtractImmedValue(STARS_uval_t &Value) const {
	bool FoundImmed = false;
	if (this->HasLeftSubTree())
		FoundImmed = this->GetLeftTree()->ExtractImmedValue(Value);
	else {
		assert(nullptr != this->GetConstLeftOperand());
		if (this->GetConstLeftOperand()->IsImmedOp()) {
			bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator());
			if (AddOrSubtract) {
				Value = this->GetConstLeftOperand()->GetImmedValue();
				bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator());
				if (Subtraction)
					Value = (0 - Value);
				FoundImmed = true;
			}
		}
	}

	if (!FoundImmed) {
		if (this->HasRightSubTree())
			FoundImmed = this->GetRightTree()->ExtractImmedValue(Value);
		else if (nullptr != this->GetConstRightOperand()) {
			if (this->GetConstRightOperand()->IsImmedOp()) {
				bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator());
				if (AddOrSubtract) {
					Value = this->GetConstRightOperand()->GetImmedValue();
					bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator());
					if (Subtraction)
						Value = (0 - Value);
					FoundImmed = true;
				}
			}
		}
	}

	return FoundImmed;
} // end of STARSExpression::ExtractImmedValue()

// Find same Immed operand as ExtractImmedValue() (OldValue) and change its value to NewValue.
bool STARSExpression::UpdateImmedValue(STARS_uval_t OldValue, STARS_uval_t NewValue) {
	STARS_sval_t SignedOldValue = (STARS_sval_t) OldValue;
	STARS_sval_t SignedNewValue = (STARS_sval_t) NewValue;
	assert(OldValue != 0);
	bool OldNegative = (0 > SignedOldValue);
	bool NewNegative = (0 > SignedNewValue);
	bool SignChange = (OldNegative != NewNegative);

	bool FoundImmed = false;
	if (this->HasLeftSubTree())
		FoundImmed = this->GetLeftTree()->UpdateImmedValue(OldValue, NewValue);
	else {
		assert(nullptr != this->GetConstLeftOperand());
		if (this->GetConstLeftOperand()->IsImmedOp()) {
			bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator());
			if (AddOrSubtract) {
				STARS_sval_t Value = (STARS_sval_t) this->GetConstLeftOperand()->GetImmedValue();
				bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator());
				FoundImmed = true;
				if (Subtraction) {
					Value = (0 - Value);
					assert(NewNegative && OldNegative); // SMP_SUBTRACT, so we should be changing negative value to smaller negative value
					// Replace the value. Subtract a positive value.
					SignedNewValue = (0 - SignedNewValue); // get abs value to subtract
				}
				else { // addition
					if (SignChange) {
						// Replace the value. Subtract a positive value.
						SignedNewValue = (0 - SignedNewValue); // get abs value to subtract
						this->SetOperator(SMP_SUBTRACT);
					}
					else {
						// Leave the SMP_ADD operator alone and change the value added.
						;
					}
				}
				assert(OldValue = (STARS_uval_t) Value);
				this->SetLeftOperand(this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t)SignedNewValue));
			}
		} // end if (this->GetLeftOperand()->IsImmedOp()) 
	}

	if (!FoundImmed) {
		if (this->HasRightSubTree())
			FoundImmed = this->GetRightTree()->UpdateImmedValue(OldValue, NewValue);
		else if (nullptr != this->GetConstRightOperand()) {
			if (this->GetConstRightOperand()->IsImmedOp()) {
				bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator());
				if (AddOrSubtract) {
					STARS_sval_t Value = (STARS_sval_t) this->GetConstRightOperand()->GetImmedValue();
					bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator());
					FoundImmed = true;
					if (Subtraction) {
						Value = (0 - Value);
						assert(NewNegative && OldNegative); // SMP_SUBTRACT, so we should be changing negative value to smaller negative value
						// Replace the value. Subtract a positive value.
						SignedNewValue = (0 - SignedNewValue); // get abs value to subtract
					}
					else { // addition
						if (SignChange) {
							// Replace the value. Subtract a positive value.
							SignedNewValue = (0 - SignedNewValue); // get abs value to subtract
							this->SetOperator(SMP_SUBTRACT);
						}
						else {
							// Leave the SMP_ADD operator alone and change the value added.
							;
						}
					}
					assert(OldValue = (STARS_uval_t)Value);
					this->SetRightOperand(this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t) SignedNewValue));
				}
			} // end if (this->GetRightOperand()->IsImmedOp()) 
		}
	}

	return FoundImmed;
} // end of STARSExpression::UpdateImmedValue()

// *****************************************************************
// Class SMPInstr
// *****************************************************************

// Constructor for instruction.
SMPInstr::SMPInstr(STARS_ea_t addr) : STARS_ID(addr) {
	this->STARS_ID.SetFileNum(global_STARS_program->GetCurrentFileNum());
	this->BasicBlock = NULL;
#if 0  // get these from STARSInstrPtr now
	this->SMPcmd.size = 0;
	this->features = 0;
#endif
	this->type = DEFAULT;
	// this->OptType = 0;
#if 0   // get address from STARS_ID.GetIDWithinFile()
	this->address = addr;
#endif
	this->StackPtrOffset = 0;
	this->STARSInstPtr = global_stars_interface->CreateInst(this->STARS_ID);
#if 0
	this->ResetGoodRTL();
	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->booleans4 = 0;
	this->booleans5 = 0;

	this->CallTarget = STARS_BADADDR;
	this->FarBranchTarget = STARS_BADADDR;
	this->AddSubSourceType = UNINIT;
	this->AddSubDefUseType = UNINIT;
#if 0
	this->AddSubSourceOp = nullptr;
	this->AddSubDefUseOp = nullptr;
#endif
	this->DEFMemOp = nullptr;
	this->USEMemOp = nullptr;
	this->MoveSource = nullptr;
	this->Defs.clear();
	this->Uses.clear();
	return;
}

// Destructor.
SMPInstr::~SMPInstr() {
	if (global_STARS_program->ShouldSTARSPerformFullAnalysis()) { // not already deleted
		this->Defs.clear();
		this->Uses.clear();
	}
	return;
}

char *SMPInstr::GetDisasm(void) const {
	return DisAsmText.GetDisAsm(this->GetAddr(), this->IsMarkerInst());
}

// Is the instruction the type that terminates a basic block?
bool SMPInstr::IsBasicBlockTerminator() const {
	if (this->GetDataFlowType() == CALL) {
		STARS_ea_t CallTarget = this->GetCallTarget();
		if (STARS_BADADDR != CallTarget) {
			STARS_Function_t *CalleeFunc = global_stars_interface->get_func(CallTarget);
			if (NULL != CalleeFunc) {
				// Terminates basic block if it is a call to a non-returning func (e.g. abort(), exit())
				return (!(CalleeFunc->HasReturnPoints()));
			}
		}
	}
	return ((type == JUMP) || (type == COND_BRANCH)
			|| (type == INDIR_JUMP) || (type == RETURN) || (type == HALT));
}

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

	for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		STARSOpndTypePtr DefOp = DefIter->GetOp();
		assert(nullptr != DefOp);
#if 0
		if (0x4000 > DefOp) {
			SMP_msg("ERROR: DefOp pointer value too small in GetFirstNonFlagsDef() at %x\n", this->GetAddr());
		}
#endif
		if (!((DefOp->IsRegOp()) && DefOp->MatchesReg(MD_FLAGS_REG)))
			break; // found a non-flags-reg DEF.
	}
	return DefIter;
}

// Fetch the operands for a shift instruction
void SMPInstr::GetShiftOperands(STARSOpndTypePtr &ShiftedOp, STARSOpndTypePtr &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 = nullptr;
		ShiftCounterOp = nullptr;
	}
	return;
} // end of SMPInstr::GetShiftOperands()

void SMPInstr::GetMemDEFAddressRegs(set<STARS_regnum_t> &AddressRegs) const {
	if (this->GetMemDef() != nullptr) {
		this->GetMemDef()->GetAddressRegs(AddressRegs);
	}
	return;
}

void SMPInstr::GetDEFRegs(std::set<int> &DefRegs) {
	for (STARSDefUseIter DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		STARSOpndTypePtr DefOp = DefIter->GetOp();
		if (DefOp->IsRegOp()) {
			int DefReg = (int) DefOp->GetReg();
			pair<set<int>::iterator, bool> InsertResult = DefRegs.insert(DefReg);
		}
	}
	return;
} // end of SMPInstr::GetDEFRegs()

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

// Is a source operand a memory reference?
bool SMPInstr::HasSourceMemoryOperand(void) const {
	return (! ((nullptr == this->USEMemOp) || this->USEMemOp->IsVoidOp()));
} // end of SMPInstr::HasSourceMemoryOperand()

bool SMPInstr::HasStaticMemWrite(void) const {
	return ((nullptr != this->DEFMemOp) && (this->DEFMemOp->IsStaticMemOp()));
}

bool SMPInstr::HasStaticMemRead(void) const {
	return ((nullptr != this->USEMemOp) && (this->USEMemOp->IsStaticMemOp()));
}

int SMPInstr::GetOptType(void) const {
	if (this->IsNop())
		return 1;
	else
		return global_STARS_program->GetOptCategory(this->GetIDAOpcode());
}

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

// Get the first memory operand in the USE list.
STARSOpndTypePtr SMPInstr::MDGetMemUseOp(void) const {
	return this->USEMemOp; // cached value
} // end of SMPInstr::MDGetMemUseOp()

// return original Lea instruction [pseudo-]memory operand.
STARSOpndTypePtr SMPInstr::GetLeaMemUseOp(void) const {
	if ((!this->MDIsLoadEffectiveAddressInstr()) || (this->BasicBlock == NULL)) {
		return nullptr;
	}
	else {
		map<STARS_ea_t, STARSOpndTypePtr>::iterator MapIter = this->GetBlock()->GetFunc()->FindLeaOperand(this->GetAddr());
		assert(MapIter != this->GetBlock()->GetFunc()->GetLastLeaOperand());
		return MapIter->second;
	}
}

STARSOpndTypePtr SMPInstr::GetMoveSource(void) {
	if (nullptr == this->MoveSource) {
		this->MoveSource = this->STARSInstPtr->MakeVoidOpnd();
	}
	return this->MoveSource;
}

STARSOpndTypePtr SMPInstr::GetUseOnlyAddSubOp(void) const { 
	unsigned short opcode = this->GetIDAOpcode();

	bool IsAddSubInst = ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode) || (STARS_NN_inc == opcode)
		|| (STARS_NN_dec == opcode) || (STARS_NN_sbb == opcode) || (STARS_NN_sub == opcode));
	if ((this->RTL.GetCount() < 1) || (!IsAddSubInst))
		return this->STARSInstPtr->MakeVoidOpnd();  // no RTL or not an addition or subtraction

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

#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
	if ((STARS_NN_adc != opcode) && (STARS_NN_sbb != opcode)) {
		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()

STARSOpndTypePtr SMPInstr::GetDefUseAddSubOp(void) const { 
	unsigned short opcode = this->GetIDAOpcode();

	bool IsAddSubInst = ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode) || (STARS_NN_inc == opcode)
		|| (STARS_NN_dec == opcode) || (STARS_NN_sbb == opcode) || (STARS_NN_sub == opcode));
	if ((this->RTL.GetCount() < 1) || (!IsAddSubInst))
		return this->STARSInstPtr->MakeVoidOpnd();  // no RTL or not an addition or subtraction

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

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

STARSOpndTypePtr SMPInstr::GetFirstRightOperand(void) const {
	return this->RTL.GetRT(0)->GetRightOperand();
}

STARSOpndTypePtr SMPInstr::GetFirstRightOperandNoNorm(void) const {
	unsigned short SignMask = 0;
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	bool SignOrZeroExtension = CurrRT->HasRightSubTree();
#if 0
	if (SignOrZeroExtension) {
		SMPoperator RightOperator = CurrRT->GetRightTree()->GetOperator();
		SignOrZeroExtension = (SMP_SIGN_EXTEND == RightOperator) || (SMP_ZERO_EXTEND == RightOperator);
	}
#endif
	if (SignOrZeroExtension || this->IsRegUpperBitsClearIdiom() || this->MDIsSignedLoad(SignMask))
		return CurrRT->GetRightTree()->GetLeftOperandNoNorm();
	else
		return CurrRT->GetRightOperandNoNorm();
}

STARSOpndTypePtr SMPInstr::GetFirstLeftOperandNoNorm(void) const {
	return this->RTL.GetRT(0)->GetLeftOperandNoNorm();
}

SMPRegTransfer * SMPInstr::GetDefRT(STARSOpndTypePtr DefOp) const {
	for (size_t index = 0; index < this->RTL.GetCount(); ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		if (SMP_NULL_OPERATOR != CurrRT->GetOperator()) {
			if (IsEqOpIgnoreBitwidth(CurrRT->GetLeftOperand(), DefOp)) {
				if (CurrRT->HasRightSubTree()) {
					return CurrRT->GetRightTree();
				}
				else {
					// Caller will have to recognize that SMP_ASSIGN operator implies only RightOperand is being returned.
					return CurrRT;
				}
			}
		}
	}
	return nullptr;
} // end of SMPInstr::GetDefRT()

// return # bytes width of first pushed operand
size_t SMPInstr::GetPushedOpndByteSize(void) const {
	size_t OpndWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
	if (this->RTL.GetRT(0)->HasRightSubTree()) {
		SMP_msg("ERROR: bad RTL structure for push instruction at %llx\n", (unsigned long long) this->GetAddr());
	}
	else {
		OpndWidth = (size_t) this->RTL.GetRT(0)->GetRightOperand()->GetByteWidth();
	}
	return OpndWidth;
}

// return first pushed operand
STARSOpndTypePtr SMPInstr::GetPushedOpnd(void) const {
	size_t OpndWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
	if ((STARS_NN_push != this->GetIDAOpcode()) || this->RTL.GetRT(0)->HasRightSubTree()) {
		SMP_msg("ERROR: bad RTL structure for push instruction at %llx\n", (unsigned long long) this->GetAddr());
		return this->STARSInstPtr->MakeVoidOpnd();
	}
	else {
		return this->RTL.GetRT(0)->GetRightOperand();
	}
}

// return STARS_BADADDR if not jump, target addr otherwise.
STARS_ea_t SMPInstr::GetJumpTarget(void) const {
	STARS_ea_t TargetAddr = STARS_BADADDR;
	if (this->HasGoodRTL() 
		&& ((this->type & (JUMP | COND_BRANCH)) || this->IsFixedCallJump())) {
		// We want to find an RTL of the form: inst_ptr_reg := code_addr
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		STARSOpndTypePtr DefOp = CurrRT->GetLeftOperand();
		if (DefOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) {
			if ((SMP_ASSIGN == CurrRT->GetOperator()) && (!CurrRT->HasRightSubTree())) {
				STARSOpndTypePtr UseOp = CurrRT->GetRightOperand();
				if (UseOp->IsNearPointer() || UseOp->IsFarPointer()) { // address
					TargetAddr = UseOp->GetAddr();
				}
			}
		}
		else if (this->IsFixedCallJump()) {
			assert(!CurrRT->HasRightSubTree());
			STARSOpndTypePtr UseOp = CurrRT->GetRightOperand();
			if (UseOp->IsImmedOp()) {
				TargetAddr = (STARS_ea_t) UseOp->GetImmedValue();
			}
			else if (UseOp->IsNearPointer() || UseOp->IsFarPointer()) {
				TargetAddr = UseOp->GetAddr();
			}
		}
	}
	return TargetAddr;
} // end SMPInstr::GetJumpTarget()

// Build set of address reg USEs, return true if any found
bool SMPInstr::GetAddressRegs(STARSDefUseSet &AddressRegs) {
	STARSOpndTypePtr MemOp = nullptr;
	int BaseReg = STARS_x86_R_none, IndexReg = STARS_x86_R_none;
	uint16_t ScaleFactor = 0;
	STARS_ea_t offset = 0;
	if (this->HasDestMemoryOperand()) {
		MemOp = this->GetMemDef();
	}
	else if (this->HasSourceMemoryOperand()) {
		MemOp = this->GetMemUse();
	}
	if (nullptr != MemOp) {
		MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor, offset);
		if (STARS_x86_R_none != BaseReg) {
			STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg);
			STARSDefUseIter BaseIter = this->FindUse(BaseOp);
			assert(this->GetLastUse() != BaseIter);
			pair<STARSDefUseIter, bool> InsertResult = AddressRegs.insert(*BaseIter);
		}
		if (STARS_x86_R_none != IndexReg) {
			STARSOpndTypePtr IndexOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg);
			STARSDefUseIter IndexIter = this->FindUse(IndexOp);
			assert(this->GetLastUse() != IndexIter);
			pair<STARSDefUseIter, bool> InsertResult = AddressRegs.insert(*IndexIter);
		}
	}
	return (!AddressRegs.empty());
}

// get COND_BRANCH operator that guards the control flow, e.g. SMP_LESS_THAN
SMPoperator SMPInstr::GetCondBranchOperator(void) const {
	SMPoperator GuardOperator = SMP_NULL_OPERATOR;
	if (this->GetDataFlowType() == COND_BRANCH) {
		SMPGuard *GuardRT = this->RTL.GetRT(0)->GetGuard();
		assert(NULL != GuardRT);
		GuardOperator = GuardRT->GetOperator();
	}

	return GuardOperator;
} // end of SMPInstr::GetCondBranchOperator()

// 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) {
	STARS_ea_t InstAddr = this->GetAddr();
	if (this->HasDestMemoryOperand()) {
		// Found a memory DEF. Is it indirect?
		STARSOpndTypePtr DefMemOp = this->MDGetMemDefOp();
		if (MDIsIndirectMemoryOpnd(DefMemOp, UseFP)) {
			this->SetIndirectMemWrite();
			if (NULL != this->GetBlock()) {
				this->GetBlock()->SetHasIndirectMemWrite();
			}
		}
		if (DefMemOp->IsStaticMemOp()) {
			if (NULL != this->GetBlock()) {
				this->GetBlock()->SetHasStaticMemWrite();
			}
		}
	}

	if (this->HasSourceMemoryOperand()) {
		// Found a memory USE. Is it indirect?
		STARSOpndTypePtr UseMemOp = this->MDGetMemUseOp();
		if (MDIsIndirectMemoryOpnd(UseMemOp, UseFP)) {
			this->SetIndirectMemRead();
			if (NULL != this->GetBlock()) {
				this->GetBlock()->SetHasIndirectMemRead();
			}
		}
		if (UseMemOp->IsStaticMemOp()) {
			STARS_ea_t AddrOffset = USEMemOp->GetAddr();
			if (!IsImmedGlobalAddress(AddrOffset) && (STARS_x86_R_none == UseMemOp->GetSegReg())) {
				SMP_msg("INFO: Doubtful identification of %llx as StaticMem at %llx\n", 
					(uint64_t) AddrOffset, (uint64_t) InstAddr);
			}
			if (NULL != this->GetBlock()) {
				this->GetBlock()->SetHasStaticMemRead();
			}
		}
	}

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

set<DefOrUse, LessDefUse>::iterator SMPInstr::GetPointerAddressReg(const STARSOpndTypePtr &MemOp) {
	int BaseReg;
	int IndexReg;
	uint16_t ScaleFactor;
	STARS_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 %llx \n",
			(unsigned long long) this->GetAddr());
		return this->GetLastUse();
	}
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();

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

	if ((STARS_x86_R_none != BaseReg) && (!MDIsStackPtrReg(BaseReg, UseFP))) {
		STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg);
		PtrIter = this->FindUse(BaseOp);
		assert(PtrIter != this->GetLastUse());
		if (IsDataPtr(PtrIter->GetType())) {
			return PtrIter;
		}
	}
	if ((STARS_x86_R_none != IndexReg) && (!MDIsStackPtrReg(IndexReg, UseFP))) {
		STARSOpndTypePtr IndexOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg);
		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 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(void) const {
	bool SecondOpImm = (this->STARSInstPtr->GetOpnd(1)->IsImmedOp());
	STARS_uval_t TempImm;

	if (SecondOpImm) {
		TempImm = this->STARSInstPtr->GetOpnd(1)->GetImmedValue();
	}

	return (SecondOpImm && IsImmedNumeric((STARS_ea_t) 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();
	STARSOpndTypePtr RightOp = nullptr;
	STARSOpndTypePtr LeftOp = RightTree->GetLeftOperand();    // Use (also DEF) operand
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
	if ((STARS_NN_adc != opcode) && (STARS_NN_sbb != opcode)) {
		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();
#if 0
	this->AddSubSourceOp = RightOp;
#endif

	UseIter = this->FindUse(LeftOp);
	assert(UseIter != this->GetLastUse());
	this->AddSubDefUseType = UseIter->GetType();
#if 0
	this->AddSubDefUseOp = LeftOp;
#endif

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

// Are all DEFs in the DEF set NUMERIC type?
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()->MatchesReg(MD_STACK_POINTER_REG))
			continue;
		AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType()));
	}
	return AllNumeric;
} // end of SMPInstr::AllDefsNumeric()

// Were the types of any DEFs derived from profiler info?
bool SMPInstr::AnyDefsProfiled(void) 
{
	bool profd = false;
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		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 {
	for (int i = 0; i < STARS_UA_MAXOP; ++i) {
		STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(i);
		if (nullptr == Opnd) // finished processing operands
			break;
		PrintOneOperand(Opnd, this->GetInstFeatures(), i);
	}
	SMP_msg(" \n");
	return;
} // end of SMPInstr::PrintOperands()

// Complete DEBUG printing.
void SMPInstr::Dump(void) const {
	if (this->IsMarkerInst()) {
		SMP_msg("%llx 1 SMPitype: %d SPOffset: %lld fnop\n", (unsigned long long) this->GetAddr(), (int) this->type,
			(long long) this->GetStackPtrOffset());
	}
	else {
		SMP_msg("%llx %zd SMPitype: %d SPOffset: %lld %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), (int) this->type,
			(long long) this->GetStackPtrOffset(), DisAsmText.GetDisAsm(this->GetAddr(), false));
	}
#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>::const_iterator UseIter, DefIter;
		int UseHashValue, DefHashValue, UseSSANum, DefSSANum;
		unsigned short SignMiscInfo, SignMask;
		bool LocalName;
		for (UseIter = this->GetFirstConstUse(); UseIter != this->GetLastConstUse(); ++UseIter) {
			UseIter->Dump();
			STARSOpndTypePtr UseOp = UseIter->GetOp();
			if (UseOp->IsRegOp()) {
				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");
		}
		if (this->Uses.GetSize() == 0)
			SMP_msg("\n");
		SMP_msg("DEFs: ");
		for (DefIter = this->GetFirstConstDef(); DefIter != this->GetLastConstDef(); ++DefIter) {
			DefIter->Dump();
			STARSOpndTypePtr DefOp = DefIter->GetOp();
			if (DefOp->IsRegOp()) {
				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");
		}
		if (this->Defs.GetSize() == 0)
			SMP_msg("\n");

	}
#else
	SMP_msg("USEs: ");
	this->Uses.Dump();
	SMP_msg("DEFs: ");
	this->Defs.Dump();
#endif
	this->RTL.Dump();
#if SMP_VERBOSE_DUMP
	this->PrintOperands();
	SMP_msg("\n");
#endif
	SMP_msg("DEFMemOp: "); PrintOperand(this->DEFMemOp); SMP_msg("\n");
	SMP_msg("USEMemOp: "); PrintOperand(this->USEMemOp); SMP_msg("\n");
	SMP_msg("booleans1: %d booleans2: %d booleans3: %d booleans4: %d booleans5: %d \n", this->booleans1,
		this->booleans2, this->booleans3, this->booleans4, this->booleans5);
	SMP_msg("\n");
	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) {
	static char DestList[STARS_MAXSTR];
	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) {
		STARSOpndTypePtr DefOpnd = CurrDef->GetOp();
		if (DefOpnd->MatchesReg(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->MatchesReg(MD_STACK_POINTER_REG) && this->MDIsPopInstr())
			continue;
		if (DefOpnd->IsRegOp()) {
			STARS_regnum_t DestReg = DefOpnd->GetReg();
			if (0 == RegDestCount) {
				SMP_strncpy(DestList, MDGetRegName(DefOpnd), 1 + strlen(MDGetRegName(DefOpnd)));
			}
			else {
				SMP_strncat(DestList, " ", STARS_MAXSTR);
				SMP_strncat(DestList, MDGetRegName(DefOpnd), STARS_MAXSTR);
			}
			++RegDestCount;
		}
	}
	if (0 >= RegDestCount) {
		SMP_msg("WARNING: No destination registers: %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
	}
	else {
		SMP_strncat(DestList, " ZZ ", STARS_MAXSTR);
	}
	return DestList;
} // end of SMPInstr::DestString()

// print the registers that are dead right before this instruction.
void SMPInstr::PrintDeadRegs(FILE *OutputFile) {
	std::size_t RegNum = (std::size_t) MD_FLAGS_REG;
	uint16_t ByteWidth = (uint16_t) global_STARS_program->GetSTARS_ISA_Bytewidth();
	// 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 ", MDGetRegNumName((STARS_regnum_t) RegNum, ByteWidth));
		}
	}
	for (RegNum = 1 + MD_FLAGS_REG; RegNum <= MD_LAST_REG_NO; ++RegNum) {
		if (this->DeadRegsBitmap[RegNum] && (!STARS_x86_is_FP8087_reg((int) RegNum))) {
			SMP_fprintf(OutputFile, "%s ", MDGetRegNumName((STARS_regnum_t) RegNum, ByteWidth));
		}
	}
	// Print sequence terminator.
	SMP_fprintf(OutputFile, "ZZ");

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

// emit SPARK Ada for string operation, perhaps with repeat prefix that makes it a loop; return true if it writes memory.
bool SMPInstr::MDEmitSPARKAdaStringOperation(FILE *OutFile) {
	bool HasRepeatEQPrefix = this->STARSInstPtr->HasRepeatIfEqualPrefix();
	bool HasRepeatNEQPrefix = this->STARSInstPtr->HasRepeatIfNotEqualPrefix();
	bool HasSomeRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix();
	uint16_t opcode = this->GetIDAOpcode();
	bool WritesMemory = false;
	bool GoodOpcode = true;

	if (opcode == STARS_NN_cmps) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " ");
		if (HasRepeatEQPrefix) {
			SMP_fprintf(OutFile, "X86.repe64_");
		}
		else if (HasRepeatNEQPrefix) {
			SMP_fprintf(OutFile, "X86.repne64_");
		}
		SMP_fprintf(OutFile, "cmps"); // procedure call
	}
	else if (opcode == STARS_NN_scas) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " ");
		if (HasRepeatEQPrefix) {
			SMP_fprintf(OutFile, "X86.repe64_");
		}
		else if (HasRepeatNEQPrefix) {
			SMP_fprintf(OutFile, "X86.repne64_");
		}
		SMP_fprintf(OutFile, "scas"); // procedure call
	}
	else if (opcode == STARS_NN_stos) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " ");
		if (HasSomeRepeatPrefix) {
			SMP_fprintf(OutFile, "X86.rep_stos"); // procedure call
		}
		else {
			SMP_fprintf(OutFile, "X86.stos"); // procedure call
		}
		WritesMemory = true;
	}
	else if (opcode == STARS_NN_movs) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " ");
		if (HasSomeRepeatPrefix) {
			SMP_fprintf(OutFile, "X86.rep_movs"); // procedure call
		}
		else {
			SMP_fprintf(OutFile, "X86.movs"); // procedure call
		}
		WritesMemory = true;
	}
#if 0
	else if (opcode == STARS_NN_movsd) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " ");
		if (HasSomeRepeatPrefix) {
			SMP_fprintf(OutFile, "X86.rep_movsd;\n"); // procedure call
		}
		else {
			SMP_fprintf(OutFile, "X86.movsd;\n"); // procedure call
		}
	}
	else if (opcode == STARS_NN_movsq) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " ");
		if (HasSomeRepeatPrefix) {
			SMP_fprintf(OutFile, "X86.rep_movsd;\n"); // procedure call
		}
		else {
			SMP_fprintf(OutFile, "X86.movsd;\n"); // procedure call
		}
	}
#endif
	else { // don't expect to see port I/O opcodes STARS_NN_ins or STARS_NN_outs yet.
		GoodOpcode = false;
		SMP_fprintf(OutFile, "ERROR: Unknown string opcode at %llx\n", (unsigned long long) this->GetAddr());
	}
	if (GoodOpcode) {
		// Append the byte-width suffix for the precise procedure call name.
		STARSOpndTypePtr FirstOpnd = this->GetOperand(0);
		uint16_t ByteWidth = FirstOpnd->GetByteWidth();
		if (1 == ByteWidth) {
			SMP_fprintf(OutFile, "b;\n");
		}
		else if (2 == ByteWidth) {
			SMP_fprintf(OutFile, "w;\n");
		}
		else if (4 == ByteWidth) {
			SMP_fprintf(OutFile, "d;\n");
		}
		else if (8 == ByteWidth) {
			SMP_fprintf(OutFile, "q;\n");
		}
		else {
			SMP_fprintf(OutFile, " ERROR ;\n");
		}
	}

	return WritesMemory;
} // end of SMPInstr::MDEmitSPARKAdaStringOperation()

// emit SPARK Ada for setting flags only (compare or test opcodes)
void SMPInstr::MDEmitSPARKAdaCompareOrTest(FILE *OutFile) {
	STARS_ea_t InstAddr = this->GetAddr();
	char OperatorString[10] = { '\0' };
	uint16_t opcode = this->GetIDAOpcode();
	bool EmitCarryFlag = false; // no carry flag for test; but yes for compare
	bool EmitOverflowFlag = false; // no overflow flag for test; but yes for compare
	bool EmitSignFlag = true;  // always emit unless flag is dead
	bool EmitZeroFlag = true;  // always emit unless flag is dead
	bool EmitParityFlag = true; // always emit unless flag is dead
	bool BitwiseAndOperation = (STARS_NN_test == opcode);
	bool SubtractionOperation = (STARS_NN_cmp == opcode);
	bool FloatingOperation = ((STARS_NN_ucomisd == opcode) || (STARS_NN_ucomiss == opcode));
	bool FloatingStackOperation = this->MDIsFloatingStackCompare();
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();

	assert(BitwiseAndOperation || SubtractionOperation || FloatingOperation || FloatingStackOperation);

	if (SubtractionOperation || FloatingOperation) { // compare opcode is subtraction based
		SMP_strncat(OperatorString, " - ", 4);
		EmitCarryFlag = true;
		EmitOverflowFlag = true; // will be zeroed out for FloatingOperation case
	}
	else if (BitwiseAndOperation) { // test opcode is based on bitwise AND
		SMP_strncat(OperatorString, " and ", 6);
	}
	else if (FloatingStackOperation) {
		SMP_strncat(OperatorString, " - ", 4);
		EmitCarryFlag = true;
	}
	else {
		SMP_fprintf(OutFile, "ERROR: Unknown compare or test opcode at %llx \n", (uint64_t) InstAddr);
		return;
	}

	// NOTE: We can optimize by analyzing which flags are actually live from this instruction.
	set<int> LiveFlagRegs;
	bool LiveFlags = this->GetBlock()->AreFlagsLiveAfterInst(InstAddr, LiveFlagRegs);
	if (!LiveFlags) {
		SMP_msg("WARNING: Compare or test inst at %llx with no live flags used after inst.\n", (uint64_t) InstAddr);
	}
	else {
		// Reset default flags to false.
		EmitCarryFlag = false;
		EmitZeroFlag = false;
		EmitSignFlag = false;
		EmitOverflowFlag = false;
		EmitParityFlag = false;
		for (set<int>::const_iterator FlagIter = LiveFlagRegs.cbegin(); FlagIter != LiveFlagRegs.cend(); ++FlagIter) {
			int FlagRegNum = (*FlagIter);
			switch (FlagRegNum) {
				case MD_CARRY_FLAG:
					EmitCarryFlag = true;
					break;

				case MD_ZERO_FLAG:
					EmitZeroFlag = true;
					break;

				case MD_SIGN_FLAG:
					EmitSignFlag = true;
					break;

				case MD_OVERFLOW_FLAG:
					EmitOverflowFlag = true;
					break;

				case MD_PARITY_FLAG:
					EmitParityFlag = true;
					break;

				default:
					SMP_msg("ERROR: Unknown live flag register %d at instruction %llx\n", FlagRegNum, (uint64_t) InstAddr);
					break;
			}
		}
	}


	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	assert(CurrRT->HasRightSubTree());
	CurrRT = CurrRT->GetRightTree();
	const STARSOpndTypePtr LeftOp = CurrRT->GetConstLeftOperandNoNorm();
	const STARSOpndTypePtr RightOp = CurrRT->GetConstRightOperandNoNorm();
	bool ReflexiveOperation = IsEqOp(LeftOp, RightOp);
	std::size_t LeftBitWidth = 8 * LeftOp->GetByteWidth();

	// For the common case of test reg1,reg1 we emit "reg1" instead of "reg1 and reg1" below.

	// ZeroFlag
	if (EmitZeroFlag) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " X86.ZeroFlag := ((");
		this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
		if (!(ReflexiveOperation && BitwiseAndOperation)) {
			SMP_fprintf(OutFile, "%s", OperatorString);
			this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
		}
		SMP_fprintf(OutFile, ") = 0);\n");
	}

	// SignFlag
	if (!FloatingStackOperation) {
		if (FloatingOperation) { // zero out the SignFlag
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " X86.SignFlag := false;\n");
		}
		else if (EmitSignFlag) {
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " X86.SignFlag := ((");
			this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
			if (!(ReflexiveOperation && BitwiseAndOperation)) {
				SMP_fprintf(OutFile, "%s", OperatorString);
				this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
			}
			SMP_fprintf(OutFile, ") > X86.MaxSignedInt%d);\n", LeftBitWidth);
		}
	}

	// ParityFlag; opaque to SPARK provers, so both results are possible
	if (EmitParityFlag) {
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " X86.ParityFlag := X86.SetParity(X86.Unsigned64(");
		this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
		SMP_fprintf(OutFile, "));\n");
	}

	// CarryFlag
	if (!BitwiseAndOperation && EmitCarryFlag) {
		// cmp A,B sets CarryFlag if A < B, unsigned
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " X86.CarryFlag := (");
		this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
		SMP_fprintf(OutFile, " < ", OperatorString);
		this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
		SMP_fprintf(OutFile, ");\n");
	}
	else if (BitwiseAndOperation) { // TEST opcode always zeroes the CarryFlag
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " X86.CarryFlag := false;\n");
	}

	// OverflowFlag
	if (EmitOverflowFlag && SubtractionOperation) {
		// cmp A,B sets OverflowFlag if A is positive, B is negative, but (A-B) is negative, or A/B/(A-B) are neg/pos/pos
		//  Note that our SPARK Ada uses Unsigned values for registers, so we look at magnitudes to infer the "sign bit"
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " X86.OverflowFlag := ((X86.SignFlag and (");
		this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
		SMP_fprintf(OutFile, " > X86.MaxSignedInt%d) and (", LeftBitWidth);
		this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
		SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d))", LeftBitWidth);
		SMP_fprintf(OutFile, " or ((not X86.SignFlag) and (");
		this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
		SMP_fprintf(OutFile, " > X86.MaxSignedInt%d) and (", LeftBitWidth);
		this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
		SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d)));\n", LeftBitWidth);
	}
	else if (BitwiseAndOperation || FloatingOperation) { // TEST opcode and floating compares always zero the OverflowFlag
		PrintSPARKIndentTabs(OutFile);
		SMP_fprintf(OutFile, " X86.OverflowFlag := false;\n");
	}

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

// emit SPARK Ada for ops that set flags (add, sub, etc.)
void SMPInstr::MDEmitSPARKAdaArithmeticSetsCondCodes(FILE *OutFile) {
	STARS_ea_t InstAddr = this->GetAddr();
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	assert((nullptr != CurrRT) && CurrRT->HasRightSubTree());
	SMPoperator CurrOper = CurrRT->GetRightTree()->GetOperator();
	bool ProcCallHandlesCondCodes = ((SMP_SUBTRACT_BORROW == CurrOper) || (SMP_ADD_CARRY == CurrOper)); 
		// X86 package procedure will set condition codes

	std::string OperatorString;
	uint16_t opcode = this->GetIDAOpcode();
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	bool PrefixProcCall = false;
	bool PrefixUnary = false;
	const STARSOpndTypePtr LeftOp = CurrRT->GetConstLeftOperandNoNorm();
	const STARSOpndTypePtr RightOp = CurrRT->GetRightTree()->GetConstRightOperandNoNorm();
	assert((nullptr != LeftOp) && (nullptr != RightOp));
	std::size_t LeftBitWidth = 8 * LeftOp->GetByteWidth();
	bool ConstFollows = RightOp->IsImmedOp();

	bool EmitCarryFlag = true;
	bool EmitOverflowFlag = true;
	bool EmitSignFlag = true;
	bool EmitZeroFlag = true;
	bool EmitParityFlag = true;

	// NOTE: We can optimize by analyzing which flags are actually live from this instruction.
	set<int> LiveFlagRegs;
	bool LiveFlags = this->GetBlock()->AreFlagsLiveAfterInst(InstAddr, LiveFlagRegs);
	if (!LiveFlags) {
		SMP_msg("INFO: Arithmetic inst at %llx with no live flags used after inst.\n", (uint64_t) InstAddr);
		// Reset default flags to false.
		EmitCarryFlag = false;
		EmitZeroFlag = false;
		EmitSignFlag = false;
		EmitOverflowFlag = false;
		EmitParityFlag = false;
	}
	else {
		// Reset default flags to false.
		EmitCarryFlag = false;
		EmitZeroFlag = false;
		EmitSignFlag = false;
		EmitOverflowFlag = false;
		EmitParityFlag = false;
		for (set<int>::const_iterator FlagIter = LiveFlagRegs.cbegin(); FlagIter != LiveFlagRegs.cend(); ++FlagIter) {
			int FlagRegNum = (*FlagIter);
			switch (FlagRegNum) {
			case MD_CARRY_FLAG:
				EmitCarryFlag = true;
				break;

			case MD_ZERO_FLAG:
				EmitZeroFlag = true;
				break;

			case MD_SIGN_FLAG:
				EmitSignFlag = true;
				break;

			case MD_OVERFLOW_FLAG:
				EmitOverflowFlag = true;
				EmitSignFlag = true; // overflow flag depends on the sign flag
				break;

			case MD_PARITY_FLAG:
				EmitParityFlag = true;
				break;

			default:
				SMP_msg("ERROR: Unknown live flag register %d at instruction %llx\n", FlagRegNum, (uint64_t) InstAddr);
				break;
			}
		} // end for all LiveFlagRegs set members
	}

	PrintSPARKAdaOperator(CurrOper, OperatorString, PrefixProcCall, PrefixUnary, ConstFollows);

	if (!ProcCallHandlesCondCodes) {
		bool Subtraction = OperatorString == " - ";
		bool Addition = OperatorString == " + ";

		// ZeroFlag
		if (EmitZeroFlag) {
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " X86.ZeroFlag := ((");
			if (!PrefixUnary) {
				this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
				SMP_fprintf(OutFile, "%s", OperatorString.c_str());
				this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
			}
			else { // unary operation like negate, bitwise not, etc.
				SMP_fprintf(OutFile, "%s", OperatorString.c_str());
				this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
			}
			SMP_fprintf(OutFile, ") = 0);\n");
		}

		// SignFlag
		if (EmitSignFlag) {
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " X86.SignFlag := ((");
			if (!PrefixUnary) {
				this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
				SMP_fprintf(OutFile, "%s", OperatorString.c_str());
				this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
			}
			else { // unary operation like negate, bitwise not, etc.
				SMP_fprintf(OutFile, "%s", OperatorString.c_str());
				this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
			}
			SMP_fprintf(OutFile, ") > X86.MaxSignedInt%d);\n", LeftBitWidth);
		}

		// ParityFlag; opaque to SPARK provers, so both results are possible
		if (EmitParityFlag) {
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " X86.ParityFlag := X86.SetParity(");
			this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
			SMP_fprintf(OutFile, ");\n");
		}

		// CarryFlag
		if (EmitCarryFlag) {
			// sub A,B sets CarryFlag if A < B, unsigned; add A,B sets CarryFlag if result > MaxInt
			if (Subtraction) {
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " X86.CarryFlag := (");
				this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
				SMP_fprintf(OutFile, " < ");
				this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
				SMP_fprintf(OutFile, ");\n");
			}
			else if (Addition) {
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " X86.CarryFlag := ((");
				this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false);
				SMP_fprintf(OutFile, " %s ", OperatorString.c_str());
				this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false);
				SMP_fprintf(OutFile, ") > X86.MaxUnsignedInt%d);\n", LeftBitWidth);
			}
		}

		// OverflowFlag
		if (EmitOverflowFlag) {
			// add or sub A,B sets OverflowFlag if A and B have the opposite sign flag from the result.
			//  Note that our SPARK Ada uses Unsigned modulo values for registers, so we look at magnitudes to infer the "sign bit"
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " X86.OverflowFlag := ((X86.SignFlag and (");
			this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, true);
			SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d) and (", LeftBitWidth);
			this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, true);
			SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d))", LeftBitWidth);
			SMP_fprintf(OutFile, " or ((not X86.SignFlag) and (");
			this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, true);
			SMP_fprintf(OutFile, " > X86.MaxSignedInt%d) and (", LeftBitWidth);
			this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, true);
			SMP_fprintf(OutFile, " > X86.MaxSignedInt%d)));\n", LeftBitWidth);
		}
	}

	// Now, emit the SPARK Ada for the arithmetic operation.
	CurrRT->EmitSPARKAda(OutFile);

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

// Emit SPARK Ada for moving a condition code value or expr into a register
void SMPInstr::MDEmitSPARKAdaSetCondCodeIntoReg(FILE *OutFile) {
	bool ErrorFound = false;
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	const STARSOpndTypePtr LeftOp = CurrRT->GetConstLeftOperandNoNorm();
	std::size_t LeftOpndByteWidth = LeftOp->GetByteWidth();
	bool LeftSubwordWidth = (global_STARS_program->GetSTARS_ISA_Bytewidth() > LeftOpndByteWidth);
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();

	// We will produce conditional assignments, Ada 2012 style:
	//  RAX := (if (CarryFlag) then 1 else 0);
	//  However, for subword registers, we need procedure calls to write:
	//  X86.Write_AL(if (CarryFlag) then 1 else 0);

	PrintSPARKIndentTabs(OutFile);
	this->PrintSPARKAdaOperand(LeftOp, OutFile, true, UseFP, true, false);
	if (LeftSubwordWidth) {
		// We have printed "X86.Write_AL(" so far, in the case of LeftOp == AL, for example.
		SMP_fprintf(OutFile, " if ");
	}
	else {
		SMP_fprintf(OutFile, " := (if ");
	}

	uint16_t opcode = this->GetIDAOpcode();
	switch (opcode) {
		case STARS_NN_seta:                // Set Byte if Above (CF=0 & ZF=0)
		case STARS_NN_setnbe:              // Set Byte if Not Below or Equal (CF=0 & ZF=0)
			SMP_fprintf(OutFile, "(not (X86.CarryFlag or X86.ZeroFlag))");
			break;

		case STARS_NN_setae:               // Set Byte if Above or Equal (CF=0)
		case STARS_NN_setnb:               // Set Byte if Not Below (CF=0)
		case STARS_NN_setnc:               // Set Byte if Not Carry (CF=0)
			SMP_fprintf(OutFile, "(not X86.CarryFlag)");
			break;

		case STARS_NN_setb:                // Set Byte if Below (CF=1)
		case STARS_NN_setc:                // Set Byte if Carry (CF=1)
		case STARS_NN_setnae:              // Set Byte if Not Above or Equal (CF=1)
			SMP_fprintf(OutFile, "(X86.CarryFlag)");
			break;

		case STARS_NN_setbe:               // Set Byte if Below or Equal (CF=1 | ZF=1)
		case STARS_NN_setna:               // Set Byte if Not Above (CF=1 | ZF=1)
			SMP_fprintf(OutFile, "(X86.CarryFlag or X86.ZeroFlag)");
			break;

		case STARS_NN_sete:                // Set Byte if Equal (ZF=1)
		case STARS_NN_setz:                // Set Byte if Zero (ZF=1)
			SMP_fprintf(OutFile, "(X86.ZeroFlag)");
			break;

		case STARS_NN_setg:                // Set Byte if Greater (ZF=0 & SF=OF)
		case STARS_NN_setnle:              // Set Byte if Not Less or Equal (ZF=0 & SF=OF)
			SMP_fprintf(OutFile, "((not X86.ZeroFlag) and (X86.SignFlag = X86.OverflowFlag))");
			break;

		case STARS_NN_setge:               // Set Byte if Greater or Equal (SF=OF)
		case STARS_NN_setnl:               // Set Byte if Not Less (SF=OF)
			SMP_fprintf(OutFile, "(X86.SignFlag = X86.OverflowFlag)");
			break;

		case STARS_NN_setl:                // Set Byte if Less (SF!=OF)
		case STARS_NN_setnge:              // Set Byte if Not Greater or Equal (ZF=1)
			SMP_fprintf(OutFile, "(X86.SignFlag /= X86.OverflowFlag)");
			break;

		case STARS_NN_setle:               // Set Byte if Less or Equal (ZF=1 | SF!=OF)
		case STARS_NN_setng:               // Set Byte if Not Greater (ZF=1 | SF!=OF)
			SMP_fprintf(OutFile, "(X86.ZeroFlag or (X86.SignFlag /= X86.OverflowFlag))");
			break;

		case STARS_NN_setne:               // Set Byte if Not Equal (ZF=0)
		case STARS_NN_setnz:               // Set Byte if Not Zero (ZF=0)
			SMP_fprintf(OutFile, "(not X86.ZeroFlag)");
			break;

		case STARS_NN_setno:               // Set Byte if Not Overflow (OF=0)
			SMP_fprintf(OutFile, "(not X86.OverflowFlag)");
			break;

		case STARS_NN_setnp:               // Set Byte if Not Parity (PF=0)
		case STARS_NN_setpo:               // Set Byte if Parity Odd  (PF=0)
			SMP_fprintf(OutFile, "(not X86.ParityFlag)");
			break;

		case STARS_NN_setns:               // Set Byte if Not Sign (SF=0)
			SMP_fprintf(OutFile, "(not X86.SignFlag)");
			break;

		case STARS_NN_seto:                // Set Byte if Overflow (OF=1)
			SMP_fprintf(OutFile, "(X86.OverflowFlag)");
			break;

		case STARS_NN_setp:                // Set Byte if Parity (PF=1)
		case STARS_NN_setpe:               // Set Byte if Parity Even (PF=1)
			SMP_fprintf(OutFile, "(X86.ParityFlag)");
			break;

		case STARS_NN_sets:                // Set Byte if Sign (SF=1)
			SMP_fprintf(OutFile, "(X86.SignFlag)");
			break;

		default:
			ErrorFound = true;
			SMP_fprintf(OutFile, "ERROR: Unknown set-condition-code opcode at %llx\n", (unsigned long long) this->GetAddr());
			break;

	} // end of switch on opcode

	if (!ErrorFound) {
		SMP_fprintf(OutFile, " then 1 else 0);\n");
	}

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

// Emit SPARK Ada equivalent for the current conditional branch.
void SMPInstr::MDEmitSPARKAdaCondition(FILE *OutFile) {
	uint16_t opcode = this->GetIDAOpcode();
	switch (opcode) {
		case STARS_NN_ja:                  // Jump if Above (CF=0 & ZF=0)
		case STARS_NN_jnbe:                // Jump if Not Below or Equal (CF=0 & ZF=0)
		case STARS_NN_cmova:				 // Move if Above (CF=0 & ZF=0)
			SMP_fprintf(OutFile, "(not (X86.CarryFlag or X86.ZeroFlag))");
			break;

		case STARS_NN_jae:                 // Jump if Above or Equal (CF=0)
		case STARS_NN_jnb:                 // Jump if Not Below (CF=0)
		case STARS_NN_jnc:                 // Jump if Not Carry (CF=0)
		case STARS_NN_cmovnb:				 // Move if Not Below (CF=0)
			SMP_fprintf(OutFile, "(not X86.CarryFlag)");
			break;

		case STARS_NN_jb:                  // Jump if Below (CF=1)
		case STARS_NN_jc:                  // Jump if Carry (CF=1)
		case STARS_NN_jnae:                // Jump if Not Above or Equal (CF=1)
		case STARS_NN_cmovb:				 // Move if Below (CF=1)
			SMP_fprintf(OutFile, "(X86.CarryFlag)");
			break;

		case STARS_NN_jbe:                 // Jump if Below or Equal (CF=1 | ZF=1)
		case STARS_NN_jna:                 // Jump if Not Above (CF=1 | ZF=1)
		case STARS_NN_cmovbe:				 // Move if Below or Equal (CF=1 | ZF=1)
			SMP_fprintf(OutFile, "(X86.CarryFlag or X86.ZeroFlag)");
			break;

		case STARS_NN_jcxz:                // Jump if CX is 0
			SMP_fprintf(OutFile, "(X86.CX = 0)");
			break;

		case STARS_NN_jecxz:               // Jump if ECX is 0
			SMP_fprintf(OutFile, "(X86.ECX = 0)");
			break;

		case STARS_NN_jrcxz:               // Jump if RCX is 0
			SMP_fprintf(OutFile, "(X86.RCX = 0)");
			break;

		case STARS_NN_je:                  // Jump if Equal (ZF=1)
		case STARS_NN_jz:                  // Jump if Zero (ZF=1)
		case STARS_NN_cmovz:				 // Move if Zero (ZF=1)
			SMP_fprintf(OutFile, "(X86.ZeroFlag)");
			break;
		
		case STARS_NN_jg:                  // Jump if Greater (ZF=0 & SF=OF)
		case STARS_NN_jnle:                // Jump if Not Less or Equal (ZF=0 & SF=OF)
		case STARS_NN_cmovg:				 // Move if Greater (ZF=0 & SF=OF)
			SMP_fprintf(OutFile, "((not X86.ZeroFlag) and (X86.SignFlag = X86.OverflowFlag))");
			break;

		case STARS_NN_jge:                 // Jump if Greater or Equal (SF=OF)
		case STARS_NN_jnl:                 // Jump if Not Less (SF=OF)
		case STARS_NN_cmovge:				 // Move if Greater or Equal (SF=OF)
			SMP_fprintf(OutFile, "(X86.SignFlag = X86.OverflowFlag)");
			break;

		case STARS_NN_jl:                  // Jump if Less (SF!=OF)
		case STARS_NN_jnge:                // Jump if Not Greater or Equal (SF!=OF)
		case STARS_NN_cmovl:				 // Move if Less (SF!=OF)
			SMP_fprintf(OutFile, "(X86.SignFlag /= X86.OverflowFlag)");
			break;

		case STARS_NN_jle:                 // Jump if Less or Equal (ZF=1 | SF!=OF)
		case STARS_NN_jng:                 // Jump if Not Greater (ZF=1 | SF!=OF)
		case STARS_NN_cmovle:				 // Move if Less or Equal (ZF=1 | SF!=OF)
			SMP_fprintf(OutFile, "(X86.ZeroFlag or (X86.SignFlag /= X86.OverflowFlag))");
			break;

		case STARS_NN_jne:                 // Jump if Not Equal (ZF=0)
		case STARS_NN_jnz:                 // Jump if Not Zero (ZF=0)
		case STARS_NN_cmovnz:				 // Move if Not Zero (ZF=0)
			SMP_fprintf(OutFile, "(not X86.ZeroFlag)");
			break;

		case STARS_NN_jno:                 // Jump if Not Overflow (OF=0)
		case STARS_NN_cmovno:				 // Move if Not Overflow (OF=0)
			SMP_fprintf(OutFile, "(not X86.OverflowFlag)");
			break;

		case STARS_NN_jnp:                 // Jump if Not Parity (PF=0)
		case STARS_NN_jpo:                 // Jump if Parity Odd  (PF=0)
		case STARS_NN_cmovnp:				 // Move if Not Parity (PF=0)
			SMP_fprintf(OutFile, "(not X86.ParityFlag)");
			break;

		case STARS_NN_jns:                 // Jump if Not Sign (SF=0)
		case STARS_NN_cmovns:				 // Move if Not Sign (SF=0)
			SMP_fprintf(OutFile, "(not X86.SignFlag)");
			break;

		case STARS_NN_jo:                  // Jump if Overflow (OF=1)
		case STARS_NN_cmovo:				 // Move if Overflow (OF=1)
			SMP_fprintf(OutFile, "(X86.OverflowFlag)");
			break;

		case STARS_NN_jp:                  // Jump if Parity (PF=1)
		case STARS_NN_jpe:                 // Jump if Parity Even (PF=1)
		case STARS_NN_cmovp:				 // Move if Parity (PF=1)
			SMP_fprintf(OutFile, "(X86.ParityFlag)");
			break;

		case STARS_NN_js:                  // Jump if Sign (SF=1)
		case STARS_NN_cmovs:				 // Move if Sign (SF=1)
			SMP_fprintf(OutFile, "(X86.SignFlag)");
			break;

		default:
			SMP_fprintf(OutFile, "ERROR: Unknown conditional branch opcode at %llx  %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm());
			break;
	}
	return;
} // end of SMPInstr::MDEmitSPARKAdaCondition()

// Invert the condition of the current conditional branch and emit SPARK Ada equivalent.
void SMPInstr::MDEmitSPARKAdaInvertedCondition(FILE *OutFile) {
	uint16_t opcode = this->GetIDAOpcode();
	switch (opcode) {
		case STARS_NN_ja:                  // Jump if Above (CF=0 & ZF=0)
		case STARS_NN_jnbe:                // Jump if Not Below or Equal (CF=0 & ZF=0)
			SMP_fprintf(OutFile, "(X86.CarryFlag or X86.ZeroFlag)");
			break;

		case STARS_NN_jae:                 // Jump if Above or Equal (CF=0)
		case STARS_NN_jnb:                 // Jump if Not Below (CF=0)
		case STARS_NN_jnc:                 // Jump if Not Carry (CF=0)
			SMP_fprintf(OutFile, "(X86.CarryFlag)");
			break;

		case STARS_NN_jb:                  // Jump if Below (CF=1)
		case STARS_NN_jc:                  // Jump if Carry (CF=1)
		case STARS_NN_jnae:                // Jump if Not Above or Equal (CF=1)
			SMP_fprintf(OutFile, "(not X86.CarryFlag)");
			break;

		case STARS_NN_jbe:                 // Jump if Below or Equal (CF=1 | ZF=1)
		case STARS_NN_jna:                 // Jump if Not Above (CF=1 | ZF=1)
			SMP_fprintf(OutFile, "(not (X86.CarryFlag or X86.ZeroFlag))");
			break;

		case STARS_NN_jcxz:                // Jump if CX is 0
			SMP_fprintf(OutFile, "(X86.CX /= 0)");
			break;

		case STARS_NN_jecxz:               // Jump if ECX is 0
			SMP_fprintf(OutFile, "(X86.ECX /= 0)");
			break;

		case STARS_NN_jrcxz:               // Jump if RCX is 0
			SMP_fprintf(OutFile, "(X86.RCX /= 0)");
			break;

		case STARS_NN_je:                  // Jump if Equal (ZF=1)
		case STARS_NN_jz:                  // Jump if Zero (ZF=1)
			SMP_fprintf(OutFile, "(not X86.ZeroFlag)");
			break;
		
		case STARS_NN_jg:                  // Jump if Greater (ZF=0 & SF=OF)
		case STARS_NN_jnle:                // Jump if Not Less or Equal (ZF=0 & SF=OF)
			SMP_fprintf(OutFile, "(X86.ZeroFlag or (X86.SignFlag /= X86.OverflowFlag))");
			break;

		case STARS_NN_jge:                 // Jump if Greater or Equal (SF=OF)
		case STARS_NN_jnl:                 // Jump if Not Less (SF=OF)
			SMP_fprintf(OutFile, "(X86.SignFlag /= X86.OverflowFlag)");
			break;

		case STARS_NN_jl:                  // Jump if Less (SF!=OF)
		case STARS_NN_jnge:                // Jump if Not Greater or Equal (SF!=OF)
			SMP_fprintf(OutFile, "(X86.SignFlag = X86.OverflowFlag)");
			break;

		case STARS_NN_jle:                 // Jump if Less or Equal (ZF=1 | SF!=OF)
		case STARS_NN_jng:                 // Jump if Not Greater (ZF=1 | SF!=OF)
			SMP_fprintf(OutFile, "((not X86.ZeroFlag) and (X86.SignFlag = X86.OverflowFlag))");
			break;

		case STARS_NN_jne:                 // Jump if Not Equal (ZF=0)
		case STARS_NN_jnz:                 // Jump if Not Zero (ZF=0)
			SMP_fprintf(OutFile, "(X86.ZeroFlag)");
			break;

		case STARS_NN_jno:                 // Jump if Not Overflow (OF=0)
			SMP_fprintf(OutFile, "(X86.OverflowFlag)");
			break;

		case STARS_NN_jnp:                 // Jump if Not Parity (PF=0)
		case STARS_NN_jpo:                 // Jump if Parity Odd  (PF=0)
			SMP_fprintf(OutFile, "(X86.ParityFlag)");
			break;

		case STARS_NN_jns:                 // Jump if Not Sign (SF=0)
			SMP_fprintf(OutFile, "(X86.SignFlag)");
			break;

		case STARS_NN_jo:                  // Jump if Overflow (OF=1)
			SMP_fprintf(OutFile, "(not X86.OverflowFlag)");
			break;

		case STARS_NN_jp:                  // Jump if Parity (PF=1)
		case STARS_NN_jpe:                 // Jump if Parity Even (PF=1)
			SMP_fprintf(OutFile, "(not X86.ParityFlag)");
			break;

		case STARS_NN_js:                  // Jump if Sign (SF=1)
			SMP_fprintf(OutFile, "(not X86.SignFlag)");
			break;

		default:
			SMP_fprintf(OutFile, "ERROR: Unknown conditional branch opcode at %llx  %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm());
			break;
	}
	return;
} // end of SMPInstr::MDEmitSPARKAdaInvertedCondition()

// emit SPARK Ada comparison expr for current signed-compare conditional branch
void SMPInstr::MDEmitSPARKAdaExprCompare(FILE *OutFile) {
	uint16_t opcode = this->GetIDAOpcode();
	switch (opcode) {
		case STARS_NN_je:                  // Jump if Equal (ZF=1)
		case STARS_NN_jz:                  // Jump if Zero (ZF=1)
			SMP_fprintf(OutFile, " = ");
			break;

		case STARS_NN_jg:                  // Jump if Greater (ZF=0 & SF=OF)
		case STARS_NN_jnle:                // Jump if Not Less or Equal (ZF=0 & SF=OF)
			SMP_fprintf(OutFile, " > ");
			break;

		case STARS_NN_jge:                 // Jump if Greater or Equal (SF=OF)
		case STARS_NN_jnl:                 // Jump if Not Less (SF=OF)
			SMP_fprintf(OutFile, " >= ");
			break;

		case STARS_NN_jl:                  // Jump if Less (SF!=OF)
		case STARS_NN_jnge:                // Jump if Not Greater or Equal (SF!=OF)
			SMP_fprintf(OutFile, " < ");
			break;

		case STARS_NN_jle:                 // Jump if Less or Equal (ZF=1 | SF!=OF)
		case STARS_NN_jng:                 // Jump if Not Greater (ZF=1 | SF!=OF)
			SMP_fprintf(OutFile, " <= ");
			break;

		case STARS_NN_jne:                 // Jump if Not Equal (ZF=0)
		case STARS_NN_jnz:                 // Jump if Not Zero (ZF=0)
			SMP_fprintf(OutFile, " /= ");
			break;

		default:
			SMP_fprintf(OutFile, "ERROR: Unexpected signed compare conditional branch opcode at %llx  %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm());
			break;
	}
	
	return;
} // end of SMPInstr::MDEmitSPARKAdaExprCompare()

// emit SPARK Ada comparison expr for current unsigned-compare conditional branch
void SMPInstr::MDEmitSPARKAdaExprTest(FILE *OutFile) {
	uint16_t opcode = this->GetIDAOpcode();
	switch (opcode) {
	case STARS_NN_je:                  // Jump if Equal (ZF=1)
	case STARS_NN_jz:                  // Jump if Zero (ZF=1)
		SMP_fprintf(OutFile, " = ");
		break;

	case STARS_NN_jg:                  // Jump if Greater (ZF=0 & SF=OF)
	case STARS_NN_jnle:                // Jump if Not Less or Equal (ZF=0 & SF=OF)
		SMP_fprintf(OutFile, " > ");
		break;

	case STARS_NN_jge:                 // Jump if Greater or Equal (SF=OF)
	case STARS_NN_jnl:                 // Jump if Not Less (SF=OF)
		SMP_fprintf(OutFile, " >= ");
		break;

	case STARS_NN_jl:                  // Jump if Less (SF!=OF)
	case STARS_NN_jnge:                // Jump if Not Greater or Equal (SF!=OF)
		SMP_fprintf(OutFile, " < ");
		break;

	case STARS_NN_jle:                 // Jump if Less or Equal (ZF=1 | SF!=OF)
	case STARS_NN_jng:                 // Jump if Not Greater (ZF=1 | SF!=OF)
		SMP_fprintf(OutFile, " <= ");
		break;

	case STARS_NN_jne:                 // Jump if Not Equal (ZF=0)
	case STARS_NN_jnz:                 // Jump if Not Zero (ZF=0)
		SMP_fprintf(OutFile, " /= ");
		break;

	default:
		SMP_fprintf(OutFile, "ERROR: Unexpected unsigned compare conditional branch opcode at %llx  %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm());
		break;
	}

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

// return SMP_GREATER_THAN for ja and jg opcodes, etc.
SMPoperator SMPInstr::MDConvertJumpToOperator(void) const {
	uint16_t opcode = this->GetIDAOpcode();
	SMPoperator RelationalOperator = SMP_NULL_OPERATOR;
	switch (opcode) {
	case STARS_NN_ja:                  // Jump if Above (CF=0 & ZF=0)
	case STARS_NN_jnbe:                // Jump if Not Below or Equal (CF=0 & ZF=0)
	case STARS_NN_cmova:			   // Move if Above (CF=0 & ZF=0)
	case STARS_NN_jg:                  // Jump if Greater (ZF=0 & SF=OF)
	case STARS_NN_jnle:                // Jump if Not Less or Equal (ZF=0 & SF=OF)
	case STARS_NN_cmovg:				 // Move if Greater (ZF=0 & SF=OF)
		RelationalOperator = SMP_GREATER_THAN;
		break;

	case STARS_NN_jae:                 // Jump if Above or Equal (CF=0)
	case STARS_NN_jnb:                 // Jump if Not Below (CF=0)
	case STARS_NN_jnc:                 // Jump if Not Carry (CF=0)
	case STARS_NN_cmovnb:				 // Move if Not Below (CF=0)
	case STARS_NN_jge:                 // Jump if Greater or Equal (SF=OF)
	case STARS_NN_jnl:                 // Jump if Not Less (SF=OF)
	case STARS_NN_cmovge:				 // Move if Greater or Equal (SF=OF)
		RelationalOperator = SMP_GREATER_EQUAL;
		break;

	case STARS_NN_jb:                  // Jump if Below (CF=1)
	case STARS_NN_jc:                  // Jump if Carry (CF=1)
	case STARS_NN_jnae:                // Jump if Not Above or Equal (CF=1)
	case STARS_NN_cmovb:				 // Move if Below (CF=1)
	case STARS_NN_jl:                  // Jump if Less (SF!=OF)
	case STARS_NN_jnge:                // Jump if Not Greater or Equal (SF!=OF)
	case STARS_NN_cmovl:				 // Move if Less (SF!=OF)
		RelationalOperator = SMP_LESS_THAN;
		break;

	case STARS_NN_jbe:                 // Jump if Below or Equal (CF=1 | ZF=1)
	case STARS_NN_jna:                 // Jump if Not Above (CF=1 | ZF=1)
	case STARS_NN_cmovbe:				 // Move if Below or Equal (CF=1 | ZF=1)
	case STARS_NN_jle:                 // Jump if Less or Equal (ZF=1 | SF!=OF)
	case STARS_NN_jng:                 // Jump if Not Greater (ZF=1 | SF!=OF)
	case STARS_NN_cmovle:				 // Move if Less or Equal (ZF=1 | SF!=OF)
		RelationalOperator = SMP_LESS_EQUAL;
		break;

	case STARS_NN_jcxz:                // Jump if CX is 0
		break;

	case STARS_NN_jecxz:               // Jump if ECX is 0
		break;

	case STARS_NN_jrcxz:               // Jump if RCX is 0
		break;

	case STARS_NN_je:                  // Jump if Equal (ZF=1)
	case STARS_NN_jz:                  // Jump if Zero (ZF=1)
	case STARS_NN_cmovz:				 // Move if Zero (ZF=1)
		RelationalOperator = SMP_EQUAL;
		break;

	case STARS_NN_jne:                 // Jump if Not Equal (ZF=0)
	case STARS_NN_jnz:                 // Jump if Not Zero (ZF=0)
	case STARS_NN_cmovnz:				 // Move if Not Zero (ZF=0)
		RelationalOperator = SMP_NOT_EQUAL;
		break;

	case STARS_NN_jno:                 // Jump if Not Overflow (OF=0)
	case STARS_NN_cmovno:				 // Move if Not Overflow (OF=0)
		RelationalOperator = SMP_NOT_OVERFLOW;
		break;

	case STARS_NN_jnp:                 // Jump if Not Parity (PF=0)
	case STARS_NN_jpo:                 // Jump if Parity Odd  (PF=0)
	case STARS_NN_cmovnp:				 // Move if Not Parity (PF=0)
		RelationalOperator = SMP_NOT_PARITY;
		break;

	case STARS_NN_jns:                 // Jump if Not Sign (SF=0)
	case STARS_NN_cmovns:				 // Move if Not Sign (SF=0)
		RelationalOperator = SMP_NOT_SIGN_BIT_SET;
		break;

	case STARS_NN_jo:                  // Jump if Overflow (OF=1)
	case STARS_NN_cmovo:				 // Move if Overflow (OF=1)
		RelationalOperator = SMP_OVERFLOW;
		break;

	case STARS_NN_jp:                  // Jump if Parity (PF=1)
	case STARS_NN_jpe:                 // Jump if Parity Even (PF=1)
	case STARS_NN_cmovp:				 // Move if Parity (PF=1)
		RelationalOperator = SMP_PARITY;
		break;

	case STARS_NN_js:                  // Jump if Sign (SF=1)
	case STARS_NN_cmovs:				 // Move if Sign (SF=1)
		RelationalOperator = SMP_SIGN_BIT_SET;
		break;

	default:
		SMP_msg("ERROR: Unknown conditional branch opcode at %llx  %s\n", (uint64_t) this->GetAddr(), this->GetDisasm());
		break;
	}

	return RelationalOperator;
} // end of SMPInstr::MDConvertJumpToOperator()


// Emit SPARK Ada Loop_Invariant pragmas at the top of each loop to assist in proofs.
void SMPInstr::EmitSPARKAdaLoopInvariants(FILE *BodyFile) const {
	assert(this->GetBlock()->GetFunc()->TranslatingLoopToProc());

	size_t LoopIndex = this->GetBlock()->GetFunc()->FindLoopNumFromHeadBlockNum(this->GetBlock()->GetNumber());
	assert(LoopIndex < this->GetBlock()->GetFunc()->GetNumLoops());

	if (this->GetBlock()->GetFunc()->DoesLoopUseStackPtrRegs(LoopIndex)) {
		// Stack pointer is loop invariant.
		PrintSPARKIndentTabs(BodyFile);
		SMP_fprintf(BodyFile, "pragma Loop_Invariant(X86.RSP = X86.RSP'Loop_Entry);\n");
		if (this->GetBlock()->GetFunc()->UsesFramePointer()) {
			// Frame pointer is loop invariant.
			PrintSPARKIndentTabs(BodyFile);
			SMP_fprintf(BodyFile, "pragma Loop_Invariant(X86.RBP = X86.RBP'Loop_Entry);\n");
		}
	}

	this->GetBlock()->GetFunc()->EmitSPARKAdaForLoopLimit(BodyFile, this->GetAddr());
	this->GetBlock()->GetFunc()->EmitIncomingLoopRegExprs(BodyFile, LoopIndex, true);

	// Repeat the same ideas in the post-conditions.
	FILE *HeaderFile = global_STARS_program->GetSPARKHeaderFile();

	bool PostPrintStarted = false;
	bool HasPreconditions = this->GetBlock()->GetFunc()->DoesLoopHavePreconditions(LoopIndex);
	if (this->GetBlock()->GetFunc()->DoesLoopUseStackPtrRegs(LoopIndex)) {
		if (!HasPreconditions) {
			SMP_fprintf(HeaderFile, ",\n"); // comma after Global section
		}
		SMP_fprintf(HeaderFile, "\tPost => (X86.RSP = X86.RSP'Old)");
		PostPrintStarted = true;
	}
	bool MemoryRangesPrinted = false;
	if (this->GetBlock()->GetFunc()->DoesLoopWriteMemory(LoopIndex)) {
		if (this->GetBlock()->GetFunc()->UsesFramePointer()) {
			if (PostPrintStarted) {
				SMP_fprintf(HeaderFile, " and \n\t\t (X86.RBP = X86.RBP'Old)");
			}
			else if (HasPreconditions) {
				SMP_fprintf(HeaderFile, "\tPost => (X86.RBP = X86.RBP'Old)");
				PostPrintStarted = true;
			}
			else {
				SMP_fprintf(HeaderFile, ",\n\tPost => (X86.RBP = X86.RBP'Old)");
				PostPrintStarted = true;
			}
		}
		// Print the memory writing range postcondition at the SMPFunction level.
		MemoryRangesPrinted = this->GetBlock()->GetFunc()->EmitSPARKLoopMemRangePostCondition(HeaderFile, BodyFile, this->GetAddr(), PostPrintStarted);
		if (!(MemoryRangesPrinted || PostPrintStarted)) {
			SMP_fprintf(HeaderFile, ";\n\n"); // No post-conditions, so emit a line separator before next procedure spec.
		}
	}
	else {
		// Just close the Globals section.
		SMP_fprintf(HeaderFile, ";\n\n");
	}

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

// Emit SPARK-Ada translation of instruction
void SMPInstr::EmitSPARKAda(FILE *OutFile) {
	// Print the disassembly as a comment before the SPARK translation.
	STARS_ea_t InstAddr = this->GetAddr();
	SMP_fprintf(OutFile, "\n");
	PrintSPARKIndentTabs(OutFile);
	SMP_fprintf(OutFile, " -- %llx  %s\n", (unsigned long long) InstAddr, this->GetDisasm());

	this->SetSPARKTranslated();
	if (this->IsNop()) {
		return;
	}

	bool PrintOperands = false;
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	SMPitype CurrDataFlowType = this->GetDataFlowType();
	std::string FuncTarget;
	STARS_ea_t NextAddr;
	std::size_t STARS_ISA_Bitwidth = global_STARS_program->GetSTARS_ISA_Bitwidth();

	// Detect start of a loop or other control structure.
	if (this->IsFirstInBlock()) {
#if 0
		if (this->GetBlock()->GetFunc()->IsJumpFollowBlock(InstAddr)) {
			uint16_t NestingDepth = this->GetBlock()->GetFunc()->GetJumpToFollowNodeCounter(InstAddr);
			// If we only have an if-then, the counter of jumps will be zero, as we do not
			//  increment the counter when we find the conditional jump around the then-clause.
			//  So, we want to consider this case to have a nesting depth of one.
			if (0 == NestingDepth) {
				NestingDepth = 1;
			}
			// Now, we want to unindent and print "endif;" for each nesting level.
			do {
				--STARS_SPARK_IndentCount;
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, "endif;\n");
				--NestingDepth;
			} while (NestingDepth > 0);
		}
#endif
		if (this->GetBlock()->IsLoopHeaderBlock()) {
			// We want to print "loop" and increase indentation.
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, "loop \n");
			++STARS_SPARK_IndentCount;
			this->EmitSPARKAdaLoopInvariants(OutFile);
		}
	}

	ControlFlowType FuncControlFlowType;
	// Treat tail calls as CALL control flows, then do the RETURN aspect as a special check
	//  inside the CALL case. NOTE: Need special handling for conditional tail calls.
	if (this->IsTailCall() || this->IsCondTailCall()) {
		CurrDataFlowType = CALL;
	}

	switch (CurrDataFlowType) {
		case DEFAULT:
		case LABEL:
		case CASE:
			PrintOperands = true;
			break;

		case JUMP:
		case COND_BRANCH:
			// Special case first: a call instruction within a function, used as a jump
			//  (perhaps as an internal thunk).
			if (this->IsCallUsedAsJump()) {
				// We need to translate the implicit push of the return address before falling through
				//  to the jump translation.
				NextAddr = InstAddr + (STARS_ea_t) this->GetSize();
				PrintSPARKIndentTabs(OutFile);
				// Comment out memory write of return address to speed up prover.
				SMP_fprintf(OutFile, " -- X86.WriteMem%d(Unsigned%d(X86.RSP - %d), 16#%llx# );\n", STARS_ISA_Bitwidth, STARS_ISA_Bitwidth, 
					global_STARS_program->GetSTARS_ISA_Bytewidth(), (unsigned long long) NextAddr);
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " X86.RSP := X86.RSP - %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth());
			}
			// Detect loop-related control flow first, then simple if-else control flow otherwise.
			FuncControlFlowType = this->GetBlock()->GetFunc()->GetControlFlowType(InstAddr);
			if (FALL_THROUGH == FuncControlFlowType) {
				if (COND_BRANCH == CurrDataFlowType) {
					SMP_fprintf(OutFile, "ERROR: Jump instruction of unknown control flow.\n");
				}
				else { // JUMP
					PrintSPARKIndentTabs(OutFile);
					SMP_fprintf(OutFile, "null;\n");
					; // jumps around else clauses are handled in SMPFunction::EmitSPARKAdaForConditional()
				}
			}
			else if (LOOP_BACK == FuncControlFlowType) {
				// We must be looping back to the loop header.
				if (JUMP == CurrDataFlowType) { // simple case
					--STARS_SPARK_IndentCount;
					PrintSPARKIndentTabs(OutFile);
					SMP_fprintf(OutFile, "end loop;\n\n");
				}
				else { // conditionally loops back, might fall out of loop if condition is false.
					// We want to invert the condition and exit on the inverted condition, then fall through
					//  to an unconditional loop back (i.e. "end loop;") statement.
					PrintSPARKIndentTabs(OutFile);
					SMP_fprintf(OutFile, "exit when ");
					this->MDEmitSPARKAdaInvertedCondition(OutFile);
					SMP_fprintf(OutFile, ";\n");
					// Two cases: Loop back from tail block, or loop back from optimized top-testing loop
					//  where the header block is moved to the bottom of the loop and reached on the first
					//  iteration by a JUMP_INTO_LOOP_TEST unconditional jump. In the tail block case, we
					//  are ready for "end loop;" but in the header block case we need to fall through into
					//  the second block of the loop.
					if (this->GetBlock()->IsLoopTailBlock()) {
						--STARS_SPARK_IndentCount;
						PrintSPARKIndentTabs(OutFile);
						SMP_fprintf(OutFile, "end loop;\n\n");
					}
					else {
						assert(this->GetBlock()->IsOptimizedTopLoopTest());
						assert(this->GetBlock()->IsLoopHeaderBlock());
					}
				}
			}
			else if ((LOOP_EXIT == FuncControlFlowType) || (INVERTED_LOOP_EXIT == FuncControlFlowType)) {
				PrintSPARKIndentTabs(OutFile);
				if (JUMP == CurrDataFlowType) {
					SMP_fprintf(OutFile, "exit;\n");
				}
				else { // conditional
					SMP_fprintf(OutFile, "exit when ");
					if (LOOP_EXIT == FuncControlFlowType)
						this->MDEmitSPARKAdaCondition(OutFile);
					else // INVERTED_LOOP_EXIT
						this->MDEmitSPARKAdaInvertedCondition(OutFile);
					SMP_fprintf(OutFile, ";\n");
				}
				// Check for bottom-testing loop case where we have:
				// loop
				//    [instructions]
				//    exit when [condition];
				// end loop;
				if (this->GetBlock()->IsLoopTailBlock()) {
					--STARS_SPARK_IndentCount;
					PrintSPARKIndentTabs(OutFile);
					SMP_fprintf(OutFile, "end loop;\n\n");
				}
			}
			else if (CASE_BREAK_TO_FOLLOW_NODE == FuncControlFlowType) {
				; // No Ada translation; next "when" keyword starts new case with implicit jump before it
			}
			else if (JUMP_TO_DEFAULT_CASE == FuncControlFlowType) {
				; // No Ada translation; the "others" keyword grabs all default case values
			}
			else if ((BRANCH_IF_THEN == FuncControlFlowType) || (BRANCH_IF_THEN_ELSE == FuncControlFlowType)) {
				// ASM looks like:
				//  test or compare to set condition codes
				//  conditionally jump around the code in the if-then
				// We want SPARK Ada:
				//  if (negated condition) then
				// EXCEPTION: An odd case for if-then is to branch to the then-block, which jumps back to the follow-block.
				//  In this odd case, we do not invert the condition:
				//  if (cond) goto then-code
				//  L1: follow-block
				//  code fragment elsewhere:   then-code
				//                             goto L1
				// This needs to translate to:
				// if (cond) then    ; do not invert the condition
				//    then-code
				// endif
				// This odd case is detected by noticing that the fall-through block has more than 1 predecessor (the extra
				//  predecessor is the unconditional jump from the then-code to it).
				bool OddIfThenCase = this->IsOddIfThenCase();
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, "if ");
				if (!OddIfThenCase) {
					this->MDEmitSPARKAdaInvertedCondition(OutFile);
				}
				else {
					this->MDEmitSPARKAdaCondition(OutFile);
				}
				SMP_fprintf(OutFile, " then \n");
				++STARS_SPARK_IndentCount;
			}
			else if ((SHORT_CIRCUIT_BRANCH == FuncControlFlowType) || (SHORT_CIRCUIT_LOOP_EXIT == FuncControlFlowType)) {
				// Multiple short circuit condition branches have been coalesced together.
				STARSCFGBlock *CurrCFGBlock = this->GetBlock()->GetFunc()->GetCFGBlockByNum((size_t) this->GetBlock()->GetNumber());
				assert(NULL != CurrCFGBlock);
				if (!CurrCFGBlock->IsCoalesced()) { // must be header block of compound conditional; header block is where we emit output
					PrintSPARKIndentTabs(OutFile);
					if (SHORT_CIRCUIT_BRANCH == FuncControlFlowType) {
						SMP_fprintf(OutFile, "if not (");
						CurrCFGBlock->GetExpr()->EmitSPARKAdaShortCircuitExpr(OutFile);
						SMP_fprintf(OutFile, ") then \n");
					}
					else { // SHORT_CIRCUIT_LOOP_EXIT
						SMP_fprintf(OutFile, "exit when (");
						CurrCFGBlock->GetExpr()->EmitSPARKAdaShortCircuitExpr(OutFile);
						SMP_fprintf(OutFile, ");\n");
						// Check for bottom-testing loop case where we have:
						// loop
						//    [instructions]
						//    exit when [condition];
						// end loop;
						if (this->GetBlock()->IsLoopTailBlock()) {
							--STARS_SPARK_IndentCount;
							PrintSPARKIndentTabs(OutFile);
							SMP_fprintf(OutFile, "end loop;\n\n");
						}
					}
					++STARS_SPARK_IndentCount;
				}
			}
#if 0
			else if (JUMP_BEFORE_ELSE == FuncControlFlowType) {
				// ASM looks like:
				//  unconditional jump around the else block to the follow block
				// We want to print SPARK Ada:
				//  else
				// Then we want to increment the counter of jumps to the follow node.
				--STARS_SPARK_IndentCount;
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, "else\n");
				++STARS_SPARK_IndentCount;
				this->GetBlock()->GetFunc()->IncrementJumpToFollowNodeCounter(InstAddr);
			}
			else if (JUMP_BEFORE_ELSIF == FuncControlFlowType) {
				// ASM looks like:
				//  unconditional jump around the rest of the if-then-elsif-elsif-...-else structure to the follow node.
				// Currently, we treat this the same as JUMP_BEFORE_ELSE. We might pretty it up in the future.
				--STARS_SPARK_IndentCount;
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, "else\n");
				++STARS_SPARK_IndentCount;
				this->GetBlock()->GetFunc()->IncrementJumpToFollowNodeCounter(InstAddr);
			}
#endif
			else {
				SMP_fprintf(OutFile, "ERROR: Jump instruction of unknown control flow.\n");
			}

			break;

		case INDIR_JUMP:
			// Start switch table translation.
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, "case ");
			this->PrintSPARKAdaOperand(this->RTL.GetRT(0)->GetConstRightOperandNoNorm(), OutFile, false, UseFP, true, false);
			SMP_fprintf(OutFile, " is\n");
			++STARS_SPARK_IndentCount;
			break;

		case CALL:
			// We emit a "call foo" ASM instruction as a sequence of three SPARK Ada statements:
			//  write return address on the stack
			//  decrement the stack pointer
			//  foo; (Ada form of a call to foo()
			NextAddr = InstAddr + (STARS_ea_t) this->GetSize();
			PrintSPARKIndentTabs(OutFile);
			// Comment out memory write of return address to speed up prover.
			SMP_fprintf(OutFile, " -- X86.WriteMem%d((X86.RSP - %d), 16#%llx# );\n",
				STARS_ISA_Bitwidth, global_STARS_program->GetSTARS_ISA_Bytewidth(), (unsigned long long) NextAddr);

			FuncTarget = this->GetTrimmedCalledFunctionName();
			if ((0 == FuncTarget.compare("exit")) || (0 == FuncTarget.compare("abort"))) {
				// The exit() call conflicts with the Ada keyword "exit."
				// FuncTarget = "Zephyr_exit";
				// We want to set Exit_Called and return up the call chain.
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " X86.Exit_Called := true;\n");
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " X86.RSP := X86.RSP + 8;\n");
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " return;\n");
			}
			else {
				if (IsLibFuncName(FuncTarget)) {
					FuncTarget = "C_Library." + FuncTarget;  // Use C_Library Ada package that we created.
				}
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " X86.RSP := X86.RSP - %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth());
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " %s ;\n", FuncTarget.c_str());

				// See if we are calling a function that might call abort() or exit(), et al., somewhere
				//  in its call chain.
				STARS_ea_t TargetAddr = this->GetCallTarget();
				if (STARS_BADADDR != TargetAddr) {
					SMPBasicBlock *CurrBlock = this->GetBlock();
					SMPFunction *TargetFunc = CurrBlock->GetFunc()->GetProg()->FindFunction(TargetAddr);
					if (nullptr != TargetFunc) {
						if ((!TargetFunc->FuncReturnsToCaller()) || TargetFunc->HasCallToNonReturningFunc() || TargetFunc->HasCalleeChainWithNonReturningFunc()) {
							// Call chain could have set X86.Exit_Called, signalling that exit() or something similar was called.
							PrintSPARKIndentTabs(OutFile);
							SMP_fprintf(OutFile, " if X86.Exit_Called then \n");
							PrintSPARKIndentTabs(OutFile);
							SMP_fprintf(OutFile, "\t return;\n");
							PrintSPARKIndentTabs(OutFile);
							SMP_fprintf(OutFile, " end if;\n");
						}
					}
				}
			}

			// Handle tail calls, whose data-flow type was altered from RETURN to CALL.
			if (this->IsTailCall() || this->IsCondTailCall()) {
				// We increase the stack size by 8 to swallow the return address, then
				//  execute a SPARK Ada return instruction.
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " X86.RSP := X86.RSP + %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth());
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " return;\n");
			}
			break;

		case INDIR_CALL:
			break;

		case RETURN:
			// We increase the stack size by 8 to swallow the return address, then
			//  execute a SPARK Ada return instruction.
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " X86.RSP := X86.RSP + %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth());
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, " return;\n");
			break;

		case HALT:
			break;
	}

	if (PrintOperands) {
		int BlockNum = this->GetBlock()->GetNumber();
		int InnerLoopNum = this->GetBlock()->GetFunc()->GetInnermostLoopNum(BlockNum);
		if (this->HasIndirectMemoryWrite()) {
			// If we are in a loop, we need to emit an assertion that the memory address expression is in bounds.
			STARSOpndTypePtr MemDefOp = this->GetMemDef();
			bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
			size_t ByteWidth = MemDefOp->GetByteWidth();
#define STARS_EMIT_SPARK_LOOP_INDIRECT_WRITE_INSAFEREGION 0
			if (0 <= InnerLoopNum) {
				// Inst is in a loop. Did we analyze memory bounds for this memory write in this loop?
				size_t LoopIndex = (size_t) InnerLoopNum;
				STARSExprBoundsIter ExprIter;
				SMPFunction *MyFunc = this->GetBlock()->GetFunc();
				for (ExprIter = MyFunc->GetFirstLoopMemWriteExprBoundsIter(LoopIndex); ExprIter != MyFunc->GetLastLoopMemWriteExprBoundsIter(LoopIndex); ++ExprIter) {
					STARSExpression *LowerExpr = ExprIter->first;
					STARSExpression *UpperExpr = ExprIter->second;
					if ((nullptr != LowerExpr) && (nullptr != UpperExpr) && (InstAddr == LowerExpr->GetOriginalParentInst()->GetAddr())) {
						bool HasArgs = this->GetBlock()->GetFunc()->DoesLoopHaveArgs(InnerLoopNum);
						for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
							PrintSPARKIndentTabs(OutFile);
							SMP_fprintf(OutFile, "pragma Assert(X86.InMemoryRange(");
							this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true);
							if (0 < ByteIndex)
								SMP_fprintf(OutFile, "+%u", ByteIndex);
							SMP_fprintf(OutFile, ", ");
							LowerExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs, true);
							SMP_fprintf(OutFile, ", ");
							UpperExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs, true);
							SMP_fprintf(OutFile, "));\n");
						}
						break; // Only process expr with matching InstAddr
					}
				} // end for all LoopMemWriteBoundExprs in this inner loop
#if STARS_EMIT_SPARK_LOOP_INDIRECT_WRITE_INSAFEREGION
				// Regardless of whether we analyzed the loop, we want to assert that
				//  the memory write is in the safe stack region, unless it is a stack frame write.
				if (!MDIsStackAccessOpnd(MemDefOp, UseFP)) {
					for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
						PrintSPARKIndentTabs(OutFile);
						SMP_fprintf(OutFile, "pragma Assert(X86.InSafeRegion64(");
						this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true);
						if (0 < ByteIndex)
							SMP_fprintf(OutFile, "+%u", ByteIndex);
						SMP_fprintf(OutFile, ", SaveStackPtr));\n");
					}
				}
#endif
			}
			else {
				// For indirect writes outside of loops, see if we mapped the address reg operand back to an incoming arg.
				//  If so, emit an assert that the address reg is just a copy of the InArg.
				STARSInArgMap::const_iterator AddrRegInArgMapIter = this->GetBlock()->GetFunc()->GetAddressRegToInArgMapping(InstAddr);
				if (AddrRegInArgMapIter != this->GetBlock()->GetFunc()->GetLastAddressRegToInArgMapping()) {
					// If RBX maps to saved InArg RDI in a func that starts at 0x400788, we want to emit:
					//  pragma Assert(X86.RBX = RDI_400788);
					// The InArg RDI will have been saved in a Ghost variable called RDI_400788 at function entry.
					STARSOpndTypePtr AddrRegOp = (*AddrRegInArgMapIter).second.first;
					STARSOpndTypePtr InArgOp = (*AddrRegInArgMapIter).second.second;
					PrintSPARKIndentTabs(OutFile);
					SMP_fprintf(OutFile, "pragma Assert(");
					this->PrintSPARKAdaOperand(AddrRegOp, OutFile, false, UseFP, true, false);
					SMP_fprintf(OutFile, "=");
					this->PrintSPARKAdaOperand(InArgOp, OutFile, false, UseFP, false, true);
					// At this point, we have "pragma Assert(RBX = RDI" and we need the "_400788" suffix
					SMP_fprintf(OutFile, "%s );\n", this->GetBlock()->GetFunc()->GetFuncSPARKSuffixString().c_str());
					// In addition to being a copy of the InArg, we want to assert that
					//  the memory write is in the safe stack region.
					for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
						PrintSPARKIndentTabs(OutFile);
						SMP_fprintf(OutFile, "pragma Assert(X86.InSafeRegion64(");
						this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true);
						if (0 < ByteIndex)
							SMP_fprintf(OutFile, "+%u", ByteIndex);
						SMP_fprintf(OutFile, ", SaveStackPtr));\n");
					}
				}
			}
		} // end if indirect memory write

		if (this->MDIsCompareOrTest()) {
			this->MDEmitSPARKAdaCompareOrTest(OutFile);
		}
		else if (this->MDIsAnySetValue()) {
			this->MDEmitSPARKAdaSetCondCodeIntoReg(OutFile);
		}
		else if (this->MDIsPossibleStringLoopingOpcode()) {
			bool WroteMemory = this->MDEmitSPARKAdaStringOperation(OutFile);
			if (WroteMemory && (InnerLoopNum >= 0)) {
				// Emit loop invariant that states that our memory range written/not-written
				//  constraints still hold immediately after the looping string write.
				size_t OutputCount = 0; // first thing written 
				STARS_sval_t IncomingStackDelta = this->GetBlock()->GetFunc()->GetLoopIncomingStackDelta((size_t) InnerLoopNum);
				if (0 > IncomingStackDelta)
					IncomingStackDelta = (0 - IncomingStackDelta);
				PrintSPARKIndentTabs(OutFile);
				this->GetBlock()->GetFunc()->EmitSPARKMemRangeLoopInvariants(OutFile, InnerLoopNum, IncomingStackDelta, false, OutputCount);
			}
		}
		else if (this->MDIsOverflowingOpcode() || this->MDIsUnderflowingOpcode()) {
			this->MDEmitSPARKAdaArithmeticSetsCondCodes(OutFile);
		}
		else {
			bool Conditional = this->MDIsConditionalMoveInstr();
			if (Conditional) {
				// We allow the move to be emitted below, but surround it with if (cond) .. end if;
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " if ");
				this->MDEmitSPARKAdaCondition(OutFile);
				SMP_fprintf(OutFile, " then \n");
				++STARS_SPARK_IndentCount;
			}

			SMPRegTransfer *CurrRT;
			for (std::size_t RTLindex = 0; RTLindex < this->RTL.GetCount(); ++RTLindex) {
				CurrRT = this->RTL.GetRT(RTLindex);
				CurrRT->EmitSPARKAda(OutFile);
			}
			if (Conditional) {
				--STARS_SPARK_IndentCount;
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, " end if;\n");
			}
		} // end if (special cases) ... else ... most insts
		bool DoubleTailBlock = false;
		if (this->IsLastInstInOptimizedLoop(DoubleTailBlock)) {
			--STARS_SPARK_IndentCount;
			PrintSPARKIndentTabs(OutFile);
			SMP_fprintf(OutFile, "end loop;\n\n");
			if (DoubleTailBlock) { // end the outer loop also
				--STARS_SPARK_IndentCount;
				PrintSPARKIndentTabs(OutFile);
				SMP_fprintf(OutFile, "end loop;\n\n");
			}
		}
		
	} // end if (PrintOperands)

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

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

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

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

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

#define MD_FIRST_ENTER_INSTR  STARS_NN_enterw
#define MD_LAST_ENTER_INSTR STARS_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.
	STARSOpndTypePtr ESPOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG);
	unsigned short opcode = this->GetIDAOpcode();
	if ((opcode == STARS_NN_sub) || (opcode == STARS_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.
			set<DefOrUse, LessDefUse>::iterator CurrUse;
			for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
				if (CurrUse->GetOp()->IsImmedOp()) {
					signed long TempImm = (signed long) CurrUse->GetOp()->GetImmedValue();
					if (((0 > TempImm) && (opcode == STARS_NN_add))
						|| ((0 < TempImm) && (opcode == STARS_NN_sub))) {
						return true;
					}
				}
				else if (CurrUse->GetOp()->IsRegOp()
						&& (!CurrUse->GetOp()->MatchesReg(MD_STACK_POINTER_REG)) // skip the ESP operand
						&& (opcode == STARS_NN_sub)) { // sub esp,reg: alloca() ?
					return true;
				}
			}
		}
	}
	else if ((opcode >= MD_FIRST_ENTER_INSTR) && (opcode <= MD_LAST_ENTER_INSTR)) {
		return true;
	}
	return false;
} // end of SMPInstr::MDIsFrameAllocInstr()

#define MD_FIRST_LEAVE_INSTR  STARS_NN_leavew
#define MD_LAST_LEAVE_INSTR STARS_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, STARS_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();
	unsigned short opcode = this->GetIDAOpcode();
	if ((opcode >= MD_FIRST_LEAVE_INSTR) && (opcode <= MD_LAST_LEAVE_INSTR))
		return true;
	else if (this->HasDestMemoryOperand() || this->HasSourceMemoryOperand() || (!this->IsAnalyzeable())) {
		// 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 && (opcode == MD_MOVE_INSTRUCTION)
		&& (FirstDef->GetOp()->MatchesReg(MD_STACK_POINTER_REG))
		&& (FirstUse->GetOp()->MatchesReg(MD_FRAME_POINTER_REG)))
		return true;
	else if ((opcode == STARS_NN_add) && (FirstDef->GetOp()->MatchesReg(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()->GetImmedValue() == ((STARS_uval_t) LocalVarsSize))
			return true;
		else if (SecondUse->GetOp()->IsImmedOp()) {
			intptr_t TempImm = (intptr_t) this->STARSInstPtr->GetOpnd(1)->GetImmedValue();
			if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc
				return false;
			else {
				SMP_msg("Used imprecise LocalVarsSize to find dealloc instr.\n");
				return true;
			}
		}
		else
			return false;
	}
	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;
	unsigned short opcode = this->GetIDAOpcode();

	if ((STARS_NN_nop == opcode) || (STARS_NN_lock == opcode))
		IsNop = true;
	else if ((MD_MOVE_INSTRUCTION == opcode) || (STARS_NN_xchg == opcode))  {
		if (this->STARSInstPtr->GetOpnd(0)->IsRegOp()
			&& this->STARSInstPtr->GetOpnd(1)->MatchesReg(this->STARSInstPtr->GetOpnd(0)->GetReg())) {
			// We have a register to register move with source == destination,
			//  or a register exchanged with itself.
			size_t BinaryByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
			bool UpperBitsClear = ((BinaryByteWidth == 8) && (4 == this->STARSInstPtr->GetOpnd(0)->GetByteWidth()));
			if (!UpperBitsClear) {
				// We exclude the case of mov eax,eax on x86-64, which clears the upper 32 bits of reg RAX.
				IsNop = true;
			}
		}
	}
	else if (STARS_NN_lea == opcode) {
		bool ZeroMemOffset = (this->STARSInstPtr->GetOpnd(1)->IsMemDisplacementOp()
			|| this->STARSInstPtr->GetOpnd(1)->IsMemNoDisplacementOp())
			&& (0 == this->STARSInstPtr->GetOpnd(1)->GetAddr());
		if (this->STARSInstPtr->GetOpnd(0)->IsRegOp() && ZeroMemOffset) {
			// We are looking for 6-byte no-ops like lea esi,[esi+0] or 4-byte lea esi,[esi]
			STARS_regnum_t destreg = this->STARSInstPtr->GetOpnd(0)->GetReg();
			if (this->STARSInstPtr->GetOpnd(1)->HasSIBByte()) {
				if ((destreg == (STARS_regnum_t) MD_STARS_sib_base(this->STARSInstPtr->GetOpnd(1)))
					&& (MD_STACK_POINTER_REG == MD_STARS_sib_index(this->STARSInstPtr->GetOpnd(1)))) {
					// STARS_x86_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->STARSInstPtr->GetOpnd(1)->GetReg()) { // only for non-SIB case
				IsNop = true;
			}
		}
	}
	return IsNop;
} // end of SMPInstr::MDIsNop()

// instruction clears the upper bits of a reg; correct the RTL if true.
bool SMPInstr::MDIsUpperBitsClear(void) {
	unsigned short opcode = this->GetIDAOpcode();
	size_t BinaryByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
	bool UpperBitsClear = (STARS_NN_mov == opcode) && ((BinaryByteWidth == 8) && (4 == this->STARSInstPtr->GetOpnd(0)->GetByteWidth()));
	if (UpperBitsClear) {
		// Correct the RTL.  reg1 := reg2 becomes reg1 := (zero-extend reg2)
		SMPRegTransfer *TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(this->RTL.GetRT(0)->GetConstRightOperandNoNorm());
		TempRT->SetOperator(SMP_ZERO_EXTEND);
		STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
		TempRT->SetRightOperand(VoidOp);
		this->RTL.GetRT(0)->SetRightOperand(VoidOp);
		this->RTL.GetRT(0)->SetRightTree(TempRT);
	}

	return UpperBitsClear;
} // end of SMPInstr::MDIsUpperBitsClear()

// Opcode always produces an UNSIGNED DEF.
bool SMPInstr::MDAlwaysUnsignedDEF(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((opcode == STARS_NN_bsf) || (opcode == STARS_NN_bsr) || (opcode == STARS_NN_div)
		|| (opcode == STARS_NN_lahf) || (opcode == STARS_NN_lar) || (opcode == STARS_NN_lgs)
		|| (opcode == STARS_NN_lss) || (opcode == STARS_NN_lds) || (opcode == STARS_NN_les)
		|| (opcode == STARS_NN_lfs) || (opcode == STARS_NN_lsl) || (opcode == STARS_NN_movzx)
		|| (opcode == STARS_NN_rcl) || (opcode == STARS_NN_rcr) || (opcode == STARS_NN_rol)
		|| (opcode == STARS_NN_ror) || (opcode == STARS_NN_shl) || (opcode == STARS_NN_shr)
		|| ((opcode >= STARS_NN_seta) && (opcode <= STARS_NN_setz)) || (opcode == STARS_NN_cpuid)
		|| (opcode == STARS_NN_rdtsc) || (opcode == STARS_NN_rdpmc) || (opcode == STARS_NN_fstsw)
		|| (opcode == STARS_NN_setalc) || (opcode == STARS_NN_packuswb) || (opcode == STARS_NN_paddusb)
		|| (opcode == STARS_NN_paddusw) || (opcode == STARS_NN_psllw) || (opcode == STARS_NN_pslld)
		|| (opcode == STARS_NN_psllq) || (opcode == STARS_NN_psrlw) || (opcode == STARS_NN_psrld)
		|| (opcode == STARS_NN_psrlq) || (opcode == STARS_NN_psubusb) || (opcode == STARS_NN_psubusw)
		|| (opcode == STARS_NN_pxor) || (opcode == STARS_NN_pavgusb) || (opcode == STARS_NN_pavgb)
		|| (opcode == STARS_NN_pavgw) || (opcode == STARS_NN_pextrw) || (opcode == STARS_NN_pmaxub) 
		|| ((opcode >= STARS_NN_pminub) && (opcode <= STARS_NN_psadbw))
		|| (opcode == STARS_NN_movmskpd) || (opcode == STARS_NN_pmuludq) || (opcode == STARS_NN_pslldq)
		|| (opcode == STARS_NN_psrldq) || ((opcode >= STARS_NN_pabsb) && (opcode <= STARS_NN_pabsd))
		|| (opcode == STARS_NN_rdtscp) || (opcode == STARS_NN_mpsadbw) || (opcode == STARS_NN_packusdw)
		|| ((opcode >= STARS_NN_pcmpeqq) && (opcode <= STARS_NN_phminposuw)) || (opcode == STARS_NN_pmaxud)
		|| (opcode == STARS_NN_pmaxuw) || (opcode == STARS_NN_pminud) || (opcode == STARS_NN_pminuw)
		|| ((opcode >= STARS_NN_pmovzxbw) && (opcode <= STARS_NN_pmovzxdq)) || ((opcode >= STARS_NN_crc32)
		&& (opcode <= STARS_NN_pcmpistrm)) || (opcode == STARS_NN_popcnt) || (opcode == STARS_NN_lzcnt)
		|| ((opcode >= STARS_NN_aesenc) && (opcode <= STARS_NN_aeskeygenassist)));
} // end of SMPInstr::MDAlwaysUnsignedDEF()

// Opcode always produces a SIGNED DEF.
bool SMPInstr::MDAlwaysSignedDEF(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((opcode == STARS_NN_cbw) || (opcode == STARS_NN_cwde) || (opcode == STARS_NN_cdqe)
		|| (opcode == STARS_NN_cwd) || (opcode == STARS_NN_cdq) || (opcode == STARS_NN_cqo)
		|| (opcode == STARS_NN_idiv) || (opcode == STARS_NN_movsx) || (opcode == STARS_NN_neg)
		|| (opcode == STARS_NN_sal) || (opcode == STARS_NN_sar) || (opcode == STARS_NN_fist)
		|| (opcode == STARS_NN_fistp) || (opcode == STARS_NN_fbstp) || (opcode == STARS_NN_packsswb)
		|| (opcode == STARS_NN_packssdw) || (opcode == STARS_NN_paddsb) || (opcode == STARS_NN_paddsw)
		|| (opcode == STARS_NN_pmaddwd) || (opcode == STARS_NN_pmulhw) || (opcode == STARS_NN_pmullw)
		|| (opcode == STARS_NN_psraw) || (opcode == STARS_NN_psrad) || (opcode == STARS_NN_psubsb)
		|| (opcode == STARS_NN_psubsw) || (opcode == STARS_NN_pfadd) || (opcode == STARS_NN_pfsub)
		|| (opcode == STARS_NN_pfsubr) || (opcode == STARS_NN_pfacc) || (opcode == STARS_NN_pfmin)
		|| (opcode == STARS_NN_pfmax) || (opcode == STARS_NN_pf2id) || (opcode == STARS_NN_pfrcp)
		|| (opcode == STARS_NN_pfrsqrt) || (opcode == STARS_NN_pfmul)
		|| (opcode == STARS_NN_pfrcpit1) || (opcode == STARS_NN_pfrsqit1) || (opcode == STARS_NN_pfrcpit2)
		|| (opcode == STARS_NN_pmulhrw) || ((opcode >= STARS_NN_addps) && (opcode <= STARS_NN_andps))
		|| ((opcode >= STARS_NN_cvtpi2ps)	&& (opcode <= STARS_NN_divss)) || ((opcode >= STARS_NN_maxps)
		&& (opcode <= STARS_NN_movlps)) || ((opcode >= STARS_NN_movss) && (opcode <= STARS_NN_sqrtss))
		|| (opcode == STARS_NN_subps) || (opcode == STARS_NN_subss) || (opcode == STARS_NN_unpckhps)
		|| (opcode == STARS_NN_unpcklps) || (opcode == STARS_NN_pmaxsw) || (opcode == STARS_NN_pminsw)
		|| (opcode == STARS_NN_movntps) || (opcode == STARS_NN_pf2iw) || (opcode == STARS_NN_pfnacc) 
		|| (opcode == STARS_NN_pfpnacc) || (opcode == STARS_NN_pi2fw) || ((opcode >= STARS_NN_addpd)
		&& (opcode <= STARS_NN_andpd)) || ((opcode >= STARS_NN_cvtdq2pd) && (opcode <= STARS_NN_divsd))
		|| (opcode == STARS_NN_maxpd) || (opcode == STARS_NN_maxsd) || ((opcode >= STARS_NN_minpd)
		&& (opcode <= STARS_NN_movapd)) || (opcode == STARS_NN_movhpd) || (opcode == STARS_NN_movlpd)
		|| (opcode == STARS_NN_movntpd) || ((opcode >= STARS_NN_movsd) && (opcode <= STARS_NN_orpd))
		|| ((opcode >= STARS_NN_sqrtpd) && (opcode <= STARS_NN_subsd)) || ((opcode >= STARS_NN_unpckhpd)
		&& (opcode <= STARS_NN_xorpd)) || ((opcode >= STARS_NN_movddup) && (opcode <= STARS_NN_movsxd))
		|| ((opcode >= STARS_NN_addsubpd) && (opcode <= STARS_NN_hsubps)) || (opcode == STARS_NN_fisttp)
		|| ((opcode >= STARS_NN_psignb) && (opcode <= STARS_NN_psignd)) || ((opcode >= STARS_NN_pmulhrsw)
		&& (opcode <= STARS_NN_phsubd)) || (opcode == STARS_NN_pfrcpv) || (opcode == STARS_NN_pfrsqrtv)
		|| ((opcode >= STARS_NN_blendpd) && (opcode <= STARS_NN_insertps)) || (opcode == STARS_NN_pmaxsb)
		|| (opcode == STARS_NN_pmaxsd) || (opcode == STARS_NN_pminsb) || (opcode == STARS_NN_pminsd)
		|| ((opcode >= STARS_NN_pmovsxbw) && (opcode <= STARS_NN_pmovsxdq)) || (opcode == STARS_NN_pmuldq)
		|| (opcode == STARS_NN_pmulld) || ((opcode >= STARS_NN_roundpd) && (opcode <= STARS_NN_roundss))
		|| (opcode == STARS_NN_movntsd) || (opcode == STARS_NN_movntss));
} // end of SMPInstr::MDAlwaysSignedDEF()

bool SMPInstr::MDIsAddition(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	bool FoundAddition = ((STARS_NN_adc == opcode) || (STARS_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->GetIDAOpcode();

	return ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode) || (STARS_NN_inc == opcode)
		|| (STARS_NN_neg == opcode) || (STARS_NN_xadd == opcode));
}

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

	return ((STARS_NN_dec == opcode) || (STARS_NN_sbb == opcode) || (STARS_NN_sub == opcode));
}

bool SMPInstr::MDIsPrefetchOpcode(void) const {
	unsigned short opcode = this->GetIDAOpcode();

	return ((STARS_NN_prefetch == opcode) || (STARS_NN_prefetchw == opcode) 
		|| ((STARS_NN_prefetcht0 <= opcode) && (STARS_NN_prefetchnta >= opcode)));
}

bool SMPInstr::MDIsUndefinedOpcode(void) const {
	unsigned short opcode = this->GetIDAOpcode();

	return (STARS_NN_ud2 == opcode);
}

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

	return ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode));
}

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

	return ((STARS_NN_neg == opcode) || (STARS_NN_sbb == opcode) || (STARS_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->GetIDAOpcode();

	// 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 = ((STARS_NN_sbb == opcode) && (this->SubtractsFromItself()));
	if (benign) {
		IdiomCode = 4;
	}
	return benign;
}

// DEF feeds into PEASOUP project blacklist for numeric errors: loop decisions, argument passes.
bool SMPInstr::HasPEASOUPBlacklistSink(bool DefReachesCall) {
	bool Blacklisted = false;

	// Check for argument passing.
	std::size_t ArgNum;
	if (DefReachesCall && this->MDIsArgumentPass(ArgNum)) {
		Blacklisted = true;
	}
	else if (this->GetBlock()->GetFunc()->IsBlockInAnyLoop(this->GetBlock()->GetNumber())) {
		// Check for loop control flow determinations.
		set<DefOrUse, LessDefUse>::iterator DefIter;
		for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
			STARSOpndTypePtr DefOp = DefIter->GetOp();
			if (MDIsGeneralPurposeReg(DefOp)) {
				int DefSSANum = DefIter->GetSSANum();
				Blacklisted = this->GetBlock()->DoesDefControlLoopFlow(DefOp, DefSSANum, this->GetAddr());
				if (Blacklisted) {
					break;
				}
			}
		}
	}

	return Blacklisted;
} // end of SMPInstr::HasPEASOUPBlacklistSink()

// Does a subtraction operator get applied to same left and right operands?
bool SMPInstr::SubtractsFromItself(void) {
	bool SelfSubtract = false;
	std::size_t RTLCount = this->RTL.GetCount();
	for (std::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.
					STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
					STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
					SelfSubtract = IsEqOp(RightOp, LeftOp);
				}
				break;
			}
		}
	}
	return SelfSubtract;
} // end of SMPInstr::SubtractsFromItself()

// Does instruction subtract an immediate value that is often used in ASCII computations,
//  such as the ASCII code for '0', 'a', or 'A' ?
bool SMPInstr::SubtractsImmedASCII(void) {
	STARSOpndTypePtr SubtrahendOp = this->GetUseOnlyAddSubOp();
	return (this->MDIsMaybeBenignUnderflowOpcode() && SubtrahendOp->IsImmedOp()
		&& (('0' == SubtrahendOp->GetImmedValue()) || ('a' == SubtrahendOp->GetImmedValue())
		|| ('A' == SubtrahendOp->GetImmedValue())));
}

// Does instruction compare a location to an immediate value that is often used in ASCII computations,
//  such as the ASCII code for '0' or '9', 'a' or 'A', 'z' or 'Z', or carriage return?
#define SMP_ASCII_CARRIAGE_RETURN 13
bool SMPInstr::MDComparesImmedASCII(void) {
	bool ComparesToASCII = false;
	if (this->GetIDAOpcode() == STARS_NN_cmp) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) {
			CurrRT = CurrRT->GetRightTree();
			if (!(CurrRT->HasRightSubTree())) {
				STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
				STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
				if (RightOp->IsImmedOp() && ((SMP_ASCII_CARRIAGE_RETURN == RightOp->GetImmedValue())	
					|| ('0' == RightOp->GetImmedValue()) || ('9' == RightOp->GetImmedValue()) 
					|| ('a' == RightOp->GetImmedValue()) || ('z' == RightOp->GetImmedValue())
					|| ('A' == RightOp->GetImmedValue()) || ('Z' == RightOp->GetImmedValue()))) {
					ComparesToASCII = true;
				}
			}
		}
	}
	return ComparesToASCII;
} // end of SMPInstr::MDComparesImmedASCII()

// Inst destroys original sign bit, e.g. shift left overwrites sign bit.
bool SMPInstr::MDDestroysSignBit(void) const {
	bool SignBitDestroyed;
	unsigned short opcode = this->GetIDAOpcode();
	SignBitDestroyed = (STARS_NN_shl == opcode); // add more cases later.
	return SignBitDestroyed;
} // end of SMPInstr::MDDestroysSignBit()

// Inst is cond branch depending only on zero/non-zero status, i.e. uses only the zero flag 
bool SMPInstr::MDIsZeroFlagCondBranch(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	bool ZeroFlagBranch = ((opcode == STARS_NN_je) || (opcode == STARS_NN_jne) || (opcode == STARS_NN_jz) || (opcode == STARS_NN_jnz));
	return ZeroFlagBranch;
} // end of SMPInstr::MDIsZeroFlagCondBranch()

// Inst is x86 string opcode that can have a repeat prefix to make it loop.
bool SMPInstr::MDIsPossibleStringLoopingOpcode(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	bool LoopingStringOperation = ((opcode == STARS_NN_cmps) || (opcode == STARS_NN_scas) || (opcode == STARS_NN_ins) 
		|| (opcode == STARS_NN_movs) || (opcode == STARS_NN_outs) || (opcode == STARS_NN_stos) || (opcode == STARS_NN_lods));
	return LoopingStringOperation;
} // end of SMPInstr::MDIsPossibleStringLoopingOpcode()

// Multiply by large constant; overflow is probably intentional.
#define STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD 0x20000000
#define STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD 0x10000000
#define STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD))
bool SMPInstr::IsMultiplyByLargeConstant(STARS_uval_t &ConstValue, unsigned short SignMask) {
	bool LargeConstFound = false;

	if (this->MDIsMultiply() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
		set<DefOrUse, LessDefUse>::iterator UseIter;
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			if (this->FindConstantValue(UseIter, ConstValue)) {
				if (FG_MASK_UNSIGNED == SignMask) {
					if (((STARS_uval_t) STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD) <= ConstValue) {
						LargeConstFound = true;
						break;
					}
				}
				else if (FG_MASK_SIGNED == SignMask) {
					int SignedConstValue = (int) ConstValue;
					if ( (((int) STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD) <= SignedConstValue)
						|| (((int) STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD) >= SignedConstValue)) {
						LargeConstFound = true;
						break;
					}
				}
			}
		}
	}

	return LargeConstFound;
} // end of SMPInstr::IsMultiplyByLargeConstant()

// Subtraction of large constant; underflow is probably intentional.
#define STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD 0x80000000
#define STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD 0x40000000
#define STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD))
bool SMPInstr::IsSubtractionOfLargeConstant(STARS_uval_t &ConstValue, unsigned short SignMask) {
	bool LargeConstFound = false;

	if (this->MDIsUnderflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
		STARSOpndTypePtr SubtrahendOp = this->GetUseOnlyAddSubOp();
		if ((nullptr != SubtrahendOp) && (! SubtrahendOp->IsVoidOp())) {
			set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SubtrahendOp);
			if (this->FindConstantValue(UseIter, ConstValue)) {
				if (FG_MASK_UNSIGNED == SignMask) {
					if (((STARS_uval_t) STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD) <= ConstValue) {
						LargeConstFound = true;
					}
				}
				else if (FG_MASK_SIGNED == SignMask) {
					int SignedConstValue = (int) ConstValue;
					if ( (((int) STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD) <= SignedConstValue)
						|| (((int) STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD) >= SignedConstValue)) {
						LargeConstFound = true;
					}
				}
			}
		}
	}

	return LargeConstFound;
} // end of SMPInstr::IsSubtractionOfLargeConstant()

// Subtraction of large constant; underflow is probably intentional.
#define STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD 0x80000000
#define STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD 0x40000000
#define STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD))
bool SMPInstr::IsAdditionOfLargeConstant(STARS_uval_t &ConstValue, unsigned short SignMask) {
	bool LargeConstFound = false;

	if (this->MDIsOverflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
		STARSOpndTypePtr AddendOp = this->GetUseOnlyAddSubOp();
		if ((nullptr != AddendOp) && (!AddendOp->IsVoidOp())) {
			set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(AddendOp);
			if (this->FindConstantValue(UseIter, ConstValue)) {
				if (FG_MASK_UNSIGNED == SignMask) {
					if (((STARS_uval_t) STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD) <= ConstValue) {
						LargeConstFound = true;
					}
				}
				else if (FG_MASK_SIGNED == SignMask) {
					int SignedConstValue = (int) ConstValue;
					if ( (((int) STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD) <= SignedConstValue)
						|| (((int) STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD) >= SignedConstValue)) {
						LargeConstFound = true;
					}
				}
			}
		}
	}

	return LargeConstFound;
} // end of SMPInstr::IsAdditionOfLargeConstant()

// MACHINE DEPENDENT: Opcode indicates 64-bit operands are the default.
bool SMPInstr::MDDefaultsTo64BitOperands(void) const {
	return this->STARSInstPtr->OpcodeDefaultsTo64BitOperands();
} // end of SMPInstr::MDDefaultsTo64BitOperands()

// MACHINE DEPENDENT: Inst has 64-bit operands
bool SMPInstr::MDHas64BitOperands(void) const {
	return this->STARSInstPtr->Has64BitOperands();
}

// MACHINE DEPENDENT: is current addressing 32-bit?
bool SMPInstr::MDIsAddressing32bit(void) const {
	return this->STARSInstPtr->Uses32BitAddressing();
}

// MACHINE DEPENDENT: is current addressing 64-bit?
bool SMPInstr::MDIsAddressing64bit(void) const {
  return this->STARSInstPtr->Uses64BitAddressing();
}

// Is current instruction the SSA marker instruction, with pseudo-address one byte before the start of the function?
bool SMPInstr::IsMarkerInst(void) const {
	return (this->MDIsFloatNop() && STARS_IsSSAMarkerPseudoID(this->GetAddr()));
}

// Does RTL show a subtraction of a constant value of 1?
bool SMPInstr::IsDecrementRTL(void) const {
	STARS_uval_t ConstValue = 0;

	STARSOpndTypePtr NonConstOperand = nullptr;
	bool ConstSubtract = this->IsSubtractionOfConstant(NonConstOperand, ConstValue);
	return (ConstSubtract && (1 == ConstValue));
}

// stack pointer reg is in the DEFs set
bool SMPInstr::HasStackPointerDEF(void) {
	for (STARSDefUseIter DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		STARSOpndTypePtr DefOp = DefIter->GetOp();
		if (DefOp->MatchesReg(MD_STACK_POINTER_REG)) {
			return true;
		}
	}
	return false;
}

bool SMPInstr::IsSetToZero(void) const {
	bool SetsToZero = false;
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	if ((!CurrRT->HasRightSubTree()) && (CurrRT->GetOperator() == SMP_ASSIGN)) {
		STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
		SetsToZero = ((RightOp->IsImmedOp()) && (0 == RightOp->GetImmedValue()));
	}
	return SetsToZero;
}

// MACHINE DEPENDENT: Is instruction a POP instruction?
#define FIRST_POP_INST   STARS_NN_pop
#define LAST_POP_INST    STARS_NN_popfq
bool SMPInstr::MDIsPopInstr(void) const {
	return ((this->GetIDAOpcode() >= FIRST_POP_INST)
			&& (this->GetIDAOpcode() <= LAST_POP_INST));
}

// MACHINE DEPENDENT: Is instruction a PUSH instruction?
#define FIRST_PUSH_INST   STARS_NN_push
#define LAST_PUSH_INST    STARS_NN_pushfq
bool SMPInstr::MDIsPushInstr(void) const {
	return ((this->GetIDAOpcode() >= FIRST_PUSH_INST)
			&& (this->GetIDAOpcode() <= LAST_PUSH_INST));
}

// MACHINE DEPENDENT: Is instruction an ENTER instruction?
bool SMPInstr::MDIsEnterInstr(void) const {
	return ((this->GetIDAOpcode() >= MD_FIRST_ENTER_INSTR)
			&& (this->GetIDAOpcode() <= MD_LAST_ENTER_INSTR));
}

// MACHINE DEPENDENT: Is instruction a LEAVE instruction?
bool SMPInstr::MDIsLeaveInstr(void) const {
	return ((this->GetIDAOpcode() >= MD_FIRST_LEAVE_INSTR)
			&& (this->GetIDAOpcode() <= MD_LAST_LEAVE_INSTR));
}

// MACHINE DEPENDENT: Is instruction a HALT instruction?
bool SMPInstr::MDIsHaltInstr(void) const {
	return (STARS_NN_hlt == this->GetIDAOpcode());
}

bool SMPInstr::IsJumpOrBranchInstr(void) const {
	// A jump is IP := address; a conditional branch is the same with a Guard RT.
	SMPRegTransfer *RT = this->GetRT(0);
	return ((1 == this->RTL.GetCount()) && (!RT->HasRightSubTree())
		&& RT->GetConstLeftOperandNoNorm()->MatchesReg(MD_INSTRUCTION_POINTER_REG));
//	return ((STARS_NN_ja <= this->GetIDAOpcode()) && (STARS_NN_jmpshort >= this->GetIDAOpcode()));
}

#define MD_FIRST_LOOP_INSTR STARS_NN_loopw
#define MD_LAST_LOOP_INSTR  STARS_NN_loopqne
bool SMPInstr::MDIsLoopInstr(void) const {
	uint16_t opcode = this->GetIDAOpcode();
	return ((opcode >= MD_FIRST_LOOP_INSTR) && (opcode <= MD_LAST_LOOP_INSTR));
}

#define MD_FIRST_COND_MOVE_INSTR STARS_NN_cmova
#define MD_LAST_COND_MOVE_INSTR  STARS_NN_fcmovnu
// MACHINE DEPENDENT: Is instruction a conditional move?
bool SMPInstr::MDIsConditionalMoveInstr(void) const {
	return ((this->GetIDAOpcode() >= MD_FIRST_COND_MOVE_INSTR)
			&& (this->GetIDAOpcode() <= MD_LAST_COND_MOVE_INSTR));
}

// MACHINE DEPENDENT: Is instruction any kind of move?
bool SMPInstr::MDIsMoveInstr(void) const {
	return ((STARS_NN_mov == this->GetIDAOpcode()) || (STARS_NN_movsx == this->GetIDAOpcode())
		|| (STARS_NN_movzx == this->GetIDAOpcode()) || this->MDIsConditionalMoveInstr());
}

// MACHINE DEPENDENT: Do opcode/operands definitely indicate signed arithmetic?
//  Generally, this is only true for certain variants of multiplication and division.
bool SMPInstr::MDIsSignedArithmetic(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	if (STARS_NN_idiv == opcode)
		return true;
	if (STARS_NN_imul == opcode) {
		// If we discard the upper N bits of the multiplication result, then the
		//  lower N bits are the same for signed and unsigned multiplication, and
		//  gcc/g++ often use the IMUL opcode for both signed and unsigned multiplies
		//  when only N bits of result are retained. Therefore, the SIGNED nature of
		//  IMUL operands can only be inferred from the case in which 2N bits are kept.
		return (!(this->AreMultiplicationBitsDiscarded()));
	}
	else { // idiv and imul are only possible signed cases
		return false;
	}
} // end of SMPInstr::MDIsSignedArithmetic()

// MACHINE DEPENDENT: Is instruction a conditional jump based on an unsigned condition?
bool SMPInstr::MDIsUnsignedBranch(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_ja == opcode) || (STARS_NN_jae == opcode) || (STARS_NN_jb == opcode) || (STARS_NN_jbe == opcode)
		|| (STARS_NN_jna == opcode) || (STARS_NN_jnae == opcode) || (STARS_NN_jnb == opcode) || (STARS_NN_jnbe == opcode));
}

// MACHINE DEPENDENT: Is instruction a conditional jump based on a signed condition?
bool SMPInstr::MDIsSignedBranch(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_jg == opcode) || (STARS_NN_jge == opcode) || (STARS_NN_jl == opcode) || (STARS_NN_jle == opcode)
		|| (STARS_NN_jng == opcode) || (STARS_NN_jnge == opcode) || (STARS_NN_jnl == opcode) || (STARS_NN_jnle == opcode)
		|| (STARS_NN_js == opcode) || (STARS_NN_jns == opcode));
}

// MACHINE DEPENDENT: Is instruction a boolean set based on an unsigned condition?
bool SMPInstr::MDIsUnsignedSetValue(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_seta == opcode) || (STARS_NN_setae == opcode) || (STARS_NN_setb == opcode) || (STARS_NN_setbe == opcode)
		|| (STARS_NN_setna == opcode) || (STARS_NN_setnae == opcode) || (STARS_NN_setnb == opcode) || (STARS_NN_setnbe == opcode));
}

// MACHINE DEPENDENT: Is instruction a boolean set based on a signed condition?
bool SMPInstr::MDIsSignedSetValue(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_setg == opcode) || (STARS_NN_setge == opcode) || (STARS_NN_setl == opcode) || (STARS_NN_setle == opcode)
		|| (STARS_NN_setng == opcode) || (STARS_NN_setnge == opcode) || (STARS_NN_setnl == opcode) || (STARS_NN_setnle == opcode)
		|| (STARS_NN_sets == opcode) || (STARS_NN_setns == opcode));
}

// MACHINE DEPENDENT: Is instruction a boolean set based on any condition?
bool SMPInstr::MDIsAnySetValue(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_seta <= opcode) && (STARS_NN_setz >= opcode));
}

// MACHINE DEPENDENT: Is instruction a left shift instruction?
bool SMPInstr::MDIsLeftShift(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_sal == opcode) || (STARS_NN_shl == opcode));
}

// MACHINE DEPENDENT: Is instruction a right shift instruction?
bool SMPInstr::MDIsRightShift(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_sar == opcode) || (STARS_NN_shr == opcode));
}

// Is kind of shift or rotate that is used in hash functions
#define STARS_HASH_SHIFT_THRESHOLD 4
bool SMPInstr::MDIsHashingArithmetic(void) const {
	bool FoundHashShift = false;
	unsigned short opcode = this->GetIDAOpcode();
	// We are looking for shifts in the leftward direction, or rotates in either directon.
	bool IsRotate = ((opcode == STARS_NN_ror) || (opcode == STARS_NN_rcr) || (opcode == STARS_NN_rcl) || (opcode == STARS_NN_rol));
	if (IsRotate) {
		FoundHashShift = true;
	}
	else if ((opcode == STARS_NN_shl) || (opcode == STARS_NN_shld)) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		assert(CurrRT->HasRightSubTree());
		do { // double-shift is a deeply nested RTL tree
			CurrRT = CurrRT->GetRightTree();
		} while (CurrRT->HasRightSubTree());
		STARSOpndTypePtr ShiftCountOp = CurrRT->GetRightOperand();
		assert(nullptr != ShiftCountOp);
		if (ShiftCountOp->IsImmedOp()) {
			STARS_uval_t CountValue = ShiftCountOp->GetImmedValue();
			FoundHashShift = (CountValue >= STARS_HASH_SHIFT_THRESHOLD);
		}
		else {
			// PEASOUP bug # 144: left shift count in CL reg, accumulates in checksum loop.
			FoundHashShift = true;
		}
	}
	return FoundHashShift;
} // end of SMPInstr::MDIsHashingArithmetic()

// Detect comparison of non-immediate to immediate. Return the two operands if true.
bool SMPInstr::MDIsCompareToPositiveConstant(STARSOpndTypePtr &NonConstOperand, STARS_uval_t &ConstValue) const {
	bool CompareToConst = false;

	if (STARS_NN_cmp == this->GetIDAOpcode()) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		assert(CurrRT->HasRightSubTree());
		CurrRT = CurrRT->GetRightTree();
		assert(!(CurrRT->HasRightSubTree()));
		STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
		STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
		if (RightOp->IsImmedOp()) {
			CompareToConst = true;
			ConstValue = (STARS_uval_t) RightOp->GetImmedValue();
			NonConstOperand = CloneIfSubwordReg(LeftOp);
		}
		else if (LeftOp->IsImmedOp()) { // rare to see immediate first
			CompareToConst = true;
			ConstValue = (STARS_uval_t) LeftOp->GetImmedValue();
			NonConstOperand = CloneIfSubwordReg(RightOp);
		}
	}

	return CompareToConst;
} // end of SMPInstr::MDIsCompareToPositiveConstant()

// Opcode is compare or test
bool SMPInstr::MDIsCompareOrTest(void) const {
	uint16_t opcode = this->GetIDAOpcode();
	return ((STARS_NN_cmp == opcode) || (STARS_NN_test == opcode) || (STARS_NN_ucomisd == opcode) || (STARS_NN_ucomiss == opcode) || this->MDIsFloatingStackCompare());
} // end of SMPInstr::MDIsCompareOrTest()

// Opcode is comparison of FP stack regs, setting EFLAGS as result
bool SMPInstr:: MDIsFloatingStackCompare(void) const {
	uint16_t opcode = this->GetIDAOpcode();
	return ((STARS_NN_fcomi == opcode) || (STARS_NN_fcomip == opcode) || (STARS_NN_fucomi == opcode) || (STARS_NN_fucomip == opcode));
} // end of SMPInstr:: MDIsFloatingStackCompare()

bool SMPInstr::IsSubtractionOfConstant(STARSOpndTypePtr &NonConstOperand, STARS_uval_t &ConstValue) const {
	bool SubtractOfConst = false;

	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	if (CurrRT->HasRightSubTree()) {
		CurrRT = CurrRT->GetRightTree();
		SMPoperator CurrOp = CurrRT->GetOperator();
		if (SMP_DECREMENT == CurrOp) {
			assert(!(CurrRT->HasRightSubTree()));
			STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
			SubtractOfConst = true;
			ConstValue = 1;
			NonConstOperand = LeftOp->clone();
		}
		else if (SMP_SUBTRACT == CurrOp) {
			assert(!(CurrRT->HasRightSubTree()));
			STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
			STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
			if (RightOp->IsImmedOp()) {
				SubtractOfConst = true;
				ConstValue = RightOp->GetImmedValue();
				NonConstOperand = LeftOp->clone();
			}
		}
		else if (this->MDIsLoadEffectiveAddressInstr() && (SMP_ADD == CurrOp)) {
			// We could have an addition of a negative constant via an lea opcode,
			//  e.g. lea ecx,[eax-48] will look like ecx := eax+(-48) in the RTL.
			if (!(CurrRT->HasRightSubTree())) {
				STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
				STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
				if (RightOp->IsImmedOp()) {
					ConstValue = RightOp->GetImmedValue();
					int SignedConstValue = (int) ConstValue;
					if (0 > SignedConstValue) {
						SubtractOfConst = true;
						NonConstOperand = LeftOp->clone();
						ConstValue = (STARS_uval_t)(-SignedConstValue); // make +(-x) into -(+x)
					}
				}
			}
		}
	}

	return SubtractOfConst;
} // end of SMPInstr::MDIsSubtractionOfConstant()

// RTL is reg := global_var_addr
bool SMPInstr::IsLoadGlobalStaticDataAddress(STARS_uval_t &GlobalAddr) {
	SMPRegTransfer *FirstRT = this->GetRT(0);
	bool GlobalFound = false;
	if (nullptr != FirstRT) {
		if ((SMP_ASSIGN == FirstRT->GetOperator()) && (!FirstRT->HasRightSubTree())) {
			const STARSOpndTypePtr RightOp = FirstRT->GetConstRightOperandNoNorm();
			if (RightOp->IsImmedOp()) {
				GlobalAddr = RightOp->GetImmedValue();
				if (IsImmedGlobalAddress((STARS_ea_t)GlobalAddr)) {
					GlobalFound = true;
				}
			}
		}
	}
	return GlobalFound;
} // end of SMPInstr::IsLoadGlobalStaticDataAddress()

// RTL is simple x := x op y where op is +, -, *
bool SMPInstr::IsBasicInductionVarArithmetic(STARSOpndTypePtr &RhsOperand, SMPoperator &RhsOperator) const {
	bool BIVOperation = false;

	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	if (CurrRT->HasRightSubTree()) {
		CurrRT = CurrRT->GetRightTree();
		SMPoperator CurrOp = CurrRT->GetOperator();
		if (!(CurrRT->HasRightSubTree())) {
			if ((SMP_SUBTRACT == CurrOp) || (SMP_ADD == CurrOp) || (SMP_S_MULTIPLY == CurrOp) || (SMP_U_MULTIPLY == CurrOp)) {
				RhsOperator = CurrOp;
				RhsOperand = CurrRT->GetRightOperand();
				BIVOperation = true;
			}
			else if ((SMP_S_LEFT_SHIFT == CurrOp) || (SMP_U_LEFT_SHIFT == CurrOp)) {
				if (CurrRT->GetRightOperand()->IsImmedOp()) {
					// Left shift by constant is just a multiplication
					RhsOperator = CurrOp;
					RhsOperand = CurrRT->GetRightOperand();
					BIVOperation = true;
				}
			}
			else if ((SMP_INCREMENT == CurrOp) || (SMP_DECREMENT == CurrOp)) {
				// Make these special case look like SMP_ADD or SMP_SUBTRACT of immediate value 1.
				STARSOpndTypePtr ImmedOneOp = this->MakeImmediateOpnd(1);
				RhsOperand = ImmedOneOp;
				if (SMP_INCREMENT == CurrOp)
					RhsOperator = SMP_ADD;
				else
					RhsOperator = SMP_SUBTRACT;
				BIVOperation = true;
			}
		}
	}

	return BIVOperation;
} // end of SMPInstr::IsBasicInductionVarArithmetic()

// RTL is linear function Add1 + Mult1*Mult2 + Add2 or some portion of it, with nullptr returned for missing operands.
bool SMPInstr::IsDependentInductionVarArithmetic(STARSOpndTypePtr &Mult1, STARSOpndTypePtr &Mult2, STARSOpndTypePtr &Add1, STARSOpndTypePtr &Add2, SMPoperator &RhsOperator) {
	bool DIVOperation = false;

	// Three cases: basic arithmetic, a copy instruction, or an LEA opcode that does multiple operations.
	STARSOpndTypePtr RhsOperand = nullptr;
	RhsOperator = SMP_NULL_OPERATOR;
	if (this->IsBasicInductionVarArithmetic(RhsOperand, RhsOperator)) {
		if ((SMP_S_MULTIPLY == RhsOperator) || (SMP_U_MULTIPLY == RhsOperator)
			|| (SMP_S_LEFT_SHIFT == RhsOperator) || (SMP_U_LEFT_SHIFT == RhsOperator)) {
			Add1 = nullptr;
			Add2 = nullptr;
			Mult2 = RhsOperand;
			Mult1 = this->RTL.GetRT(0)->GetRightTree()->GetLeftOperand();
			DIVOperation = true;
		}
		else if ((SMP_ADD == RhsOperator) || (SMP_SUBTRACT == RhsOperator)) {
			// Turn x + y into 1 * x + y.
			Mult1 = this->MakeImmediateOpnd(1);
			Mult2 = this->RTL.GetRT(0)->GetRightTree()->GetLeftOperand();
			Add1 = RhsOperand;
			Add2 = nullptr;
			DIVOperation = true;
		}
	}
	else if (this->MDIsLoadEffectiveAddressInstr()) {
		// Need to signal our caller that we have more than one operation.
		RhsOperator = SMP_SIGNAL; // random junk operator

		STARSOpndTypePtr LeaOpnd = this->GetLeaMemUseOp();
		int BaseReg, IndexReg;
		uint16_t Scale;
		STARS_ea_t offset;
		LeaOpnd->MDExtractAddressFields(BaseReg, IndexReg, Scale, offset);
		if (STARS_x86_R_none == IndexReg) {
			if (STARS_x86_R_none != BaseReg) {
				// Simple case: Lhs := BaseReg + offset
				STARS_uval_t ImmedValue = (STARS_uval_t) offset;
				Add1 = this->MakeRegOpnd((STARS_regnum_t) BaseReg);
				Add2 = this->MakeImmediateOpnd(ImmedValue);
				Mult1 = nullptr;
				Mult2 = nullptr;
				DIVOperation = true;
			}
			else { // both regs are null, e.g. PC-relative expression
				Add1 = nullptr;
				Add2 = nullptr;
				Mult1 = nullptr;
				Mult2 = nullptr;
				DIVOperation = false;
			}
		}
		else {
			STARS_uval_t ImmedValue = (STARS_uval_t) offset;
			if (BaseReg != STARS_x86_R_none)
				Add1 = this->MakeRegOpnd((STARS_regnum_t) BaseReg);
			else
				Add1 = nullptr;
			Add2 = this->MakeImmediateOpnd(ImmedValue);
			Mult1 = this->MakeRegOpnd((STARS_regnum_t) IndexReg);
			ImmedValue = (STARS_uval_t) (1 << Scale); // turn exponent into multiplier
			Mult2 = this->MakeImmediateOpnd(ImmedValue);
			DIVOperation = true;
		}
	}
	else if (this->IsSimpleCopy(RhsOperand)) {
		Add1 = nullptr;
		Add2 = nullptr;
		Mult1 = RhsOperand;
		STARS_uval_t ImmedValue = 1; // Assignment is multiplication by 1
		Mult2 = this->MakeImmediateOpnd(ImmedValue);
		DIVOperation = true;
	}

	return DIVOperation;
} // end of SMPInstr::IsDependentInductionVarArithmetic()

// is AND operation that masks off lower BytesMasked bytes
bool SMPInstr::MDIsSubregMaskInst(std::size_t &BytesMasked) {
	bool MaskingFound = false;

	if (this->MDIsBitwiseAndOpcode()) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		if (CurrRT->HasRightSubTree()) {
			CurrRT = CurrRT->GetRightTree();
			SMPoperator CurrOp = CurrRT->GetOperator();
			assert(SMP_BITWISE_AND == CurrOp);
			STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
			if (RightOp->IsImmedOp()) {
				STARS_uval_t MaskValue = RightOp->GetImmedValue();
				if (0x01000000 > MaskValue) {
					MaskingFound = true;
					if (0x100 > MaskValue) {
						BytesMasked = 1;
					}
					else if (0x10000 > MaskValue) {
						BytesMasked = 2;
					}
					else {
						BytesMasked = 3;
					}
				}
			}
		}
	}

	return MaskingFound;
}

// MACHINE DEPENDENT: Does instruction use a callee-saved register?
bool SMPInstr::MDUsesCalleeSavedReg(void) {
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
		STARSOpndTypePtr CurrOp = CurrUse->GetOp();
		if (CurrOp->MatchesReg(MD_FRAME_POINTER_REG) || CurrOp->MatchesReg(STARS_x86_R_si)
			|| CurrOp->MatchesReg(STARS_x86_R_di) || CurrOp->MatchesReg(STARS_x86_R_bx)) {
			return true;
		}
	}
	return false;
} // end of SMPInstr::MDUsesCalleeSavedReg()

// Is the instruction a register to register copy of a stack pointer or frame pointer
//  into a general purpose register (which mmStrata will now need to track as a stack 
//  relative pointer)?
bool SMPInstr::MDIsStackPointerCopy(bool UseFP) {
	if (!this->HasGoodRTL())
		return false;

	// OptType 3 indicates a move instruction
	// The lea instruction can perform three operand arithmetic, e.g.
	//  lea ebx,[esp+12] is just ebx := esp+12, so it is a stack pointer copy.
	if (((this->GetOptType() == 3) || this->MDIsLoadEffectiveAddressInstr())
		&& this->IsAnalyzeable()
		&& (this->GetFirstDef()->GetOp()->IsRegOp())
		&& (!(this->GetFirstDef()->GetOp()->MatchesReg(MD_STACK_POINTER_REG)))  // not rsp := rsp operator opnd
		&& (!(this->HasSourceMemoryOperand()))) { // reg to reg move
		set<DefOrUse, LessDefUse>::iterator UseIter = this->GetFirstUse();
		if (UseIter == this->GetLastUse()) {
			if (!this->MDIsLoadEffectiveAddressInstr()) {
				// lea reg,immediate_address can have no USEs, so skip ERROR msg in that case.
				SMP_msg("ERROR: No first USE at %llx in MDIsStackPointerCopy\n", (unsigned long long) this->GetAddr());
			}
		}
		else if (UseFP) {
			if (UseIter->GetOp()->MatchesReg(MD_FRAME_POINTER_REG))
				// Move of base pointer EBP into a general register
				return true;
			else if ((UseIter->GetOp()->MatchesReg(MD_STACK_POINTER_REG))
				&& !(this->GetFirstDef()->GetOp()->MatchesReg(MD_FRAME_POINTER_REG)))
				// Move of ESP into something besides a base pointer
				return true;
		}
		else if (this->GetFirstUse()->GetOp()->MatchesReg(MD_STACK_POINTER_REG)) {
			// Move of ESP into a register; no base pointer used in this function
			return true;
		}
	}
	return false;
} // end of SMPInstr::MDIsStackPointerCopy()

bool SMPInstr::IsStackBasedLoadEffectiveAddress(bool UseFP) const {
	bool StackPtrLEA = false;
	if (this->MDIsLoadEffectiveAddressInstr()) {
		StackPtrLEA = this->GetRT(0)->IsStackPtrUsedInRT(UseFP);
	}

	return StackPtrLEA;
} // end of SMPInstr::IsStackBasedLoadEffectiveAddress()

bool SMPInstr::IsGlobalStaticLoadEffectiveAddress(void) const {
	bool GlobalStatic = false;
	if (this->MDIsLoadEffectiveAddressInstr()) {
		GlobalStatic = this->GetLeaMemUseOp()->IsStaticMemOp();
	}
	return GlobalStatic;
} // end of SMPInstr::IsGlobalStaticLoadEffectiveAddress()


// Does any RTL fit the alloca() pattern: stack_pointer -= non-immediate-operand
bool SMPInstr::HasAllocaRTL(void) {
	bool FoundAlloca = false;
	std::size_t RTLCount = this->RTL.GetCount();
	std::size_t RTLIndex;

	for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
		if (CurrRT->IsAllocaRTL()) {
			FoundAlloca = true;
			break;
		}
	}

	return FoundAlloca;
} // end of SMPInstr::HasAllocaRTL()

// Determine if the instruction saves or restores a pointer into the stack frame.
// If it saves a stack pointer, set Save to true, set the StackDelta saved, and set
//   the operand that received the saved stack pointer into CopyOp. and return true.
// If it restores a stack pointer, set Save to false, set CopyOp to the operand that
//   held the value being restored, set RestoreOp to the stack pointer or frame pointer
//   register (whichever was restored), leave StackDelta alone for later computation
//   based on reaching definitions, and return true.
// For most instructions, no save or restore of a stack pointer, so return false.
bool SMPInstr::MDIsStackPtrSaveOrRestore(bool UseFP, STARS_sval_t FPDelta, bool &Save, STARS_sval_t &StackDelta, STARSOpndTypePtr &CopyOp, bool &Error) {
	bool StackPointerSaveOrRestore = false;
	std::size_t RTLCount = this->RTL.GetCount();
	std::size_t RTLIndex;
	STARSOpndTypePtr TempOp = nullptr;
	int BaseReg, IndexReg, CopyReg;
	uint16_t Scale;
	STARS_ea_t offset;
	SMPoperator CurrOper;
	bool LookUpStackDelta; // Get stack delta from reaching defs for TempOp
	STARS_sval_t DeltaAdjust; // add to StackDelta after computing from reaching defs, e.g. lea esp,[ecx-4] get TempOp of ecx
							//  and DeltaAdjust of -4

	Error = false;

	if ((!this->IsAnalyzeable()) || (this->GetDataFlowType() != DEFAULT))
		return false;

	for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
		bool FPRestore = false; // frame pointer is restored
		bool SPRestore = false; // stack pointer is restored
		StackPointerSaveOrRestore = false; // default unless we detect a save or restore of the stack or frame pointer
		LookUpStackDelta = false;
		DeltaAdjust = 0;
		Save = false; // default unless we detect a stack pointer save

		// The stack alignment instructions (SP := SP bitwise_and immediate_value)
		//  look like something that needs to be processed here, but we always ignore
		//  these instructions. They have a variable effect on the stack pointer, from zero
		//  to -15 delta, but we assume that the delta is zero. This works for us because
		//  no stack accesses will occur into the padding region.
		// Also, any instruction that definitely does not restore the stack pointer or
		//  frame pointer from an arbitrary register or memory location, e.g. a leave instruction
		//  in x86 CPUs, is already handled in normal stack delta computations and needs
		//  no lookups from reaching defs, etc.
		if (this->IsStackAlignmentInst() || this->MDIsLeaveInstr() || this->MDIsFrameAllocInstr()) {
			break; // exit and return false
		}

		SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
		CurrOper = CurrRT->GetOperator();
		if (SMP_ASSIGN != CurrOper) {
			break; // not a regular RTL
		}
		STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
		if (4 > LeftOp->GetByteWidth()) {
			continue; // Not tracking copies of less than the full stack or frame pointer
			// NOTE: We hard code 4 bytes because we will track bottom 32 bits, often seen in 64-bit code.
		}
		if (LeftOp->MatchesReg(MD_STACK_POINTER_REG)) {
			SPRestore = true; // temporary; might just be a push or pop RTL, etc., in which case we will reset.
		}
		else if (UseFP && LeftOp->MatchesReg(MD_FRAME_POINTER_REG)) {
			FPRestore = true; // likewise temporary
		}
		if (!(SPRestore || FPRestore)) {
#if 0
			if (LeftOp->MatchesReg(MD_FLAGS_REG)) {
				break; // No point in looking for a save into the flags register
			}
#endif
			Save = true;  // Maybe; keep looking for save
		}

		// If we are assigning to the stack pointer reg or the frame pointer reg, we need to analyze the right
		//  hand side of the RTL to see if it is a stack/frame pointer value, and not a simple push, pop, etc.
		if (!(CurrRT->HasRightSubTree())) {
			// Simple assignment.
			STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
			if (RightOp->IsRegOp() || IsMemOperand(RightOp)) { // register or memory
				if (RightOp->MatchesReg(MD_STACK_POINTER_REG)) {
					// Stack pointer reg is being saved.
					Save = true;
					StackDelta = this->GetStackPtrOffset(); // LeftOp := SP, so saved delta is just current delta
					CopyOp = LeftOp;
					StackPointerSaveOrRestore = true;
					FPRestore = false; // treat FP := SP as a save of SP rather than a restoration of FP
					break;
				}
				else if (!SPRestore && UseFP && RightOp->MatchesReg(MD_FRAME_POINTER_REG)) {
					// Frame pointer is being saved
					Save = true;
					StackDelta = FPDelta;
					CopyOp = LeftOp;
					StackPointerSaveOrRestore = true;
					break;
				}
				else if (SPRestore || FPRestore) {
					// stack or frame pointer is being restored; leave Save=false and set other outgoing arguments.
					TempOp = RightOp;
					CopyOp = RightOp;
					StackPointerSaveOrRestore = true;
					LookUpStackDelta = true;
				}
				else { // RightOp is register or non-stack-pointer memory expr; either might hold stack delta
					TempOp = RightOp;
					CopyOp = LeftOp;
					LookUpStackDelta = true; // See if RightOp is holding a stack delta
					StackPointerSaveOrRestore = true;  // Maybe; flag tells us to keep looking
				}
			}
			else {
				if (SPRestore || FPRestore) {
					SMP_msg("ERROR: Invalid operand type for assignment to stack or frame pointer at %llx\n",
						(unsigned long long) this->GetAddr());
				}
				StackPointerSaveOrRestore = false;
				break;
			}
		}
		else { // we have a right subtree in the CurrRT
			SMPRegTransfer *RightRT = CurrRT->GetRightTree();
			// In order to have a right subtree, we must have something like:
			//   lea esp,[ecx-4]  which produces the RTL: esp := ecx - 4
			// We should consider any other RTL structure besides a basic addition or
			//  subtraction on the right subtree to be invalid.
			CurrOper = RightRT->GetOperator();
			if ((SMP_ADD == CurrOper) || (SMP_SUBTRACT == CurrOper)) {
				STARSOpndTypePtr RightLeftOp = RightRT->GetLeftOperand();
				if (RightLeftOp->IsRegOp()) {
					if (RightRT->HasRightSubTree()) {
						// Complex RTL such as lea esp,[ebx+ecx*4] ; cannot analyze
						StackPointerSaveOrRestore = false;
					}
					else {
						STARSOpndTypePtr RightRightOp = RightRT->GetRightOperand();
						if (!RightRightOp->IsImmedOp()) {
							// Complex RTL such as lea esp,[ebx+ecx] ; cannot analyze
							StackPointerSaveOrRestore = false;
						}
						else {
							TempOp = RightLeftOp;
							DeltaAdjust = (STARS_sval_t) RightRightOp->GetImmedValue();
							if ((STARS_uval_t) DeltaAdjust > STARS_ESP_ADDITION_OVERFLOW_THRESHOLD) {
								// Really a subtraction via addition of a negative,
								//  or addition via subtraction of a negative.
								//  E.g. add esp, 0xfffffff0 is sub esp,16 and sub esp,0xfffffff0 is add esp,16
								int32_t TempDelta = (int32_t) (DeltaAdjust & 0xffffffff);
								DeltaAdjust = (STARS_sval_t) TempDelta;
							}
							if (SMP_SUBTRACT == CurrOper) {
								// Negate the stack delta adjustment, e.g. lea esp,[ecx-4] needs DeltaAdjust of -4, not 4.
								DeltaAdjust = (0 - DeltaAdjust);
							}
							LookUpStackDelta = true;
							StackPointerSaveOrRestore = true;
							if (SPRestore || FPRestore) {
								CopyOp = RightLeftOp;
							}
							else {
								CopyOp = LeftOp;
							}
						}
					}
				}
				else { // weird RTL; LeftOp := (MemoryOp OPER ???)
					StackPointerSaveOrRestore = false;
				}
			}
			else { // not ADD or SUBTRACT
				StackPointerSaveOrRestore = false;
			}
		}

		if (LookUpStackDelta) {
			bool StackAccess = false;
			bool NonStackMemAccess = false;
			// We need to set StackDelta based on the reaching defs for TempOp
			// A reg is probably a general register, but could have lea ebx,[esp+4] so it could be stack or frame pointer.
			if (TempOp->MatchesReg(MD_STACK_POINTER_REG)) {
				// Weed out RTs that increment or decrement the stack pointer, e.g. SP := SP -4.
				//  These are not the kind of "save" or "restore" RTs that we are tracking.
				if (CopyOp->MatchesReg(MD_STACK_POINTER_REG)) {
					StackPointerSaveOrRestore = false;
					SPRestore = false;
					FPRestore = false;
					Save = false;
				}
				else {
					StackDelta = this->GetStackPtrOffset();
					StackDelta += DeltaAdjust;
					LookUpStackDelta = false; // just got it; no need for reaching defs
					StackPointerSaveOrRestore = true;
				}
			}
			else if (UseFP && TempOp->MatchesReg(MD_FRAME_POINTER_REG)) {
				StackDelta = FPDelta;
				StackDelta += DeltaAdjust;
				LookUpStackDelta = false; // just got it; no need for reaching defs
				StackPointerSaveOrRestore = true;
			}
			else if (TempOp->IsRegOp()) { // general reg, not frame or stack pointer reg
				CopyReg = TempOp->GetReg();
			}
			else {
				MDExtractAddressFields(TempOp, BaseReg, IndexReg, Scale, offset);
				CopyReg = BaseReg;
				bool IndexedAccess = ((STARS_x86_R_none != BaseReg) && (STARS_x86_R_none != IndexReg));
				if (IndexedAccess) {
					StackPointerSaveOrRestore = false;  // Cannot analyze indexed accesses into the stack
				}
				else if (MDIsStackPtrReg(BaseReg, UseFP)) {
					StackAccess = true;
				}
				else {
					// memory expr that is not stack or frame pointer
					NonStackMemAccess = true;  // something like [ecx] might actually turn out to be stack access
					DeltaAdjust = (STARS_sval_t) TempOp->GetAddr(); // get normalized delta from addr field
				}
			}

			if (StackPointerSaveOrRestore && LookUpStackDelta) {
				STARSOpndTypePtr FindOp = nullptr;
				if (StackAccess || NonStackMemAccess) {
					FindOp = TempOp;
				}
				else {
					FindOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) CopyReg);
				}
				if (this->GetBlock()->GetFunc()->IsInStackPtrCopySet(FindOp)) {
					// Screened out time wasters that are not in copy set; now,
					//  look up reaching defs.
					// We need to find out which are the reaching definitions for the FindOp at the current InstAddr.
					this->GetBlock()->GetFunc()->ComputeTempReachingDefs(FindOp, this->GetAddr());
					this->GetBlock()->GetFunc()->ComputeTempStackDeltaReachesList(FindOp);
					// See if TempStackDeltaReachesList has a consistent delta value.
					StackPointerSaveOrRestore = this->GetBlock()->GetFunc()->FindReachingStackDelta(StackDelta); // consistent SavedDelta value across entire list
					StackDelta += DeltaAdjust;
					if (StackPointerSaveOrRestore && NonStackMemAccess) {
						// We have something like [ecx] or [ecx+DeltaAdjust]. It turns out that
						//  ECX has a copy of the stack pointer or frame pointer in it, but that
						//  does not mean that the memory location [ecx] has a copy of a stack or
						//  frame pointer. We need to look up the normalized stack address [esp+StackDelta]
						//  in the StackPtrCopySet just like we did for ECX before we conclude that a
						//  stack pointer save or restore is happening.
						FindOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, (STARS_ea_t) StackDelta);
						if (this->GetBlock()->GetFunc()->IsInStackPtrCopySet(FindOp)) {
							// Screened out time wasters that are not in copy set; now,
							//  look up reaching defs.
							// We need to find out which are the reaching definitions for the FindOp at the current InstAddr.
							this->GetBlock()->GetFunc()->ComputeTempReachingDefs(FindOp, this->GetAddr());
							this->GetBlock()->GetFunc()->ComputeTempStackDeltaReachesList(FindOp);
							// See if TempStackDeltaReachesList has a consistent delta value.
							StackPointerSaveOrRestore = this->GetBlock()->GetFunc()->FindReachingStackDelta(StackDelta); // consistent SavedDelta value across entire list
							// StackPointerSaveOrRestore will now be true only if [ecx] pointed to a saved stack or frame pointer with consistent delta.
						}
						else {
							// E.g. [ecx] pointed to stack location that was not holding a saved stack or frame pointer.
							StackPointerSaveOrRestore = false;
						}
					}
				}
				else {
					StackPointerSaveOrRestore = false; // reset, not in stack pointer copy set
				}
			}
		} // end if (LookupStackDelta)

		if (!StackPointerSaveOrRestore && !Save && (SPRestore || FPRestore)) {
			// Any restore that could not be analyzed is an error.
			Error = true;
			break; // error exit
		}
		else if (StackPointerSaveOrRestore) {
			if (FPRestore) {
				// If we succeeded in looking up a stack delta that goes into the frame pointer reg,
				//  then we want to consider this instruction to be a save of a stack delta into
				//  a register (which happens to be the frame pointer reg in this case).
				FPRestore = false;
				Save = true;
			}
			break; // assume only one save or restore in an instruction; exit with success
		}
	} // end for all RTs in the RTL

	return StackPointerSaveOrRestore;
} // end of SMPInstr::MDIsStackPtrSaveOrRestore()

// return true if current inst mem write is unsafe, false otherwise
bool SMPInstr::DetectUnsafeMemWrite(void) {
	bool UnsafeWrite = false;
	STARS_ea_t InstAddr = this->GetAddr();
	if (this->HasIndirectMemoryWrite()) {
		this->GetBlock()->GetFunc()->ResetProcessedBlocks();
		set<DefOrUse, LessDefUse> SearchDEFs;
		bool FoundAddressRegs = this->GetAddressRegs(SearchDEFs);
		assert(FoundAddressRegs);
		assert(!SearchDEFs.empty());
		// Pre-screen SearchDEFs for unsafe criteria before calling IsMemWriteUnsafe().
		STARSDefUseIter UseIter = SearchDEFs.begin();
		while (UseIter != SearchDEFs.end()) {
			bool Prescreened = this->GetBlock()->PrescreenUnsafeAddrReg(UseIter, InstAddr);
			if (Prescreened) {
				UseIter = SearchDEFs.erase(UseIter);
				UnsafeWrite = true;
			}
			else {
				++UseIter;
			}
		}
		if (!UnsafeWrite) {
			UnsafeWrite = this->GetBlock()->IsMemWriteUnsafe(this->GetAddr(), true, SearchDEFs);
		}
		SearchDEFs.clear();
	}
	this->SetAnalyzedWriteSafety();
	return UnsafeWrite;
} // end of SMPInstr::DetectUnsafeMemWrite()

// Make list of regs and their stack offsets in RTLs for any push instruction
bool SMPInstr::GetPushedRegsList(map<uint32_t, STARS_sval_t> &PushedRegs) {
	std::size_t RTLCount = this->RTL.GetCount();
	std::size_t RTLIndex;
	STARSOpndTypePtr LeftOp = nullptr, RightOp = nullptr;
	int BaseReg, IndexReg;
	uint16_t Scale;
	STARS_ea_t offset;
	SMPoperator CurrOper;

	for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
		CurrOper = CurrRT->GetOperator();
		// Only process simple pushes of registers
		LeftOp = CurrRT->GetLeftOperand();
		if (MDIsStackAccessOpnd(LeftOp, false) && (!(CurrRT->HasRightSubTree())) && (SMP_ASSIGN == CurrOper)) {
			RightOp = CurrRT->GetRightOperand();
			if (RightOp->IsRegOp()) {
				MDExtractAddressFields(LeftOp, BaseReg, IndexReg, Scale, offset);
				// Exclude indexed stack writes.
				if (STARS_x86_R_none == IndexReg) {
					STARS_sval_t ESPOffset = (STARS_sval_t) offset;
					map<uint32_t, STARS_sval_t>::iterator FindIter = PushedRegs.find((uint32_t) RightOp->GetReg());
					if (FindIter == PushedRegs.end()) { // Not already pushed earlier
						pair<uint32_t, STARS_sval_t> TempPair((uint32_t) RightOp->GetReg(), ESPOffset);
						pair<map<uint32_t, STARS_sval_t>::iterator, bool> InsertResult;
						InsertResult = PushedRegs.insert(TempPair);
						assert(InsertResult.second);
					}
				}
			}
		}
	} // end for all RTs in RTL

	return (!PushedRegs.empty());
} // end of SMPInstr::GetPushedRegsList()

// Make list of regs and their stack offsets in RTLs for any pop instruction
bool SMPInstr::GetPoppedRegsList(bool FirstReturnBlock, map<uint32_t, STARS_sval_t> &PoppedRegs) {
	bool MisMatch = false;
	std::size_t RTLCount = this->RTL.GetCount();
	std::size_t RTLIndex;
	std::size_t IncomingSize = PoppedRegs.size(); // from return blocks already processed
	std::size_t MatchCount = 0; // count of matches to incoming data
	STARSOpndTypePtr LeftOp = nullptr, RightOp = nullptr;
	int BaseReg, IndexReg;
	uint16_t Scale;
	STARS_ea_t offset;
	SMPoperator CurrOper;

	for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
		CurrOper = CurrRT->GetOperator();
		// Only process simple pops of registers
		LeftOp = CurrRT->GetLeftOperand();
		if ((LeftOp->IsRegOp()) && (!(CurrRT->HasRightSubTree())) && (SMP_ASSIGN == CurrOper)) {
			RightOp = CurrRT->GetRightOperand();
			if (MDIsStackAccessOpnd(RightOp, false)) {
				MDExtractAddressFields(RightOp, BaseReg, IndexReg, Scale, offset);
				// Exclude indexed stack reads.
				if (STARS_x86_R_none == IndexReg) {
					STARS_sval_t ESPOffset = (STARS_sval_t) offset;
					map<uint32_t, STARS_sval_t>::iterator FindIter = PoppedRegs.find((uint32_t) LeftOp->GetReg());
					if (FindIter == PoppedRegs.end()) { // Not already popped in another block
						if (FirstReturnBlock) {
							pair<uint32_t, STARS_sval_t> TempPair((uint32_t) LeftOp->GetReg(), ESPOffset);
							pair<map<uint32_t, STARS_sval_t>::iterator, bool> InsertResult;
							InsertResult = PoppedRegs.insert(TempPair);
							assert(InsertResult.second);
						}
						else {
							// We should not find a new pop in return block N not seen in return block N-1
							MisMatch = true;
							PoppedRegs.clear(); // causes a return value of false
							break;
						}
					}
					else {
						// Already in map; check for consistency across return points.
						if (ESPOffset != FindIter->second) { // inconsistent
							MisMatch = true;
							PoppedRegs.clear(); // causes a return value of false
							break;
						}
						else {
							++MatchCount;
						}
					}
				}
			}
		}
	} // end for all RTs in RTL

	if (FirstReturnBlock) {
		IncomingSize = 0; // Not trying to match within first return block
	}

	return ((!MisMatch) && (!PoppedRegs.empty()));
} // end of SMPInstr::GetPoppedRegsList()

// If call instruction is to malloc(), set the DEF register EAX type to
//  HEAPPTR and return true.
bool SMPInstr::MDFindMallocCall(const STARSOpndTypePtr &TargetOp) {
	bool changed = false;
	STARS_Function_t *TargetFunc = SMP_get_func(TargetOp->GetAddr());
#if 0
	if (TargetFunc) {
#endif
		string FuncName = this->GetTrimmedCalledFunctionName();
		if (0 == strcmp("malloc", FuncName.c_str())) {
#if SMP_VERBOSE_FIND_POINTERS
			SMP_msg("Found call to malloc at %x\n", this->GetAddr());
#endif
			this->GetBlock()->GetFunc()->SetHasMallocCall();
			STARSOpndTypePtr SearchOp = this->STARSInstPtr->MakeRegOpnd(MD_RETURN_VALUE_REG);
			set<DefOrUse, LessDefUse>::iterator EAXDEF = this->SetDefType(SearchOp, HEAPPTR);
			int SSANum = EAXDEF->GetSSANum();
			changed = true;
			if (this->BasicBlock->IsLocalName(SearchOp)) {
				(void) this->BasicBlock->PropagateLocalDefType(SearchOp, HEAPPTR,
						this->GetAddr(), SSANum, false);
			}
			else { // global name
				this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
				(void) this->BasicBlock->PropagateGlobalDefType(SearchOp, HEAPPTR,
						SSANum, false, false);
			}
		} // end if "malloc"
#if 0
	} // end if (TargetFunc)
#endif
	return changed;
} // end of SMPInstr::MDFindMallocCall()

// Is instruction a branch (conditional or unconditional) to a
//  code target that is not in the current chunk?
bool SMPInstr::IsBranchToFarChunk(void) {
	if (this->IsFarBranchComputed()) { // answer is cached
		return this->IsBranchesToFarChunk();
	}
	bool FarBranch = false;
	if ((JUMP | COND_BRANCH) & this->GetDataFlowType()) {
		// Instruction is a direct branch, conditional or unconditional
		if (this->NumUses() > 0) {
			FarBranch = this->STARSInstPtr->IsBranchToFarChunk(this, this->FarBranchTarget);
			if (FarBranch) {
				this->SetBranchesToFarChunk();
			}
		}
	}
	this->SetFarBranchComputed();
	return FarBranch;
} // end of SMPInstr::IsBranchToFarChunk()

// instr branches or jumps to another function
bool SMPInstr::IsBranchToOtherFunc(void) {
	bool Safe = (NULL != this->GetBlock());
	STARS_ea_t FarTarget = this->GetJumpTarget();
	return (Safe && (STARS_BADADDR != FarTarget) && (!this->GetBlock()->GetFunc()->IsInstIDInFunc(FarTarget)));
}

// is poorly-optimized if-then COND_BRANCH with extra jumps
bool SMPInstr::IsOddIfThenCase(void) const {
	// The common case is to jump around the ThenBlock, which can then fall through to the FollowBlock:
	//  if (cond) then goto L1;
	//   then-block
	//  L1: 
	// However, it is also possible to jump to the ThenBlock, which then jumps or falls through to the FollowBlock:
	// if (cond) then goto L2;
	// L1: 
	//      somewhere else:  L2: then-block
	//                           goto L1
	// This could be odd code generation or hand-written code.
	// In this odd case, the FallThroughBlock has more than 1 predecessor. In the normal case, the
	//  FallThroughBlock has only one predecessor (the COND_BRANCH block falls through to it). We can use
	//  the number of predecessor blocks to distinguish the two cases, with the additional limitation
	//  that one predecessor reaches the fall-through block via unconditional direct jump.
	bool OddIfThenCase = false;
	SMPBasicBlock *CurrBlock = this->GetBlock();
	STARS_ea_t InstAddr = this->GetAddr();
	ControlFlowType FuncControlFlowType = CurrBlock->GetFunc()->GetControlFlowType(InstAddr);
	if (BRANCH_IF_THEN == FuncControlFlowType) {
		list<SMPBasicBlock *>::const_iterator SuccIter = CurrBlock->GetFallThroughSucc();
		assert(SuccIter != CurrBlock->GetLastConstSucc());
		size_t PredCount = (*SuccIter)->GetNumPredsMinusBackEdges();
		// Don't let loop-back edges increase the PredCount, e.g.:
		//   if cond then
		//      loop
		//         [loop body]
		//      end loop;
		//      ...
		//   end if;
		// The normal if-then case will fall through to a loop header block, and branch to the follow block
		//  for the if-then. That is not the odd case.

		OddIfThenCase = (1 < PredCount); // fall-through block has more than 1 predecessor
#if 1
		// See if we have an unconditional jump to the fall-through block.
		if (OddIfThenCase) {
			OddIfThenCase = false;
			for (list<SMPBasicBlock *>::const_iterator PredIter = (*SuccIter)->GetFirstConstPred(); PredIter != (*SuccIter)->GetLastConstPred(); ++PredIter) {
				if ((*PredIter)->HasDirectJump()) {
					OddIfThenCase = true;
					break;
				}
			}
			if (!OddIfThenCase) {
				SMP_msg("INFO: SMPInstr::IsOddIfThenCase() false due to second criterion at %llx in func %s\n",
					(uint64_t) InstAddr, this->GetBlock()->GetFunc()->GetFuncName());
			}
		}
#endif
	}
	return OddIfThenCase;
} // end of SMPInstr::IsOddIfThenCase()

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseSSA(const STARSOpndTypePtr &CurrOp, int SSASub) {
	return this->Uses.SetSSANum(CurrOp, SSASub);
};

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefSSA(const STARSOpndTypePtr &CurrOp, int SSASub) {
	return this->Defs.SetSSANum(CurrOp, SSASub);
};

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseType(const STARSOpndTypePtr &CurrOp, SMPOperandType CurrType) {
	return this->Uses.SetType(CurrOp, CurrType, this);
};

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefType(const STARSOpndTypePtr &CurrOp, SMPOperandType CurrType) {
	return this->Defs.SetType(CurrOp, CurrType, this);
};

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefMetadata(const STARSOpndTypePtr &CurrOp, SMPMetadataType Status) {
	return this->Defs.SetMetadata(CurrOp, Status);
};

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefIndWrite(const STARSOpndTypePtr &CurrOp, bool IndWriteFlag) {
	return this->Defs.SetIndWrite(CurrOp, IndWriteFlag);
};

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefLoopInvariant(const STARSOpndTypePtr &CurrOp) {
	return this->Defs.SetLoopInvariant(CurrOp);
};

STARSDefUseIter SMPInstr::SetDefSafeMemWrite(const STARSOpndTypePtr &CurrOp) {
	return this->Defs.SetSafeMemWrite(CurrOp);
}


set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseNoTruncate(const STARSOpndTypePtr &CurrOp, bool NoTruncFlag) {
	return this->Uses.SetNoTruncation(CurrOp, NoTruncFlag);
};

set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefNoOverflow(const STARSOpndTypePtr &DefOp, bool NoOverflowFlag) {
	return this->Defs.SetNoOverflow(DefOp, NoOverflowFlag);
};

// Set the DeadRegsBitmap entry for Regnum.
void SMPInstr::SetRegDead(std::size_t RegNum) {
	this->DeadRegsBitmap.set(RegNum);
	return;
}

bool SMPInstr::FillCmd(void) {
	// Fill cmd structure with disassembly of instr
	assert(STARS_SSA_MARKER_PSEUDO_ID != this->GetAddr());

	return this->STARSInstPtr->STARS_GetCmd();

}

// Analyze the instruction and its operands.
void SMPInstr::Analyze(void) {
	bool DebugFlag = false;

	if (0x8049b00 == this->GetAddr()) {
		// Setting up breakpoint line.
		DebugFlag = true;
	}

	if (!(this->FillCmd()))
		return;

	size_t BinaryByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();

	uint16_t opcode = this->GetIDAOpcode();

	// Record what type of instruction this is, simplified for the needs
	//  of data flow and type analysis.
	this->type = DFACategory[opcode];
	// Record optimization category.
	// this->OptType = global_STARS_program->GetOptCategory(opcode);

	if ((STARS_NN_int == opcode) || (STARS_NN_into == opcode) || (STARS_NN_int3 == opcode)) {
		this->SetInterrupt();
	}
	else {
		this->ResetInterrupt();
	}

	// Fix the IDA Pro mistakes in the operand list.
	this->MDFixupIDAProOperandList();

	// See if instruction is an ASM idiom for clearing a register.
	if ((STARS_NN_xor == opcode) || (STARS_NN_lea == opcode) || (STARS_NN_pxor == opcode)) {
		STARSOpndTypePtr FirstOpnd = this->STARSInstPtr->GetOpnd(0);
		STARSOpndTypePtr SecondOpnd = this->STARSInstPtr->GetOpnd(1);
		if (!(FirstOpnd->IsMemOp() || FirstOpnd->IsNearPointer() || FirstOpnd->IsFarPointer())) {
			if ((STARS_NN_xor == opcode) || (STARS_NN_pxor == opcode)) {
				// Check for xor of reg with itself
				// NOTE: We code with IsEqOp() instead of MatchesReg() because we want to include
				//  odd reg types like xmm, ymm, mmx, etc.
				if (IsEqOp(FirstOpnd, SecondOpnd)) {
					if (FirstOpnd->GetByteWidth() >= 4) {
						// xor using 1-byte or 2-byte regs does not clear the upper bits,
						//  so those are not reg clear idioms. 4-byte xor reg1,reg1 is a clear
						//  of the entire reg1, even on x86-64, e.g. xor eax,eax is a shorter way
						//  of encoding xor rax,rax or mov rax,0.
						this->SetRegClearIdiom();
					}
				}
			}
			else { // must be lea
				// check for lea reg,[nobasereg+noindexreg+0]
				if (SecondOpnd->IsMemOp()) {
					int BaseReg, IndexReg;
					uint16_t ScaleFactor;
					STARS_ea_t Offset;
					MDExtractAddressFields(SecondOpnd, BaseReg, IndexReg, ScaleFactor, Offset);
					if ((STARS_x86_R_none == BaseReg) && (STARS_x86_R_none == IndexReg) && (0 == Offset)) {
						this->SetRegClearIdiom();
					}
				}
			}
		}
	}

	// See if instruction is simple nop or ASM idiom for nop.
	if (this->MDIsNop()) {
		this->SetNop();
	}

	// Build the tree RTL for the inst.
	this->FindMemOps();
	bool GoodRTL = this->BuildRTL();
	if (GoodRTL) {
		this->SetGoodRTL();
		this->MDFixFloatingPointRTL();
	}
	else {
		SMP_msg("ERROR: RTL not built at %llx  %s\n", (unsigned long long) this->GetAddr(),
			DisAsmText.GetDisAsm(this->GetAddr()));
		return;
	}

	if (this->MDIsUpperBitsClear()) {
		this->SetRegUpperBitsClearIdiom();
		// SMP_msg("INFO: Found x86-64 upper-bits-clear idiom at %p and fixed RTL.\n", this->GetAddr());
	}

	// Build the DEF and USE lists for the instruction.
	this->BuildSMPDefUseLists();

	// Determine whether the instruction is a jump target by looking
	//  at its cross references and seeing if it has "TO" code xrefs.
	if (global_stars_interface->IsInstJumpTarget(this->GetInstID())) {
		this->SetJumpTarget();
	}

	// If instruction is a call or indirect call, see if a call target has been recorded
	//  by IDA Pro.
	if (this->GetDataFlowType() == INDIR_CALL) {
		if (this->MDIsSystemCall()) {
			this->CallTarget = STARS_BADADDR;
			if (NULL != this->GetBlock()) {
				this->GetBlock()->GetFunc()->SetHasSystemCalls();
			}
		}
		else {
			STARS_InstructionID_t CallTargetInstID = global_stars_interface->FindFirstCallTarget(this->GetInstID());
			this->CallTarget = CallTargetInstID.GetIDWithinFile();
		}
	} // end if INDIR_CALL
	else if (this->GetDataFlowType() == CALL) {
		set<DefOrUse, LessDefUse>::iterator CurrUse;
		for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
			if (CurrUse->GetOp()->IsNearPointer() || CurrUse->GetOp()->IsFarPointer()) {
				this->CallTarget = CurrUse->GetOp()->GetAddr();
			}
		}
		if (STARS_BADADDR == this->CallTarget) {
			SMP_msg("ERROR: Target not found for direct call at %llx\n", (unsigned long long) this->GetAddr());
		}
	}

	if (this->MDIsPushInstr()) {
		if (this->STARSInstPtr->IsPushFromFixedCall()) {
			this->SetFixedCallPush();
			SMP_msg("INFO: Found internal code address push from fixed call at %llx\n", (unsigned long long) this->GetAddr());
		}
	}

	if (DebugFlag) {
		SMP_msg("Analyzed debug instruction at %llx\n", (unsigned long long) this->GetAddr());
	}
	return;
} // end of SMPInstr::Analyze()

// Analyze the floating point NOP marker instruction at the top of the function.
void SMPInstr::AnalyzeMarker(void) {
	// Set the instr disassembly text.
	DisAsmText.SetMarkerInstText(this->GetAddr());

	// Record what type of instruction this is, simplified for the needs
	//  of data flow and type analysis.
	this->type = DFACategory[this->GetIDAOpcode()];
	// Record optimization category.
	// this->OptType = global_STARS_program->GetOptCategory(this->GetIDAOpcode());

	bool GoodRTL = BuildRTL();
	if (GoodRTL) {
		this->SetGoodRTL();
	}

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

// fix machine-specific FP reg encodings
void SMPInstr::MDFixFloatingPointRTL(void) {
	for (size_t RTindex = 0; RTindex < this->RTL.GetCount(); ++RTindex) {
		this->RTL.GetRT(RTindex)->MDFixFloatingPointRTL();
	}
	return;
}

// Detect oddities of call instructions, such as pseudo-calls that are
//  actually jumps within a function
void SMPInstr::AnalyzeCallInst(STARS_ea_t FirstFuncAddr) {
	STARS_ea_t TargetAddr = this->GetCallTarget();
	if (STARS_BADADDR != TargetAddr) {
		if (this->GetCallTarget() == FirstFuncAddr) {
			this->SetDirectRecursiveCall();
		}
		else {
			this->ResetDirectRecursiveCall();
			if (this->GetBlock()->GetFunc()->IsInstIDInFunc(TargetAddr)) {
				this->SetCallUsedAsJump();
				// Remove the call target from the sets and lists in the function.
				bool Removed;
				if (CALL == this->GetDataFlowType()) {
					set<STARS_ea_t>::iterator NextTarget = this->GetBlock()->GetFunc()->RemoveDirectCallTarget(TargetAddr);
				}
				else if (INDIR_CALL == this->GetDataFlowType()) {
					Removed = this->GetBlock()->GetFunc()->RemoveIndirectCallTarget(TargetAddr);
					// assert(Removed);
				}
				this->type = JUMP;
			}
			else {
				this->ResetCallUsedAsJump();
				// See if we call a non-returning function.
				if (CALL == this->GetDataFlowType()) {
					if (TargetAddr != STARS_BADADDR) {
						SMPBasicBlock *CurrBlock = this->GetBlock();
						SMPFunction *TargetFunc = CurrBlock->GetFunc()->GetProg()->FindFunction(TargetAddr);
						if ((nullptr != TargetFunc) && (!TargetFunc->FuncReturnsToCaller())) {
							CurrBlock->SetHasNonReturningCall();
							CurrBlock->GetFunc()->SetCallsNonReturningFunc();
						}
					}
				}
			}
		}
	}
	return;
} // end of SMPInstr::AnalyzeCallInst()

STARS_sval_t SMPInstr::AnalyzeStackPointerDelta(STARS_sval_t IncomingDelta, STARS_sval_t PreAllocDelta) {
	uint16_t InstType = this->GetIDAOpcode();
	STARS_sval_t InstDelta = global_STARS_program->GetStackAlteration(InstType);
	SMPitype FlowType = this->GetDataFlowType();
	bool TailCall = this->IsTailCall();

	if (this->IsCallUsedAsJump() || this->IsInterruptCall() || this->IsCondTailCall()) {
		// Call is used within function as a jump. Happens when setting up
		//  thunk offsets, for example; OR, call is an interrupt call, in which
		//  the interrupt return cleans up the stack, leaving a delta of zero, but
		//  we do not have the system call code to analyze, OR, the call is a conditional
		//  jump to another function (conditional tail call), in which case the current
		//  function must have a return statement to fall into which will clean up the
		//  only thing left on the stack (the return address) and the conditional jump
		//  has no effect on the stack pointer.
		; // leave InstDelta equal to negative or zero value from StackAlterationTable[]
	}
	else if (this->IsRecursiveCall() || TailCall) {
		// We don't have the net stack delta for our own function yet, so we cannot
		//  look it up. We must assume that each call has no net effect on the stack delta.
		// Alternatively, we could call this->GetBlock()->GetFunc()->GetStackDeltaForCallee() as below.
		// Also, a tail call happens when the stack delta is down to zero, and the callee does not
		//  return to the caller, unlike the call cases below, so the callee's net stack delta is
		//  irrelevant to the caller.
		if (this->IsFixedCallJump()) {
			// Fixed call push has happened with delta of -4 or -8; correct it
			InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA;
		}
		else {
			InstDelta = 0;
		}
	}
	else if (this->IsAllocaCall() || this->HasAllocaRTL()) {
		InstDelta = STARS_DEFAULT_ALLOCA_SIZE;
	}
	else if ((CALL == FlowType) || (INDIR_CALL == FlowType)) {
		// A real call instruction, which pushes a return address on the stack,
		//  not a call used as a branch within the function. A return instruction
		//  will usually cancel out the stack push that is implicit in the call, which 
		//  means that the function will have a net stack ptr delta of +4, which will
		//  cancel out the -4 value of the call instruction and set the delta to zero.
		//  However, this is not true in all cases, so we get the net stack ptr delta
		//  directly from the called function unless it is an unresolved indirect call,
		//  in which case we assume +4. !!!!****!!!! In the future, we could analyze
		//  the code around an unresolved indirect call to see if it seems to be
		//  removing items left on the stack by the callee.
#if 0
		// SPECIAL CASE: A jump used as a tail call will have a stack ptr effect that is equal
		//  to the net stack ptr effect of its target function, usually +4, whereas a jump
		//  would otherwise have a net stack ptr effect of 0.
#endif
		STARS_ea_t CalledFuncAddr = this->GetCallTarget();
		if ((STARS_BADADDR == CalledFuncAddr) || (0 == CalledFuncAddr)) {
			if (this->IsFixedCallJump()) {  // push happens previously; callee should swallow return address
				InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA;
			}
			else {
				InstDelta = 0;
			}
		}
		else { // We have a call target
			SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr);
			STARS_sval_t AdjustmentDelta;
			if (nullptr != CalleeFunc) {
				if (!CalleeFunc->HasSTARSStackPtrAnalysisCompleted()) {
					// Phase ordering issue in the call graph. A mutually recursive clique of functions has to
					//  be broken by starting processing somewhere, and all callees cannot be processed before
					//  we start. If we got our stack down to zero and then made a tail call, then we have to assume
					//  that the callee will use our return address, so we assume the default stack delta. If not a
					//  tail call, we ask our function to see if the information is available from IDA Pro analyses,
					//  or if it can be inferred from the fact that the call is followed by a stack adjustment.
					if (TailCall) {
						InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA;
						SMP_msg("WARNING: Callee stack ptr analysis not yet performed at tail call inst %llx ; normal delta assumed\n",
							(unsigned long long) this->GetAddr());
					}
					else {
						AdjustmentDelta = this->GetBlock()->GetFunc()->GetStackDeltaForCallee(CalledFuncAddr);
						InstDelta += AdjustmentDelta;
						SMP_msg("WARNING: Callee stack ptr analysis not yet performed at inst %llx ; stack adjustment used\n",
							(unsigned long long) this->GetAddr());
					}
				}
				else if (!CalleeFunc->StackPtrAnalysisSucceeded()) {
					// Callee analyses were done, but they failed. In order to proceed, we have to assume
					//  the same situation as we just did in the case where analyses have not been performed.
					SMP_msg("WARNING: Callee stack ptr analysis failed at inst %llx ; normal delta assumed\n",
						(unsigned long long) this->GetAddr());
					if (TailCall) {
						InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA;
					}
					else {
						AdjustmentDelta = this->GetBlock()->GetFunc()->GetStackDeltaForCallee(this->GetAddr());
						InstDelta += AdjustmentDelta;
					}
				}
				else {
					// Callee's analyses have succeeded, so get delta straight from callee.
					InstDelta += CalleeFunc->GetNetStackPtrDelta();
				}
			}
			else {
#if 0
				SMP_msg("ERROR: SMPInstr::AnalyzeStackPointerDelta failed to find func at %llx in inst %llx\n",
					(unsigned long long) CalledFuncAddr, (unsigned long long) this->GetAddr());
				InstDelta = SMP_STACK_DELTA_ERROR_CODE;
#else
				SMP_msg("ERROR: SMPInstr::AnalyzeStackPointerDelta failed to find func at %llx in inst %llx\n",
					(unsigned long long) CalledFuncAddr, (unsigned long long) this->GetAddr());
				if (TailCall) {
					InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA;
				}
				else {
					InstDelta = 0;
				}
#endif
			}
		}
	} // end CALL or INDIR_CALL or TailCall case
	else if (1 == InstDelta) { 
		// value of 1 is trigger to investigate the RTL for the 
		//  true value, which cannot be found simply by table lookup
		// In the special case of an x86 LEAVE instruction, the effect
		//  on the stack pointer is to deallocate the local frame size,
		//  plus pop the saved frame pointer into EBP. Helper functions
		//  need to know whether to look for this special case.
		bool IsLeaveInstr = this->MDIsLeaveInstr();
		InstDelta = this->RTL.TotalStackPointerAlteration(IsLeaveInstr, IncomingDelta, PreAllocDelta);
	}
	return InstDelta;
} // end of SMPInstr::AnalyzeStackPointerDelta()

// Total the stack adjustment bytes, as happens after a call to a function that leaves
//  outgoing args on the stack or swallows incoming args from the stack.
STARS_sval_t SMPInstr::FindStackAdjustment(void) {
	uint16_t InstType = this->GetIDAOpcode();
	STARS_sval_t InstDelta = global_STARS_program->GetStackAlteration(InstType);

	if (1 == InstDelta) { 
		// value of 1 is trigger to investigate the RTL for the 
		//  true value, which cannot be found simply by table lookup
		// In the special case of an x86 LEAVE instruction, the effect
		//  on the stack pointer is to deallocate the local frame size,
		//  plus pop the saved frame pointer into EBP. Helper functions
		//  need to know whether to look for this special case.
		bool IsLeaveInstr = this->MDIsLeaveInstr();
		if (!IsLeaveInstr) {
			InstDelta = this->RTL.TotalStackPointerAlteration(IsLeaveInstr, 0, 0);
		}
		else {
			InstDelta = 0; // LEAVE is not the kind of instr we are looking for
		}
	}
	return InstDelta;
} // end of SMPInstr::FindStackAdjustment()

// Normalize stack operands to have a displacement from the stack pointer value on entry to the function,
//  rather than the current stack pointer value.
// UseFP indicates we are using a frame pointer in the function.
// FPDelta holds the stack delta (normalized) for the frame pointer.
// DefOp comes in with the operand to be normalized, and contains the normalized operand upon return.
// Return true if operand is a register or stack location, false otherwise (true => include in data flow analysis sets and SSA.)
bool SMPInstr::MDComputeNormalizedDataFlowOp(bool UseFP, STARS_sval_t FPDelta, STARSOpndTypePtr &DefOp) {
#if 0
	if ((nullptr == DefOp) || (this->GetStackPtrOffset() == 0))
		return false;
#else  // instead of optimizing, need all stack operands to pass through SIBWithNoIndexReg check and correction
	if (nullptr == DefOp)
		return false;
#endif

	if (DefOp->IsRegOp()) {
		return true;
	}
	else if (MDIsStackAccessOpnd(DefOp, UseFP)) {
		STARSOpndTypePtr OldOp = DefOp->clone();
		int SignedOffset = (int) DefOp->GetAddr();
		STARS_sval_t NormalizedDelta = 0;

		if (DefOp->HasSIBByte()) {
			// We must deal with a potentially indexed memory expression. We want to
			//  normalize two different cases here: e.g. [esp+ebx+4] will become [esp+ebx-24]
			//  and [ebp+ebx-8] will become [esp+ebx-12] after normalization. A wrinkle
			//  on the second case is when the base register and index register are swapped
			//  in the SIB byte, and we make [ebx+ebp-4] into [esp+ebx-12], which involves
			//  correcting the index/base reg order in the SIB, because an index reg of ESP
			//  is the SIB encoding for "no index register" and we cannot leave it like that.
			int BaseReg = MD_STARS_sib_base(DefOp);
			int IndexReg = (int) MD_STARS_sib_index(DefOp);
			if (X86_STACK_POINTER_REG == IndexReg) { // signifies no index register
				IndexReg = STARS_x86_R_none;
			}
			if (BaseReg == X86_STACK_POINTER_REG) {
				// We probably have an indexed ESP-relative operand.
				//  We leave the sib byte alone and normalize the offset.
				NormalizedDelta = this->GetStackPtrOffset() + (STARS_sval_t) SignedOffset;
			}
			else {
				// Must be EBP-relative.
				NormalizedDelta = FPDelta + (STARS_sval_t) SignedOffset;
				// Unfortunately, when we are dealing with a SIB byte in the opcode, we cannot
				//  just say DefOp.reg = MD_STACK_POINTER_REG to convert from the frame pointer
				//  to the stack pointer. Instead, we have to get into the nasty machine code
				//  level and change the SIB bits that specify either the base register or the
				//  index register, whichever one is the frame pointer.
				if (BaseReg == X86_FRAME_POINTER_REG) {
					// The three least significant bits of the SIB byte are the base register.
					//  They must contain a 5, which is the x86 value for register EBP, and we
					//  want to convert it to a 4, denoting register ESP. We can just zero out
					//  the least significant bit to accomplish that.
					char OldSIB = DefOp->GetSIB();
					DefOp->SetSIB(OldSIB & 0xfe);
				}
				else {
					// We sometimes have an instruction in which the frame pointer is used as
					//  the "index" register in the SIB byte, and the true index register is
					//  in the "base" register position in the SIB byte.
					assert(IndexReg == X86_FRAME_POINTER_REG);
					// The true index reg is in the lowest three bits, while the next three
					//  bits must contain a 5 (register EBP) and we want to make them a 4 (ESP).
					//  We must swap base and index regs as we normalize (see explanation above).
					char SIBtemp = DefOp->GetSIB();
					char SIBindex = SIBtemp & 0x38;
					char SIBbase = SIBtemp & 0x07;
					assert ((SIBindex >> 3) == 5); // must be EBP
					SIBtemp &= 0xa0; // zero out lower 6 bits; upper 2 bits are scale factor - leave them alone
					SIBtemp &= (SIBbase << 3); // make old base reg (e.g. ebx) into a proper index reg
					SIBtemp |= 0x04; // make the new base reg be 4 (reg ESP)
					DefOp->SetSIB(SIBtemp);
				}
				this->SetFPNormalizedToSP();
				// Add the stack pointer to the USE set for the instruction.
				this->MDAddRegUse(X86_STACK_POINTER_REG, false);
			}
		} // end if SIB byte

		else if (DefOp->GetReg() == MD_FRAME_POINTER_REG) {  // no SIB byte, just o_displ with one address reg
			// If FPDelta is -4 and SignedOffset is +8, then we have [ebp+8] as DefOp, and this
			//  is equivalent to [esp+4] where esp has its entry value, i.e. this would be the first incoming
			//  argument. If SignedOffset is -12, we have [ebp-12] as DefOp, and this is [esp-16] when
			//  normalized to the entry point value of the stack pointer. In both cases, we can see that the
			//  normalized stack delta is just FPDelta+SignedOffset.
			NormalizedDelta = FPDelta + (STARS_sval_t) SignedOffset;
			// Now, we simply convert the memory operand from EBP to ESP and replace the SignedOffset with the
			//  NormalizedDelta just computed.
			DefOp->SetReg(MD_STACK_POINTER_REG);
			DefOp->SetByteWidth(OldOp->GetByteWidth()); // undo possible width change in SetReg()
			this->SetFPNormalizedToSP();
			// Add the stack pointer to the USE set for the instruction.
			this->MDAddRegUse(MD_STACK_POINTER_REG, false);
		}
		else {
			assert(DefOp->GetReg() == MD_STACK_POINTER_REG);
			// We only need to adjust the offset to reflect the change in the stack pointer since the function
			//  was entered, e.g. [esp+4] is normalized to [esp-28] if the current esp value is 32 less than it
			//  was upon function entry. We get the value "-32" in that case from a member variable.
			NormalizedDelta = this->GetStackPtrOffset() + (STARS_sval_t) SignedOffset;
		}
		DefOp->SetAddr((STARS_ea_t) NormalizedDelta); // common to frame and stack pointer cases
		this->GetBlock()->GetFunc()->UpdateMaxDirectStackAccessOffset(NormalizedDelta); // maintain record of maximum
		if (NormalizedDelta == 0) {
			// [esp+0] is the return address location. Reading or writing the return address makes
			//  the function unsafe for the Strata fast return mechanism.
			if (this->HasDestMemoryOperand()) {
				this->GetBlock()->GetFunc()->SetUnsafeForFastReturns(true, RETURN_ADDRESS_WRITE);
				SMP_msg("INFO: Return address overwritten in instruction at %llx\n", (unsigned long long) this->GetAddr());
			}
			else {
				this->GetBlock()->GetFunc()->SetUnsafeForFastReturns(true, RETURN_ADDRESS_READ);
				SMP_msg("INFO: Return address read in instruction at %llx\n", (unsigned long long) this->GetAddr());
			}
		}

		// Clean up unnecessary SIB byte, make sure offset matches operand type, etc.
		DefOp->CleanOpndEncoding();

		this->GetBlock()->GetFunc()->AddNormalizedStackOperand(OldOp, this->GetAddr(), DefOp);
		return true;
	}
	else {
		return false;
	}
} // end of SMPInstr::MDComputeNormalizedDataFlowOp()

// Normalize stack operands in all DEFs and USEs to have stack deltas relative to the function entry stack pointer.
// Return true if any stack DEFs or USEs were normalized.
bool SMPInstr::MDNormalizeStackOps(bool UseFP, STARS_sval_t FPDelta, bool Recomputing, STARS_sval_t DeltaIncrement) {
	if (!this->IsAnalyzeable())
		return false;

	bool StackOpFound = false;
	bool OpNormalized;
	bool UniqueDEFMemOp = true; // Does DEFMemOp not match any DEFs?
	bool UniqueUSEMemOp = true; // Does USEMemOp not match any USEs?
	bool UniqueLeaUSEMemOp = true; // Does LeaUSEMemOp not match any USEs?
	bool UniqueMoveSource = true; // Does MoveSource not match any USEs?
	bool HasDEFMemOp = (nullptr != this->DEFMemOp);

	set<DefOrUse, LessDefUse>::iterator DefIter, UseIter;
	list<pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> > DefWorkList, UseWorkList;
	list<pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> >::iterator WorkIter;
	STARSOpndTypePtr OldOp = nullptr, NewOp = nullptr;
	
	// Find all the DEFs that need changing, and put their iterators into a list.
	// Normalizing stack ops could change their sort order, hence we could skip over
	//  a DEF in the set by erasing a DEF and reinserting a normalized DEF, so we
	//  make all the changes after we iterate through the DEFS set.
	for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		OldOp = DefIter->GetOp();
		if ((! OldOp->IsRegOp()) && (! OldOp->IsImmedOp())) {
			NewOp = OldOp->clone();
			if (Recomputing) {
				OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, true, NewOp);
			}
			else {
				OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, NewOp);
			}
			if (OpNormalized) {
				StackOpFound = true;
				if (HasDEFMemOp && IsEqOp(OldOp, this->DEFMemOp)) {
					UniqueDEFMemOp = false;
					this->DEFMemOp = NewOp;
				}
				else {
					assert(!HasDEFMemOp);
				}
				pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> DefItem(DefIter, NewOp);
				DefWorkList.push_back(DefItem);
			}
		}
	}
	// Now go through the DEF worklist and change stack operands to normalized stack operands.
	for (WorkIter = DefWorkList.begin(); WorkIter != DefWorkList.end(); ++WorkIter) {
		DefIter = WorkIter->first;
#if 0
		if (!Recomputing) { // Just replace DefOp at DefIter with normalized op if not recomputing
			DefIter = this->Defs.SetOp(DefIter, WorkIter->second);
		}
		else { // Keep both old and new forms of DefOp in the Def set if recomputing
			this->AddDef(WorkIter->second, DefIter->GetType(), DefIter->GetSSANum());
		}
#else
		DefIter = this->Defs.SetOp(DefIter, WorkIter->second);
#endif
	}
	// Normalize STARSOpndTypePtr private data member DEFs.
	if (HasDEFMemOp && UniqueDEFMemOp) { // DefOp and this->DEFMemOp could be shared_ptr to same object; don't duplicate work if so
		if (Recomputing) {
			OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueDEFMemOp, this->DEFMemOp);
		}
		else  {
			OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, this->DEFMemOp);
		}
	}

	bool HasUSEMemOp = ((nullptr != this->USEMemOp) && (!this->USEMemOp->IsVoidOp()));
	bool HasLeaMemUseOp = (nullptr != this->GetLeaMemUseOp());
	bool HasMoveSourceMemOp = this->GetMoveSource()->IsMemOp();

#if 0  // pop instructions have none of these flags true
	if (HasUSEMemOp || HasLeaMemUseOp || HasMoveSourceMemOp) {
#endif
		// Find all USEs that need changing, and build a second work list.
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			OldOp = UseIter->GetOp();
			if ((!OldOp->IsRegOp()) && (!OldOp->IsImmedOp())) {
				NewOp = OldOp->clone();
				if (Recomputing) {
					OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, true, NewOp);
				}
				else {
					OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, NewOp);
				}
				if (OpNormalized) {
					StackOpFound = true;
					if (HasUSEMemOp) {
						if (IsEqOp(OldOp, this->USEMemOp)) {
							UniqueUSEMemOp = false;
							this->USEMemOp = NewOp;
						}
						else {
							SMP_msg("\nFATAL ERROR in MDNormalizeStackOps: Stack operand is not the USEMemOp. Inst dump follows.\n");
							SMP_msg("Recomputing: %d  DeltaIncrement: %d\n", Recomputing, DeltaIncrement);
							SMP_msg("Stack Op: ");
							PrintOperand(OldOp);
							SMP_msg("\nUSEMemOp: ");
							PrintOperand(this->USEMemOp);
							SMP_msg(" \n");
							this->Dump();
							assert(false);
						}
					}
					if (HasLeaMemUseOp && IsEqOp(OldOp, this->GetLeaMemUseOp())) {
						UniqueLeaUSEMemOp = false;
						this->SetLeaMemUseOp(NewOp);
					}
					if (HasMoveSourceMemOp && IsEqOp(OldOp, this->GetMoveSource())) {
						UniqueMoveSource = false;
						this->MoveSource = NewOp;
					}
					pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> UseItem(UseIter, NewOp);
					UseWorkList.push_back(UseItem);
				}
			}
		}

		// Now go through the USE worklist and change stack operands to normalized stack operands.
		for (WorkIter = UseWorkList.begin(); WorkIter != UseWorkList.end(); ++WorkIter) {
			UseIter = WorkIter->first;
#if 0
			if (!Recomputing) { // Just replace UseOp at UseIter with normalized op if not recomputing
				UseIter = this->Uses.SetOp(UseIter, WorkIter->second);
			}
			else { // Keep both old and new forms of UseOp in the Use set if recomputing
				this->AddUse(WorkIter->second, UseIter->GetType(), UseIter->GetSSANum());
			}
#else
			UseIter = this->Uses.SetOp(UseIter, WorkIter->second);
#endif
		}
		// Normalize STARSOpndTypePtr private data member USEs.
		if (Recomputing) {
			if (HasUSEMemOp && UniqueUSEMemOp) {
				OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueUSEMemOp, this->USEMemOp);
			}
			if (this->MDIsLoadEffectiveAddressInstr()) {
				STARSOpndTypePtr TempLeaMemOp = nullptr;
				if (HasLeaMemUseOp)
					TempLeaMemOp = this->GetLeaMemUseOp()->clone();
				OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueLeaUSEMemOp, TempLeaMemOp);
				if (OpNormalized)
					this->SetLeaMemUseOp(TempLeaMemOp);
			}
			if (HasMoveSourceMemOp && UniqueMoveSource) {
				OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueMoveSource, this->MoveSource);
			}
		}
		else {
			if (HasUSEMemOp && UniqueUSEMemOp) // avoid shared_ptr duplicate normalization
				OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, this->USEMemOp);
			if (HasLeaMemUseOp && UniqueLeaUSEMemOp && this->MDIsLoadEffectiveAddressInstr()) { // avoid shared_ptr duplicate normalization
				STARSOpndTypePtr TempLeaMemOp = this->GetLeaMemUseOp()->clone();
				OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, TempLeaMemOp);
				if (OpNormalized)
					this->SetLeaMemUseOp(TempLeaMemOp);
			}
			if (HasMoveSourceMemOp && UniqueMoveSource) // avoid shared_ptr duplicate normalization
				OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, this->MoveSource);
		}
#if 0
	} // end if we have some mem USE to normalize
#endif

	// Declare victory.
	this->SetDefsNormalized();

	return StackOpFound;
} // end of SMPInstr::MDNormalizeStackOps()

// Renormalize SP-relative stack operands in functions that call alloca() by adding DeltaIncrement to their stack displacements.
// DefOp comes in with the operand to be renormalized, and contains the normalized operand upon return.
// Return true if operand is a register or stack location, false otherwise (true => include in data flow analysis sets and SSA.)
bool SMPInstr::MDRecomputeNormalizedDataFlowOp(STARS_sval_t DeltaIncrement, bool UpdateMaps, STARSOpndTypePtr &DefOp) {
	if ((nullptr == DefOp) || (DeltaIncrement == 0))
		return false;

	if (DefOp->IsRegOp()) {
		return true;
	}
	else if (MDIsStackAccessOpnd(DefOp, this->GetBlock()->GetFunc()->UsesFramePointer())) {
		if (this->HasFPNormalizedToSP()) {
			// FP-relative operands do not change in alloca() functions when the alloca()
			//  causes the SP to change.
			return true;
		}

		// The remaining cases are simple. The ESP-relative displacement is incremented by
		//  DeltaIncrement, regardless of the presence of a SIB byte.
		int SignedOffset = (int) DefOp->GetAddr();
		STARS_sval_t NormalizedDelta = DeltaIncrement + (STARS_sval_t) SignedOffset;

		STARSOpndTypePtr OldOp = DefOp->clone();
		DefOp->SetAddr((STARS_ea_t) NormalizedDelta);

		if (DefOp->IsMemNoDisplacementOp() && (0 != NormalizedDelta)) {
			// mov [esp],eax has an [esp] operand of type o_phrase, because there is no
			//  displacement field. After normalization, it will have a displacement field, so
			//  it has become an operand like [esp-32] and is now type o_displ.
			DefOp->SetTypeToMemDisplacement();
		}

		if (UpdateMaps) { // We don't update maps for duplicate entries, e.g. USEMemOp, DEFMemOp, MoveSource
			this->GetBlock()->GetFunc()->AddNormalizedStackOperand(OldOp, this->GetAddr(), DefOp);
		}
		return true;
	}
	else {
		return false;
	}
} // end of SMPInstr::MDRecomputeNormalizedDataFlowOp()

// If NormOp is a normalized stack memory operand, unnormalize it.
void SMPInstr::MDGetUnnormalizedOp(STARSOpndTypePtr &NormOp) {
	STARS_sval_t SignedOffset;
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if (this->AreDefsNormalized() && (0 != this->GetStackPtrOffset()) && MDIsStackAccessOpnd(NormOp, UseFP)) {
		if (this->HasFPNormalizedToSP()) {
			size_t NormOpByteWidth = NormOp->GetByteWidth();
			// Need to convert NormOp back to frame-pointer-relative address.
			if (NormOp->HasSIBByte()) {
				// Convert base register from stack pointer back to frame pointer.
				char OldSIB = NormOp->GetSIB();
				NormOp->SetSIB(OldSIB | 0x01);
			}
			else {
				NormOp->SetReg(MD_FRAME_POINTER_REG);
				NormOp->SetByteWidth(NormOpByteWidth); // undo possible width change in SetReg()
			}
			SignedOffset = (STARS_sval_t) NormOp->GetAddr();
			SignedOffset -= this->GetBlock()->GetFunc()->GetFramePtrStackDelta();
		}
		else {
			// NormOp should remain stack-pointer-relative address, but it
			//  should be a positive offset from the current stack pointer instead
			//  of a negative offset from the entry point of the function.
			SignedOffset = (STARS_sval_t) NormOp->GetAddr();
			SignedOffset -= this->GetStackPtrOffset();
			assert((0 <= SignedOffset) || this->GetBlock()->GetFunc()->DoesStackFrameExtendPastStackTop());
		}
		NormOp->SetAddr((STARS_ea_t) SignedOffset);
	}
	return;
} // end of SMPInstr::MDGetUnnormalizedOp()

// Find USE-not-DEF operand that is not the flags register.
STARSOpndTypePtr SMPInstr::GetSourceOnlyOperand(void) const {
	std::size_t OpNum;
	// loop through all operands
	for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
		// if operand[OpNum]->IsDefOperand() /* is it written? */
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			;
		}
		// if operand[OpNum]->IsUseOperand() /* is it read? */
		else if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			STARSOpndTypePtr CurrOp = this->STARSInstPtr->GetOpnd(OpNum);
			if (!(CurrOp->MatchesReg(X86_FLAGS_REG))) {
				return CurrOp;
			}
		}
	}
	// It is expected that increment, decrement, and floating point stores
	//  will not have a USE-only operand. Increment and decrement have an
	//  operand that is both USEd and DEFed, while the floating point stack
	//  registers are implicit in most floating point opcodes. Also, exchange
	//  and exchange-and-add instructions have multiple DEF-and-USE operands.
	int TypeGroup = SMPTypeCategory[this->GetIDAOpcode()];
	if ((TypeGroup != 2) && (TypeGroup != 4) && (TypeGroup != 9) && (TypeGroup != 12)
		&& (TypeGroup != 13)) {
		SMP_msg("ERROR: Could not find source only operand at %llx in %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
	}
	return nullptr;
} // end of SMPInstr::GetSourceOnlyOperand()

// Should apparent memory operands be ignored? e.g. lea opcode on x86
bool SMPInstr::MDIgnoreMemOps(void) {
	return this->MDIsLoadEffectiveAddressInstr();
}

// Find memory DEFs and USEs, store in DEFMemOp and USEMemOp
void SMPInstr::FindMemOps(void) {

	if (!(this->MDIgnoreMemOps())) {
		for (size_t OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
			STARSOpndTypePtr TempOp = this->GetOperand(OpNum);
			if ((nullptr != TempOp) && TempOp->IsMemOp()) {
				if (this->STARSInstPtr->IsDefOpnd(OpNum)) {
					if ((nullptr == this->DEFMemOp) || this->DEFMemOp->IsVoidOp()) { // only save first mem DEF
						this->DEFMemOp = TempOp;
					}
				}
				if (this->STARSInstPtr->IsUseOpnd(OpNum)) {
					if ((nullptr == this->USEMemOp) || this->USEMemOp->IsVoidOp()) { // only save first mem DEF
						this->USEMemOp = TempOp;
					}
				}
			}
		} // end for each operand
	}
	this->SetMemOpsFound();
	return;
} // end of SMPInstr::FindMemOps()

// Fix problems with the operands list in SMPcmd.
void SMPInstr::MDFixupIDAProOperandList(void) {
	// IDA Pro often takes the instruction imul eax,0x80 and creates the following operands and features bits:
	//  Opnd[0] = EAX, both DEF and USE
	//  Opnd[1] = EAX, just USE
	//  Opnd[2] = immediate, neither DEF nor USE
	//  Our RTL building keys in on the DEF/USE bits in features, so this looks like imul eax,eax to us.
	//  We want it to look like:
	//  Opnd[0] = EAX, both DEF and USE
	//  Opnd[1] = immediate, just USE
	if (STARS_NN_imul == this->GetIDAOpcode()) {
		STARSOpndTypePtr Opnd2 = this->STARSInstPtr->GetOpnd(2);
		if ((!(this->STARSInstPtr->IsDefOpnd(2)))
			&& (!(this->STARSInstPtr->IsUseOpnd(2)))) {
			if ((nullptr != Opnd2) && (!Opnd2->IsVoidOp())) {
				// We have a third operand that is neither DEF nor USE.
				SMP_msg("INFO: Fixing IMUL operand list at %llx\n", (unsigned long long) this->GetAddr());
				// this->Dump();
				// Two cases: Operands[0] == Operands[1], e.g. imul eax,Opnd2
				//  or else three-operand form: e.g. imul eax,ecx,Opnd2
				// For the three-operand form, make sure Opnd0 is DEF only, others
				//  are USE only. For the two-operand form, make sure Opnd0 is DEF and USE,
				//  Opnd1 is current Opnd2 and is USE only.
				STARSOpndTypePtr Opnd0 = this->STARSInstPtr->GetOpnd(0);
				STARSOpndTypePtr Opnd1 = this->STARSInstPtr->GetOpnd(1);
				if (IsEqOp(Opnd0, Opnd1)) {
					// No need for three-operand form.
					this->STARSInstPtr->SetOpDefed(0);
					this->STARSInstPtr->SetOpUsed(0);
					this->STARSInstPtr->RemoveIDAOp1ForIMUL();
				}
				else { // Must have three-operand form.
					this->STARSInstPtr->SetOpUsed(2); // set missing USE bit.
					this->STARSInstPtr->SetOpNotUsed(0); // Ensure no USE of Opnd0.
				}
				this->Dump();
			}		
		}
	}
	return;
} // SMPInstr::MDFixupIDAProOperandList()

// Fill the Defs and Uses private data members.
void SMPInstr::BuildSMPDefUseLists(void) {
	std::size_t OpNum;
	bool DebugFlag = (0x8049b00 == this->GetAddr());
	bool WidthDoubler = this->MDDoublesWidth();

	this->Defs.clear();
	this->Uses.clear();

	if (this->IsNop())
		return;

	// Start with the Defs.
	for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			STARSOpndTypePtr TempOp = nullptr;
			if (WidthDoubler) {
				// Opcodes that sign-extend a byte to a word, or a word to a dword, 
				//  have only one operand. It is implicit, and it is the shorter USE.
				//  That means the DEF will have the same width as the USE, e.g. if
				//  we are sign-extending AX to EAX, the USE and DEF will both be AX without
				//  a special fix. We fix this problem with the DEF operand now.
				TempOp = this->STARSInstPtr->GetOpnd(OpNum)->clone(); // Prepare to double the width
				uint16_t CurrByteWidth = TempOp->GetByteWidth();
				if ((1 == CurrByteWidth) || (2 == CurrByteWidth) || (4 == CurrByteWidth)) {
					TempOp->DoubleRegWidth();
				}
				else {
					SMP_msg("ERROR: Instruction operand %zu not 1,2, or 4 bytes at %llx ; Width : %u\n",
						OpNum, (unsigned long long) this->GetAddr(), TempOp->GetByteWidth());
				}
			}
			else { // no need to clone, as we are not doubling the width
				TempOp = this->STARSInstPtr->GetOpnd(OpNum);
			}
			if (MDKnownOperandType(TempOp)) {
				if (DebugFlag) {
					SMP_msg("DEBUG: Setting DEF for: ");
					PrintOperand(TempOp);
					SMP_msg("\n");
				}
				this->Defs.SetRef(TempOp);
			}
		}
	} // end for (OpNum = 0; ...)

	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	if ((NULL != CurrRT) && CurrRT->IsSubregMove()) { // we built a subreg := imm or subreg := subreg RT
		// Upper bits of full reg are USEd, unchanged.
		this->Uses.SetRef(CurrRT->GetLeftOperand(), NUMERIC);  // GetLeftOperand() normalizes to full reg
	}
	if (this->IsRegClearIdiom()) {
		// Something like xor eax,eax clears eax but does not really
		//  use eax. It is the same as mov eax,0 and we don't want to
		//  extend the prior def-use chain for eax to this instruction
		//  by treating the instruction as xor eax,eax. Instead, we
		//  build the DEF and USE lists and RTL as if it were mov eax,0.
		// The exception is something like xor al,al where the upper bits
		//  are carried over, hence we do USE the full RAX/EAX register. 
		//  That is a special case of subreg := immediate. See code above.
		STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);
		this->Uses.SetRef(ZeroOp, NUMERIC);
		return;
	}

	// Now, do the Uses. Uses have special case operations, because
	//  any memory operand could have register uses in the addressing
	//  expression, and we must create Uses for those registers. For
	//  example:  mov eax,[ebx + esi*2 + 044Ch]
	//  This is a two-operand instruction with one def: eax. But
	//  there are three uses: [ebx + esi*2 + 044Ch], ebx, and esi.
	//  The first use is an op_t of type o_phrase (memory phrase),
	//  which can be copied from cmd.Operands[1]. Likewise, we just
	//  copy cmd.Operands[0] into the defs list. However, we must create
	//  op_t types for register ebx and register esi and append them
	//  to the Uses list. This is handled by the machine dependent
	//  method MDFixupDefUseLists().
	for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
		if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
			if (MDKnownOperandType(TempOp)) {
				if (DebugFlag) {
					SMP_msg("DEBUG: Setting USE for: ");
					PrintOperand(TempOp);
					SMP_msg("\n");
				}
				this->Uses.SetRef(TempOp);
			}
		}
	} // end for (OpNum = 0; ...)

	if (this->MDIsConditionalMoveInstr()) {
		// We need to represent the possibility that the DEF operand will not
		//  be set because the move is conditional. We will add the DEF operand
		//  into the USE set and special case our type inferences so that the
		//  USE and the pseudo-USE (prior SSA value of the DEF operand) must
		//  agree in type before we can be sure of the result type.
		assert(this->Defs.GetSize() == 1);
		this->Uses.SetRef(this->Defs.GetFirstRef()->GetOp());
	}

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

// Declare a branch/jump to be a tail call, clean up def/use lists.
void SMPInstr::SetTailCall(void) { 
	this->booleans1 |= INSTR_SET_TAIL_CALL;
	if (this->type == COND_BRANCH) {
		this->SetCondTailCall();
	}
	else {
		this->ResetCondTailCall();
	}
	this->CallTarget = this->GetJumpTarget();
	if (!this->MDIsSystemCall()) {
		if (INDIR_JUMP == this->GetDataFlowType()) {
			this->GetBlock()->GetFunc()->SetHasIndirectCalls();
			if (STARS_BADADDR == this->CallTarget)  {
				// Already recorded as unresolved jump.
				;
#if 0
				this->GetBlock()->GetFunc()->SetHasUnresolvedIndirectCalls();
#endif
			}
			else {
				(void) this->GetBlock()->GetFunc()->AddIndirectCallTarget(this->CallTarget);
			}
		}
		else { // direct jump
			if (STARS_BADADDR == this->CallTarget)  {
				SMP_msg("ERROR: SMPInstr::SetTailCall() has STARS_BADADDR as call target at %llx\n", (unsigned long long) this->GetAddr());
			}
			else {
				(void) this->GetBlock()->GetFunc()->AddDirectCallTarget(this->CallTarget);
			}
		}
	}
	this->type = RETURN;
	this->GetBlock()->SetReturns(true);

	// We want to add the caller-saved registers to the USEs and DEFs lists
	this->MDAddRegDef(STARS_x86_R_ax, false);
	this->MDAddRegDef(STARS_x86_R_cx, false);
	this->MDAddRegDef(STARS_x86_R_dx, false);
	this->MDAddRegUse(STARS_x86_R_ax, false);
	this->MDAddRegUse(STARS_x86_R_cx, false);
	this->MDAddRegUse(STARS_x86_R_dx, false);
} // end of SMPInstr::SetTailCall()

// record original Lea instruction [pseudo-]memory operand.
void SMPInstr::SetLeaMemUseOp(STARSOpndTypePtr NewLeaOperand) {
	if (NULL != this->BasicBlock) {
		this->GetBlock()->GetFunc()->AddLeaOperand(this->GetAddr(), NewLeaOperand);
	}
	return;
}

// Reset a jump instruction to be a pseudo-call because it was obtained by transforming
//  a call to a "push retaddr/jump calltarget" pair.
void SMPInstr::SetFixedCallJump(void) {
	this->booleans5 |= INSTR_SET_FIXED_CALL_JUMP;
	this->CallTarget = this->GetJumpTarget();
	this->RTL.GetRT(0)->SetOperator(SMP_CALL);
	this->RTL.GetRT(0)->SetLeftOperand(this->STARSInstPtr->MakeVoidOpnd());
	if (this->type == JUMP) {
		this->type = CALL;   // Important: Change type to CALL only after calling GetJumpTarget()
	}
	else {
		assert(this->type == INDIR_JUMP);
		this->type = INDIR_CALL;
	}
	return;
} // end of SMPInstr::SetFixedCallJump()

// If DefReg is not already in the DEF list, add a DEF for it.
void SMPInstr::MDAddRegDef(STARS_regnum_t DefReg, bool Shown, SMPOperandType Type) {
	STARSOpndTypePtr TempDef = this->STARSInstPtr->MakeRegOpnd(DefReg);
	CanonicalizeOpnd(TempDef);
	if (!Shown)
		TempDef->SetNotVisible();
	this->Defs.SetRef(TempDef, Type);
	return;
} // end of SMPInstr::MDAddRegDef()

// If UseReg is not already in the USE list, add a USE for it.
void SMPInstr::MDAddRegUse(STARS_regnum_t UseReg, bool Shown, SMPOperandType Type) {
	STARSOpndTypePtr TempUse = this->STARSInstPtr->MakeRegOpnd(UseReg);
	if (!Shown)
		TempUse->SetNotVisible();
	this->Uses.SetRef(TempUse, Type);
	return;
} // end of SMPInstr::MDAddRegUse()

// Perform machine dependent ad hoc fixes to the def and use lists.
//  For example, some multiply and divide instructions in x86 implicitly
//  use and/or define register EDX. For memory phrase examples, see comment
//  in BuildSMPDefUseLists().
void SMPInstr::MDFixupDefUseLists(void) {
	// First, handle the uses hidden in memory addressing modes. Note that we do not
	//  care whether we are dealing with a memory destination operand or source
	//  operand, because register USEs, not DEFs, happen within the addressing expressions.
	std::size_t OpNum;
	SMPOperandType RefType;
	unsigned short opcode = this->GetIDAOpcode();
	int BaseReg;
	int IndexReg;
	uint16_t ScaleFactor;
	STARS_ea_t displacement;
	bool UseFP = true;
	bool HasIndexReg = false;
	bool SingleAddressReg = false;
	bool leaInst = this->MDIsLoadEffectiveAddressInstr();
	bool DebugFlag = (this->GetAddr() == 0xac6e0);
	if (DebugFlag) {
		SMP_msg("DEBUG: Fixing up DEF-USE lists for debug location\n");
		this->Dump();
	}

#if SMP_BASEREG_POINTER_TYPE
	// Some instructions are analyzed outside of any function or block when fixing up
	//  the IDB, so we have to assume the block and func pointers might be NULL.
	if ((NULL != this->BasicBlock) && (NULL != this->BasicBlock->GetFunc()))
		UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
#endif

	if (DebugFlag) {
		SMP_msg("DEBUG: UseFP = %d\n", UseFP);
	}

	for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
		STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == Opnd) // finished processing operands
			break;
		if (Opnd->IsMemOp()) {
			MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement);
			SingleAddressReg = ((0 == displacement) && ((STARS_x86_R_none == BaseReg) || (STARS_x86_R_none == IndexReg)));
			if (STARS_x86_R_none != IndexReg) { 
				STARSOpndTypePtr IndexOpnd = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg);
				if (0 == ScaleFactor)
					this->Uses.SetRef(IndexOpnd);
				else { // scaling == shift ==> NUMERIC
					HasIndexReg = true;
					this->Uses.SetRef(IndexOpnd, NUMERIC);
				}
			}
			if (STARS_x86_R_none != BaseReg) {
				STARSOpndTypePtr BaseOpnd = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg);
				RefType = UNINIT;
#if SMP_BASEREG_POINTER_TYPE
				// STARS_x86_R_sp and STARS_x86_R_bp will get type STACKPTR in SMPInstr::SetImmedTypes().
				//  Other registers used as base registers should get their USEs as
				//  base registers typed as POINTER, which might get refined later
				//  to STACKPTR, GLOBALPTR, HEAPPTR, etc.
				// NOTE: the STARS_NN_lea opcode is often used without a true base register.
				//  E.g. lea eax,[eax+eax+5] is an x86 idiom for eax:=eax*2+5, which
				//  could not be done in one instruction without using the addressing
				//  modes of the machine to do the arithmetic. We don't want to set the
				//  USE of EAX to POINTER in this case, so we will conservatively skip
				//  all lea instructions here.
				// We cannot be sure that a register is truly a base register unless
				//  there is also an index register. E.g. with reg+displacement, we
				//  could have memaddr+indexreg or basereg+offset, depending on what
				//  the displacement is. The exception is if there is no offset and only
				//  one addressing register, e.g. mov eax,[ebx].
				if (BaseOpnd->MatchesReg(MD_STACK_POINTER_REG) || (UseFP && BaseOpnd->MatchesReg(MD_FRAME_POINTER_REG))
					|| leaInst || (!HasIndexReg && !SingleAddressReg)) {
					;
				}
				else {
					RefType = POINTER;
				}
#endif
				this->Uses.SetRef(BaseOpnd, RefType);
			} // end if STARS_x86_R_none != BaseReg
		} // end if (o_phrase or o_displ operand)
	} // end for (all operands)

	// The lea (load effective address) instruction looks as if it has
	//  a memory USE:  lea ebx,[edx+esi]
	//  However, this instruction is really just: ebx := edx+esi
	//  Now that the above code has inserted the "addressing" registers
	//  into the USE list, we should remove the "memory USE".
	if (leaInst) {
		set<DefOrUse, LessDefUse>::iterator CurrUse;
		for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
			STARSOpndTypePtr UseOp = CurrUse->GetOp();
			if (UseOp->IsMemOp()) {
				this->SetLeaMemUseOp(UseOp);
				this->EraseUse(CurrUse);
				this->USEMemOp = nullptr;
				break;
			}
		}
	}

	// Next, handle repeat prefices in the instructions. The Intel REPE/REPZ prefix
	//  is just the text printed for SCAS/CMPS instructions that have a REP prefix.
	//  Only two distinct prefix codes are actually defined: REP and REPNE/REPNZ, and
	//  REPNE/REPNZ only applies to SCAS and CMPS instructions.
	bool HasRepPrefix = this->STARSInstPtr->HasRepeatIfEqualPrefix();
	bool HasRepnePrefix = this->STARSInstPtr->HasRepeatIfNotEqualPrefix();
	if (HasRepPrefix && HasRepnePrefix)
		SMP_msg("ERROR: REP and REPNE both present at %llx %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
	if (HasRepPrefix || HasRepnePrefix) {
		// All repeating instructions use ECX as the countdown register.
		STARSOpndTypePtr BaseOpnd = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
		BaseOpnd->SetNotVisible();
		this->Defs.SetRef(BaseOpnd, NUMERIC);
		this->Uses.SetRef(BaseOpnd, NUMERIC);
	}
	if ((opcode == STARS_NN_cmps) || (opcode == STARS_NN_scas) || (opcode == STARS_NN_movs) || (opcode == STARS_NN_stos)) {
		// ESI and EDI are USEd and DEFed to point to source and dest strings for CMPS/MOVS.
		//  Only EDI is involved with SCAS/STOS.
		if ((opcode == STARS_NN_cmps) || (opcode == STARS_NN_movs)) {
			STARSOpndTypePtr BaseOpnd = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si);
			BaseOpnd->SetNotVisible();
			this->Defs.SetRef(BaseOpnd, POINTER);
			this->Uses.SetRef(BaseOpnd, POINTER);
		}
		STARSOpndTypePtr BaseOpnd2 = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di);
		BaseOpnd2->SetNotVisible();
		this->Defs.SetRef(BaseOpnd2, POINTER);
		this->Uses.SetRef(BaseOpnd2, POINTER);
	}
	else if ((STARS_NN_loopw <= opcode) && (STARS_NN_loopqne >= opcode)) {
		STARSOpndTypePtr LoopCounterOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
		this->Defs.SetRef(LoopCounterOp, NUMERIC);
		this->Uses.SetRef(LoopCounterOp, NUMERIC);
	}

	// Now, handle special instruction categories that have implicit operands.
	bool BranchOutsideFunc = this->IsBranchToOtherFunc();
	if (STARS_NN_cmpxchg == opcode) {
		// x86 Compare and Exchange conditionally sets EAX. We must keep data flow analysis
		//  sound by declaring that EAX is always a DEF.
		this->MDAddRegDef(STARS_x86_R_ax, false);
	} // end if STARS_NN_cmpxchg
	else if ((this->type == CALL) || (this->type == INDIR_CALL) || this->IsTailCall() || BranchOutsideFunc) {
		// NOTE: Phase ordering issue with IsTailCall(), so we check if branch to other func.
		// We want to add the caller-saved registers to the USEs and DEFs lists
		for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCallerSavedReg(); RegIter != global_STARS_program->GetLastCallerSavedReg(); ++RegIter) {
			STARS_regnum_t RegNum = (*RegIter);
			this->MDAddRegDef(RegNum, false);
			this->MDAddRegUse(RegNum, false);
		}
		// Because we don't know what is going on with callees in external modules, we have to be conservative and
		//  assume that callee-saved registers might be LiveIn to them.
		if (NULL != this->GetBlock()) {
			STARS_ea_t CalledFuncAddr = this->GetCallTarget();
			if ((STARS_BADADDR == CalledFuncAddr) && BranchOutsideFunc) {
				CalledFuncAddr = this->GetJumpTarget();
			}
			SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr);
			bool UnAnalyzedCalleeCase = ((nullptr == CalleeFunc) || (this->type == INDIR_CALL) || CalleeFunc->IsLinkerStub());
#if !STARS_CONSERVATIVE_DEADREGS
			if (UnAnalyzedCalleeCase) {
#endif
				for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCalleeSavedReg(); RegIter != global_STARS_program->GetLastCalleeSavedReg(); ++RegIter) {
					STARS_regnum_t RegNum = (*RegIter);
					this->MDAddRegUse(RegNum, false);
				}
#if !STARS_CONSERVATIVE_DEADREGS
			}
#endif
		}

#if 1   // Optimize: Need to check if these regs were ever referenced in current func
		if (this->IsInterruptCall() || BranchOutsideFunc) {
#endif
			this->MDAddRegUse(STARS_x86_R_bx, false);
			this->MDAddRegUse(STARS_x86_R_si, false);
			if (this->IsInterruptCall()) {
				this->MDAddRegDef(STARS_x86_R_bx, false);
				this->MDAddRegDef(STARS_x86_R_si, false);
			}
#if 1
		}
#endif
	}
	else if (this->MDIsPopInstr() || this->MDIsPushInstr() || this->HasReturnOpcode()) {
		// IDA does not include the stack pointer in the DEFs or USEs.
		this->MDAddRegDef(MD_STACK_POINTER_REG, false);
		this->MDAddRegUse(MD_STACK_POINTER_REG, false);
#if 0
		if (!this->HasReturnOpcode()) {
			// We always reference [esp+0] or [esp-4 or 8], so add it to the DEF or USE list.
			if (this->MDIsPopInstr()) {
				STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 0); // [ESP+0]
				this->Uses.SetRef(StackOp);  // USE
			}
			else {
				STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
					(-((STARS_ea_t) global_STARS_program->GetSTARS_ISA_Bytewidth())));  // [ESP-4] or [ESP-8]
				this->Defs.SetRef(StackOp); // DEF
			}
		}
#endif
	}
	else if (this->MDIsEnterInstr() || this->MDIsLeaveInstr()) {
		// Entire function prologue or epilogue microcoded.
		this->MDAddRegDef(MD_STACK_POINTER_REG, false);
		this->MDAddRegUse(MD_STACK_POINTER_REG, false);
		this->MDAddRegDef(MD_FRAME_POINTER_REG, false);
		this->MDAddRegUse(MD_FRAME_POINTER_REG, false);
	}
	else if ((opcode == STARS_NN_maskmovq) || (opcode == STARS_NN_maskmovdqu)) {
		this->MDAddRegUse(STARS_x86_R_di, false, POINTER);
	}
	else if (8 == this->GetOptType()) {
		// This category implicitly writes to EDX:EAX.
		this->MDAddRegDef(STARS_x86_R_dx, false);
		this->MDAddRegDef(STARS_x86_R_ax, false);
	} // end else if (8 == GetOptType)
	else if (7 == this->GetOptType()) {
		// Category 7 instructions sometimes write implicitly to EDX:EAX or DX:AX.
		//  DX is the same reg # as EDX to IDA Pro (and SMP); ditto for EAX and AX.
		// DIV, IDIV, and MUL all have hidden EAX or AX operands (hidden in the IDA Pro
		//  sense, because they are not displayed in the disassembly text). For example:
		//  mul ebx means EDX:EAX <-- EAX*EBX, and mul bx means DX:AX <-- AX*BX. If the
		//  source operand is only 8 bits wide, there is room to hold the result in AX
		//  without using DX:  mul bl means AX <-- AL*BL.
		// IMUL has forms with a hidden EAX or AX operand and forms with no implicit
		//  operands:  imul ebx means EDX:EAX <-- EAX*EBX, but imul ebx,edx means that
		//  EBX*EDX gets truncated and the result placed in EBX (no hidden operands).
		for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
			STARSOpndTypePtr TempUse = this->STARSInstPtr->GetOpnd(OpNum);
			if (nullptr == TempUse) // finished processing operands
				break;
			if (!TempUse->IsVisible()) { // hidden operand
				if (TempUse->MatchesReg(STARS_x86_R_ax)) { // not STARS_x86_R_al, so it is not 8 bits
					if ((STARS_NN_div == opcode) || (STARS_NN_idiv == opcode)) {
						this->MDAddRegUse(STARS_x86_R_dx, false);
					}
					this->MDAddRegDef(STARS_x86_R_ax, false);
					this->MDAddRegDef(STARS_x86_R_dx, false);
				}
			}
		}
	} // end else if (7 == OptType)

#if 0
	// The floating point instructions in type categories 14 and 15 often USE and DEF
	//  the floating point register stack, e.g. pushing a value onto that stack is a
	//  massive copy downward of stack locations. We don't really care about the USE of
	//  the stack if the value being pushed came from elsewhere than the stack. For example,
	//  an "fld" opcode pushes its source onto the stack. We build RTLs with a simple
	//  move structure, but the RTL building can be fooled by seeing two "source" operands
	//  in the USE list.
	if ((14 == SMPTypeCategory[opcode])
		|| (15 == SMPTypeCategory[opcode])) {
	}
#endif

#if 0  // Not true for LOOP instructions that use only the ECX counter register.
	if (this->type == COND_BRANCH) {
		assert(SMPUsesFlags[opcode]);
	}
#endif
	// The return value register EAX is not quite like a caller-save or callee-save
	//  register (technically, it is caller-save). Within a callee, it might appear
	//  that EAX has become dead by the time a return instruction is reached, but
	//  the USE that would make it not dead is in the caller. To prevent type inference
	//  from mistakenly thinking that all USEs of EAX have been seen in the callee,
	//  we add EAX to the USE list for all return instructions, as well as for all
	//  tail calls, which are essentially returns in terms of data flow analysis.
	// This USE of EAX will always be of type UNINIT unless its DEF has a known type
	//  that propagates to it. Thus, it will prevent an invalid back inference of the
	//  DEF type from "all" USE types that are visible in the callee; even if they
	//  were all NUMERIC, this return USE will be UNINIT and inhibit the invalid
	//  type inference. EAX could be loaded with a pointer from memory, for example,
	//  and USEd only in a comparison instruction, making it falsely appear to be
	//  a NUMERIC, without this extra USE at the return instruction.
	// Because some of the library functions pass values around in EBX, EDI, etc.,
	//  we will add these general purpose registers to the USE list for returns
	//  in order to prevent erroneous analyses of dead registers or unused
	//  metadata.
	if ((this->type == RETURN) || this->IsTailCall()) {
		// We want to add the caller-saved registers to the USEs list
		for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCallerSavedReg(); RegIter != global_STARS_program->GetLastCallerSavedReg(); ++RegIter) {
			STARS_regnum_t RegNum = (*RegIter);
			this->MDAddRegUse(RegNum, false);
		}

		this->MDAddRegUse(STARS_x86_R_bx, false);
		if (!UseFP)
			this->MDAddRegUse(MD_FRAME_POINTER_REG, false);
		size_t BitWidth = global_STARS_program->GetSTARS_ISA_Bitwidth();
		if (BitWidth == 32) { // already caller-saved in x86-64
			this->MDAddRegUse(STARS_x86_R_si, false);
			this->MDAddRegUse(STARS_x86_R_di, false);
		}
		else if (BitWidth == 64) {
			// Add callee-saved regs R12 through R15. We can optimize these away with later analysis,
			//  after we have GlobalNames and LocalNames defined.
			this->MDAddRegUse(STARS_x86_R_r12, false);
			this->MDAddRegUse(STARS_x86_R_r13, false);
			this->MDAddRegUse(STARS_x86_R_r14, false);
			this->MDAddRegUse(STARS_x86_R_r15, false);
		}
	}

	// Next, add the flags register to the DEFs and USEs for those instructions that
	//  are marked as defining or using flags.
	if (!this->IsDefsFlags() && SMPDefsFlags[opcode]) {
		this->MDAddRegDef(X86_FLAGS_REG, false);
		this->SetDefsFlags();
	}
	if (!this->IsUsesFlags() && SMPUsesFlags[opcode]) {
		this->MDAddRegUse(X86_FLAGS_REG, false);
		this->SetUsesFlags();
	}

#if 1
	if (this->IsNop()) {
		// Clear the DEFs and USEs for no-ops.
		//  These include machine idioms for no-ops, e.g. mov esi,esi
		//  or xchg ax,ax or lea esi,[esi].
		this->Defs.clear();
		this->Uses.clear();
		this->MoveSource = nullptr;
		this->DEFMemOp = nullptr;
		this->USEMemOp = nullptr;
		this->SetLeaMemUseOp(nullptr);
		// this->OptType = 1;
	}
#endif

	if (DebugFlag) {
		SMP_msg("DEBUG after MDFixupDefUseLists:\n");
		this->Dump();
	}
	return;
} // end of SMPInstr::MDFixupDefUseLists()

// Erase DEFs and USEs of callee-preserved registers in call instructions.
bool SMPInstr::MDFixupCallDefUseLists(void) {
	bool InstChanged = false;
#if STARS_CONSERVATIVE_DEADREGS
	return InstChanged;
#endif
	if ((this->type == CALL) || (this->type == INDIR_CALL) || this->IsTailCall()) {
		// We want to add the caller-saved registers to the USEs and DEFs lists
		if ((NULL != this->GetBlock()) && (!this->IsInterruptCall())) {
			STARS_ea_t CalledFuncAddr = this->GetCallTarget();
			SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr);
			if ((nullptr != CalleeFunc) && (!CalleeFunc->IsLinkerStub())) {
				// If CalleeFunc has preserved registers by saving them on entry and restoring them before 
				//  all return points, then there is no need to conservatively consider these registers to
				//  be USEs or DEFs. They essentially are untouched by the callee.
				set<DefOrUse, LessDefUse>::iterator DefIter, UseIter;
				bool CalleeAnalyzed = (CalleeFunc->HasSTARSStackPtrAnalysisCompleted() && CalleeFunc->StackPtrAnalysisSucceeded() && (!CalleeFunc->HasUnresolvedIndirectJumps()));
#if 0 // get more conservative for now
				int IndirCallRegNum = STARS_x86_R_none;
				if (CalleeAnalyzed && (INDIR_CALL == this->type)) {
					// We want to avoid removing the register USE for indirect calls, e.g. eax in call eax
					SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
					assert(!CurrRT->HasRightSubTree());
					IndirCallRegNum = (int) CurrRT->GetRightOperand()->GetReg();
				}
#endif
				for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCallerSavedReg(); RegIter != global_STARS_program->GetLastCallerSavedReg(); ++RegIter) {
					STARS_regnum_t RegNum = (*RegIter);
					STARSOpndTypePtr SearchOp = this->STARSInstPtr->MakeRegOpnd(RegNum);
					bool ErasedDEF = false;
					if ((RegNum != MD_RETURN_VALUE_REG) && CalleeFunc->IsRegPreserved(RegNum)) {
						DefIter = this->FindDef(SearchOp);
						// assert(DefIter != this->GetLastDef());	// not true for some reason?
						if (DefIter != this->GetLastDef()) {
							this->EraseDef(DefIter);
							ErasedDEF = true;
							UseIter = this->FindUse(SearchOp);
							assert(UseIter != this->GetLastUse());
							this->EraseUse(UseIter);
							InstChanged = true;
						}
					}
#if 0 // get conservative on indirect calls, which can have reg or memory or address reg USEs
					else if (CalleeAnalyzed && (RegNum != IndirCallRegNum) && (!CalleeFunc->IsLiveIn(SearchOp))) {
#else
					else if (CalleeAnalyzed && (this->type != INDIR_CALL) && (!CalleeFunc->IsLiveIn(SearchOp))) {
#endif
						// Callee stack analysis was successful, so function LiveIn set was computed,
						//  but this register is not LiveIn. We should remove it from the USE list of the call.
						UseIter = this->FindUse(SearchOp);
						if (UseIter == this->GetLastUse()) {
							// Might happen if IDA Pro has chunked a function incorrectly and created what
							//  looks like a tail call as a result. Also, now that we iterate, the USE could have
							//  been removed on a previous iteration.
							;
						}
						else {
							this->EraseUse(UseIter);
							InstChanged = true;
						}
					}
					if ((!ErasedDEF) && CalleeAnalyzed && (RegNum != MD_RETURN_VALUE_REG) && (!CalleeFunc->IsVarKill(SearchOp))) {
						// Callee has been analyzed, and register is not killed. We should remove it from the DEFs.
						DefIter = this->FindDef(SearchOp);
						if (DefIter == this->GetLastDef()) {
							// Might happen if IDA Pro has chunked a function incorrectly and created what
							//  looks like a tail call as a result. Also, now that we iterate, the USE could have
							//  been removed on a previous iteration.
							;
						}
						else {
							this->EraseDef(DefIter);
							InstChanged = true;
						}
					}
				}
			}
		}
	}
	return InstChanged;
} // end of SMPInstr::MDFixupCallDefUseLists()

// If we can definitely identify which part of the addressing expression
//  used in MemOp is the POINTER type, and it is not a STACKPTR or GLOBALPTR
//  immediate, set the USE type for that register to POINTER and return true.
//  If we can find definite NUMERIC addressing registers that are not already
//  typed as NUMERIC, set their USE types to NUMERIC and return true.
bool SMPInstr::MDFindPointerUse(const STARSOpndTypePtr &MemOp, bool UseFP) {
	bool changed = false;
	int BaseReg;
	int IndexReg;
	SMPOperandType BaseType = UNKNOWN;
	SMPOperandType IndexType = UNKNOWN;
	uint16_t ScaleFactor;
	STARS_ea_t offset;
	set<DefOrUse, LessDefUse>::iterator BaseIter;
	set<DefOrUse, LessDefUse>::iterator IndexIter;

	if (this->MDIsLoadEffectiveAddressInstr())
		return false;  // lea instruction really has no memory operands
	if (STARS_NN_fnop == this->GetIDAOpcode())
		return false;  // SSA marker instruction

	STARSOpndTypePtr BaseOp = nullptr;
	STARSOpndTypePtr IndexOp = nullptr;
	MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor, offset);
	if (STARS_x86_R_none != IndexReg) {
		IndexOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg));
		IndexIter = this->FindUse(IndexOp);
		assert(IndexIter != this->GetLastUse());
		IndexType = IndexIter->GetType();
	}
	if (STARS_x86_R_none != BaseReg) {
		BaseOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg));
		BaseIter = this->FindUse(BaseOp);
		assert(BaseIter != this->GetLastUse());
		BaseType = BaseIter->GetType();
	}
	if (MDIsStackPtrReg(BaseReg, UseFP)) {
		if ((STARS_x86_R_none != IndexReg) && (!IsNumeric(IndexType))) {
			// We have an indexed access into the stack frame.
			//  Set IndexReg USE type to NUMERIC.
			changed = true;
			IndexIter = this->SetUseType(IndexOp, NUMERIC);
			assert(IndexIter != this->GetLastUse());
		}
		return changed; // stack accesses will get STACKPTR type in SetImmedTypes()
	}
	if (MDIsStackPtrReg(IndexReg, UseFP)) {
		if ((STARS_x86_R_none != BaseReg) && (!IsNumeric(BaseType))) {
			// We have an indexed access into the stack frame.
			//  Set BaseReg USE type to NUMERIC.
			// Note that BaseReg is really an IndexReg and vice versa.
			changed = true;
			BaseIter = this->SetUseType(BaseOp, NUMERIC);
			assert(BaseIter != this->GetLastUse());
			SMP_msg("WARNING: BaseReg is index, IndexReg is base: %s\n",
				DisAsmText.GetDisAsm(this->GetAddr()));
		}
		return changed; // stack accesses will get STACKPTR type in SetImmedTypes()
	}
	if (IsImmedGlobalAddress(offset)) {
		if ((STARS_x86_R_none != IndexReg) && (!IsNumeric(IndexType))) {
			// We have an indexed access into a global.
			//  Set IndexReg USE type to NUMERIC.
			changed = true;
			IndexIter = this->SetUseType(IndexOp, NUMERIC);
			assert(IndexIter != this->GetLastUse());
		}
		if ((STARS_x86_R_none != BaseReg) && (!IsNumeric(BaseType))) {
			// We have an indexed access into a global.
			//  Set BaseReg USE type to NUMERIC.
			// Note that BaseReg is really an index register.
			changed = true;
			BaseIter = this->SetUseType(BaseOp, NUMERIC);
			assert(BaseIter != this->GetLastUse());
#if SMP_VERBOSE_FIND_POINTERS
			SMP_msg("WARNING: BaseReg used as index: %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
#endif
		}
		return changed;  // global immediate is handled in SetImmedTypes()
	}

	// At this point, we must have a base address in a register, not used
	//  to directly address the stack or a global.
	if ((0 < ScaleFactor) || (STARS_x86_R_none == IndexReg)) {
		// IndexReg is scaled, meaning it is NUMERIC, so BaseReg must
		//  be a POINTER; or IndexReg is not present, so BaseReg is the
		//  only possible holder of an address.
		if (STARS_x86_R_none != BaseReg) {
			if (UNINIT == BaseIter->GetType()) {
				changed = true;
				BaseIter = this->SetUseType(BaseOp, POINTER);
				assert(BaseIter != this->GetLastUse());
			}
		}
	}
	else if (STARS_x86_R_none == BaseReg) {
		// We have an unscaled IndexReg and no BaseReg and offset was
		//  not a global offset, so IndexReg must be a POINTER.
		if (STARS_x86_R_none != IndexReg) {
			if (UNINIT == IndexType) {
				changed = true;
				IndexIter = this->SetUseType(IndexOp, POINTER);
				assert(IndexIter != this->GetLastUse());
			}
		}
	}
	else { // We have BaseReg and an unscaled IndexReg.
		// The only hope for typing something like [ebx+edx] is for
		//  one register to already be typed NUMERIC, in which case
		//  the other one must be a POINTER, or if one register is
		//  already POINTER, then the other one must be NUMERIC.
		if (IsNumeric(BaseType)) {
			if (UNINIT == IndexType) {
				// Set to POINTER or PROF_POINTER
				changed = true;
				IndexIter = this->SetUseType(IndexOp, POINTER);
				assert(IndexIter != this->GetLastUse());
			}
			else if (IsNumeric(IndexType)) {
				SMP_msg("ERROR: BaseReg and IndexReg both NUMERIC at %llx: %s\n",
					(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			}
		}
		else { // BaseReg was not NUMERIC
			if (UNINIT == BaseType) { // BaseReg is UNINIT
				if (IsNumeric(IndexType)) {
					changed = true;
					BaseIter = this->SetUseType(BaseOp, POINTER);
					assert(BaseIter != this->GetLastUse());
				}
				else if (IsDataPtr(IndexType)) {
					// IndexReg is POINTER, so make BaseReg NUMERIC.
					changed = true;
					BaseIter = this->SetUseType(BaseOp, NUMERIC);
					assert(BaseIter != this->GetLastUse());
				}
			}
			else if (IsDataPtr(BaseType)) {
				// BaseReg was a pointer type. IndexReg must be NUMERIC.
				if (UNINIT == IndexType) {
					changed = true;
					IndexIter = this->SetUseType(IndexOp, NUMERIC);
					assert(IndexIter != this->GetLastUse());
				}
				else if (IsDataPtr(IndexType)) {
					SMP_msg("ERROR: BaseReg and IndexReg both POINTER at %llx: %s\n",
						(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
				}
			}
		}
	}

	return changed;
} // end of SMPInstr::MDFindPointerUse()

// Are all DEFs typed to something besides UNINIT?
bool SMPInstr::AllDEFsTyped(void) {
	if (this->AreDEFsTyped()) {
		return true;
	}
	bool FoundUNINIT = false;
	set<DefOrUse, LessDefUse>::iterator DefIter;
	for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		if (IsEqType(UNINIT, DefIter->GetType())) {
			FoundUNINIT = true;
			break;
		}
	}
	if (!FoundUNINIT) {
		this->SetDEFsTyped();
	}
	return (!FoundUNINIT);
} // end of SMPInstr::AllDEFsTyped()

// Are all USEs typed to something besides UNINIT?
bool SMPInstr::AllUSEsTyped(void) {
	if (this->AreUSEsTyped()) {
		return true;
	}
	bool FoundUNINIT = false;
	set<DefOrUse, LessDefUse>::iterator UseIter;
	for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
		if (IsEqType(UNINIT, UseIter->GetType())) {
			FoundUNINIT = true;
			break;
		}
	}
	if (!FoundUNINIT) {
		this->SetUSEsTyped();
	}
	return (!FoundUNINIT);
} // end of SMPInstr::AllUSEsTyped()

// Return true if UseOp is a USE reg, not just an address reg in a memory USE
bool SMPInstr::IsNonAddressReg(const STARSOpndTypePtr &UseOp) const { 
	bool FoundUse = false;
	STARS_regnum_t SearchReg = MDCanonicalizeSubReg(UseOp->GetReg());
	for (std::size_t OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
		STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(OpNum);
		if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			if (Opnd->IsRegOp()) {
				STARS_regnum_t TestReg = MDCanonicalizeSubReg(Opnd->GetReg());
				if (TestReg == SearchReg) {
					FoundUse = true;
					break;
				}
			}
		}
	}
	return FoundUse;
} // end of SMPInstr::IsNonAddressReg()

STARS_uval_t SMPInstr::MDGetShiftCount(void) const {
	STARS_uval_t ShiftCount = 0;

	if (this->MDIsShiftOrRotate()) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		assert(CurrRT->HasRightSubTree());
		CurrRT = CurrRT->GetRightTree();
		if (this->MDIsDoubleRegShift()) {
			// RTL has extra level of depth.
			assert(CurrRT->HasRightSubTree());
			CurrRT = CurrRT->GetRightTree();
		}
		STARSOpndTypePtr ShiftCountOp = CurrRT->GetRightOperand();
		assert(nullptr != ShiftCountOp);
		if (ShiftCountOp->IsImmedOp()) {
			ShiftCount = ShiftCountOp->GetImmedValue();
		}
	}

	return ShiftCount;
} // end of SMPInstr::MDGetShiftCount()

// RTL shows DEF operand is subreg.
bool SMPInstr::IsReducedWidthDef(void) const {
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	STARSOpndTypePtr DefOp = CurrRT->GetLeftOperand();
	return ((nullptr != DefOp) && (! DefOp->IsVoidOp()) && (DefOp->GetByteWidth() < 4));
}

// 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.
bool SMPInstr::IsSubRegUsedAsShiftCount(const STARSOpndTypePtr &UseOp) {
	bool ShiftCounter = false;

	if ((UseOp->IsRegOp()) && this->MDIsShiftOrRotate()) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		assert(CurrRT->HasRightSubTree());
		CurrRT = CurrRT->GetRightTree();
		if (this->MDIsDoubleRegShift()) {
			// RTL has extra level of depth.
			assert(CurrRT->HasRightSubTree());
			CurrRT = CurrRT->GetRightTree();
		}
		STARSOpndTypePtr ShiftCountOp = CurrRT->GetRightOperand();
		assert(nullptr != ShiftCountOp);
		if (ShiftCountOp->IsRegOp()) {
			STARS_regnum_t UseReg = UseOp->GetReg();
			STARS_regnum_t ShiftCountReg = ShiftCountOp->GetReg();
			STARS_regnum_t WideUseReg = MDCanonicalizeSubReg(UseReg);
			STARS_regnum_t WideShiftCountReg = MDCanonicalizeSubReg(ShiftCountReg);
			if ((UseReg != ShiftCountReg) && (WideUseReg == WideShiftCountReg)) {
				// Registers were not equal, but their canonical enclosing
				//  registers are equal. Because shift counters that are not
				//  immediate are the 8-bit subregister in x86 (MD here !!!!!!)
				//  it must be that the ShiftCountReg is a subreg of UseReg.
				//  This is the condition we are looking for.
				ShiftCounter = true;
			}
		}
	}

	return ShiftCounter;
} // end of SMPInstr::IsSubRegUsedAsShiftCount()

// Does UseOp ultimately come from a small positive constant?
bool SMPInstr::IsOpSourceSmallPositiveConstant(const STARSOpndTypePtr &UseOp, int UseSSANum) {
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool FoundSmallConst = false;
	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame
		|| (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs; must be stack or register.
		//  SSAMarker 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.
		FoundSmallConst = false; 
	}
	else if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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 small constants
		//  but we only need one of the Phi USEs to come from
		//  a small constant 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 small constant.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
				int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
				if (this->IsOpSourceSmallPositiveConstant(UseOp, PhiUseSSANum)) {
					FoundSmallConst = true; // only one success on all Phi USEs is needed
					break;
				}
			}
		}
	}
	else {
		bool ValueFound;
		STARS_uval_t ConstValue;
		SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
		if (DefInst->MDIsSimpleAssignment(ValueFound, ConstValue)) {
			FoundSmallConst = (ValueFound && (ConstValue <= 2));
			if (!FoundSmallConst && !ValueFound && DefInst->MDIsMoveInstr()) {
				// We have a non-immediate move. Trace back through move source to find small const.
				STARSOpndTypePtr CopyUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
				CanonicalizeOpnd(CopyUseOp);
				set<DefOrUse, LessDefUse>::iterator UseIter = DefInst->FindUse(CopyUseOp);
				assert(UseIter != DefInst->GetLastUse());
				int CopyUseSSANum = UseIter->GetSSANum();
				FoundSmallConst = DefInst->IsOpSourceSmallPositiveConstant(CopyUseOp, CopyUseSSANum);
			}
		}
	}

	return FoundSmallConst;
} // end of SMPInstr::IsOpSourceSmallPositiveConstant()

// Does UseOp ultimately come from a bitwise not instruction?
bool SMPInstr::IsOpSourceBitwiseNot(const STARSOpndTypePtr &UseOp, int UseSSANum) {
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool FoundBitwiseNotInst = false;
	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if (STARS_IsSSAMarkerPseudoID(UseDefAddr) || AboveStackFrame
		|| (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs; must be stack or register.
		//  SSAMarker 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.
		FoundBitwiseNotInst = false;
	}
	else if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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 bitwise nots
		//  but we only need one of the Phi USEs to come from
		//  a bitwise not 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 bitwise not.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
				int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
				if (this->IsOpSourceBitwiseNot(UseOp, PhiUseSSANum)) {
					FoundBitwiseNotInst = true; // only one success on all Phi USEs is needed
					break;
				}
			}
		}
	}
	else {
		SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
		if (DefInst->MDIsBitwiseNotOpcode()) {
			FoundBitwiseNotInst = true;
		}
		else if (DefInst->MDIsMoveInstr()) {
			STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
			if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
				CanonicalizeOpnd(MoveUseOp);
				set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
				assert(MoveUseIter != DefInst->GetLastUse());
				int MoveUseSSANum = MoveUseIter->GetSSANum();
				FoundBitwiseNotInst = DefInst->IsOpSourceBitwiseNot(MoveUseOp, MoveUseSSANum); // recurse
			}
		}
		else {
			// Not a move, not a bitwise not. We must return false.
			FoundBitwiseNotInst = false;
		}
	}

	return FoundBitwiseNotInst;
} // end of SMPInstr::IsOpSourceBitwiseNot()

// Does UseOp ultimately come from a set-condition-code instruction?
bool SMPInstr::IsOpSourceConditionCode(const STARSOpndTypePtr &UseOp, int UseSSANum) {
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool FoundConditionalSetInst = false;
	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs; must be stack or register.
		//  SSAMarker 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.
		FoundConditionalSetInst = false; 
	}
	else if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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 condition codes
		//  but we only need one of the Phi USEs to come from
		//  a condition code 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 condition code.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
				int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
				if (this->IsOpSourceConditionCode(UseOp, PhiUseSSANum)) {
					FoundConditionalSetInst = true; // only one success on all Phi USEs is needed
					break;
				}
			}
		}
	}
	else {
		SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
		if (DefInst->MDIsAnySetValue()) {
			FoundConditionalSetInst = true;
		}
		else if (DefInst->MDIsMoveInstr()) {
			STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
			if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
				CanonicalizeOpnd(MoveUseOp);
				set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
				assert(MoveUseIter != DefInst->GetLastUse());
				int MoveUseSSANum = MoveUseIter->GetSSANum();
				FoundConditionalSetInst = DefInst->IsOpSourceConditionCode(MoveUseOp, MoveUseSSANum); // recurse
			}
		}
		else {
			// Not a move, not a condition code transfer. We must return false.
			FoundConditionalSetInst = false;
		}
	}

	return FoundConditionalSetInst;
} // end of SMPInstr::IsOpSourceConditionCode()

// Does UseOp ultimately come from a shift left instruction?
bool SMPInstr::IsOpSourceLeftShift(const STARSOpndTypePtr &UseOp, int UseSSANum, STARSOpndTypePtr &ShiftCounterOp, STARSOpndTypePtr &ShiftedOp, STARS_ea_t &ShiftInstAddr) {
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool FoundLeftShiftInst = false;
	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs; must be stack or register.
		//  SSAMarker 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.
		FoundLeftShiftInst = false; 
	}
	else if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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 condition codes
		//  but we only need one of the Phi USEs to come from
		//  a condition code 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 condition code.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
				int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
				if (this->IsOpSourceLeftShift(UseOp, PhiUseSSANum, ShiftCounterOp, ShiftedOp, ShiftInstAddr)) {
					FoundLeftShiftInst = true; // only one success on all Phi USEs is needed
					break;
				}
			}
		}
	}
	else {
		SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
		if (DefInst->MDIsLeftShift()) {
			FoundLeftShiftInst = true;
			ShiftInstAddr = UseDefAddr;
			DefInst->GetShiftOperands(ShiftedOp, ShiftCounterOp);
		}
		else if (DefInst->MDIsMoveInstr()) {
			STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
			if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
				CanonicalizeOpnd(MoveUseOp);
				set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
				assert(MoveUseIter != DefInst->GetLastUse());
				int MoveUseSSANum = MoveUseIter->GetSSANum();
				FoundLeftShiftInst = DefInst->IsOpSourceLeftShift(MoveUseOp, MoveUseSSANum, ShiftCounterOp, ShiftedOp, ShiftInstAddr); // recurse
			}
		}
		else {
			// Not a move, not a condition code transfer. We must return false.
			FoundLeftShiftInst = false;
		}
	}

	return FoundLeftShiftInst;
} // end of SMPInstr::IsOpSourceLeftShift()

// Does UseOp ultimately come from a move-with-zero-extension instruction?
bool SMPInstr::IsOpSourceZeroExtendedMove(const STARSOpndTypePtr &UseOp, int UseSSANum, bool TruncationCheck) {
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool FoundMoveZX = false;
	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs; must be stack or register.
		//  SSAMarker 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.
		FoundMoveZX = false; 
	}
	else if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
				int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
				if (this->IsOpSourceZeroExtendedMove(UseOp, PhiUseSSANum, TruncationCheck)) {
					FoundMoveZX = 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)) {
			FoundMoveZX = (FG_MASK_UNSIGNED == SignMask);
		}
		else if (DefInst->MDIsMoveInstr()) {
			STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
			if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
				CanonicalizeOpnd(MoveUseOp);
				set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
				assert(MoveUseIter != DefInst->GetLastUse());
				int MoveUseSSANum = MoveUseIter->GetSSANum();
				FoundMoveZX = DefInst->IsOpSourceZeroExtendedMove(MoveUseOp, MoveUseSSANum, TruncationCheck); // recurse
			}
		}
		else if (TruncationCheck && DefInst->MDIsNonOverflowingBitManipulation()) {
			// 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.
			set<DefOrUse, LessDefUse>::iterator BitUseIter = DefInst->FindUse(UseOp);
			if (BitUseIter != DefInst->GetLastUse()) {
				int BitUseSSANum = BitUseIter->GetSSANum();
				FoundMoveZX = DefInst->IsOpSourceZeroExtendedMove(UseOp, BitUseSSANum, true); // recurse up the chain
			}
		}
		else {
			FoundMoveZX = false;
		}
	}

	return FoundMoveZX;
} // end of SMPInstr::IsOpSourceZeroExtendedMove()

// Does UseOp ultimately come from a move-with-zero-extension instruction OR from a condition code OR from a right shift?
bool SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(const STARSOpndTypePtr &UseOp, int UseSSANum, bool TruncationCheck) {
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool FoundMoveZXCC = false;
	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame
		|| (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs; must be stack or register.
		//  SSAMarkerID 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.
		FoundMoveZXCC = false; 
	}
	else if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
				int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
				if (this->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(UseOp, PhiUseSSANum, TruncationCheck)) {
					FoundMoveZXCC = 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)) {
			FoundMoveZXCC = (FG_MASK_UNSIGNED == SignMask);
		}
		else if (DefInst->MDIsAnySetValue() || DefInst->MDIsShiftRight()) {
			FoundMoveZXCC = true;
		}
		else if (DefInst->MDIsMoveInstr()) {
			STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
			if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
				CanonicalizeOpnd(MoveUseOp);
				set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp);
				assert(MoveUseIter != DefInst->GetLastUse());
				int MoveUseSSANum = MoveUseIter->GetSSANum();
				FoundMoveZXCC = DefInst->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(MoveUseOp, MoveUseSSANum, TruncationCheck); // 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();
				FoundMoveZXCC = DefInst->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(UseOp, BitUseSSANum, true); // recurse up the chain
			}
		}
		else {
			FoundMoveZXCC = false;
		}
	}

	return FoundMoveZXCC;
} // end of SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode()

// Trace through moves to any of the above cases, return source inst
bool SMPInstr::IsOpSourceSpecial(const STARSOpndTypePtr &UseOp, int UseSSANum, bool TruncationCheck, STARS_ea_t &SourceInstAddr) {
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool FoundMoveNotZXCCSubreg = false;
	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs; must be stack or register.
		//  SSAMarker 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 (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::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()) {
			STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
			if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack 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 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();
			}
		}
	}

	return FoundMoveNotZXCCSubreg;
} // end of SMPInstr::IsOpSourceSpecial()

// Does UseOp ultimately come from a byte swap?
bool SMPInstr::IsOpSourceByteSwap(const STARSOpndTypePtr &UseOp, int UseSSANum, STARS_ea_t &ByteSwapAddr) {
	// Byte swap operations typically look like:
	//  byte move memloc into reg1, zero-extended
	//  byte mov memloc+1 into reg2, zero-extended
	//  shift reg1 left 8 bits
	//  OR reg2 into reg1
	// reg1 is now a byte-swap of the two bytes at memloc+1:memloc
	bool ByteSwapFound = false;

	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
		return false;
	}

	bool RegDef = (UseOp->IsRegOp());
	bool LocalName = this->GetBlock()->IsLocalName(UseOp);
	bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
	bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false)));
	STARS_ea_t UseAddr = this->GetAddr();
	STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
	STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
	bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr);

	if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) {
		// Try to find in the function level.
		UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
	}

	if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) {
		// Cannot search for general memory DEFs for non-local names; must be stack or register.
		//  SSAMarker 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.
		ByteSwapFound = false; 
	}
	else if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
		// 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 byte-swap
		//  moves into the UseOp register, but we only need one of the Phi USEs to come from
		//  a byte-swap to potentially lead to a user tainting of the critical argument. We
		//  will recurse on all Phi USEs, declaring success if we find a single one of them
		//  to come from a byte swap.
		std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(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());
			std::size_t PhiListSize = DefPhiIter->GetPhiListSize();
			PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
			for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) {
				int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex);
				if (this->IsOpSourceByteSwap(UseOp, PhiUseSSANum, ByteSwapAddr)) {
					ByteSwapFound = true; // only one success on all Phi USEs is needed
					break;
				}
			}
		}
	}
	else {
		SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
		if (DefInst->MDIsBitwiseOrOpcode()) {
			// Found the OR operation. Find zero-extended byte loads of each operand of the OR.
			SMPRegTransfer *CurrRT = DefInst->RTL.GetRT(0);
			assert(CurrRT->HasRightSubTree());
			CurrRT = CurrRT->GetRightTree();
			if (!CurrRT->HasRightSubTree()) {
				assert(SMP_BITWISE_OR == CurrRT->GetOperator());
				STARSOpndTypePtr LeftOp = CloneIfSubwordReg(CurrRT->GetLeftOperand());
				STARSOpndTypePtr RightOp = CloneIfSubwordReg(CurrRT->GetRightOperand());
				if (! RightOp->IsImmedOp()) {
					bool LeftSuccess = true;
					// Trace OR DEF/USE LeftOp back to shift left within its same block.
					CanonicalizeOpnd(LeftOp);
					set<DefOrUse, LessDefUse>::iterator UseIter = DefInst->FindUse(LeftOp);
					assert(UseIter != DefInst->GetLastUse());
					int LeftUseSSANum = UseIter->GetSSANum();
					bool LocalName2 = DefInst->GetBlock()->IsLocalName(LeftOp);
					STARS_ea_t ShiftAddr = DefInst->GetBlock()->GetDefAddrFromUseAddr(LeftOp, UseDefAddr, LeftUseSSANum, LocalName2);
					SMPInstr *ShiftInst;
					bool UseDefAddrIsPseudoID = (STARS_PSEUDO_ID_MIN <= UseDefAddr);
					// Limit to case where shift left is in same block as OR.
					if (!UseDefAddrIsPseudoID && (ShiftAddr >= DefInst->GetBlock()->GetFirstAddr()) && (ShiftAddr < UseDefAddr)) {
						ShiftInst = DefInst->GetBlock()->FindInstr(ShiftAddr);
						if (ShiftInst->MDIsLeftShift()) {
							STARSOpndTypePtr ShiftedOp, ShiftCounterOp;
							ShiftInst->GetShiftOperands(ShiftedOp, ShiftCounterOp);
							if ((ShiftCounterOp->IsImmedOp()) && (8 == ShiftCounterOp->GetImmedValue())) {
								;
							}
							else {
								LeftSuccess = false; // failure
							}
						}
						else {
							LeftSuccess = false; // failure
						}
					}
					else {
						LeftSuccess = false; // failure
					}

					STARSOpndTypePtr LeftMemOp = nullptr;
					STARSOpndTypePtr RightMemOp = nullptr;

					// Trace LeftOp and RightOp back to zero-extended byte memory loads.
					if (LeftSuccess && IsMemOperand(LeftOp) && (1 == LeftOp->GetByteWidth())) {
						// We are using OR on a byte memory location; already found the ultimate memory source.
						LeftMemOp = LeftOp;
					}
					else if (LeftSuccess && LeftOp->IsRegOp()) {
						// Trace reg back to zero-extended load.
						set<DefOrUse, LessDefUse>::iterator UseIter = ShiftInst->FindUse(LeftOp);
						assert(UseIter != ShiftInst->GetLastUse());
						int LeftUseSSANum = UseIter->GetSSANum();
						STARS_ea_t LeftMemAddr;
						if (ShiftInst->IsOpSourceSpecial(LeftOp, LeftUseSSANum, false, LeftMemAddr)) {
							SMPInstr *LeftDefInst = ShiftInst->GetBlock()->GetFunc()->GetInstFromAddr(LeftMemAddr);
							unsigned short SignMask;
							if (LeftDefInst->MDIsSignedLoad(SignMask)) {
								if (SignMask == FG_MASK_UNSIGNED) { // zero-extended load
									LeftMemOp = LeftDefInst->GetMoveSource();
								}
							}
						}
					}
					if (IsMemOperand(RightOp) && (1 == RightOp->GetByteWidth())) {
						// We are using OR on a byte memory location; already found the ultimate memory source.
						RightMemOp = RightOp;
					}
					else if (LeftSuccess && IsMemOperand(LeftMemOp) && RightOp->IsRegOp()) {
						// Trace reg back to zero-extended load.
						CanonicalizeOpnd(RightOp);
						set<DefOrUse, LessDefUse>::iterator UseIter = DefInst->FindUse(RightOp);
						assert(UseIter != DefInst->GetLastUse());
						int RightUseSSANum = UseIter->GetSSANum();
						STARS_ea_t RightMemAddr;
						if (DefInst->IsOpSourceSpecial(RightOp, RightUseSSANum, false, RightMemAddr)) {
							SMPInstr *RightDefInst = DefInst->GetBlock()->GetFunc()->GetInstFromAddr(RightMemAddr);
							unsigned short SignMask;
							if (RightDefInst->MDIsSignedLoad(SignMask)) {
								if (SignMask == FG_MASK_UNSIGNED) { // zero-extended load
									RightMemOp = RightDefInst->GetMoveSource();
								}
							}
						}
					}
					if (LeftSuccess && IsMemOperand(LeftMemOp) && IsMemOperand(RightMemOp) && (1 == LeftMemOp->GetByteWidth()) && (1 == RightMemOp->GetByteWidth())) {
						// Is RightMemOp equal to LeftMemOp plus one in the address space?
						STARS_ea_t LeftAddr = LeftMemOp->GetAddr();
						if (RightMemOp->GetAddr() == (LeftAddr + 1)) {
							LeftMemOp->SetAddr(LeftAddr + 1); // increment before comparing all fields
							if (IsEqOp(LeftMemOp, RightMemOp)) {
								ByteSwapFound = true;
								ByteSwapAddr = UseDefAddr; // record address of the OR instruction
							}
						}
					}
				}
			}
		}
	}

	return ByteSwapFound;
} // end of SMPInstr::IsOpSourceByteSwap()

bool IsOpSourceInArg(const STARSOpndTypePtr &UseOp, int UseSSANum, STARSOpndTypePtr &InArgOp); // Does UseOp trace back to InArgOp in SSA marker inst?

bool SMPInstr::MDIsDivision(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_div == opcode) || (STARS_NN_idiv == opcode));
}

// 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
//  used as a helper for IsSubRegUsedAsShiftCount().
bool SMPInstr::MDIsShiftOrRotate(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return (((STARS_NN_rcl <= opcode) && (STARS_NN_ror >= opcode))
		|| ((STARS_NN_sal <= opcode) && (STARS_NN_shr >= opcode))
		|| (STARS_NN_shld == opcode) || (STARS_NN_shrd == opcode));
} // end of SMPInstr::MDIsShiftOrRotate()

// Is opcode a shift to the right?
bool SMPInstr::MDIsShiftRight(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_sar == opcode) || (STARS_NN_shr == opcode));
}

// Shift of two regs concatenated together?
bool SMPInstr::MDIsDoubleRegShift(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_shld == opcode) || (STARS_NN_shrd == opcode));
}

// Does the shift or rotate RTL move the upper HalfBitWidth bits
//  into the lower half of the register? Or, if MustBeHalfRegWidth is false,
//  do we shift right by HalfBitWidth bits?
bool SMPInstr::ShiftMakesUpperBitsLower(std::size_t HalfBitWidth, bool MustBeHalfRegWidth) {
	bool FullCircle = false;

	if (!MustBeHalfRegWidth || (MD_NORMAL_MACHINE_BITWIDTH == (HalfBitWidth * 2))) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		if ((NULL != CurrRT) && (CurrRT->HasRightSubTree())) {
			CurrRT = CurrRT->GetRightTree();
			SMPoperator CurrOper =  CurrRT->GetOperator();
			bool LeftRotate = (SMP_ROTATE_LEFT == CurrOper);
			if ((SMP_U_RIGHT_SHIFT == CurrOper) || (SMP_S_RIGHT_SHIFT == CurrOper)
				|| LeftRotate || (SMP_ROTATE_RIGHT == CurrOper)) {
				if (CurrRT->HasRightSubTree()) { // double-word shift
					CurrRT = CurrRT->GetRightTree();
				}
				assert(!(CurrRT->HasRightSubTree()));
				STARSOpndTypePtr ShiftCount = CurrRT->GetRightOperand();
				if (ShiftCount->IsImmedOp()) {
					STARS_uval_t ImmVal = ShiftCount->GetImmedValue();
					// If we rotate left by e.g. 32-HalfBitWidth bits, then we are processing
					//  bytes or halfregs one at a time; if we rotate or shift right by HalfBitWidth,
					//  we are processing the register one HalfBitWidth at a time. We also a
					if (MustBeHalfRegWidth || (!LeftRotate)) {
						FullCircle = (HalfBitWidth == ImmVal);
					}
					else {
						// Left rotate amount plus HalfBitWidth must add up to full register width
						FullCircle = (MD_NORMAL_MACHINE_BITWIDTH == (ImmVal + HalfBitWidth));
					}
				}
			}
		}
	}
	return FullCircle;
} // SMPInstr::ShiftMakesUpperBitsLower()

#if 0
// Find SearchDelta in StackDeltaSet, inserting it if not found. Return whether it was initially found.
bool SMPInstr::FindStackPtrDelta(STARS_sval_t SearchDelta) const {
	bool found = (this->StackDeltaSet.find(SearchDelta) != this->StackDeltaSet.end());
	if (!found) {
		this->StackDeltaSet.insert(SearchDelta);
		if (SearchDelta < this->StackPtrOffset) {
			// Mimic IDA Pro, which seems to keep the biggest stack frame possible.
			//  With negative stack deltas, this means the smallest stack delta is kept.
			this->SetStackPtrOffset(SearchDelta);
		}
	}
	return found;
} // end of SMPInstr::FindStackPtrDelta()
#endif

// Set the type of all immediate operands found in the USE set.
// Set all flags and floating point register USEs and DEFs to NUMERIC also,
//  along with easily determined types for special cases.
void SMPInstr::SetImmedTypes(bool UseFP) {
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	STARSOpndTypePtr UseOp = nullptr;
	STARSOpndTypePtr DefOp = nullptr;
	STARS_uval_t ImmVal;
	bool DebugFlag = false;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
	DebugFlag = DebugFlag || (this->GetAddr() == 0x805cd52) || (this->GetAddr() == 0x805cd56);
	DebugFlag |= (0 == strncmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName(), 15));
#endif

	CurrUse = this->GetFirstUse();
	while (CurrUse != this->GetLastUse()) {
		UseOp = CurrUse->GetOp();
#if SMP_VERBOSE_DEBUG_BUILD_RTL
		if (DebugFlag) {
			SMP_msg("SetImmedTypes USE: ");
			PrintOperand(UseOp);
			SMP_msg("\n");
		}
#endif
		if (UseOp->IsImmedOp()) {
			ImmVal = UseOp->GetImmedValue();
			bool NonZero = (0 != ImmVal);
			if (IsImmedGlobalAddress((STARS_ea_t) ImmVal)) { 
				// NOTE: Const could fall in this range by chance. !!!!****!!!!****
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting to GLOBALPTR\n");
#endif
				CurrUse = this->SetUseType(UseOp, GLOBALPTR);
			}
#if 1
			else if (global_STARS_program->IsImmedDataAddress((STARS_ea_t) ImmVal)) {
				// NOTE: We must have a deeper analysis before we call IsImmedCodeAddress()
				//  to catch the data addresses within the code address range.
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting to POINTER\n");
#endif
				CurrUse = this->SetUseType(UseOp, POINTER);
			}
#endif
			else if (this->IsInterruptCall() || (NonZero && global_STARS_program->IsImmedCodeAddress((STARS_ea_t) ImmVal))) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting to CODEPTR\n");
#endif
				CurrUse = this->SetUseType(UseOp, CODEPTR);
			}
			else { // NUMERIC
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting to NUMERIC\n");
#endif
				CurrUse = this->SetUseType(UseOp, NUMERIC);
			}
		}
		else if (UseOp->IsRegOp()) {
			if (UseOp->MatchesReg(MD_FLAGS_REG)) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting flags reg to NUMERIC\n");
#endif
				CurrUse = this->SetUseType(UseOp, NUMERIC);
			}
			else if (UseOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting program counter reg to CODEPTR\n");
#endif
				CurrUse = this->SetUseType(UseOp, CODEPTR);
			}
#if 1
			else if (MDIsStackOrFramePointerReg(UseOp, UseFP)) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting reg to STACKPTR\n");
#endif
				CurrUse = this->SetUseType(UseOp, STACKPTR);
			}
#endif
		}
#if 0  // could these registers have pointers in them?
		else if (UseOp->IsTestRegOp() || UseOp->IsDebugRegOp() || UseOp->IsControlRegOp()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
			if (DebugFlag) SMP_msg("Setting special reg to NUMERIC\n");
#endif
			CurrUse = this->SetUseType(UseOp, NUMERIC);
		}
#endif
		else if (UseOp->IsFloatingPointRegOp() || UseOp->IsMMXRegOp() || UseOp->IsXMMRegOp() || UseOp->IsYMMRegOp()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
			if (DebugFlag) SMP_msg("Setting floating point reg to NUMERIC\n");
#endif
			CurrUse = this->SetUseType(UseOp, NUMERIC);
		}
		else if (UseOp->IsMemOp()) {
			// For memory operands, we need to identify the POINTER value that
			//  is used in the addressing mode, if possible.
			(void) this->MDFindPointerUse(UseOp, UseFP);
		}
		++CurrUse;
	} // end while all USEs via CurrUse

	CurrDef = this->GetFirstDef();
	while (CurrDef != this->GetLastDef()) {
		DefOp = CurrDef->GetOp();
#if SMP_VERBOSE_DEBUG_BUILD_RTL
		if (DebugFlag) {
			SMP_msg("SetImmedTypes DEF: ");
			PrintOperand(DefOp);
			SMP_msg("\n");
			SMP_msg("FuncName: %s\n", this->BasicBlock->GetFunc()->GetFuncName());
		}
#endif
		if (DefOp->IsRegOp()) {
			if (DefOp->MatchesReg(X86_FLAGS_REG)) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting flags reg DEF to NUMERIC\n");
#endif
				CurrDef = this->SetDefType(DefOp, NUMERIC);
				// No need to propagate this DEF type, as all flags will become NUMERIC.
			}
#if 1
			else if (MDIsStackOrFramePointerReg(DefOp, UseFP)) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (DebugFlag) SMP_msg("Setting reg DEF to STACKPTR\n");
#endif
				CurrDef = this->SetDefType(DefOp, STACKPTR);
				assert(CurrDef != this->Defs.GetLastRef());
				// No need to propagate; all stack and frame pointers will become STACKPTR.
			}
#endif
		}
		else if (DefOp->IsFloatingPointRegOp() || DefOp->IsMMXRegOp() || DefOp->IsXMMRegOp() || DefOp->IsYMMRegOp()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
			if (DebugFlag) SMP_msg("Setting floating point reg DEF to NUMERIC\n");
#endif
			CurrDef = this->SetDefType(DefOp, NUMERIC);
			// No need to propagate; all FP reg uses will become NUMERIC anyway.
		}
#if 0  // could these registers have pointers in them?
		else if (DefOp->IsTestRegOp() || DefOp->IsDebugRegOp() || DefOp->IsControlRegOp()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
			if (DebugFlag) SMP_msg("Setting special reg DEF to NUMERIC\n");
#endif
			CurrDef = this->SetDefType(DefOp, NUMERIC);
		}
#endif	
		else if (DefOp->IsMemOp()) {
			// For memory operands, we need to identify the POINTER value that
			//  is used in the addressing mode, if possible.
			(void) this->MDFindPointerUse(DefOp, UseFP);
		}
		++CurrDef;
	} // end while all DEFs via CurrDef
	return;
} // end of SMPInstr::SetImmedTypes()

// Is the instruction a load from the stack?
void SMPInstr::MDFindLoadFromStack(bool UseFP) {
	set<DefOrUse, LessDefUse>::iterator UseIter;

	if ((3 == this->GetOptType()) && (this->HasSourceMemoryOperand())) {
		// Loads and stores are OptCategory 3. We want only loads from the stack.
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			STARSOpndTypePtr UseOp = UseIter->GetOp();
			if (MDIsStackAccessOpnd(UseOp, UseFP)) {
				this->SetLoadFromStack();
				break;
			}
		}
	}
	return;
} // end of SMPInstr::MDFindLoadFromStack()

// return true if instruction is a system call
bool SMPInstr::MDIsSystemCall(void) {
	unsigned short opcode = this->GetIDAOpcode();
	bool SystemCall = ((STARS_NN_syscall == opcode) || (STARS_NN_sysenter == opcode));
	if (!SystemCall && this->IsInterruptCall()) {
		// If interrupt call is int 0x80 then it is a system call
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		assert(NULL != CurrRT);
		if (!CurrRT->HasRightSubTree()) {
			if (CurrRT->GetConstRightOperandNoNorm()->IsImmedOp()) {
				SystemCall = (0x80 == CurrRT->GetConstRightOperandNoNorm()->GetImmedValue());
			}
		}
	}
	if (SystemCall)
		SMP_msg("INFO: System call found at %llx\n", (unsigned long long) this->GetAddr());
	return SystemCall;
} // end of SMPInstr::MDIsSystemCall()

// Determine if instr is inherently signed load instruction.
//  True if sign or zero-extended; pass out mask bits if true.
bool SMPInstr::MDIsSignedLoad(unsigned short &SignMask) const {
	unsigned short opcode = this->GetIDAOpcode();
	if (STARS_NN_movzx == opcode) {
		SignMask = FG_MASK_UNSIGNED;
	}
	else if ((STARS_NN_movsx == opcode) || (STARS_NN_movsxd == opcode)) {
		SignMask = FG_MASK_SIGNED;
	}
	else {
		return false;
	}
	return true;
}

// e.g. add-with-carry or subtract-with-borrow
bool SMPInstr::MDIsArithmeticUsingCarryFlag(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((opcode == STARS_NN_adc) || (opcode == STARS_NN_sbb));
}

// true if increment or addition of small positive immediate value
#define STARS_SMALL_POS_VALUE_LIMIT 255
bool SMPInstr::MDIsSmallPositiveAddition(void) {
	unsigned short opcode = this->GetIDAOpcode();
	bool found = (STARS_NN_inc == opcode);
	STARS_uval_t ImmVal;

	if (!found && ((STARS_NN_add == opcode) || (STARS_NN_adc == opcode))) {
		set<DefOrUse, LessDefUse>::iterator UseIter;
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			STARSOpndTypePtr UseOp = UseIter->GetOp();
			if (UseOp->IsImmedOp()) {
				ImmVal = UseOp->GetImmedValue();
				if ((ImmVal <= STARS_SMALL_POS_VALUE_LIMIT) && (0 < ImmVal)) {
					found = true;
					break;
				}
			}
		}
	}
	else if (this->MDIsLoadEffectiveAddressInstr()) {
		// See if we have the form: lea reg1,[reg2+const]
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		if (CurrRT->HasRightSubTree()) {
			CurrRT = CurrRT->GetRightTree();
			SMPoperator CurrOp = CurrRT->GetOperator();
			if ((SMP_ADD == CurrOp) && (!CurrRT->HasRightSubTree())) {
				STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
				if (RightOp->IsImmedOp()) {
					ImmVal = RightOp->GetImmedValue();
					if ((ImmVal <= STARS_SMALL_POS_VALUE_LIMIT) && (0 < ImmVal)) {
						found = true;
					}
				}
			}
		}
	}

	return found;
} // end of SMPInstr::MDIsSmallPositiveAddition()

// true if increment, decrement, or addition or subtraction of small immediate value
bool SMPInstr::MDIsSmallAdditionOrSubtraction(void) {
	unsigned short opcode = this->GetIDAOpcode();
	bool found = ((STARS_NN_inc == opcode) || (STARS_NN_dec == opcode));

	if ((STARS_NN_add == opcode) || (STARS_NN_adc == opcode) || (STARS_NN_sub == opcode) || (STARS_NN_sbb == opcode)) {
		set<DefOrUse, LessDefUse>::iterator UseIter;
		for (UseIter = this->GetFirstUse(); !found && (UseIter != this->GetLastUse()); ++UseIter) {
			STARSOpndTypePtr UseOp = UseIter->GetOp();
			if (UseOp->IsImmedOp()) {
				STARS_uval_t ImmVal = UseOp->GetImmedValue();
				int SignedImmVal = (int) ImmVal;
				found = ((SignedImmVal >= (-STARS_SMALL_POS_VALUE_LIMIT)) && (SignedImmVal <= STARS_SMALL_POS_VALUE_LIMIT));
			}
		}
	}

	return found;
} // end of SMPInstr::MDIsSmallAdditionOrSubtraction()

// Inst is move or register clear.
bool SMPInstr::MDIsSimpleAssignment(bool &ValueFound, STARS_uval_t &ConstValue) {
	bool Simple = false;
	ValueFound = false;

	if (this->IsRegClearIdiom()) {
		Simple = true;
		ValueFound = true;
		ConstValue = 0;
	}
	else if (this->MDIsMoveInstr()) {
		Simple = true;
		if (this->GetMoveSource()->IsImmedOp()) {
			ValueFound = true;
			ConstValue = this->GetMoveSource()->GetImmedValue();
		}
	}

	return Simple;
} // end of SMPInstr::MDIsSimpleAssignment()

// RTL is just x := y;
bool SMPInstr::IsSimpleCopy(STARSOpndTypePtr &rhs) const {
	bool SimpleCopyRTL = false;
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	if ((NULL != CurrRT) && (this->RTL.GetCount() == 1) && (NULL == CurrRT->GetGuard())) { // skip conditional moves
		bool Simple = ((!CurrRT->HasRightSubTree()) || this->IsRegUpperBitsClearIdiom());
		if (Simple && (SMP_ASSIGN == CurrRT->GetOperator())) {
			SimpleCopyRTL = (DEFAULT == this->GetDataFlowType());
			if (SimpleCopyRTL) {
				if (this->IsRegUpperBitsClearIdiom()) {
					rhs = this->GetFirstRightOperandNoNorm();
					if (this->AreDefsNormalized() && MDIsStackAccessOpnd(rhs, this->GetBlock()->GetFunc()->UsesFramePointer())) {
						rhs = this->GetBlock()->GetFunc()->GetNormalizedOperand(this->GetAddr(), rhs);
					}
				}
				else {
					rhs = CurrRT->GetRightOperand();
				}
			}
		}
	}

	return SimpleCopyRTL;
} // SMPInstr::IsSimpleCopy()

// RTL is just x := y; don't normalize rhs operand
bool SMPInstr::IsSimpleCopyNoNorm(STARSOpndTypePtr &rhs) const {
	bool SimpleCopyRTL = false;
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	if ((NULL != CurrRT) && (this->RTL.GetCount() == 1) && (NULL == CurrRT->GetGuard())) { // skip conditional moves
		if (!CurrRT->HasRightSubTree() && (SMP_ASSIGN == CurrRT->GetOperator())) {
			SimpleCopyRTL = (DEFAULT == this->GetDataFlowType());
			if (SimpleCopyRTL)
				rhs = CurrRT->GetRightOperandNoNorm();
		}
	}

	return SimpleCopyRTL;
} // SMPInstr::IsSimpleCopyNoNorm()

// Inst clears register or adds or subtracts small immediate value, as is done with counter variables.
bool SMPInstr::IsCounterOperation(void) {
	bool CounterOperation = false;
	if (this->IsAnalyzeable()) {
		bool ImmedValueFound = false;
		STARS_uval_t ConstValue = 1;
		if (this->MDIsSimpleAssignment(ImmedValueFound, ConstValue)) {
			CounterOperation = (ImmedValueFound && (0 == ConstValue));
		}
		else {
			CounterOperation = this->MDIsSmallAdditionOrSubtraction();
		}
	}

	return CounterOperation;
} // end of SMPInstr::IsCounterOperation()

// Inst does an AND, OR, XOR operation; does not do add, subtract, etc.
bool SMPInstr::MDIsNonOverflowingBitManipulation(void) const {
	unsigned short opcode = this->GetIDAOpcode();
	return ((STARS_NN_and == opcode) || (STARS_NN_not == opcode) || (STARS_NN_or == opcode) || (STARS_NN_shl == opcode)
		|| ((STARS_NN_xor == opcode) && !this->IsRegClearIdiom()));
} // end of SMPInstr::MDIsNonOverflowingBitManipulation()

// return true if traced USE to a constant value
bool SMPInstr::FindConstantValue(set<DefOrUse, LessDefUse>::iterator UseIter, STARS_uval_t &ConstValue) {
	bool FoundConst = false;
	assert(UseIter != this->GetLastUse());
	STARSOpndTypePtr UseOp = UseIter->GetOp();
	if (UseOp->IsImmedOp()) {
		ConstValue = UseOp->GetImmedValue();
		FoundConst = true;
	}
	else {
		bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
		if (MDIsDataFlowOpnd(UseOp, UseFP)) {
			// We can trace registers and stack locations through SSA chains, if the stack location is directly accessed.
			int UseSSANum = UseIter->GetSSANum();
			bool LocalName = this->GetBlock()->IsLocalName(UseOp);
			STARS_ea_t UseAddr = this->GetAddr();
			STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
			if (STARS_IsBlockNumPseudoID(UseDefAddr)) {
				// 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 a single 
				//  constant value, but this is highly unlikely. Terminate search.
				;
			}
			else if (STARS_IsLiveInPseudoID(UseDefAddr) || (STARS_BADADDR == UseDefAddr)) {
				// The DEF is in a Phi function in the current block, or is STARS_BADADDR. Terminate search.
				;
			}
			else {
				SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr);
				bool ValueFound = false;
				if (DefInst->MDIsSimpleAssignment(ValueFound, ConstValue)) {
					if (ValueFound) {
						FoundConst = true; // ConstValue holds the value that was found.
					}
					else {
						set<DefOrUse, LessDefUse>::iterator NewUseIter = DefInst->GetFirstUse();
						// A simple assignment should have only one USE. Recurse on that USE.
						FoundConst = DefInst->FindConstantValue(NewUseIter, ConstValue);
					}
				}
			}
		}
	}

	return FoundConst;
} // end of SMPInstr::FindConstantValue()


// Infer sign, bit width, other type info for simple cases where all the info needed is
//  within the instruction or can be read from the FineGrainedStackTable in the SMPFunction.
// NOTE: Must be called after SSA analysis is complete.
void SMPInstr::MDSetWidthSignInfo(bool UseFP) {
	if (! this->IsAnalyzeable())
		return;

	set<DefOrUse, LessDefUse>::iterator UseIter;
	set<DefOrUse, LessDefUse>::iterator DefIter;
	STARSOpndTypePtr UseOp = nullptr, DefOp = nullptr;
	struct FineGrainedInfo FGEntry;
	unsigned short SignMask=0, TempSign=0, WidthMask=0;
	int DefHashValue=0, UseHashValue=0;
	STARS_ea_t DefAddr=0;  // for flags USE in conditional set
	int SSANum=0;    // for flags USE in conditional set
	bool LocalFlags=0;  // is flags register a local name?
	bool case1=0, case2=0, case3=0, case4=0, case5=0, case6=0, case7=0, case8=0;
	bool SignedSetOpcode = this->MDIsSignedSetValue();
	bool UnsignedSetOpcode = this->MDIsUnsignedSetValue();

	case1 = this->IsLoadFromStack();
	case2 = this->MDIsSignedLoad(SignMask); // sets value of SignMask if it returns true
	case3 = (7 == this->GetOptType());  // Multiplies and divides
	case4 = ((CALL == this->GetDataFlowType()) || (INDIR_CALL == this->GetDataFlowType()));
	case5 = (SignedSetOpcode || UnsignedSetOpcode); // set boolean based on flag condition
	case6 = this->MDDoublesWidth(); // convert byte to word, word to dword, etc.
	case7 = this->MDAlwaysUnsignedDEF();
	case8 = this->MDAlwaysSignedDEF();

	// Case 1: Load from stack location.
	if (case1) {
		bool success = false;
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			UseOp = UseIter->GetOp();
			if (MDIsStackAccessOpnd(UseOp, UseFP)) {
				// Found the stack location being loaded into a register. Now we need
				//  to get the sign and width info from the fine grained stack frame
				//  analysis.
				success = this->GetBlock()->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), UseOp, FGEntry);
				assert(success);
				// Now we have signedness info in FGEntry. We need to OR it into the register target of the load.
				if (FGEntry.SignMiscInfo == 0) 
					break; // nothing to OR in; save time
				for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
					DefOp = DefIter->GetOp();
					if (DefOp->IsRegOp()) {
						TempSign = FGEntry.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS; // Get both sign bit flags
						DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
						if (this->BasicBlock->IsLocalName(DefOp)) {
							this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, TempSign);
						}
						else {
							this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, TempSign);
						}
						break;  // Should be only one register target for stack load, and no flags are set.
					}
				}
				break; // Only concerned with the stack operand
			}
		}
		assert(success);
	} // end if this->IsLoadFromStack()

	// Case 2: Loads that are sign-extended or zero-extended imply signed and unsigned, respectively.
	//  NOTE: If from the stack, they were handled in Case 1, and the signedness of the stack location
	//  was recorded a long time ago in SMPFunction::FindOutgoingArgsSize();
	else if (case2) {
		DefIter = this->GetFirstDef();
		while (DefIter != this->GetLastDef()) {
			// All non-memory DEFs besides the flags register should get the new SignMask ORed in.
			// On x86, there should only be one DEF for this move, and no flags, but we will generalize
			//  in case other architectures are odd.
			DefOp = DefIter->GetOp();
			if (!(IsMemOperand(DefOp) || MDIsFlagsReg(DefOp))) {
				DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
				if (this->BasicBlock->IsLocalName(DefOp)) {
					this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, SignMask);
				}
				else {
					this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask);
				}
			}
			++DefIter;
		}

		// If the signed load is from memory, the only USEs are the memory
		//  operand and addressing registers. We do not want to claim that
		//  EBX is signed in the instruction movsx eax,[ebx]. Only the DEF
		//  register EAX and the memory location [EBX] are signed, and we
		//  have no idea where [EBX] is, so we punt on all USEs if we have
		//  a memory source operand.
		if (!(this->HasSourceMemoryOperand())) {
			UseIter = this->GetFirstUse();
			while (UseIter != this->GetLastUse()) {
				// All non-memory USEs besides the flags register should get the new SignMask ORed in.
				UseOp = UseIter->GetOp();
				if (!(IsMemOperand(UseOp) || MDIsFlagsReg(UseOp))) {
					UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum());
					if (this->BasicBlock->IsLocalName(UseOp)) {
						this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, SignMask);
					}
					else {
						this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask);
					}
				}
				++UseIter;
			}
		}
	} // end of case 2

	// Case 3: multiplies and divides can be signed or unsigned.
	else if (case3) { // Multiplies and divides are type 7.
		if (this->MDIsSignedArithmetic()) {
			SignMask = FG_MASK_SIGNED;
		}
		else if (this->MDIsUnsignedArithmetic()) {
			SignMask = FG_MASK_UNSIGNED;
		}
		else {
			SignMask = 0; // unknown, uninitialized
		}
		if (0 != SignMask) {
			DefIter = this->GetFirstDef();
			while (DefIter != this->GetLastDef()) {
				// All DEFs besides the flags register should get the new SignMask ORed in.
				DefOp = DefIter->GetOp();
				if ((DefOp->IsRegOp()) && (!(DefOp->MatchesReg(X86_FLAGS_REG)))) {
					DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
					if (this->BasicBlock->IsLocalName(DefOp)) {
						this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, SignMask);
					}
					else {
						this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask);
					}
				}
				++DefIter;
			}

			UseIter = this->GetFirstUse();
			while (UseIter != this->GetLastUse()) {
				// All USEs besides the flags register should get the new SignMask ORed in.
				UseOp = UseIter->GetOp();
				if ((UseOp->IsRegOp()) && (!(UseOp->MatchesReg(X86_FLAGS_REG)))) {
					UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum());
					if (this->BasicBlock->IsLocalName(UseOp)) {
						this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, SignMask);
					}
					else {
						this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask);
					}
				}
				++UseIter;
			}
		} // end if (0 != SignMask)
	} // end of case 3 (multiplies and divides)

	// Case 4: Calls to library functions can reveal the type of the return register.
	else if (case4) {
		STARS_ea_t InstAddr = this->GetAddr();

		// Get name of function called.
		string FuncName = this->GetTrimmedCalledFunctionName();

		// See if we are throwing an exception.
		if (0 == strcmp("cxa_throw", FuncName.c_str()) && (NULL != this->GetBlock())) {
			this->GetBlock()->GetFunc()->GetProg()->SetProgramThrowsExceptions();
		}

		// Get FG info, if any, for the return value of the called function.
		GetLibFuncFGInfo(FuncName, FGEntry);

		// See if anything was returned in FGEntry.
		if ((FGEntry.SignMiscInfo != 0) || (FGEntry.SizeInfo != 0)) {
			// Need to update the FG info for the DEF of the return register.
			//  Also can infer POINTER or NUMERIC and propagate.
			DefOp = this->STARSInstPtr->MakeRegOpnd(MD_RETURN_VALUE_REG);
			DefIter = this->FindDef(DefOp);
			assert(DefIter != this->GetLastDef());
			int DefSSANum = DefIter->GetSSANum();
			DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum);
			SMPOperandType DefType = DefIter->GetType();
			SMPOperandType NewDefType = UNINIT;
			if (FGEntry.SizeInfo & FG_MASK_INTEGER) {
				NewDefType = NUMERIC;
			}
			else if (FGEntry.SizeInfo & FG_MASK_DATAPOINTER) {
				NewDefType = POINTER;
			}
			bool TypeErrorFlag = false;
			NewDefType = SMPTypeMeet(DefType, NewDefType, TypeErrorFlag);
			if (TypeErrorFlag) {
				SMP_msg("ERROR: TypeMeet error in MDSetWidthSignInfo() at %llx\n",
					(uint64_t) this->GetAddr());
			}
			bool UpdateType = ((NewDefType != DefType) && (DefType == UNINIT));
			if (UpdateType) {
				DefIter = this->SetDefType(DefOp, NewDefType);
			}
			if (this->BasicBlock->IsLocalName(DefOp)) {
				this->BasicBlock->UpdateDefFGInfo(DefHashValue, FGEntry);
				if (UpdateType) {
					this->GetBlock()->PropagateLocalDefType(DefOp, NewDefType, InstAddr, DefSSANum, false, false);
				}
			}
			else {
				this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, FGEntry);
				if (UpdateType) {
					this->GetBlock()->GetFunc()->ResetProcessedBlocks();
					this->GetBlock()->PropagateGlobalDefType(DefOp, NewDefType, DefSSANum, false, false);
				}
			}
		}

		// See if we make a call to a library function that needs signedness checks on
		//  unsigned incoming args.
		unsigned int ArgPosBits = 0;
		GetUnsignedArgPositionsForCallName(FuncName, ArgPosBits);
		if (0 < ArgPosBits) {
			// Mark our basic block as containing this type of call, so signedness checks
			//  can be done later.
			this->GetBlock()->SetCallsUnsignedArgFunc();
			bool IsMallocCall = (0 == FuncName.compare("malloc"));
			// Find the argument assignments and mark them, to trigger later signedness checks.
			this->GetBlock()->MarkUnsignedArgs(InstAddr, ArgPosBits, IsMallocCall);
		}

		// See if we make a call to a library function that has POINTER args.
		ArgPosBits = 0;
		GetPointerArgPositionsForCallName(FuncName, ArgPosBits);
		if (0 < ArgPosBits) {
			bool IsBufferLibFunc = IsBufferArgFuncName(FuncName);
			// Find the argument assignments and mark them, to trigger later signedness checks.
			this->GetBlock()->MarkPointerArgs(InstAddr, ArgPosBits, IsBufferLibFunc);
		}

	} // end of case4 (function calls)
	else if (case5) { // signed or unsigned conditional set opcode
		if (UnsignedSetOpcode) {
			SignMask = FG_MASK_UNSIGNED;
		}
		else {
			assert(SignedSetOpcode);
			SignMask = FG_MASK_SIGNED;
		}
		// Find the flags USE.
		UseOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); // set up a dummy op for searching
		UseIter = this->FindUse(UseOp);
		assert(UseIter != this->GetLastUse());
		UseOp = UseIter->GetOp(); // get full info in all fields of UseOp
		SSANum = UseIter->GetSSANum();
		LocalFlags = this->GetBlock()->IsLocalName(UseOp);

		DefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, this->GetAddr(), SSANum, LocalFlags);
		// Pass DefAddr to recursive helper function to propagate signedness of the set opcode.
		this->GetBlock()->PropagateBranchSignedness(DefAddr, UseOp, SignMask);
	}
	else if (case6) { // sign extend to double the width of USE operand into DEF operand
		DefIter = this->GetFirstNonFlagsDef();
		assert(DefIter != this->GetLastDef());
		DefOp = DefIter->GetOp();
		assert(DefOp->IsRegOp());
		SSANum = DefIter->GetSSANum();
		DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum);
		UseIter = this->GetFirstUse();
		assert(UseIter != this->GetLastUse());
		UseOp = UseIter->GetOp();
		assert(UseOp->IsRegOp());
		assert(UseOp->GetReg() == DefOp->GetReg());
		UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum()); 
		SignMask = FG_MASK_SIGNED;  // opcodes do sign extension => signed
		// Mark DEF and USE as signed.
		if (this->GetBlock()->IsLocalName(DefOp)) {
			this->GetBlock()->UpdateDefSignMiscInfo(DefHashValue, SignMask);
			this->GetBlock()->UpdateUseSignMiscInfo(UseHashValue, SignMask);
		}
		else {
			this->GetBlock()->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask);
			this->GetBlock()->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask);
		}
	}
	else if (case7 || case8) { // always unsigned DEF or always signed DEF.
		DefIter = this->GetFirstNonFlagsDef();
		if (DefIter != this->GetLastDef()) {
			DefOp = DefIter->GetOp();
			if (DefOp->IsRegOp()) {
				SSANum = DefIter->GetSSANum();
				DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum);
				if (case7)
					SignMask = FG_MASK_UNSIGNED;
				else
					SignMask = FG_MASK_SIGNED;
				// Mark DEF as signed or unsigned.
				if (this->GetBlock()->IsLocalName(DefOp)) {
					this->GetBlock()->UpdateDefSignMiscInfo(DefHashValue, SignMask);
				}
				else {
					this->GetBlock()->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask);
				}
			}
		}
	}

	// For all register DEFs and USEs, we should get the obvious register width info
	//  updated. Need to use the RTL operands to get accurate widths.
	SMPRegTransfer *CurrRT;
	for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) {
		CurrRT = this->RTL.GetRT(index);
		STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
		if ((nullptr != LeftOp) && (!case2))
			DefOp = CloneIfSubwordReg(LeftOp);
		else
			DefOp = nullptr;
		// Avoid setting def width for case 2; we leave it as zero so that
		//  later uses can determine whether the zero-extension or sign-extension
		//  bits ever got used. See more discussion in EmitIntegerErrorAnnotations()
		//  for the CHECK TRUNCATION case.
		// NOTE: case2 can be set to true even in the case1/case2 overlap case that
		//  only passes through the case1 code above. This is intentional. We want
		//  to leave the DEF width set to 0 for all of case2 including the case1 overlap.
		if (!case2) {
			if (MDIsGeneralPurposeReg(DefOp)) {
				WidthMask = ComputeOperandBitWidthMask(DefOp, 0);
				CanonicalizeOpnd(DefOp);
				DefIter = this->FindDef(DefOp);
				assert(DefIter != this->GetLastDef());
				DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
				if (this->BasicBlock->IsLocalName(DefOp)) {
					this->BasicBlock->UpdateDefWidthTypeInfo(DefHashValue, WidthMask);
				}
				else {
					this->BasicBlock->GetFunc()->UpdateDefWidthTypeInfo(DefHashValue, WidthMask);
				}
			}
		}
		if (CurrRT->HasRightSubTree()) {
			this->MDSetRTLRegWidthInfo(CurrRT->GetRightTree());
		}
		else {
			UseOp = CurrRT->GetRightOperand();
			this->SetRTLUseOpRegWidthInfo(UseOp);
		}
	}  // end for all RTLs 

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

// Infer sign from the SMP types for USEs and DEFs.
void SMPInstr::InferSignednessFromSMPTypes(bool UseFP) {
	// Start with registers only, infer that all kids of pointers are UNSIGNED.
	set<DefOrUse, LessDefUse>::iterator DefIter, UseIter;
	int SSANum;
	int DefHashValue, UseHashValue;
	SMPOperandType DefType, UseType;
	unsigned short DefSignMiscInfo = FG_MASK_UNSIGNED, UseSignMiscInfo = FG_MASK_UNSIGNED;
	bool GlobalName;

	for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
		STARSOpndTypePtr DefOp = DefIter->GetOp();
		if (MDIsGeneralPurposeReg(DefOp)) {
			DefType = DefIter->GetType();
			if (IsDataPtr(DefType) || (CODEPTR == DefType)) {
				GlobalName = this->BasicBlock->GetFunc()->IsGlobalName(DefOp);
				SSANum = DefIter->GetSSANum();
				DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum);
				if (GlobalName) {
					this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, DefSignMiscInfo);
				}
				else {
					this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, DefSignMiscInfo);
				}
			}
		}
	}

	for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
		STARSOpndTypePtr UseOp = UseIter->GetOp();
		if (MDIsGeneralPurposeReg(UseOp)) {
			UseType = UseIter->GetType();
			if (IsDataPtr(UseType) || (CODEPTR == UseType)) {
				GlobalName = this->BasicBlock->GetFunc()->IsGlobalName(UseOp);
				SSANum = UseIter->GetSSANum();
				UseHashValue = HashGlobalNameAndSSA(UseOp, SSANum);
				if (GlobalName) {
					this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, UseSignMiscInfo);
				}
				else {
					this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, UseSignMiscInfo);
				}
			}
		}
	}

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


// Helper to set width info for a UseOp from an RTL
void SMPInstr::SetRTLUseOpRegWidthInfo(const STARSOpndTypePtr &UseOp) {
	unsigned short WidthMask;
	set<DefOrUse, LessDefUse>::iterator UseIter;
	unsigned int UseHashValue;

	if (MDIsGeneralPurposeReg(UseOp)) {
		WidthMask = ComputeOperandBitWidthMask(UseOp, 0);
		STARSOpndTypePtr UseOpClone = CloneIfSubwordReg(UseOp);
		CanonicalizeOpnd(UseOpClone);
		UseIter = this->FindUse(UseOpClone);
		assert(UseIter != this->GetLastUse());
		UseHashValue = HashGlobalNameAndSSA(UseOpClone, UseIter->GetSSANum());
		if (this->BasicBlock->IsLocalName(UseOpClone)) {
			this->BasicBlock->UpdateUseWidthTypeInfo(UseHashValue, WidthMask);
		}
		else {
			this->BasicBlock->GetFunc()->UpdateUseWidthTypeInfo(UseHashValue, WidthMask);
		}
	}

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

// Walk the RTL and update the register USE operands' width info.
void SMPInstr::MDSetRTLRegWidthInfo(SMPRegTransfer *CurrRT) {
	STARSOpndTypePtr UseOp = CurrRT->GetLeftOperand();
	this->SetRTLUseOpRegWidthInfo(UseOp);
	if (CurrRT->HasRightSubTree()) {
		this->MDSetRTLRegWidthInfo(CurrRT->GetRightTree());
	}
	else {
		UseOp = CurrRT->GetRightOperand();
		this->SetRTLUseOpRegWidthInfo(UseOp);
	}

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

// Do we not consider truncation on this type of instruction to be an error?
bool SMPInstr::IsBenignTruncation(int &IdiomCode) {
	bool benign = false;
	unsigned short SignMask;
	STARSOpndTypePtr UseOp = nullptr, SearchOp = nullptr;

	if (3 == this->GetOptType()) { // Move instruction
		bool ExtendedLoad = this->MDIsSignedLoad(SignMask);
		if (ExtendedLoad && (SignMask & FG_MASK_UNSIGNED)) {
			// We have a zero-extended load. Compilers zero-extend both
			//  signed (unfortunately) and unsigned sub-regs when they know
			//  from the source language types that only the lower bits matter,
			//  e.g. when a char has been stored in the lower bits and regardless
			//  of whether that char was sign-extended or zero-extended previously,
			//  only the char itself is useful info. Otherwise, the compiler could
			//  move the whole register, e.g. instead of edi := zero-extend(cx), the
			//  compiler could have generated edi := ecx. The zero-extension loads
			//  are therefore not good candidates for truncation checks, as they lead
			//  to lots of false positives.
			benign = true;
			IdiomCode = 5;
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			++BenignTruncationCount;
#endif
		}
		else { // Move, and not extended load, which was handled above.
			// Next case: A move instruction whose USE falsely appears to be a truncation,
			//  but in fact the apparently unused portion of the register is used later, e.g.:
			//   mov [ebp-12],ax  ; looks like EAX is being truncated to AX and stored
			//   shr eax,16       ; gets upper 16 bits into lower 16 bits
			//   mov [ebp-14],ax  ; store what used to be the upper 16 bits of EAX
			// The first instruction will trigger a CHECK TRUNCATION annotation that
			//  causes false positives. We need to analyze the context of the instruction
			//  to see that the whole register EAX was used, so no truncation occurred.
			//  The context analysis in the basic block will mark the second move as
			//  a "truncation" that should be ignored, so we check the flag here to short
			//  circuit redundant analysis.
			UseOp = CloneIfSubwordReg(this->GetMoveSource());
			assert((nullptr != UseOp) && (!UseOp->IsVoidOp()));
			SearchOp = UseOp;
			if (UseOp->IsRegOp()) {
				CanonicalizeOpnd(SearchOp);
			}
			set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
			assert(UseIter != this->GetLastUse());
			SMPOperandType UseType = UseIter->GetType();
			if (UseIter->DoesNotTruncate()) {
				benign = true;
				IdiomCode = 2;
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
				++SuppressTruncationRegPiecesAllUsed;
#endif
			}
			else if (IsDataPtr(UseType)) {
				benign = true;
				IdiomCode = 30;
			}
			else {
				set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef();
				assert(DefIter != this->GetLastDef());
				int DefSSANum = DefIter->GetSSANum();
				SMPOperandType DefType = DefIter->GetType();
				if (IsDataPtr(DefType)) {
					benign = true;
					IdiomCode = 30;
				}
				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,
					//  not an actual truncation.
					int UseSSANum = UseIter->GetSSANum();
					// Prepare for possible recursive traversals through the function blocks.
					this->GetBlock()->GetFunc()->ResetProcessedBlocks();
					if (this->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(SearchOp, UseSSANum, true)) {
						IdiomCode = 14;
						benign = true;
					}
				}
				if (!benign) {
					// Fourth case: bits within a byte are copied and shifted (some left, some right) and written
					//  out to different byte addresses. The left and right shifts of two copies of the same byte
					//  are the kind of bit-twiddling done when disassembling some network packets.
					int UseSSANum = UseIter->GetSSANum();
					// Prepare for possible recursive traversals through the function blocks.
					this->GetBlock()->GetFunc()->ResetProcessedBlocks();
					STARS_ea_t ShiftInstAddr;
					STARSOpndTypePtr ShiftedOperand;
					STARSOpndTypePtr ShiftCounterOperand;
					if (this->IsOpSourceLeftShift(SearchOp, UseSSANum, ShiftCounterOperand, ShiftedOperand, ShiftInstAddr)) {
						if (ShiftCounterOperand->IsImmedOp() && (8 > ShiftCounterOperand->GetImmedValue())) {
							SMPInstr *ShiftInst = this->GetBlock()->GetFunc()->GetInstFromAddr(ShiftInstAddr);
							if (ShiftInst->GetBlock()->IsUseCopiedAndShiftedRight(ShiftedOperand, ShiftInstAddr)) {
								IdiomCode = 25;
								benign = true;
							}
						}
					}
				}
			}
		}
	}
	return benign;
} // end of SMPInstr::IsBenignTruncation()

// Do we not consider overflow or underflow on this type of instruction to be an error?
bool SMPInstr::IsBenignOverflow(int &IdiomCode) {
	bool benign = false;
	set<DefOrUse, LessDefUse>::iterator DefIter, UseIter;
	SMPOperandType DefType, UseType;
	int DefSSANum;
	STARS_ea_t DefAddr;
	STARSOpndTypePtr DefOp = nullptr;

	if (this->MDIsDefiniteBenignUnderflowOpcode(IdiomCode)) {
		// No further analysis at block or function scope is needed.
		benign = true;
	}
	else if (this->MDIsMaybeBenignUnderflowOpcode()) { // might have the subtract instruction in tricky sequence
		// We are looking to suppress overflow and underflow warnings on the following
		//  code sequence: PTR1-PTR2+1 gets a loop invariant code motion optimization
		//  that pulls  temp := 1-PTR2 out of the loop, and leaves temp2 := PTR1+temp
		//  inside the loop. The hoisted subtraction could underflow, and the addition
		//  that is not hoisted could overflow. The net effect of these two instructions
		//  is benign, however, so we want to suppress underflow and overflow checks on
		//  both of them, but only if we can match the pair of instructions.
		DefIter = this->GetFirstNonFlagsDef();
		assert(DefIter != this->GetLastDef());
		if (DefIter->DoesNotOverflow()) {
			benign = true; // short circuit; already analyzed
		}
		else {
			DefType = DefIter->GetType();
			if (IsEqType(DefType, NEGATEDPTR)) { // We have candidate subtract instruction
				DefOp = DefIter->GetOp();
				DefSSANum = DefIter->GetSSANum();
				DefAddr = this->GetAddr();
				benign = this->GetBlock()->GetFunc()->IsBenignUnderflowDEF(DefOp, DefSSANum, DefAddr, IdiomCode);
				if (!benign) {
					// If we did not find the complicated sequence, we still don't want to have a false positive
					//  on any instruction that is producing a NEGATEDPTR.
					benign = true;
					IdiomCode = 13;
				}
			}
		}
	}
	else if (this->MDIsMaybeBenignOverflowOpcode()) { // might have the add instruction in tricky sequence
		DefIter = this->GetFirstNonFlagsDef();
		assert(DefIter != this->GetLastDef());
		if (DefIter->DoesNotOverflow()) {
			benign = true; // short circuit; already analyzed
			IdiomCode = 6;
		}
		else { // Bad luck to encounter addition first. See what types tell us.
			if (this->HasNegatedPtrUSE()) { // We have candidate for addition.
				DefType = DefIter->GetType();
				if (IsEqType(DefType, PTROFFSET)) {
					// Current instruction is definitely the addition instruction of some
					//  benignly underflowing and overflowing pair of instructions. It does
					//  not really matter that we have not found the subtraction yet; we will
					//  get to it eventually. We should suppress overflow checks on this inst.
					DefOp = DefIter->GetOp();
					DefIter = this->Defs.SetNoOverflow(DefOp, true);
					benign = true;
					IdiomCode = 6;
				}
				else {
					// A bit of a quandary. Ideally, we would have successful SMP type inference
					//  and always have PTROFFSET := POINTER + NEGATEDPTR. However, sometimes we
					//  might have ?? := ?? + NEGATEDPTR. The instruction could be of the type
					//  NEGATEDPTR := NUMERIC + NEGATEDPTR, so we cannot just assume here that 
					//  we have detected the benign case. However, these instructions are likely
					//  to cause false positives and unlikely to be a source of false negatives,
					//  so we will err on the side of false positive suppression based on experience
					//  (even though we usually do the opposite).
					benign = true;
					IdiomCode = 13;
				}
			}
		}
	}

	if (!benign) {
		// Any overflow or underflow producing a PTROFFSET type should be suppressed.
		for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
			DefType = DefIter->GetType();
			if (IsEqType(DefType, PTROFFSET)) {
				benign = true;
				IdiomCode = 19;
			}
		}
	}
	if (!benign) {
		// Any overflow or underflow using a PTROFFSET type should be suppressed.
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			UseType = UseIter->GetType();
			if (IsEqType(UseType, PTROFFSET)) {
				benign = true;
				IdiomCode = 19;
			}
		}
	}

	return benign;
} // end of SMPInstr::IsBenignOverflow()

// Do we detect a situation in which it is safe to check for signedness errors on
//  the stack write (return false), or not (return true to be safe).
bool SMPInstr::SkipSignednessCheckOnStackWrite(int DefSSANum, bool SourceIsSigned) {
	bool SkipCheck = (!(this->IsUnsignedArg()));
	STARSOpndTypePtr StackDefOp = this->DEFMemOp;
	std::size_t DefBitWidth = 8 * StackDefOp->GetByteWidth();
	if (DefBitWidth < MD_NORMAL_MACHINE_BITWIDTH) {
		// If we are not dealing with a shortened bit width, then
		//  the next load from the stack will not be sign-extended
		//  or zero-extended.
		if (this->GetBlock()->IsStackOpNextUsedWithSignedness(StackDefOp, this->GetAddr(), DefSSANum)) {
			SkipCheck = false;
		}
	}
	if (SkipCheck) {
		this->GetBlock()->GetFunc()->ResetProcessedBlocks();
		bool Signed;
		if (this->GetBlock()->IsDefUsedInLoopCompareAndBranch(this->GetAddr(), StackDefOp, DefSSANum, Signed)) {
			if (Signed != SourceIsSigned) { // signedness of source copied into StackDefOp is not the same as branch signedness
				SkipCheck = false;
			}
		}
	}
	return SkipCheck;
} // end of SMPInstr::SkipSignednessCheckOnStackWrite()

// Does inst pass an outgoing argument? If so, pass back argument position #, starting at zero for [esp], 1 for [esp+4], etc.
bool SMPInstr::MDIsArgumentPass(std::size_t &ArgumentNumber) {
	bool OutArgPass = false;
	//  NOTE: More precise would be to guarantee that the DEF reaches the next call inst.  !!!!****!!!!

	if (!STARS_IsSSAMarkerPseudoID(this->GetAddr())) {
		if (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64) {
			// x86-64 passes the first six arguments in registers EDI, ESI, EDX, ECX, R8 and R9, in that order.
			set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef();
			if (DefIter != this->GetLastDef()) {
				STARSOpndTypePtr DefOp = DefIter->GetOp();
				if (DefOp->IsRegOp()) {
					STARS_regnum_t RegNum = DefOp->GetReg();
					std::size_t ArgIndex = 0;
					if (global_STARS_program->GetArgRegPosition(RegNum, ArgIndex)) {
						OutArgPass = true;
						ArgumentNumber = ArgIndex;
					}
				}
			}
		}
		else { // 32 bits
			// Current model is writing outargs to stack. For other compiler targets in the
			//  future, we would also include pushes onto the stack.
			if (this->HasDestMemoryOperand() && (this->GetOptType() == 3)) { // move to memory
				if (this->GetBlock()->GetFunc()->OutArgsRegionComputed()) {
					STARSOpndTypePtr DefOp = this->DEFMemOp;
					OutArgPass = this->GetBlock()->GetFunc()->IsInOutgoingArgsRegion(DefOp);
					if (OutArgPass) {
						STARSOpndTypePtr UnnormalizedDefOp = CloneIfNecessary(DefOp, this->GetBlock()->GetFunc()->UsesFramePointer());
						this->MDGetUnnormalizedOp(UnnormalizedDefOp);
						std::size_t StandardByteSize = (MD_NORMAL_MACHINE_BITWIDTH / 8);
						ArgumentNumber = (UnnormalizedDefOp->GetAddr() / StandardByteSize);
					}
				}
			}
		}
	}
	return OutArgPass;
} // end of SMPInstr::MDIsArgumentPass()

// Get comparison expr; valid only for signed or unsigned comparison insts
void SMPInstr::GetCompareOrTestExpr(struct LoopComparison &LoopExpr) {
	assert(this->MDIsCompareOrTest());
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	assert(CurrRT->HasRightSubTree());
	CurrRT = CurrRT->GetRightTree();
	LoopExpr.CompareOperator = CurrRT->GetOperator();
	STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand();
	if (LeftOp->IsImmedOp()) {
		DefOrUse LeftImmedUse(LeftOp);
		LoopExpr.Operand1 = LeftImmedUse;
	}
	else {
		STARSDefUseIter LeftUseIter = this->FindUse(LeftOp);
		if (LeftUseIter == this->GetLastUse()) { // Not a reg or stack operand?
			LoopExpr.CompareOperator = SMP_NULL_OPERATOR; // signal an analysis failure
			return;
		}
		LoopExpr.Operand1 = (*LeftUseIter);
	}
	assert(!CurrRT->HasRightSubTree());
	STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
	if (RightOp->IsImmedOp()) {
		DefOrUse RightImmedUse(RightOp);
		LoopExpr.Operand2 = RightImmedUse;
	}
	else {
		STARSDefUseIter RightUseIter = this->FindUse(RightOp);
		if (RightUseIter == this->GetLastUse()) { // Not a reg or stack operand?
			LoopExpr.CompareOperator = SMP_NULL_OPERATOR; // signal an analysis failure
			return;
		}
		LoopExpr.Operand2 = (*RightUseIter);
	}

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

// create Expr for DefOp from right-hand-side of first RT.
//  DefOp is used when this inst is an SSA Marker inst.
STARSExpression* SMPInstr::CreateDefExpr(const STARSOpndTypePtr &DefOp) {
	if (this->IsMarkerInst()) {
		// There will probably be lots of DEFs. Just create a DefExpr for the DefOp argument.
		STARSExpression *DefExpr = new STARSExpression();
		DefExpr->SetOperator(SMP_ASSIGN);
		DefExpr->SetParentInst(this);
		DefExpr->SetOriginalParentInst(this);
		DefExpr->SetParentFunc(this->GetBlock()->GetFunc());
		DefExpr->SetLeftOperand(DefOp);
		DefExpr->SetLeftUseAddr(this->GetAddr());
		DefExpr->SetLeftSSANum(0);
		return DefExpr;
	}
	else {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
		if (CurrRT->HasRightSubTree()) {
			CurrRT = CurrRT->GetRightTree();
			STARSExpression *DefExpr = new STARSExpression(CurrRT);
			return DefExpr;
		}
		else {
			STARSExpression *DefExpr = new STARSExpression();
			DefExpr->SetOperator(SMP_ASSIGN);
			DefExpr->SetParentInst(this);
			DefExpr->SetOriginalParentInst(this);
			DefExpr->SetParentFunc(this->GetBlock()->GetFunc());
			STARSOpndTypePtr RightOp = CurrRT->GetRightOperand();
			DefExpr->SetLeftOperand(RightOp);
			DefExpr->SetLeftUseAddr(this->GetAddr());
			if (MDIsDataFlowOpnd(RightOp, DefExpr->GetParentFunc()->UsesFramePointer())) {
				STARSDefUseIter UseIter = this->FindUse(RightOp);
				assert(UseIter != this->GetLastUse());
				DefExpr->SetLeftSSANum(UseIter->GetSSANum());
			}
			DefExpr->SetRightOperand(this->MakeVoidOpnd());
			return DefExpr;
		}
	}
} // end of SMPInstr::CreateDefExpr()

// create Expr from left-hand-side of first RT, e.g. [RAX+8] => SMP_ADD(RAX, 8)
STARSExpression* SMPInstr::CreateMemDefAddrExpr(void) {
	int BaseReg, IndexReg;
	uint16_t ScaleFactor;
	STARS_ea_t Offset;
	STARSOpndTypePtr MemDefOp = this->RTL.GetRT(0)->GetLeftOperandNoNorm();
	if (((nullptr == MemDefOp) || !MemDefOp->IsMemOp()) && (1 < this->RTL.GetCount())) {
		MemDefOp = this->RTL.GetRT(1)->GetLeftOperandNoNorm();
	}
	if (nullptr == MemDefOp)
		return nullptr;

	assert(MemDefOp->IsMemOp());
	MemDefOp->MDExtractAddressFields(BaseReg, IndexReg, ScaleFactor, Offset);
	STARSExpression *MemAddrExpr = nullptr;
	if ((ScaleFactor == 0) || (Offset == 0)) { // avoid too much complexity
		MemAddrExpr = new STARSExpression();
		MemAddrExpr->SetParentInst(this);
		MemAddrExpr->SetOriginalParentInst(this);
		MemAddrExpr->SetParentFunc(this->GetBlock()->GetFunc());
		if (BaseReg != STARS_x86_R_none) {
			STARSOpndTypePtr BaseOp = this->MakeRegOpnd((STARS_regnum_t) BaseReg);
			MemAddrExpr->SetLeftOperand(BaseOp);
			MemAddrExpr->SetLeftUseAddr(this->GetAddr());
		}
		else {
			assert(IndexReg != STARS_x86_R_none);
			STARSOpndTypePtr IndexOp = this->MakeRegOpnd((STARS_regnum_t) IndexReg);
			MemAddrExpr->SetLeftOperand(IndexOp);
			MemAddrExpr->SetLeftUseAddr(this->GetAddr());
		}
		STARSDefUseIter RegUseIter = this->FindUse(MemAddrExpr->GetConstLeftOperand());
		assert(RegUseIter != this->GetLastUse());
		MemAddrExpr->SetLeftSSANum(RegUseIter->GetSSANum());
		// Set address reg to default bytewidth even if memory write is smaller.
		size_t DefaultWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
		if (MemDefOp->GetByteWidth() < DefaultWidth) {
			MemAddrExpr->GetLeftOperand()->SetByteWidth(DefaultWidth);
		}

		if (Offset != 0) {
			MemAddrExpr->SetOperator(SMP_ADD);
			MemAddrExpr->SetRightOperand(this->MakeImmediateOpnd((STARS_uval_t) Offset));
		}
		else if (ScaleFactor != 0) {
			MemAddrExpr->SetOperator(SMP_U_MULTIPLY);
			MemAddrExpr->SetRightOperand(this->MakeImmediateOpnd((STARS_uval_t) (1 << ScaleFactor)));
		}
		else { // No ScaleFactor, no Offset
			MemAddrExpr->SetOperator(SMP_ASSIGN);
		}
	}
	return MemAddrExpr;
} // end of SMPInstr::CreateMemDefAddrExpr()

// Does UseOp arithmetically affect the value of the NonFlagsDef for this inst?
bool SMPInstr::OperandTransfersValueToDef(const STARSOpndTypePtr &UseOp) {
	bool FoundTransfer = false;
	for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		if (CurrRT->OperandTransfersValueToDef(UseOp)) {
			FoundTransfer = true;
			break;
		}
	}
	return FoundTransfer;
} // end of SMPInstr::OperandTransfersValueToDef()

// Evaluate constants in assignment statement for SCCP algorithm
void SMPInstr::SCCPEvaluateAssignment(list<pair<int, int> > &SSAWorkList) {
	for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		STARS_SCCP_Const_Struct ConstResult = CurrRT->SCCPEvaluateRTLConsts(SSAWorkList);
		if (ConstResult.ConstType == STARS_CONST_HAS_VALUE) {
			++ConstantDEFCount;
		}
	}
	return;
} // end of SMPInstr::SCCPEvaluateAssignment()

// Evaluate conditional branch using constant values from SCCP
void SMPInstr::SCCPEvaluateCondBranch(enum STARSBranchConst &BranchEval) {
	// The conditional branch RTL is just a jump with a Guard RT.
	//  We evaluate the Guard RT to see if it is always true or always false.
	SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
	SMPGuard *BranchCondition = CurrRT->GetGuard();
	assert(NULL != BranchCondition);
	STARSOpndTypePtr LeftOp = CloneIfSubwordReg(BranchCondition->GetConstLeftOperand());
	CanonicalizeOpnd(LeftOp);
	STARSOpndTypePtr RightOp = CloneIfSubwordReg(BranchCondition->GetConstRightOperand());
	CanonicalizeOpnd(RightOp);
	STARS_SCCP_Const_Struct LeftValue, RightValue;
	this->SCCPFetchConstUseValue(LeftOp, LeftValue);
	this->SCCPFetchConstUseValue(RightOp, RightValue);
	if ((LeftValue.ConstType == STARS_CONST_HAS_VALUE) && (RightValue.ConstType == STARS_CONST_HAS_VALUE)) {
		SMPoperator GuardOper = BranchCondition->GetOperator();
		if (GuardOper == SMP_EQUAL) {
			if (LeftValue.ConstValue == RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_NOT_EQUAL) {
			if (LeftValue.ConstValue != RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_GREATER_THAN) {
			if ((STARS_sval_t) LeftValue.ConstValue > (STARS_sval_t) RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_GREATER_EQUAL) {
			if ((STARS_sval_t) LeftValue.ConstValue >= (STARS_sval_t) RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_LESS_THAN) {
			if ((STARS_sval_t) LeftValue.ConstValue < (STARS_sval_t) RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_LESS_EQUAL) {
			if ((STARS_sval_t) LeftValue.ConstValue <= (STARS_sval_t) RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_BELOW) {
			if (LeftValue.ConstValue < RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_BELOW_EQUAL) {
			if (LeftValue.ConstValue <= RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_ABOVE) {
			if (LeftValue.ConstValue > RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else if (GuardOper == SMP_ABOVE_EQUAL) {
			if (LeftValue.ConstValue >= RightValue.ConstValue) {
				BranchEval = STARS_BRANCH_ALWAYS_TAKEN;
				++AlwaysTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr());
#endif
			}
			else {
				BranchEval = STARS_BRANCH_NEVER_TAKEN;
				++NeverTakenBranchCount;
#if 0
				SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr());
#endif
			}
		}
		else {
			SMP_msg("WARNING: SCCP unknown GuardOper %d in conditional branch at %llx\n", GuardOper, (unsigned long long) this->GetAddr());
			BranchEval = STARS_BRANCH_UNKNOWN;
		}
	}
	else {
		BranchEval = STARS_BRANCH_UNKNOWN;
	}

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

// Fetch constant value, if any, for a USE operand.
void SMPInstr::SCCPFetchConstUseValue(const STARSOpndTypePtr &UseOp, STARS_SCCP_Const_Struct &ConstStruct) {
	ConstStruct.ConstType = STARS_CONST_TOP; // default
	if (UseOp->IsImmedOp()) {
		ConstStruct.ConstType = STARS_CONST_HAS_VALUE;
		ConstStruct.ConstValue = UseOp->GetImmedValue();
	}
	else if (UseOp->IsRegOp()) {
		// Look up reg DEF value in local or global map
		STARSOpndTypePtr SearchOp = CloneIfSubwordReg(UseOp);
		CanonicalizeOpnd(SearchOp);
		set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
		if (UseIter != this->GetLastUse()) {
			int UseSSANum = UseIter->GetSSANum();
			int UseHashValue = HashGlobalNameAndSSA(SearchOp, UseSSANum);
			if (this->GetBlock()->IsLocalName(SearchOp)) { // local name
				map<int, struct STARS_SCCP_Const_Struct>::iterator ConstValIter = this->GetBlock()->FindLocalConstValue(UseHashValue);
				if (ConstValIter != this->GetBlock()->GetLastLocalConstValueIter()) { // Has current const val entry
					ConstStruct = ConstValIter->second;
				}
			}
			else { // global name
				map<int, struct STARS_SCCP_Const_Struct>::iterator ConstValIter = this->GetBlock()->GetFunc()->FindConstValue(UseHashValue);
				if (ConstValIter != this->GetBlock()->GetFunc()->GetLastConstValueIter()) { // Has current const val entry
					ConstStruct = ConstValIter->second;
				}
			}
		}
	}
	else if (UseOp->IsStaticMemOp()) {
		// Fetch read-only data value, if any.
		STARS_ea_t MemAddr = UseOp->GetAddr();
		bool GoodAddr = (STARS_BADADDR != MemAddr);
#if 1
#if 1
		int BaseReg = STARS_x86_R_none;
		if (UseOp->HasSIBByte()) {
			BaseReg = UseOp->MDGetSIBIndexReg();
			if (MD_STACK_POINTER_REG == BaseReg) {
				// ESP IndexReg in SIB byte means no index reg
				// seg reg without index or base reg, e.g.:  FS:0x28
				BaseReg = STARS_x86_R_none;
				GoodAddr = false; // until we track segment register values
#if 0	
				SMP_msg("ERROR: StaticMemOp with SIB byte and no index reg at %llx\n", (unsigned long long) this->GetAddr());
#endif
			}
		}
#else
		int BaseReg = (int) UseOp->GetReg();
		if (MD_STACK_POINTER_REG == BaseReg) {
			// ESP BaseReg in means no base reg for StaticMemOp
			BaseReg = STARS_x86_R_none;
		}
		if (UseOp->HasSIBByte()) {
			BaseReg = UseOp->MDGetSIBBaseReg();
			if ((STARS_x86_R_none == BaseReg) || (MD_FRAME_POINTER_REG == BaseReg)) {
				// EBP BaseReg for StaticMemOp means no base reg
				BaseReg = UseOp->MDGetSIBIndexReg();
				if (MD_STACK_POINTER_REG == BaseReg) {
					// ESP IndexReg in SIB byte means no index reg
					BaseReg = STARS_x86_R_none;
				}
			}
		}
#endif
		if (STARS_x86_R_none != BaseReg) { // have an offset reg to add to the static mem addr
			// TODO: Fetch constant value for general purpose reg, with SSANum from USE set.
			GoodAddr = false;
		}
#endif
		if (GoodAddr) {
			STARS_Segment_t *MemSeg = global_stars_interface->getseg(MemAddr);
			if (NULL != MemSeg) {
				if (MemSeg->IsWriteableSegment()) {
					ConstStruct.ConstType = STARS_CONST_BOTTOM; // cannot know writable memory value without alias analysis, etc.
				}
				else {
					size_t UseOpByteWidth = UseOp->GetByteWidth();
					if (UseOpByteWidth == 8) {
						uint64_t MemValue;
						if (MemSeg->GetReadOnlyMem64BitValue(MemAddr, MemValue)) {
							ConstStruct.ConstType = STARS_CONST_HAS_VALUE;
							ConstStruct.ConstValue = (STARS_uval_t) MemValue;
						}
					}
					else if (UseOpByteWidth == 4) {
						uint32_t MemValue;
						if (MemSeg->GetReadOnlyMem32BitValue(MemAddr, MemValue)) {
							ConstStruct.ConstType = STARS_CONST_HAS_VALUE;
							ConstStruct.ConstValue = (STARS_uval_t) MemValue;
						}
					}
					else if (UseOpByteWidth == 2) {
						uint16_t MemValue;
						if (MemSeg->GetReadOnlyMem16BitValue(MemAddr, MemValue)) {
							ConstStruct.ConstType = STARS_CONST_HAS_VALUE;
							ConstStruct.ConstValue = (STARS_uval_t) MemValue;
						}
					}
					else if (UseOpByteWidth == 1) {
						uint8_t MemValue;
						if (MemSeg->GetReadOnlyMem8BitValue(MemAddr, MemValue)) {
							ConstStruct.ConstType = STARS_CONST_HAS_VALUE;
							ConstStruct.ConstValue = (STARS_uval_t) MemValue;
						}
					}
				}
			}
		}
		else { // not GoodAddr
			ConstStruct.ConstType = STARS_CONST_BOTTOM;
		}
	}
	else if (UseOp->IsMemOp()) {  // Any memory operand that is not a StaticMemOp
		ConstStruct.ConstType = STARS_CONST_BOTTOM;
	}

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

// Fetch constant value, if any, for a DEF operand.
void SMPInstr::SCCPFetchConstDefValue(const STARSOpndTypePtr &DefOp, STARS_SCCP_Const_Struct &ConstStruct) {
	ConstStruct.ConstType = STARS_CONST_TOP; // default
	if (DefOp->IsImmedOp()) {
		ConstStruct.ConstType = STARS_CONST_HAS_VALUE;
		ConstStruct.ConstValue = DefOp->GetImmedValue();
	}
	else if (DefOp->IsRegOp()) {
		// Look up reg DEF value in local or global map
		STARSOpndTypePtr SearchOp = CloneIfSubwordReg(DefOp);
		CanonicalizeOpnd(SearchOp);
		set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp);
		if (DefIter != this->GetLastDef()) {
			int DefSSANum = DefIter->GetSSANum();
			SMPBasicBlock *CurrBlock = this->GetBlock();
			int DefHashValue = HashGlobalNameAndSSA(SearchOp, DefSSANum);
			bool LocalName = CurrBlock->IsLocalName(SearchOp);
			STARSSCCPMapIter ConstValIter;
			if (this->GetBlock()->IsLocalName(SearchOp)) { // local name
				ConstValIter = this->GetBlock()->FindLocalConstValue(DefHashValue);
				if (ConstValIter != this->GetBlock()->GetLastLocalConstValueIter()) { // Has current const val entry
					ConstStruct = ConstValIter->second;
				}
			}
			else { // global name
				ConstValIter = CurrBlock->GetFunc()->FindConstValue(DefHashValue);
				if (ConstValIter != CurrBlock->GetFunc()->GetLastConstValueIter()) { // Has current const val entry
					ConstStruct = ConstValIter->second;
				}
			}
		}
	}
	return;
} // end of SMPInstr::SCCPFetchConstDefValue()

// Trace UseOp through register moves back to its stack location or immediate value source.
//  Return true if we are passing an immediate or stack location back in UltSource.
bool SMPInstr::TraceUltimateMoveSource(const STARSOpndTypePtr &UseOp, int UseSSANum, STARSOpndTypePtr &UltSource, bool &FPRelative) {
	// If we hit an immediate value or a stack location, we are done.
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
	STARSOpndTypePtr DefOp = nullptr, ImmOp = nullptr;
	int NewUseSSANum;
	set<DefOrUse,LessDefUse>::iterator UseIter;
	bool LocalName;
	STARS_ea_t DefAddr;
	SMPInstr *DefInst;

	UltSource = nullptr;
	bool StackOp = MDIsDirectStackAccessOpnd(UseOp, UseFP);
	bool RegisterOp = (UseOp->IsRegOp());

	if (this->GetOptType() == 3) { // move instruction
		if (UseOp->IsImmedOp()) {
			UltSource = UseOp;
			return true;
		}
		else if ((!RegisterOp) && (!StackOp)) {
			// We only trace the move chain through registers or stack locations to an ultimate 
			//  load-effective-address of a stack location, or a move of an immediate value.
			return false;
		}
	} 
	else if (!this->MDIsLoadEffectiveAddressInstr()) {
		return false;
	}
	else { // Load effective address instruction.
		// If it is a stack location being loaded, trace succeeded, else it failed.
		if (StackOp) {
			UltSource = UseOp;
			FPRelative = this->HasFPNormalizedToSP();
			return true;
		}
		else {
			return false;
		}
	}

	// If we reach this point, we have a move instruction but did not return true or false above.

	// Recursion case. Going back up the move chain has just produced a register or
	//  a stack location, and we still need to find the stack address or immediate value
	//  that was stored in the register or stack location. The stack location could hold
	//  a pointer to a stack object, produced by an earlier LEA instruction, or it
	//  could hold an immediate value (e.g. constant size argument passed to memset() or
	//  similar function).
	LocalName = this->GetBlock()->IsLocalName(UseOp);
	DefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, this->GetAddr(), UseSSANum, LocalName);
	if ((STARS_BADADDR == DefAddr) || (STARS_IsBlockNumPseudoID(DefAddr))) {
		// Def was not found, or was found in Phi function (DefAddr was block number, not instruction addr).
		return false;
	}

	if (STARS_IsLiveInPseudoID(DefAddr)) {
		// If DefAddr is 1 byte less than the first addr in the block, then
		//  it is a pseudo-def in the global DU chains, signifying that the
		//  value was LiveIn and the true DEF is in another block. We could
		//  handle this in the future, but right now we will only deal with
		//  the simpler case in which the move source can be traced
		//  within the basic block.
		return false;
	}

	// Everything is OK so far; time to recurse up the move chain.
	STARSOpndTypePtr NewUseOp = nullptr; // next UseOp up the move chain
	DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr);
	if (DefInst->GetOptType() == 3) {
		NewUseOp = CloneIfSubwordReg(DefInst->GetMoveSource());
	}
	else if (DefInst->MDIsLoadEffectiveAddressInstr()) {
		NewUseOp = DefInst->GetLeaMemUseOp();
		if (MDIsDirectStackAccessOpnd(NewUseOp, UseFP)) {
			UltSource = NewUseOp;
			FPRelative = DefInst->HasFPNormalizedToSP();
			return true;
		}
		else {
			return false;
		}
	}
	// We don't have a move instruction or a load effective address instruction, which
	//  can be used to move a stack address into a register. We don't try to trace through
	//  arithmetic except for two easy cases.
	// Case 1: A register is cleared. Same as assigning immediate value zero to the reg.
	else if (DefInst->IsRegClearIdiom()) {
		UltSource = this->STARSInstPtr->MakeImmediateOpnd(0);
		// why would we memset a zero byte region?
		return true;
	}
	// Easy arithmetic Case 2: we have reg += ImmediateValue, and reg was DEFed by reg := LEA(StackLoc).
	else if (DefInst->MDIsAddImmediateToReg(DefOp, ImmOp)) {
		SMPInstr *NewDefInst;
		UseIter = DefInst->FindUse(DefOp);
		assert(UseIter != DefInst->GetLastUse());
		NewUseSSANum = UseIter->GetSSANum();
		LocalName = DefInst->GetBlock()->IsLocalName(DefOp);
		DefAddr = DefInst->GetBlock()->GetDefAddrFromUseAddr(DefOp, DefInst->GetAddr(), NewUseSSANum, LocalName);
		if ((STARS_BADADDR == DefAddr) || (STARS_IsBlockNumPseudoID(DefAddr))) {
			// Def was not found, or was found in Phi function (DefAddr was block number, not instruction addr).
			return false;
		}
		NewDefInst = DefInst->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr);
		if (NewDefInst->MDIsLoadEffectiveAddressInstr()) {
			NewUseOp = NewDefInst->GetLeaMemUseOp()->clone();
			if (MDIsDirectStackAccessOpnd(NewUseOp, UseFP)) {
				// We have the code sequence we were searching for when we first saw the
				//  addition of an immediate value to a register, e.g.:
				//   lea ebx,[ebp-2000]
				//   add ebx,1000
				//
				// We are essentially making this sequence into a single instruction:
				//   lea ebx,[ebp-1000]
				//  by adding the immediate value to the address offset. With a stack that grows
				//  downward, it does not matter if we add 1000 to [esp+500] to produce [esp+1500],
				//  or we add 1000 to [ebp-2000] to make [ebp-1000]. Either way, we are simulating the
				//  addition of 1000 as we move up in the stack frame.
				STARS_ea_t NewAddr = NewUseOp->GetAddr() + ImmOp->GetImmedValue();
				NewUseOp->SetAddr(NewAddr); // perform the address arithmetic addition
				UltSource = NewUseOp;
				FPRelative = NewDefInst->HasFPNormalizedToSP();
				return true;
			}
			else {
				return false;
			}
		}
		else {
			return false;
		}
	}
	else {
		// Not the kind of instruction we need; cut short the recursion.
		return false;
	}

	// NewUseOp is the move source operand that we seek.
	CanonicalizeOpnd(NewUseOp);
	UseIter = DefInst->FindUse(NewUseOp);
	assert(UseIter != DefInst->GetLastUse());
	NewUseSSANum = UseIter->GetSSANum();  // unused for immediates, used for regs and stack
	// Recurse
	return DefInst->TraceUltimateMoveSource(NewUseOp, NewUseSSANum, UltSource, FPRelative);

} // end of SMPInstr::TraceUltimateMoveSource()

// inst has no code xrefs?
bool SMPInstr::HasNoCodeXrefs(void) {
	return global_stars_interface->InstHasNoCodeXrefs(this->GetInstID());
} // end of SMPInstr::HasNoCodeXrefs()

// true => jump is used to exit a loop
bool SMPInstr::IsLoopExitStatement(bool &InvertedExit) {
	bool FoundLoopExit = false;
	bool SingleBlockLoop = false;

	// NOTE: We assume that this method will not be called for 
	//  functions with irreducible CFGs.

	// For reducible CFGs, if we jump to a different loop nesting level,
	//  this is a loop exit jump.
	SMPBasicBlock *SourceBlock = this->GetBlock();
	int SourceBlockNum = SourceBlock->GetNumber();
	int TargetBlockNum = SMP_BLOCKNUM_UNINIT;
	if (SourceBlock->GetFunc()->IsBlockInAnyLoop(SourceBlockNum)) { // we are currently in a loop
		InvertedExit = false;
		SingleBlockLoop = SourceBlock->IsSelfLoop();
		if (!SingleBlockLoop) {
			int InnerLoopNum = SourceBlock->GetFunc()->GetInnermostLoopNum(SourceBlockNum);
			STARS_ea_t JumpTargetAddr = this->GetJumpTarget();
			if ((STARS_BADADDR != JumpTargetAddr) && (!(this->IsTailCall() || this->IsCondTailCall() || this->IsBranchToOtherFunc()))) {
				SMPInstr *JumpTargetInst = SourceBlock->GetFunc()->GetInstFromAddr(JumpTargetAddr);
				TargetBlockNum = JumpTargetInst->GetBlock()->GetNumber();
				// If TargetBlockNum is not in the current block's innermost loop num, we are exiting the innermost loop num.
				FoundLoopExit = (!(SourceBlock->GetFunc()->IsBlockInLoop(TargetBlockNum, InnerLoopNum)));
			}
			// Special case: Code layout by compiler puts loop header block at bottom of address range.
			//  If COND_BRANCH is not taken, we fall out of the loop; if taken, we stay in the loop.
			//  This is the INVERTED_LOOP_EXIT case.
			//  Recent addition: Can fall out of any block in loop, not just loop header block. 03-APR-2017
			if (!FoundLoopExit) {
				// We are currently in a loop, and taking the branch keeps us in the same inner loop.
				//  Does not taking the branch cause us to fall out of the loop?
				list<SMPBasicBlock *>::const_iterator SuccIter = SourceBlock->GetFallThroughSucc();
				if (SuccIter != SourceBlock->GetLastConstSucc()) {
					int FallThroughBlockNum = (*SuccIter)->GetNumber();
					bool FallThroughLeavesLoop = (!(SourceBlock->GetFunc()->IsBlockInLoop(FallThroughBlockNum, InnerLoopNum)));
					if (FallThroughLeavesLoop) {
						// We found the INVERTED_LOOP_EXIT case.
						InvertedExit = true;
						FoundLoopExit = true;
						if (!SourceBlock->IsLoopHeaderBlock()) {
							SMP_msg("INFO: Found special case of INVERTED_LOOP_EXIT at %llx in %s\n",
								(uint64_t) this->GetAddr(), this->GetBlock()->GetFunc()->GetFuncName());
						}
					}
				}
			}
		}
	}

	return FoundLoopExit;
} // end of SMPInstr::IsLoopExitStatement()



// For the SSA Marker instruction at the beginning of a function, see if incoming register types
//  can be obtained from the union/meet of all call sites.
bool SMPInstr::InferMarkerInstTypes(void) {
	bool changed = false;
	if (this->IsMarkerInst()) {
		// SSA marker instruction is a floating nop placed at a pseudo-address.
		// Go through all USEs that are untyped and see if types can be obtained.
		set<DefOrUse, LessDefUse>::iterator MarkerDefIter = this->GetFirstDef();
		while (MarkerDefIter != this->GetLastDef()) {
			STARSOpndTypePtr MarkerDefOp = MarkerDefIter->GetOp();
			if (MarkerDefOp->IsRegOp() && (UNINIT == MarkerDefIter->GetType())) {
				// Find type of DEF, obtained from type meet function across all call site USEs.
				STARS_regnum_t RegNum = MarkerDefOp->GetReg();
				SMPOperandType IncomingType = this->GetBlock()->GetFunc()->GetIncomingRegType(RegNum);
				if (UNINIT != IncomingType) {
					// Need to update type and propagate.
					MarkerDefIter = this->SetDefType(MarkerDefOp, IncomingType);
					changed = true;
					bool LocalName = this->GetBlock()->IsLocalName(MarkerDefOp);
					int DefSSANum = MarkerDefIter->GetSSANum();
					if (LocalName) {
						this->GetBlock()->PropagateLocalDefType(MarkerDefOp, IncomingType, this->GetAddr(), DefSSANum, false, false);
					}
					else {
						this->GetBlock()->GetFunc()->ResetProcessedBlocks();
						this->GetBlock()->PropagateGlobalDefType(MarkerDefOp, IncomingType, DefSSANum, false, false);
					}
				}
			}
			++MarkerDefIter;
		}
	}
	return changed;
} // end of SMPInstr::InferMarkerInstTypes()

// Infer DEF, USE, and RTL SMPoperator types within the instruction based on the type
//  of operator, the type category of the instruction, and the previously known types 
//  of the operands.
bool SMPInstr::InferTypes(void) {
	bool changed = false;  // return value
	int SSANum;
	unsigned short opcode = this->GetIDAOpcode();
	int TypeCategory = SMPTypeCategory[opcode];
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	STARSOpndTypePtr DefOp = nullptr, UseOp = nullptr;
	bool DebugFlag = false;
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
	bool SafeFunc = this->BasicBlock->GetFunc()->IsSafe();
	bool IsMemOp;
#if SMP_VERBOSE_DEBUG_INFER_TYPES
	DebugFlag |= (0 == strcmp("ext_wmatch", this->BasicBlock->GetFunc()->GetFuncName()));

#if 1
	if (DebugFlag) {
		SMP_msg("InstAddr: %llx opcode: %d TypeCategory: %d\n", 
			(uint64_t) this->GetAddr(), opcode, TypeCategory);
	}
#endif
#endif

	// If we are already finished with all types, return false.
	if (this->IsTypeInferenceComplete())
		return false;

	if (this->AllDEFsTyped() && this->AllUSEsTyped()) {
		this->SetTypeInferenceComplete();
		return false;
	}

	if (this->HasDestMemoryOperand()) {
		changed |= this->MDFindPointerUse(this->MDGetMemDefOp(), UseFP);
	}
	if (this->HasSourceMemoryOperand()) {
		changed |= this->MDFindPointerUse(this->MDGetMemUseOp(), UseFP);
	}

	// The control flow instructions can be handled simply based on their type
	//  and do not need an RTL walk.
	SMPitype DFAType = this->GetDataFlowType();
	bool CallInst = ((DFAType == CALL) || (DFAType == INDIR_CALL) || this->IsTailCall());
#if SMP_VERBOSE_DEBUG_INFER_TYPES
	if (DebugFlag) {
		SMP_msg("%llx DFAType: %d  CategoryInferenceComplete: %d\n",
			(uint64_t) this->GetAddr(), DFAType, this->IsCategoryInferenceComplete());
	}
#endif

	STARS_regnum_t IndirCallReg = STARS_x86_R_none;
	if (DFAType == INDIR_CALL) {
		STARSOpndTypePtr TargetOp = this->STARSInstPtr->GetOpnd(0);
		if (TargetOp->IsRegOp())
			IndirCallReg = TargetOp->GetReg();
	}

	if (IsBranchOrCall(DFAType) || this->IsTailCall()) {
		// All USEs are either the flags (NUMERIC) or the target address (CODEPTR).
		//  The exceptions are the USE list for calls, which includes
		//  the caller-saved regs, and indirect calls through a memory
		//  operand, such as call [ebx+esi+20h], where the memory operand
		//  is a CODEPTR but the addressing registers are a BaseReg and
		//  IndexReg as in any other memory addressing.
		CurrUse = this->GetFirstUse();
		while (CurrUse != this->GetLastUse()) {
			UseOp = CurrUse->GetOp();
			bool NotCodePtrType = !IsCodePtr(CurrUse->GetType());
			bool AddressReg = (this->HasSourceMemoryOperand() && UseOp->IsRegOp() && (!this->IsNonAddressReg(UseOp)));
			if (UseOp->MatchesReg(X86_FLAGS_REG))
				CurrUse = this->SetUseType(UseOp, NUMERIC);
#if 0
			else if ((CurrUse->GetType() != CODEPTR)
				&& (!(this->IsInterruptCall() && (UseOp->IsRegOp())))
				&& (!(CallInst && (UseOp->IsRegOp())))
				&& (!(this->HasSourceMemoryOperand() && (INDIR_CALL == this->GetDataFlowType()) && (UseOp->IsRegOp())))
					) {
#else
			else if (!UseOp->IsRegOp() && NotCodePtrType) {
#endif
				CurrUse = this->SetUseType(UseOp, CODEPTR);
				if (CallInst) {
					// If the call is to malloc(), then the DEF of the return
					//  register is of type HEAPPTR.
					changed |= this->MDFindMallocCall(UseOp);
				}
			}
			else if (NotCodePtrType && CallInst && UseOp->MatchesReg(IndirCallReg)) {
				CurrUse = this->SetUseType(UseOp, CODEPTR);
			}
			if (CallInst && (CurrUse->GetType() == CODEPTR)) {
				// See if callee function has a type inferred for registers that it DEFs.
				//  NOTE: We could do this more than once in the future, in case we iterate
				//  over all funcs in the program graph.
				STARS_ea_t CalleeAddr = UseOp->GetAddr();
				SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalleeAddr);
				if (nullptr != CalleeFunc) {
					CurrDef = this->GetFirstDef();
					while (CurrDef != this->GetLastDef()) {
						DefOp = CurrDef->GetOp();
						if (DefOp->IsRegOp()) {
							SMPOperandType RegType = (SMPOperandType) CalleeFunc->GetReturnRegType(DefOp->GetReg());
							bool LocalName = this->GetBlock()->IsLocalName(DefOp);
							if (UNINIT != RegType) {
								SMPOperandType CurrentRegType = CurrDef->GetType();
								if (UNINIT == CurrentRegType) {
									// Use type from callee.
									CurrDef = this->SetDefType(DefOp, RegType);
									bool PtrOverride = IsDataPtr(RegType); // Certain we are getting POINTER from callee, so change NUMERIC USEs to POINTER
									if (LocalName) {
										this->GetBlock()->PropagateLocalDefType(DefOp, RegType, this->GetAddr(), CurrDef->GetSSANum(), false, PtrOverride);
									}
									else {
										this->GetBlock()->GetFunc()->ResetProcessedBlocks(); // prepare for recursion
										this->GetBlock()->PropagateGlobalDefType(DefOp, RegType, CurrDef->GetSSANum(), false, PtrOverride);
									}
								}
							}
							// Do the same for FGInfo.
							if (DefOp->GetReg() < (decltype(DefOp->GetReg()))CalleeFunc->GetReturnRegFGInfoSize()) {
								int DefSSANum = CurrDef->GetSSANum();
								int DefHashIndex = HashGlobalNameAndSSA(DefOp, DefSSANum);
								struct FineGrainedInfo CalleeRegFGInfo = CalleeFunc->GetReturnRegFGInfo(DefOp->GetReg());
								if (LocalName) {
									this->GetBlock()->UpdateDefFGInfo(DefHashIndex, CalleeRegFGInfo);
								}
								else {
									this->GetBlock()->GetFunc()->UpdateDefFGInfo(DefHashIndex, CalleeRegFGInfo);
								}
							}
						}
						++CurrDef;
					} // end while not the last DEF

					// Get types for USEs of the CALL inst from the MarkerInst types inside CalleeFunc
					STARSDefUseIter CallUseIter = this->GetFirstUse();
					while (CallUseIter != this->GetLastUse()) {
						SMPOperandType CallUseType = UNINIT;
						STARSOpndTypePtr CallUseOp = CallUseIter->GetOp();
						if (CalleeFunc->GetMarkerInstDefType(CallUseOp, CallUseType)) {
							// CalleeFunc marker inst DEFed the current use with type CallUseType.
							bool TypeErrorFlag = false;
							CallUseType = SMPTypeMeet(CallUseType, CallUseIter->GetType(), TypeErrorFlag);
							if (TypeErrorFlag) {
								SMP_msg("ERROR: TypeMeet error at call addr %llx CalleeAddr %llx\n", 
									(uint64_t) this->GetAddr(), (uint64_t) CalleeAddr);
							}
							CallUseIter = this->SetUseType(CallUseOp, CallUseType);
						}
						++CallUseIter;
					}
				} // end if (NULL != CalleeFunc)
			} // end if (CallInst and CODEPTR USE)
			++CurrUse;
		} // end while all USEs
		this->SetTypeInferenceComplete();
		return true;
	}

	// First, see if we can infer something about DEFs and USEs just from the 
	//  type category of the instruction.
	if (!this->IsCategoryInferenceComplete()) {
		bool MemPropagate = false;
		switch (TypeCategory) {
			case 0: // no inference possible just from type category
			case 1: // no inference possible just from type category
			case 3:  // MOV instructions; inference will come from source to dest in RTL walk.
			case 5:  // binary arithmetic; inference will come in RTL walk.
			case 10:  // binary arithmetic; inference will come in RTL walk.
			case 11:  // push and pop instructions; inference will come in RTL walk.
			case 12:  // exchange instructions; inference will come in RTL walk.
				this->SetCategoryInferenceComplete();
				break;

			case 2: // Result type is always NUMERIC.
			case 7: // Result type is always NUMERIC.
			case 8: // Result type is always NUMERIC.
			case 9: // Result type is always NUMERIC.
			case 13: // Result type is always NUMERIC.
			case 14: // Result type is always NUMERIC.  !!!!****!!!! scas should not be here, or don't reset POINTERs to NUMERICs
			case 15: // Result type is always NUMERIC.
				CurrDef = this->GetFirstDef();
				while (CurrDef != this->GetLastDef()) {
					if (!IsEqType(NUMERIC, CurrDef->GetType())) {
						DefOp = CurrDef->GetOp();
						SSANum = CurrDef->GetSSANum();
						CurrDef = this->SetDefType(DefOp, NUMERIC);
						changed = true;
						// Be conservative and only propagate register DEFs and SAFE stack locs. We
						//  can improve this in the future. **!!**
						bool IsMemOp = (! DefOp->IsRegOp());
						bool MemPropagate = MDIsDirectStackAccessOpnd(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 ((DefOp->IsRegOp()) || MemPropagate) {
							if (this->BasicBlock->IsLocalName(DefOp)) {
								(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
									this->GetAddr(), SSANum, IsMemOp);
							}
							else { // global name
								this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
								(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
									SSANum, IsMemOp, false);
							}
						}
					}
					++CurrDef;
				}
				this->SetCategoryInferenceComplete();
				break;

			case 4: // Unary INC, DEC, etc.: dest=source, so type remains the same
				assert(1 == this->RTL.GetCount());
				assert(this->RTL.GetRT(0)->HasRightSubTree());
				UseOp = this->RTL.GetRT(0)->GetLeftOperand(); // USE == DEF
				CurrUse = this->Uses.FindRef(UseOp);
				assert(CurrUse != this->GetLastUse());
				if (UNINIT != CurrUse->GetType()) {
					// Only one USE, and it has a type assigned, so assign that type
					// to the DEF.
					CurrDef = this->GetFirstDef();
					while (CurrDef != this->GetLastDef()) {
						// Two DEFs: EFLAGS is NUMERIC, dest==source
						DefOp = CurrDef->GetOp();
						SSANum = CurrDef->GetSSANum();
						if (DefOp->MatchesReg(X86_FLAGS_REG)) {
							; // SetImmedTypes already made it NUMERIC
						}
						else {
							CurrDef = this->SetDefType(DefOp, CurrUse->GetType());
							// Be conservative and only propagate register DEFs and SAFE stack locs. We
							//  can improve this in the future. **!!**
							bool IsMemOp = (! DefOp->IsRegOp());
							MemPropagate = MDIsDirectStackAccessOpnd(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 ((DefOp->IsRegOp()) || MemPropagate) {
								if (this->BasicBlock->IsLocalName(DefOp)) {
									(void) this->BasicBlock->PropagateLocalDefType(DefOp, CurrUse->GetType(),
										this->GetAddr(), SSANum, IsMemOp);
								}
								else { // global name
									this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
									(void) this->BasicBlock->PropagateGlobalDefType(DefOp, CurrUse->GetType(),
										SSANum, IsMemOp, false);
								}
							}
						}
						++CurrDef;
					}
					this->SetCategoryInferenceComplete();
					changed = true;
					this->SetTypeInferenceComplete();
				}
				break;

			case 6: // Result is always POINTER
				DefOp = this->GetFirstDef()->GetOp();
				SSANum = this->GetFirstDef()->GetSSANum();
				CurrDef = this->SetDefType(DefOp, POINTER);
				this->SetCategoryInferenceComplete();
				changed = true;
				// Be conservative and only propagate register DEFs and SAFE stack locs. We
				//  can improve this in the future. **!!**
				IsMemOp = (! DefOp->IsRegOp());
				MemPropagate = MDIsDirectStackAccessOpnd(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 ((DefOp->IsRegOp()) || MemPropagate)  {
					if (this->BasicBlock->IsLocalName(DefOp)) {
						(void) this->BasicBlock->PropagateLocalDefType(DefOp, POINTER,
							this->GetAddr(), SSANum, IsMemOp);
					}
					else { // global name
						this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
						(void) this->BasicBlock->PropagateGlobalDefType(DefOp, POINTER,
							SSANum, IsMemOp, false);
					}
				}
				break;

			default:
				SMP_msg("ERROR: Unknown type category for %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
				this->SetCategoryInferenceComplete();
				break;
		} // end switch on TypeCategory
	} // end if (!CategoryInference)

	// Walk the RTL and infer types based on operators and operands.
#if SMP_VERBOSE_DEBUG_INFER_TYPES
	if (DebugFlag) {
		SMP_msg("RTcount: %zu\n", this->RTL.GetCount());
	}
#endif
	for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
			continue;
		if (!(CurrRT->IsTypeInferenceComplete())) {
			changed |= this->InferOperatorType(CurrRT);
		}
#if SMP_VERBOSE_DEBUG_INFER_TYPES
		if (DebugFlag) {
			SMP_msg("returned from InferOperatorType\n");
		}
#endif
	} // end for all RTs in the RTL
	return changed;
} // end of SMPInstr::InferTypes()

// Infer the type of an operator within an RT based on the types of its operands and
//  based on the operator itself. Recurse down the tree if necessary.
// Return true if the operator type of the RT is updated.
bool SMPInstr::InferOperatorType(SMPRegTransfer *CurrRT) {
	bool updated = false;
	bool LeftNumeric, RightNumeric, OperNumeric;
	bool LeftPointer, RightPointer, OperPointer;
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
	bool SafeFunc = this->BasicBlock->GetFunc()->IsSafe();
	set<DefOrUse, LessDefUse>::iterator CurrDef;
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	set<DefOrUse, LessDefUse>::iterator LeftUse;
	set<DefOrUse, LessDefUse>::iterator RightUse;
	SMPOperandType LeftType = UNINIT;
	SMPOperandType RightType = UNINIT;
	SMPOperandType OperType = CurrRT->GetOperatorType();
	STARSOpndTypePtr UseOp = nullptr, DefOp = nullptr, LeftOp = nullptr, RightOp = nullptr;
	SMPoperator CurrOp = CurrRT->GetOperator();
	bool TypeInferenceFinished = false;
#if SMP_VERBOSE_DEBUG_INFER_TYPES
	bool DebugFlag = false;
#if 1
	DebugFlag |= (0 == strcmp("ext_wmatch", this->BasicBlock->GetFunc()->GetFuncName()));
#endif
	DebugFlag = DebugFlag || ((this->GetAddr() == 0x806453b) || (this->GetAddr() == 0x806453e));
#endif

#if SMP_VERBOSE_DEBUG_INFER_TYPES
	if (DebugFlag) {
		SMP_msg("Entered InferOperatorType for CurrOp: %s at %llx\n", OperatorText[CurrOp], (uint64_t) this->GetAddr());
	}
#endif

	if (CurrRT->IsTypeInferenceComplete()) {
		return updated;
	}

	switch (CurrOp) {
		case SMP_NULL_OPERATOR:
		case SMP_SIGNAL: // signal or raise exception
			TypeInferenceFinished = true;
			break;

		case SMP_CALL:  // CALL instruction
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(CODEPTR, this);
				updated = true;
				UseOp = CurrRT->GetRightOperand();
				CurrUse = this->Uses.FindRef(UseOp);
				assert(CurrUse != this->GetLastUse());
				if (UNINIT == CurrUse->GetType()) {
					CurrUse = this->SetUseType(UseOp, CODEPTR);
				}
				else if (CODEPTR != CurrUse->GetType()) {
					SMP_msg("WARNING: call target is type %d, setting to CODEPTR at %llx in %s\n",
						CurrUse->GetType(), (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
					CurrUse = this->SetUseType(UseOp, CODEPTR);
				}

			}
			TypeInferenceFinished = true;
			break;

		case SMP_INPUT:  // input from port
		case SMP_OUTPUT: // output to port
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(NUMERIC, this);
				updated = true;
			}
			break;

#if 0
		case SMP_SIGN_EXTEND:
		case SMP_ZERO_EXTEND:
			// Should we infer that all operands are NUMERIC?  !!!???!!!!
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(NUMERIC, this);
				updated = true;
			}
			break;
#endif

		case SMP_ADDRESS_OF: // take effective address
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(POINTER, this);
				// Left operand is having its address taken, but we cannot infer what its
				//  type is.
				updated = true;
			}
			break;

		case SMP_UNARY_POINTER_OPERATION: // increment or decrement a pointer
			if (UNINIT == CurrRT->GetOperatorType()) {
				CurrRT->SetOperatorType(POINTER, this);
				updated = true;
				// Left operand should be NUMERIC if it exists.
				UseOp = CurrRT->GetLeftOperand();
				if ((nullptr != UseOp) && (!UseOp->IsVoidOp())) {
					CurrUse = this->Uses.FindRef(UseOp);
					if (CurrUse == this->GetLastUse()) {
						SMP_msg("SERIOUS WARNING: Adding missing USE of ");
						PrintOperand(UseOp);
						SMP_msg(" at %llx in %s\n", (uint64_t) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						this->Uses.SetRef(UseOp, POINTER, -1);
					}
					else if (UNINIT == CurrUse->GetType()) {
						CurrUse = this->SetUseType(UseOp, NUMERIC);
					}
				}
			}
			break;

#if 0
		case SMP_S_COMPARE: // signed compare (subtraction-based)
		case SMP_U_COMPARE: // unsigned compare (AND-based)
			// not much to do; perhaps propagate LeftType or RightType to the other?
			LeftOp = CurrRT->GetLeftOperand();
			RightOp = CurrRT->GetRightOperand();
			assert((nullptr != LeftOp) && (!LeftOp->IsVoidOp()));
			assert((nullptr != RightOp) && (!RightOp->IsVoidOp()));
			LeftUse = this->FindUse(LeftOp);
			RightUse = this->FindUse(RightOp);
			if ((LeftUse != this->GetLastUse()) && (RightUse != this->GetLastUse())) {
				LeftType = LeftUse->GetType();
				RightType = RightUse->GetType();
				if (((UNINIT == LeftType) || (UNINIT == RightType)) && (LeftType != RightType)) {
					// One type is UNINIT, the other is not. Propagate type to the UNINIT side.
					if (UNINIT == LeftType) {
						this->SetUseType(LeftOp, RightType);
					}
					else {
						this->SetUseType(RightOp, LeftType);
					}
					updated = true;
				}
				if ((LeftType == RightType) && (UNINIT == OperType) && (UNINIT != LeftType)) {
					CurrRT->SetOperatorType(LeftType, this);
					updated = true;
				}
			}
			break; 
#endif

		case SMP_SIGN_EXTEND:
		case SMP_ZERO_EXTEND:
		case SMP_U_LEFT_SHIFT: // unsigned left shift
		case SMP_S_LEFT_SHIFT: // signed left shift
		case SMP_U_RIGHT_SHIFT: // unsigned right shift
		case SMP_S_RIGHT_SHIFT: // signed 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_S_MULTIPLY:
		case SMP_U_DIVIDE:
		case SMP_S_DIVIDE:
		case SMP_U_REMAINDER:
		case SMP_BITWISE_XOR:
		case SMP_BITWISE_AND_NOT:
#if 1
		case SMP_S_COMPARE: // signed compare (subtraction-based)
		case SMP_U_COMPARE: // unsigned compare (AND-based)
#endif
		case SMP_GENERAL_COMPARE:
		case SMP_LESS_THAN: // boolean test operators
		case SMP_GREATER_THAN:
		case SMP_LESS_EQUAL:
		case SMP_GREATER_EQUAL:
		case SMP_EQUAL:
		case SMP_NOT_EQUAL:
		case SMP_BELOW:
		case SMP_BELOW_EQUAL:
		case SMP_ABOVE:
		case SMP_ABOVE_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
		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_FLOATING_ADD:
		case SMP_FLOATING_SUBTRACT:
		case SMP_FLOATING_MULTIPLY:   // floating-point multiplication of any precision; all NUMERIC
		case SMP_FLOATING_DIVIDE:     // floating-point division of any precision; all NUMERIC
		case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; NUMERIC
		case SMP_REVERSE_SHIFT_U:   // all the same to our type system; all NUMERIC
		case SMP_SHUFFLE:   // all the same to our type system; all NUMERIC
		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 inequality 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:  // interleave fields from two packed operands; NUMERIC
		case SMP_CONCATENATE:   // all the same to our type system; all NUMERIC
		case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation
		case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length
			if ((SMP_ZERO_EXTEND == CurrOp) && this->IsRegUpperBitsClearIdiom()) {
				// The zero extension is not movzx rbx,al; it is mov r8d,eax where
				//  the upper 32 bits of R8 get zeroed by the move. EAX could have
				//  any type, and we wish to preserve it.
				UseOp = CurrRT->GetLeftOperand();
				assert((nullptr != UseOp) && (!UseOp->IsVoidOp()));
				CurrUse = this->Uses.FindRef(UseOp);
				if (CurrUse == this->GetLastUse()) {
					SMP_msg("SERIOUS WARNING: Adding missing USE of ");
					PrintOperand(UseOp);
					SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
					this->Uses.SetRef(UseOp, NUMERIC, -1);
					updated = true;
				}
				else if (UNINIT != CurrUse->GetType()) {
					CurrRT->SetOperatorType(CurrUse->GetType(), this);
					updated = true;
				}
			}
			else {
				if (UNINIT == CurrRT->GetOperatorType()) {
					CurrRT->SetOperatorType(NUMERIC, this);
					updated = true;
				}
				// Left operand should be NUMERIC if it exists.
				UseOp = CurrRT->GetLeftOperand();
				if ((nullptr != UseOp) && (!UseOp->IsVoidOp())) {
					CurrUse = this->Uses.FindRef(UseOp);
					if (CurrUse == this->GetLastUse()) {
						SMP_msg("SERIOUS WARNING: Adding missing USE of ");
						PrintOperand(UseOp);
						SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						this->Uses.SetRef(UseOp, NUMERIC, -1);
						updated = true;
					}
					else if (UNINIT == CurrUse->GetType()) {
						CurrUse = this->SetUseType(UseOp, NUMERIC);
						updated = true;
					}
				}
				// Right operand should be NUMERIC if it exists.
				if (CurrRT->HasRightSubTree()) {
					// Recurse into subtree
#if SMP_AGGRESSIVE_TYPE_INFERENCE
					if (UNINIT == CurrRT->GetRightTree()->GetOperatorType()) {
						CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
						updated = true;
					}
#endif
					updated |= this->InferOperatorType(CurrRT->GetRightTree());
				}
				else {
					UseOp = CurrRT->GetRightOperand();
					if ((nullptr != UseOp) && (!UseOp->IsVoidOp())) {
						CurrUse = this->Uses.FindRef(UseOp);
						if (CurrUse == this->GetLastUse()) {
							SMP_msg("SERIOUS WARNING: Adding missing USE of ");
							PrintOperand(UseOp);
							SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
							this->Uses.SetRef(UseOp, NUMERIC, -1);
							updated = true;
						}
						else if (UNINIT == CurrUse->GetType()) {
							CurrUse = this->SetUseType(UseOp, NUMERIC);
							updated = true;
						}
					}
				}
			}
			break;

		case SMP_BITWISE_NOT: // unary operator
		case SMP_NEGATE:    // unary negation
			UseOp = CurrRT->GetLeftOperand();
			assert((nullptr != UseOp) && (! UseOp->IsVoidOp()));
			CurrUse = this->Uses.FindRef(UseOp);
			if (CurrUse == this->GetLastUse()) {
				SMP_msg("SERIOUS WARNING: Adding missing USE of ");
				PrintOperand(UseOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
				updated = true;
			}
			else {
				OperType = CurrRT->GetOperatorType();
				LeftType = CurrUse->GetType();
				// Only tricky cases are the negation of a POINTER or PTROFFSET.
				//  Negation of PTROFFSET could be inefficient code that computed
				//  PTR1 - PTR2 and later corrected it to PTR2 - PTR1 by negation.
				//  The type remains PTROFFSET. Negating a POINTER could be an unusual
				//  case similar to subtracting a POINTER from a NUMERIC. See comments
				//  in the SMP_ADD case below, and also the SMP_SUBTRACT case.
				if (LeftType == PTROFFSET) {
					// Override any prior operator type, in case PTROFFSET was inferred late
					//  in our analysis and the operator was set to NUMERIC.
					CurrRT->SetOperatorType(PTROFFSET, this);
					updated = true;
					if (CurrOp == SMP_BITWISE_NOT)
						SMP_msg("INFO: NOT of PTROFFSET at %llx %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
				}
				else if (IsDataPtr(LeftType)) {
					// Override any prior operator type, in case POINTER was inferred late
					//  in our analysis and the operator was set to NUMERIC.
					CurrRT->SetOperatorType(NEGATEDPTR, this);
					SMP_msg("INFO: Pointer negated at %llx %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
					updated = true;
				}
				else if (OperType == UNINIT) {
					// Default to NUMERIC for most negations.
					CurrRT->SetOperatorType(NUMERIC, this);
					// But, leave left operand type alone, in case an UNINIT operand
					//  might be determined later to be PTROFFSET or NEGATEDPTR.
					//  Leaving it alone causes us not to set TypeInferenceFinished to true
					//  at the end of this function in the UNINIT case.
					updated = true;
				}
			}
			break;

		case SMP_INCREMENT:
		case SMP_DECREMENT:
			// The type of the left operand is propagated to the operator, or vice
			//  versa, whichever receives a type first.
			assert(!CurrRT->HasRightSubTree());
			UseOp = CurrRT->GetLeftOperand();
			assert((nullptr != UseOp) && (! UseOp->IsVoidOp()));
			CurrUse = this->Uses.FindRef(UseOp);
			if (CurrUse == this->GetLastUse()) {
				SMP_msg("SERIOUS WARNING: Adding missing USE of ");
				PrintOperand(UseOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
				this->Uses.SetRef(UseOp);
				updated = true;
				break;
			}
			if (UNINIT == CurrRT->GetOperatorType()) {
				if (UNINIT != CurrUse->GetType()) {
					// Propagate operand type up to the operator.
					CurrRT->SetOperatorType(CurrUse->GetType(), this);
					updated = true;
				}
			}
			else if (UNINIT == CurrUse->GetType()) {
				// Propagate operator type to operand.
				CurrUse = this->SetUseType(UseOp, CurrRT->GetOperatorType());
				updated = true;
			}
			break;

		case SMP_ADD:
		case SMP_ADD_CARRY:   // add with carry
		case SMP_BITWISE_AND:
		case SMP_BITWISE_OR:
			// Extract the current types of right and left operands and the operator.
			OperType = CurrRT->GetOperatorType();
			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());
				RightType = CurrRT->GetRightTree()->GetOperatorType();
			}
			else {
				RightOp = CurrRT->GetRightOperand();
				if ((nullptr == RightOp) || RightOp->IsVoidOp()) {
					SMP_msg("ERROR: void operand at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
					return updated;
				}
				else {
					CurrUse = this->Uses.FindRef(RightOp);
					if (CurrUse == this->GetLastUse()) {
						SMP_msg("SERIOUS WARNING: Adding missing USE of ");
						PrintOperand(RightOp);
						SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						this->Uses.SetRef(RightOp);
						updated = true;
						break;
					}
					else {
						RightType = CurrUse->GetType();
					}
				}
			}

			// 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) && ((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);
			if (UNINIT == OperType) {
				// Infer operator type from left and right operands.
				if (LeftNumeric && RightNumeric) {
					CurrRT->SetOperatorType(NUMERIC, this);
					updated = true;
					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;
						break;
					}
					else if (RightNumeric && (UNINIT != LeftType) 
						&& ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) {
						CurrRT->SetOperatorType(LeftType, this);
						updated = true;
						break;
					}
				}
				else if (LeftPointer && RightPointer) {
					// Arithmetic on two pointers
					if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) {
						CurrRT->SetOperatorType(UNKNOWN, this);
						updated = true;
					}
					else { // bitwise AND or OR of two pointers
						SMP_msg("WARNING: hash of two pointers at %llx in %s\n",
							(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						// hash operation? leave operator as UNINIT
					}
					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);
						updated = true;
					}
					else { // bitwise AND or OR of pointer and pointer difference
						SMP_msg("WARNING: hash of PTROFFSET and POINTER at %llx in %s\n",
							(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						// hash operation? leave operator as UNINIT
					}
					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 %llx in %s\n",
							(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
						// hash operation? leave operator as UNINIT
					}
					break;
				}
				else if (IsEqType(CODEPTR, LeftType) || IsEqType(CODEPTR, RightType)) {
					if ((LeftType <= CODEPTR) && (RightType <= CODEPTR)) {
						// Both types are NUMERIC or UNINIT with one or both of them CODEPTR
						CurrRT->SetOperatorType(CODEPTR, this);
						updated = true;
					}
					else {
						SMP_msg("WARNING: add of CODEPTR and odd type %d plus %d at %llx in %s\n",
							LeftType, RightType, (unsigned long long) 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());
						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;
						}
					}
				}
				else if (OperPointer) {
					// If we add NUMERIC + UNINIT and get POINTER, then the UNINIT is a POINTER.  Ditto for AND and OR.
					if (LeftNumeric && (UNINIT == RightType)) {
						if (CurrRT->HasRightSubTree()) {
							CurrRT->GetRightTree()->SetOperatorType(OperType, this);
						}
						else {
							CurrUse = this->SetUseType(RightOp, OperType);
							updated = true;
							assert(CurrUse != this->GetLastUse());
						}
						break;
					}
					else if (RightNumeric && (UNINIT == LeftType)) {
						CurrUse = this->SetUseType(LeftOp, OperType);
						updated = true;
						assert(CurrUse != this->GetLastUse());
						break;
					}
				}
			}
			break;

		case SMP_SUBTRACT:
		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 ((nullptr == RightOp) || RightOp->IsVoidOp()) {
					SMP_msg("ERROR: void operand in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
					return false;
				}
				else {
					RightUse = this->Uses.FindRef(RightOp);
					if (RightUse == this->GetLastUse()) {
						SMP_msg("WARNING: Adding missing USE of ");
						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);
			if (LeftNumeric) {
				// 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);
					updated = true;
				}
				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 0
				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;
				}
#endif
			} // 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 %llx in %s\n", 
							(unsigned long long) 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) {
#if 0
								// PTR := PTR - ?? ==> ?? is NUMERIC  Why? ?? could be PTROFFSET
								CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
								updated = true;
#endif
								updated |= this->InferOperatorType(CurrRT->GetRightTree());
							}
							else if (OperType == PTROFFSET) {
								// PTROFFSET := PTR - ?? ==> ?? is PTR
								CurrRT->GetRightTree()->SetOperatorType(LeftType, this);
								updated = true;
								updated |= this->InferOperatorType(CurrRT->GetRightTree());
							}
							else if (OperNumeric) {
								SMP_msg("WARNING: PTR - ?? produces NUMERIC at %llx in %s\n", 
									(unsigned long long) 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;
							}
							else if (OperNumeric) {
								SMP_msg("WARNING: PTR - ?? produces NUMERIC at %llx in %s\n", 
									(unsigned long long) 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:
			// 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
			LeftType = CurrDef->GetType();
			if (CurrRT->HasRightSubTree()) {
				updated |= this->InferOperatorType(CurrRT->GetRightTree());
				RightType = CurrRT->GetRightTree()->GetOperatorType();
			}
			else {
				UseOp = CurrRT->GetRightOperand();
				if ((nullptr == UseOp) || UseOp->IsVoidOp()) {
					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()) {
						SMP_msg("WARNING: Adding missing USE of ");
						PrintOperand(UseOp);
						SMP_msg(" in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
						this->Uses.SetRef(UseOp);
						updated = true;
						break;
					}
					else {
						RightType = CurrUse->GetType();
					}
				}
			}

#if SMP_VERBOSE_DEBUG_INFER_TYPES
			if (DebugFlag) {
				SMP_msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->GetAddr(), LeftType,
					OperType, RightType);
			}
#endif
			if ((UNINIT == RightType) && (UNINIT == LeftType)) {
				unsigned short TempSignMask;
				if (this->MDIsReducedWidthMove() && (!this->MDIsSignedLoad(TempSignMask))) {
					CurrDef = this->SetDefType(DefOp, NUMERIC); // e.g. mov al,cl cannot be a POINTER
					updated = true;
					if (!CurrRT->HasRightSubTree()) {
						CurrUse = this->SetUseType(UseOp, NUMERIC);
					}
					assert(UNINIT == OperType);
					CurrRT->SetOperatorType(NUMERIC, this);
				}
				break;
			}
			else if (UNINIT == OperType) {
				// UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT.
				bool UpdatedOperType = false;
				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);
						updated = true;
						OperType = RightType;
						UpdatedOperType = true;
					}
				}
				else { // LeftType must not be UNINIT
					CurrRT->SetOperatorType(LeftType, this);
					updated = true;
					UpdatedOperType = true;
					OperType = LeftType;
				}
				// 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 = (! DefOp->IsRegOp());
						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 ((DefOp->IsRegOp()) || 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, false);
							}
						}
					}
				}
				break;
			}
			else if (UNINIT == LeftType) {
				// SMP_ASSIGN operator has type, so propagate it.
				CurrDef = this->SetDefType(DefOp, OperType);
				LeftType = OperType;
				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 = (! DefOp->IsRegOp());
					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 ((DefOp->IsRegOp()) || 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, false);
						}
					}
				}
				break;
			}
			else if (UNINIT == RightType) {
				// SMP_ASSIGN operator has type, so propagate it.
				if (CurrRT->HasRightSubTree()) {
					CurrRT->GetRightTree()->SetOperatorType(OperType, this);
					updated = true;
					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 %llx for: ",
								CurrUse->GetType(), OperType, (unsigned long long) this->GetAddr());
							PrintOperand(CurrUse->GetOp());
							SMP_msg("\n");
						}
					}
					CurrUse = this->SetUseType(UseOp, OperType);
					updated = true;
					RightType = OperType;
				}
				break;
			}
			break;

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

	// 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
				case SMP_UNARY_POINTER_OPERATION:
					// 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 ((nullptr != UseOp) && (! UseOp->IsVoidOp())) {
							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->IsVoidOp()) {
					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;
				}
			}
			TypeInferenceFinished = (FinishedLeft && FinishedRight);
		} // end if (FinishedOperator)
	} // end if (updated && (!TypeInferenceFinished))
	if (TypeInferenceFinished) {
		CurrRT->SetTypeInferenceComplete();
	}
#if SMP_VERBOSE_DEBUG_INFER_TYPES
	if (updated && DebugFlag) {
		SMP_msg("INFO: Types updated at %llx Left: %d Operator: %d Right: %d\n", (uint64_t) this->GetAddr(),
			LeftType, OperType, RightType);
	}
#endif
	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
		case SMP_SIGNAL: // signal or raise exception
			// 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_S_COMPARE: // signed compare (subtraction-based)
		case SMP_U_COMPARE: // unsigned compare (AND-based)
		case SMP_GENERAL_COMPARE:
		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:
		case SMP_BELOW:
		case SMP_BELOW_EQUAL:
		case SMP_ABOVE:
		case SMP_ABOVE_EQUAL:
		case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation
		case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length
		case SMP_UNARY_POINTER_OPERATION: 
			// 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_FLOATING_ADD:
		case SMP_FLOATING_SUBTRACT:
		case SMP_FLOATING_MULTIPLY:   // floating-point multiplication of any precision; all NUMERIC
		case SMP_FLOATING_DIVIDE:     // floating-point division of any precision; all NUMERIC
		case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; 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_NE_AND_SET: // Compare for inequality 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
			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()

// Transfer function: Does operator propagate width of its operands to its result?
bool SMPInstr::DoesOperatorTransferWidth(SMPoperator CurrOp) {
	bool transfer = true;

	if ((CurrOp == SMP_CONVERT_INT_TO_FP) || (CurrOp == SMP_CONVERT_FP_TO_INT)) {
		transfer = false;
	}
	return transfer;
} // end of SMPInstr::DoesOperatorTransferWidth()

// Adjust signedness based on SSA def-use info.
void SMPInstr::MDFixupSignedness(void) {
	set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef();
	set<DefOrUse, LessDefUse>::iterator UseIter;
	unsigned short SignMask;
	STARSOpndTypePtr DefOp = nullptr;
	int DefSSANum = -1;
	int IdiomCode;
	bool UnderflowOpcode = this->MDIsUnderflowingOpcode();
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();

	if (DefIter != this->GetLastDef()) {
		DefOp = DefIter->GetOp();
		DefSSANum = DefIter->GetSSANum();
	}

	int TypeGroup = SMPTypeCategory[this->GetIDAOpcode()];
	if (this->IsNop())
		TypeGroup = 1; // no-op idioms need their category reset
	if (5 == TypeGroup) {
		this->SetAddSubSourceType();
	}

	if (this->MDIsSignedLoad(SignMask)) {
		assert(nullptr != DefOp);
		// Compilers can generate zero-extensions just to clear unused bits in a register.
		//  We can wrongly infer UNSIGNED for the DEF as a result. The problem can be detected
		//  by seeing whether the zeroed-out bits are ever used. If all USEs of this register DEF
		//  only use the same number of bits as the source operand for the move, then the
		//  zero-extension bits do not mean anything, so we reset the signedness to unknown.
		//  This will hopefully not conflict with other sources of an UNSIGNED inference that
		//  could also have occurred (e.g. a MEDS type of POINTER is unlikely to occur with a 
		//  zero-extended operand).
		if (SignMask == FG_MASK_UNSIGNED) {
			STARSOpndTypePtr MoveSource = this->GetMoveSource();
			std::size_t SourceBitWidth = 8 * MoveSource->GetByteWidth();
			assert(DefIter != this->GetLastDef());
			if (!(IsMemOperand(DefOp) || MDIsFlagsReg(DefOp))) {
				int DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum);
				struct FineGrainedInfo DefUseFGInfo;
				bool LocalName = this->BasicBlock->IsLocalName(DefOp);
				if (LocalName) {
					DefUseFGInfo = this->BasicBlock->GetUseFGInfo(DefHashValue);
				}
				else {
					DefUseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(DefHashValue);
				}
				std::size_t DefUseMaxBitWidth = LargestBitWidthFromMask(DefUseFGInfo.SizeInfo);
				if ((DefUseMaxBitWidth <= SourceBitWidth) && (0 != DefUseMaxBitWidth)) {
					// We never use more bits than the original source had before it was zero-extended.
					//  We exclude the bitwidth==0 special case that signals that it was only used in
					//  a zero-extension or sign-extension move.
					if (LocalName) {
						this->BasicBlock->ClearDefSignedness(DefHashValue);
					}
					else {
						this->BasicBlock->GetFunc()->ClearDefSignedness(DefHashValue);
					}
				}
			}
		}
	}

	// 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
	//  has been set, e.g.:
	//  [arithmetic operation or comparison]
	//  seta al  ; if "above" flag then al := 1 else al := 0
	//  setb bl  ; if "below" flag then bl := 1 else bl := 0
	//  mov ecx,eax  ; make copy of eax (including al) into ecx
	//  sub al,bl ; al := al - bl
	//  The resulting value in al will be 1 if the above flag was set, -1 if below, 0 if neither.
	//  We see the seta/setb as implying unsigned values, which is true, but if al becomes -1
	//   we do not want to consider this to be an underflow.
	//  The same logic applies to overflow opcodes: lea edx,[eax+eax-1] is hard to classify as
	//   potential underflow or overflow. If eax comes from a condition code (seta eax), the values
	//   will be small and no overflow check is needed.
	int UseSSANum;
	bool BenignUnderflow = false;
	if (UnderflowOpcode && MDIsDataFlowOpnd(DefOp, UseFP)) {
		UseIter = this->FindUse(DefOp); // DEF is also USE in subtraction
		assert(UseIter != this->GetLastUse());
		UseSSANum = UseIter->GetSSANum();
		if (this->IsOpSourceConditionCode(DefOp, UseSSANum)) {
			// If we had a decrement opcode, we are done, and underflow is benign.
			if (this->IsDecrementRTL()) {
				BenignUnderflow = true;
			}
			else { // For subtraction, need to see if BOTH operands came from condition codes (flags).
				STARSOpndTypePtr UseOp = CloneIfSubwordReg(this->GetUseOnlyAddSubOp());
				if (MDIsDataFlowOpnd(UseOp, UseFP)) {
					CanonicalizeOpnd(UseOp);
					UseIter = this->FindUse(UseOp);
					assert(UseIter != this->GetLastUse());
					UseSSANum = UseIter->GetSSANum();
					BenignUnderflow = this->IsOpSourceConditionCode(UseOp, UseSSANum);
				}
			}
		}
		if (BenignUnderflow) {
			// We detected a subtraction or decrement that is permitted to produce a negative
			//  result. This means that the DEF is really SIGNED. We don't want to emit
			//  any underflow checks on this instruction, and we also want to propagate SIGNED
			//  as the type of DEF.
			this->SetSuppressNumericAnnotation();
			SignMask = FG_MASK_SIGNED;
			struct FineGrainedInfo NewFG;
			NewFG.SignMiscInfo = SignMask;
			NewFG.SizeInfo = 0;
			// Note that old FG info should be null at this point in FG inference,
			//  so we only have to pass in the SIGNED bits.
			bool MapsChanged = this->UpdateDefOpFGInfo(DefOp, NewFG);
		}
	} // end if Underflow on register

	if (this->MDIsDefiniteBenignUnderflowOpcode(IdiomCode) || this->MDIsSignBitFill()) {
		// We have a pattern that changes sign, e.g. sbb edx,edx puts
		//  0 or -1 in edx; likewise for sar edx,31. This needs no annotation.
		this->SetSuppressNumericAnnotation();
		// Furthermore, if we find add edx,positive_immediate_value
		//  in the SSA chain for this instruction, then we don't want
		//  to get false positives from the addition, which often changes
		//  the temporarily SIGNED value back to its original UNSIGNED:
		//   sbb edx,edx ; if edx is UNSIGNED, false positive when we produce -1.
		//   add edx,2   ; another false positive when we convert (0 or -1) to (1 or 2).
		this->GetBlock()->SuppressAnnotOnSignChangingAddition(DefOp, DefSSANum, this->GetAddr());
	}

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

// 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);
			changed = true;
			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)
		case SMP_GENERAL_COMPARE:
			// 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
#if STARS_NO_SHIFT_SIGNEDNESS_IN_SCALEFACTOR
			if (!this->MDIsLoadEffectiveAddressInstr()) {
				// The left shift in the RTL for lea edx,[ebx+eax*4]
				//  does not imply that EAX is UNSIGNED. For other
				//  unsigned left shift RTLs, UNSIGNED is fine.
				InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
				changed = true;
			}
			break;
#endif
		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_BELOW:
		case SMP_BELOW_EQUAL:
		case SMP_ABOVE:
		case SMP_ABOVE_EQUAL:
		case SMP_UNARY_POINTER_OPERATION:
			InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			changed = true;
			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 multiplication 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;
			changed = true;
			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
		case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
		case SMP_CREATE_MASK: // Create AND-mask from operand and byte/word/dword position # in immediate
		case SMP_SIGNAL:  // signal or raise exception
			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_FLOATING_ADD:
		case SMP_FLOATING_SUBTRACT:
		case SMP_FLOATING_MULTIPLY:   // floating-point multiplication of any precision; all NUMERIC
		case SMP_FLOATING_DIVIDE:     // floating-point division of any precision; all NUMERIC
		case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; NUMERIC
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			InitFG.SizeInfo |= FG_MASK_FLOAT_MMX;
			changed = true;
			break;

		case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
		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 inequality 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_MAX_S: // dest := signed_max(dest, src)
		case SMP_MIN_S: // dest := signed_min(dest, src)
		case SMP_ABSOLUTE_VALUE: // take absolute value
			InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
			// Fall through here to next cases
		case SMP_CONVERT_INT_TO_FP: // convert integer to floating point
		case SMP_CONVERT_FP_TO_INT: // convert floating point to integer
			InitFG.SignMiscInfo |= FG_MASK_SIGNED;
			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
		case SMP_MAX_U: // dest := unsigned_max(dest, src)
		case SMP_MIN_U: // dest := unsigned_min(dest, src)
		case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation
		case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length
			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);
			changed = true;
			break;

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

	return changed;
} // end of SMPInstr::InitFGInfoFromOperator()

// Helper to take USE operand, find its SSANum, and return its UseHashValue.
int SMPInstr::GetUseOpHashAndSSA(const STARSOpndTypePtr &UseOp, int &SSANum) {
	STARSOpndTypePtr SearchOp = CloneIfSubwordReg(UseOp);
	CanonicalizeOpnd(SearchOp);
	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(const STARSOpndTypePtr &DefOp, int &SSANum) {
	STARSOpndTypePtr SearchOp = CloneIfSubwordReg(DefOp);
	CanonicalizeOpnd(SearchOp);
	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(const STARSOpndTypePtr &DefOp, struct FineGrainedInfo NewFG) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	int SSANum;
	int DefHashValue;
	bool LocalName;
	struct FineGrainedInfo OldFG, UnionFG;

	if (DefOp->IsRegOp()) {
		// 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);
		}

		// Get rid of stack access bits being passed around in InferOperatorFGInfo()
		//  for register operands in RTLs.
		NewFG.SignMiscInfo &= FG_MASK_SIGNEDNESS_BITS;

		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' (or the sizes).
			MapsChanged = true;
			if (LocalName)
				this->BasicBlock->UpdateDefFGInfo(DefHashValue, UnionFG);
			else
				this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, UnionFG);
		}
	}
	else if (MDIsDirectStackAccessOpnd(DefOp, this->GetBlock()->GetFunc()->UsesFramePointer())) {
		STARS_ea_t InstAddr = this->GetAddr();
		MapsChanged = this->GetBlock()->GetFunc()->MDUpdateFGStackLocInfo(InstAddr, DefOp, NewFG);
	}

	return MapsChanged;
} // end of SMPInstr::UpdateDefOpFGInfo()

// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
bool SMPInstr::UpdateUseOpFGInfo(const STARSOpndTypePtr &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 (UseOp->IsRegOp()) {
		// 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);
		}

		// Get rid of stack access bits being passed around in InferOperatorFGInfo()
		//  for register operands in RTLs.
		NewFG.SignMiscInfo &= FG_MASK_SIGNEDNESS_BITS;

		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);
			else
				this->BasicBlock->GetFunc()->UpdateUseFGInfo(UseHashValue, UnionFG);
		}
	}
	else if (MDIsDirectStackAccessOpnd(UseOp, this->GetBlock()->GetFunc()->UsesFramePointer())) {
		STARS_ea_t InstAddr = this->GetAddr();
		MapsChanged = this->GetBlock()->GetFunc()->MDUpdateFGStackLocInfo(InstAddr, UseOp, NewFG);
	}

	return MapsChanged;
} // end of SMPInstr::UpdateUseOpFGInfo()

// pass-through to STARS_Instruction_t::MakeRegOpnd()
STARSOpndTypePtr SMPInstr::MakeRegOpnd(STARS_regnum_t RegNum) const {
	return this->STARSInstPtr->MakeRegOpnd(RegNum);
}

// pass-through to STARS_Instruction_t::MakeFloatingPointRegOpnd()
STARSOpndTypePtr SMPInstr::MakeFloatingPointRegOpnd(STARS_regnum_t RegNum) const {
	return this->STARSInstPtr->MakeFloatingPointRegOpnd(RegNum);
}

// pass-through to STARS_Instruction_t::MakeVoidOpnd()
STARSOpndTypePtr SMPInstr::MakeVoidOpnd(void) const {
	return this->STARSInstPtr->MakeVoidOpnd();
}

// pass-through to STARS_Instruction_t::MakeImmediateOpnd()
STARSOpndTypePtr SMPInstr::MakeImmediateOpnd(STARS_uval_t value) const {
	return this->STARSInstPtr->MakeImmediateOpnd(value);
}

// Helper to fetch DEF signedness info for UseOp that has none.
unsigned short SMPInstr::GetDefSignInfoFromUseOp(const STARSOpndTypePtr &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;
	struct FineGrainedInfo RightFG;
	STARSOpndTypePtr LeftOp = nullptr, RightOp = nullptr;
	unsigned short WidthMask, SignMask;
	bool CurrOpTransfersSign = this->DoesOperatorTransferSign(CurrOp);
	bool CurrOpTransfersWidth = this->DoesOperatorTransferWidth(CurrOp);
	bool SpecialTransferCase = false;
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
	bool success;
	int DefHashValue, UseHashValue, SSANum;

#if SMP_AGGRESSIVE_SIGN_TRANSFER
	// 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 multiplication when only the lower
	//  N bits are retained and the upper N bits are discarded.
	// As a result, InitFGInfoFromOperator() did not set FG_MASK_SIGNED
	//  for the result of the multiplication. If we now detect that two
	//  unsigned operands are being multiplied together using the "signed"
	//  multiply operator, we need to transfer UNSIGNED to the result.
	if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) {
		SpecialTransferCase = true;
	}
#endif

	// 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->IsImmedOp()) {
			// If immediate operand is a data address or code address, we can infer that it is unsigned.
			STARS_uval_t ImmVal = RightOp->GetImmedValue();
			if (IsImmedGlobalAddress((STARS_ea_t) ImmVal)) { // NOTE: Can be false. !!!!****!!!!
				// Data address (type GLOBALPTR)
				RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			}
			else if (this->IsInterruptCall() || global_STARS_program->IsImmedCodeAddress((STARS_ea_t) ImmVal)) {
				// Code address (type CODEPTR)
				RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
			}
		}
		else if ((RightOp->IsRegOp()) && !RightOp->MatchesReg(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)
#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 || SpecialTransferCase)) {
				// 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 reg)
		else if (MDIsDirectStackAccessOpnd(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->GetAddr(), 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->IsRegOp()) && !LeftOp->MatchesReg(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 || SpecialTransferCase)) {
				// 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 or SpecialTransferCase 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.
					LeftFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
				}
				else {
					// Get FG info from function level.
					LeftFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
				}
			}
			else { // LeftOp is a DEF
				DefHashValue = this->GetDefOpHashAndSSA(LeftOp, SSANum);
				if (this->BasicBlock->IsLocalName(LeftOp)) {
					// Get FG info from block.
					LeftFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
				}
				else {
					// Get FG info from function level.
					LeftFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
				}
				// See if RightFG has sign info to transfer to LeftFG.
				SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
				unsigned short LeftSignMask = (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
				bool UpdateLeftSignMask = ((SignMask != 0) && (SignMask != LeftSignMask));
#if 1
				if (OpIsDEF && (0 != LeftSignMask)) {
					// We have a signedness value for the DEF operand. These values are
					//  highly reliable, e.g. MEDS type inference detects that the DEF is
					//  a POINTER and therefore it must be UNSIGNED, or the opcode always
					//  produces a SIGNED result, etc. We do not want to produce a mixed
					//  signedness DEF in these cases, regardless of what happens when
					//  we examine operands in the RTLs, because compiler code generation
					//  can produce screwy results that are less reliable than our early
					//  determinations of DEF signedness (e.g. compilers can zero-extend
					//  bytes even though they are signed, and hand-code assembly authors
					//  can sign-extend bytes that are unsigned and get away with it 
					//  because the values are always very small and have a sign bit of zero.)
					UpdateLeftSignMask = false;
				}
#endif
				if (UpdateLeftSignMask) {
					// SignMask from RightFG has bits that will change LeftFG.SignMiscInfo.
					LeftFG.SignMiscInfo |= SignMask;
					MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
				}
			}
		}
#endif
	} // end of register case for LeftOp
	else if (OpIsDEF && MDIsDirectStackAccessOpnd(LeftOp, UseFP) 
		&& (!this->BasicBlock->GetFunc()->IsInOutgoingArgsRegion(LeftOp))) {
		// For stores into the stack, if the operand being stored has signedness
		//  and the stack location has no signedness, then we have a case where
		//  none of the loads from the stack location were signed, so it is
		//  safe to infer signedness of the stack location based on what is being
		//  stored into it, as no store signedness will conflict with load signedness.
		success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), LeftOp, LeftFG);
		assert(success);
		if (0 == (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) {
			// No previous signedness info for the stack location.
			//  Get signedness info from RightFG.
			SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
			if ((0 != SignMask) && (FG_MASK_INCONSISTENT_SIGN != SignMask)) {
				// Operand being stored has signedness.
				//  Transfer the signedness to the stack location.
				struct FineGrainedInfo TempFG;
				TempFG.SignMiscInfo = SignMask;
				TempFG.SizeInfo = 0; // just update signedness
				success = this->BasicBlock->GetFunc()->MDUpdateFGStackLocInfo(this->GetAddr(), LeftOp, TempFG);
				MapsChanged |= success;
			}
		}
	}

	// Prepare to return FG info for operator. First, OR the left and right FG infos.
	if (NewChange || MapsChanged || CurrOpTransfersSign || SpecialTransferCase) {
		OpFG.SignMiscInfo |= LeftFG.SignMiscInfo;
		OpFG.SignMiscInfo |= RightFG.SignMiscInfo;
		if (CurrOpTransfersWidth) {
			OpFG.SizeInfo |= LeftFG.SizeInfo;
			OpFG.SizeInfo |= RightFG.SizeInfo;
		}
	}
	// An operator could override the width or signedness info of its operands.
	if (CurrOp == SMP_ADDRESS_OF) {
		// Result is 32-bit data pointer.
		OpFG.SizeInfo &= (~FG_MASK_BITWIDTH_FIELDS); // clear all width bits
		OpFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_DATAPOINTER);
		OpFG.SignMiscInfo &= (~FG_MASK_SIGNED);
		OpFG.SignMiscInfo |= FG_MASK_UNSIGNED;
	}

	return MapsChanged;
} // end of SMPInstr::InferOperatorFGInfo()


// infer width on first pass, signedness on all passes
bool SMPInstr::InferFGInfo(unsigned short IterCount) {
	bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
	struct FineGrainedInfo OpFG;
	SMPitype DFType = this->GetDataFlowType();

	assert(0 < IterCount); // start IterCount at 1, not 0.


	if (DFType != DEFAULT) {
		// We have a control flow instruction, e.g. call, return, branch, jump
		//  No data operands unless these instructions are indirect through a register,
		//  and the indirect operand is a memory operand in that case, e.g. [eax].
		return MapsChanged;
	}

	if (1 == IterCount) {
		// Fix signedness info now that complete SSA chains have been analyzed.
		this->MDFixupSignedness();
	}

	for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) {
		SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
		if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
			continue;
		OpFG.SignMiscInfo = 0;
		OpFG.SizeInfo = 0;

		MapsChanged |= this->InferOperatorFGInfo(CurrRT, (1 == IterCount), OpFG);
		if (SMP_CALL == CurrRT->GetOperator()) // no LeftOp DEF
			continue;
	} // end for all RTs in the RTL

	return MapsChanged;
} // end of SMPInstr::InferFGInfo()

// Get the meet of the metadata types of all non-flags DEFs.
SMPMetadataType SMPInstr::GetDefMetadataType(void) {
	SMPMetadataType MeetType = DEF_METADATA_UNANALYZED;
	set<DefOrUse, LessDefUse>::iterator CurrDef;

	for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
		SMPMetadataType CurrType;
		STARSOpndTypePtr DefOp = CurrDef->GetOp();
		if (DefOp->MatchesReg(X86_FLAGS_REG))
			continue; // flags are always unused metadata; irrelevant
		CurrType = CurrDef->GetMetadataStatus();
		if (MeetType == CurrType)
			continue; // no meet operation to perform
		// Any time we find USED metadata, that overrides all other types.
		if (0 != (CurrType & DEF_METADATA_USED))
			return CurrType;
		bool MeetUsed = ((MeetType >= DEF_METADATA_USED) && (MeetType < DEF_METADATA_REDUNDANT));
		bool CurrUsed = ((CurrType >= DEF_METADATA_USED) && (CurrType < DEF_METADATA_REDUNDANT));
		if (MeetType == DEF_METADATA_UNANALYZED)
			MeetType = CurrType;
		else if (MeetUsed && CurrUsed) {
			// Two different variations of USED. Union the explanations.
			int TempInt = (int) MeetType;
			TempInt |= (int) CurrType;
			MeetType = (SMPMetadataType) CurrType;
		}
		else if (MeetType < DEF_METADATA_REDUNDANT) {
			// Conflict between types of different DEFs. It could be that
			//  a multiply or divide instruction DEFs EAX and EDX, and one
			//  of them is used in a store and the other is unused. In that
			//  case, the final MeetType is USED and we can return. Or, if
			//  one type is UNUSED and the other is REDUNDANT, we can set
			//  the final type to the REDUNDANT type and return. The USED case
			//  is handled above, so we must have the UNUSED vs. REDUNDANT case.
			assert(CurrType >= DEF_METADATA_REDUNDANT);
			MeetType = CurrType;
		}
		else { // MeetType REDUNDANT, not equal to CurrType.
			if (CurrType >= DEF_METADATA_REDUNDANT) {
				// One type is profile derived, both are REDUNDANT.
				MeetType = DEF_METADATA_PROF_REDUNDANT;
			}
			else {
				assert(DEF_METADATA_UNUSED == CurrType);
				// leave MeetType as REDUNDANT
			}
		}
	} // end for all DEFs

	return MeetType;
} // end of SMPInstr::GetDefMetadataType()

// last inst in optimized top-testing loop will fall through to relocated loop header block
bool SMPInstr::IsLastInstInOptimizedLoop(bool &DoubleTailBlock) {
	bool SpecialLastInst = false;
	if ((this->GetBlock()->GetLastAddr() == this->GetAddr()) && this->GetBlock()->IsLoopTailBlock()) {
		int LoopHeaderBlockNum = this->GetBlock()->GetLoopHeaderNumber();
		assert(0 <= LoopHeaderBlockNum);
		SMPBasicBlock *HeaderBlock = this->GetBlock()->GetFunc()->GetBlockByNum((size_t) LoopHeaderBlockNum);
		SpecialLastInst = HeaderBlock->IsOptimizedTopLoopTest();
		if (SpecialLastInst)
			DoubleTailBlock = this->GetBlock()->IsDoubleLoopTailBlock();
	}
	return SpecialLastInst;
} // end of SMPInstr::IsLastInstInOptimizedLoop()

// Are numeric values from a system call trusted input, so that all numeric errors
//  derived from the returned values should be treated as benign?
bool SMPInstr::IsNumericTrustedSystemCall(void) {
	bool TrustedCall = false;
	if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) {
		// We have a resolved call target address, either via direct or indirect call.
		string FuncName = this->GetTrimmedCalledFunctionName();
		TrustedCall = global_STARS_program->IsNumericSafeSystemCall(FuncName);
	}

	return TrustedCall;
} // end of SMPInstr::IsNumericTrustedSystemCall()

// Is register RegNum dead coming into this function, based on the DeadRegsBitmap?
bool SMPInstr::IsIncomingRegDead(int RegNum) {
	bool RegDead = true;
	if ((0 <= RegNum) && (RegNum < ((int) this->DeadRegsBitmap.size()))) {
		RegDead = this->DeadRegsBitmap[(std::size_t) RegNum];
	}
	return RegDead;
} // end of SMPInstr::IsIncomingRegDead()

// Handle x86 opcode SIB byte annotations.
void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, const STARSOpndTypePtr &Opnd, STARS_ea_t offset, bool UseFP) {
	int BaseReg;
	int IndexReg;
	STARS_ea_t displacement;
	uint16_t ScaleFactor;
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
	int SignedOffset = (int) offset;

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

	if (BaseReg == MD_STACK_POINTER_REG) { // ESP cannot be IndexReg
		// ESP-relative constant offset
		SMP_fprintf(AnnotFile,
				"%18llx %6d PTRIMMEDESP STACK %d displ %s\n",
				(unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm);
	}
	else if (UseFP && ((IndexReg == MD_FRAME_POINTER_REG) || (BaseReg == MD_FRAME_POINTER_REG))) {
		// EBP-relative constant offset
		SMP_fprintf(AnnotFile,
				"%18llx %6d PTRIMMEDEBP STACK %d displ %s\n",
				(unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm);
	}

	return;
} // end of MDAnnotateSIBStackConstants

// Emit annotations for constants used as ptr offsets from EBP or
//  ESP into the stack frame. Only pay attention to EBP-relative
//  offsets if EBP is being used as a frame pointer (UseFP == true).
void SMPInstr::AnnotateStackConstants(bool UseFP, FILE *AnnotFile) {
	STARS_ea_t offset;
	int BaseReg;
	int IndexReg;
	uint16_t ScaleFactor;
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
	int SignedOffset;

#if 0
	if (this->GetAddr() == 0x80925f4) {
		SMP_msg("PROBLEM INSTRUCTION: \n");
		this->PrintOperands();
	}
#endif
	for (int i = 0; i < STARS_UA_MAXOP; ++i) {
		STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(i);
		if (nullptr == Opnd) // finished processing operands
			break;
		if (Opnd->IsMemDisplacementOp() || Opnd->IsMemNoDisplacementOp())
			MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
		SignedOffset = (int) offset;

		if (Opnd->IsMemDisplacementOp()) {
			if (Opnd->HasSIBByte()) {
				MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
			}
			else { // no SIB
				if (BaseReg == MD_STACK_POINTER_REG) {
					// ESP-relative constant offset
					SMP_fprintf(AnnotFile,
							"%18llx %6d PTRIMMEDESP STACK %d displ %s\n",
							(unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm);
				}
				else if (UseFP && (BaseReg == MD_FRAME_POINTER_REG)) {
					// EBP-relative constant offset
					SMP_fprintf(AnnotFile,
							"%18llx %6d PTRIMMEDEBP STACK %d displ %s\n",
							(unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm);
				}
			} // end if (Opnd.hasSIB) ... else ...
		} // end if (Opnd.type == o_displ) 
		else if (Opnd->IsMemNoDisplacementOp()) {
			offset = 0; // mmStrata thinks [esp] is [esp+0]
			if (Opnd->HasSIBByte()) {
				MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
			}
			else { // Something like [ecx]; is it [esp] or [ebp] ?
				if (BaseReg == MD_STACK_POINTER_REG) {
					// ESP-relative constant offset
					SMP_fprintf(AnnotFile,
							"%18llx %6d PTRIMMEDESP STACK %d displ %s\n",
							(unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm);
				}
				else if (UseFP && (BaseReg == MD_FRAME_POINTER_REG)) {
					// EBP-relative constant offset
					SMP_fprintf(AnnotFile,
							"%18llx %6d PTRIMMEDEBP STACK %d displ %s\n",
							(unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm);
				}
			} // end if (Opnd.hasSIB) ... else ...
		} // end else if (Opnd.type == o_phrase)
	} // end for all operands

	// If we move a stack pointer or frame pointer into another register, we
	//  need to annotate the implicit zero offset, e.g. mov edi,esp == mov edi,esp+0
	//  and edi is becoming a stack pointer that mmStrata needs to track.
	if (this->MDIsStackPointerCopy(UseFP)) {
		// Two possibilities: a move of the stack pointer, or an "lea"
		//  opcode, e.g. lea eax,[esp+8] ==> eax:=esp+8. In the move
		//  instruction (e.g. mov eax,esp), we have the implicit zero
		//  offset from the stack pointer register, but in the lea case,
		//  we might have zero or some other offset (lea eax,[esp] has
		//  the implicit zero).
		int ESPoffset = 0;
		if (this->MDIsLoadEffectiveAddressInstr()) {
			ESPoffset = this->MDGetImmedUse();
		}
		// NOTE: Looks like this next line should be "else" because an lea instruction
		//  looks like it has a memory operand, hence it has already been handled above.
		//  We are getting duplicate annotations for lea instructions.
		else {
			if (UseFP && this->GetFirstUse()->GetOp()->MatchesReg(MD_FRAME_POINTER_REG)) {
				SMP_fprintf(AnnotFile,	"%18llx %6d PTRIMMEDEBP STACK %d displ %s\n",
						(unsigned long long) this->GetAddr(), this->GetSize(), ESPoffset, disasm);
			}
			else {
				SMP_fprintf(AnnotFile,	"%18llx %6d PTRIMMEDESP STACK %d displ %s\n",
						(unsigned long long) this->GetAddr(), this->GetSize(), ESPoffset, disasm);
			}
		}
	}

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

// emit all reasons that fast returns are unsafe, or emit that they are safe.
void SMPInstr::EmitFastReturnStatus(unsigned short FastReturnStatus) {
	SMPitype FlowType = this->GetDataFlowType();
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
	char InstrString[12];

	if (FlowType == CALL) {
		SMP_snprintf(InstrString, 10, "CALL");
	}
	else if (FlowType == INDIR_CALL) {
		SMP_snprintf(InstrString, 10, "INDIRCALL");
	}
	else if (FlowType == RETURN) {
		SMP_snprintf(InstrString, 10, "RETURN");
	}
	else {
		SMP_msg("ERROR: EmitFastReturnStatus: Invalid data flow type at %llx \n", (unsigned long long) this->GetAddr());
		return;
	}

	SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR %s ",
		(unsigned long long) this->GetAddr(), this->GetSize(), InstrString);

	if (!global_STARS_program->ShouldSTARSPerformFullAnalysis()) {
		SMP_fprintf(global_STARS_program->GetCallReturnFile(), "NOFASTRETURN REDUCEDANALYSIS");
	}
	else if (FastReturnStatus == SAFE_FAST_RETURN) {
		SMP_fprintf(global_STARS_program->GetCallReturnFile(), "FASTRETURN ");
	}
	else {
		// Iterate through possible reasons and print each reason.
		SMP_fprintf(global_STARS_program->GetCallReturnFile(), "NOFASTRETURN ");
		if (UNSAFE_RETURN_ADDRESS & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "RAUNSAFE ");
		}
		if (RETURN_ADDRESS_WRITE & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "RAWRITE ");
		}
		if (RETURN_ADDRESS_READ & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "RAREAD ");
		}
		if (INDIRECTLY_CALLED & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "INDIRECT ");
		}
		if (NO_CALLERS & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "NOCALLERS ");
		}
		if (TAIL_CALL_TARGET & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "TAILCALLED ");
		}
		if (MAKES_TAIL_CALL & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "MAKES_TAIL_CALL ");
		}
		if (MULTIPLE_ENTRY_POINTS & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "MULTIENTRY ");
		}
		if (UNRESOLVED_INDIR_JUMP & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "INDIRJUMP ");
		}
		if (EH_FRAME_ENTRY & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "EXCEPTION_HANDLING ");
		}
		if (RAUNSAFE_CALLEES & FastReturnStatus) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(), "UNSAFE_CALLEES ");
		}
	}
	SMP_fprintf(global_STARS_program->GetCallReturnFile(), "ZZ %s \n", disasm);

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

// Emit fast return and unsafe return address info into *.STARScallreturn file
void SMPInstr::EmitCallReturnStatus(SMPProgram *CurrProg) {
	SMPitype FlowType = this->GetDataFlowType();
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
	bool ValidFunc = ((NULL != this->GetBlock()) && (NULL != this->GetBlock()->GetFunc()));

	if (CALL == FlowType) {
		STARS_ea_t CalleeAddr = this->GetCallTarget();
		SMPFunction *CalleeFunc = NULL;
		if (ValidFunc) {
			CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalleeAddr);
		}
		else if (NULL != CurrProg) {
			CalleeFunc = CurrProg->FindFunction(CalleeAddr);
		}
		if (nullptr == CalleeFunc) {
			SMP_msg("ERROR: Cannot find callee function for CALL at %llx \n", (unsigned long long) this->GetAddr());
			SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR CALL RAUNSAFE %s\n",
				(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
			this->EmitFastReturnStatus((unsigned short) NO_CALLERS);
		}
		else {
			FuncType RetAddrStatus = CalleeFunc->GetReturnAddressStatus();
			unsigned short FastReturnStatus = CalleeFunc->GetFastReturnStatus();
			if (FUNC_SAFE != RetAddrStatus) {
				SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR CALL RAUNSAFE %s\n",
					(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
			}
			else {
				SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR CALL RASAFE %s\n",
					(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
			}
			this->EmitFastReturnStatus(FastReturnStatus);
		}
	}
	else if (INDIR_CALL == FlowType) {
		STARS_ea_t CalleeAddr = this->GetCallTarget();
		if ((STARS_BADADDR == CalleeAddr) || (!global_STARS_program->ShouldSTARSPerformFullAnalysis())) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR INDIRCALL RAUNSAFE UNKNOWNTARGET %s\n",
				(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
			unsigned short DummyReturnStatus = INDIRECTLY_CALLED;
			this->EmitFastReturnStatus(DummyReturnStatus);
		}
		else {
			SMPFunction *CalleeFunc = NULL;
			if (ValidFunc) {
				CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalleeAddr);
			}
			else if (NULL != CurrProg) {
				CalleeFunc = CurrProg->FindFunction(CalleeAddr);
			}
			if (nullptr == CalleeFunc) {
				SMP_msg("ERROR: Cannot find callee function for CALL at %llx \n", (unsigned long long) this->GetAddr());
				SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR CALL RAUNSAFE %s\n",
					(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
				this->EmitFastReturnStatus((unsigned short) NO_CALLERS);
			}
			else {
				FuncType RetAddrStatus = CalleeFunc->GetReturnAddressStatus();
				unsigned short FastReturnStatus = CalleeFunc->GetFastReturnStatus();
				if (FUNC_SAFE != RetAddrStatus) {
					SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR INDIRCALL RAUNSAFE %s\n",
						(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
				}
				else {
					SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR INDIRCALL RASAFE %s\n",
						(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
				}
				this->EmitFastReturnStatus(FastReturnStatus);
			}
		}
	}
	else if (RETURN == FlowType) {
		if (this->IsCondTailCall()) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR CALL CONDTAILCALL %s\n",
				(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
		}
		else if (this->IsTailCall()) {
			SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR CALL TAILCALL %s\n",
				(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
		}
		else if (this->HasReturnOpcode()) {
			FuncType RetAddrStatus = FUNC_UNSAFE;
			unsigned short FastReturnStatus = NO_CALLERS;
			if (ValidFunc) {
				RetAddrStatus = this->GetBlock()->GetFunc()->GetReturnAddressStatus();
				FastReturnStatus = this->GetBlock()->GetFunc()->GetFastReturnStatus();
			}
			
			if (FUNC_SAFE == RetAddrStatus) {
				SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR RETURN RASAFE %s\n",
					(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
			}
			else {
				SMP_fprintf(global_STARS_program->GetCallReturnFile(),	"%18llx %6d INSTR RETURN RAUNSAFE %s\n",
					(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
			}
			this->EmitFastReturnStatus(FastReturnStatus);
		}
		else {
			SMP_msg("ERROR: Unknown instruction with RETURN data flow type at %llx \n", (unsigned long long) this->GetAddr());
		}
	}

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

// Emit all annotations for the instruction in the absence of RTL type inference.
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile, SMPProgram *CurrProg) {
	if (!this->HasGoodRTL())
		return;

	STARS_ea_t addr = this->GetAddr();
	SMPitype DataFlowType = this->GetDataFlowType();
	int OptType = this->GetOptType();
#if 0  // wait on INDIR_CALL until we have good targets and sound analysis
	bool CallInst = ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall());
#else
	bool CallInst = ((CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall());
#endif
	bool IndirJumpInst = (INDIR_JUMP == DataFlowType);
	bool IndirJumpAnalyzed = IndirJumpInst && (NULL != this->GetBlock()) && (!this->GetBlock()->GetFunc()->HasUnresolvedIndirectJumps());
	bool MemDest = this->HasDestMemoryOperand();
	bool MemSrc = this->HasSourceMemoryOperand();
	bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(); 	// assumes 2nd source is Imm or not-numeric?!
	bool NoWarnFlag = false; // NOWARN annotation emitted?
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());

#if SMP_CHILDACCESS_ALL_CODE
	bool OrphanCode = (NULL == this->BasicBlock);
	ProfilerInformation *ProfInfo = NULL;
	if (!OrphanCode)
		ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
#endif

	global_STARS_program->IncrementOptCount(this->GetOptType()); // keep count for debugging info

#if SMP_ANNOTATE_ALL_MEMORY_OPERANDS
	// Emit informational annotations for memory operands.
	if (MemSrc) {
		STARSOpndTypePtr MemSrcOp = this->MDGetMemUseOp();
		std::size_t SrcBitWidth = 8 * MemSrcOp->GetByteWidth();
		STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemSrcOp, UseFP);
		// Need to unnormalize stack memory DEFs and USEs before printing annotations.
		this->MDGetUnnormalizedOp(AnnotDefOp);
		SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSRC %d", (unsigned long long) addr, this->GetSize(), SrcBitWidth);
		AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit());
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	}
	if (MemDest) {
		STARSOpndTypePtr MemDestOp = this->MDGetMemDefOp();
		std::size_t DestBitWidth = 8 * MemDestOp->GetByteWidth();
		STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemDestOp, UseFP);
		// Need to unnormalize stack memory DEFs and USEs before printing annotations.
		this->MDGetUnnormalizedOp(AnnotDefOp);
		SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMDEF %d", (unsigned long long) addr, this->GetSize(), DestBitWidth);
		AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit());
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	}
#endif

	// If the instruction is a CALL (or INDIR_CALL that has been resolved to
	//  a single target address), then we need to see if the call is to a 
	//  function that has been forbidden by a security policy. If so, we
	//  need to output a security alert.
	// In the near future, we will output SPRI instrumentation to prevent
	//  the system/library call from executing.
	if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) {
		// We have a resolved call target address, either via direct or indirect call.
		string FuncName = this->GetTrimmedCalledFunctionName();
		ZST_SysCallType FuncCallType = global_STARS_program->GetCallTypeFromFuncName(FuncName);
		ZST_Policy FuncCallPolicy = global_STARS_program->GetPolicyFromCallType(FuncCallType);
		if (ZST_DISALLOW == FuncCallPolicy) {
			if ((NULL != this->GetBlock()) && (NULL != this->GetBlock()->GetFunc())) {
				SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM: Call to %s will be disallowed at %llx in %s\n", 
					FuncName.c_str(), (unsigned long long) this->GetAddr(), this->GetBlock()->GetFunc()->GetFuncName());
			}
			else {
				SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM: Call to %s will be disallowed at %llx\n",
					FuncName.c_str(), (unsigned long long) this->GetAddr());
			}
			SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]);
			SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR SECURITYCALL Disallow 1 1 %s \n",
				(unsigned long long) addr, this->GetSize(), disasm);
		}
	}


#if SMP_DEBUG_MEM
	if (MemDest || MemSrc) {
		SMP_msg("OptType: %d %s", OptType, disasm);
		this->PrintOperands();
	}
#endif

	// Emit appropriate optimization annotations.
	bool SDTInstrumentation = false;
	switch (OptType) {
		case 0:  // SDT will have to handle these
		{
#if SMP_DEBUG_TYPE0
			SMP_msg("OptType 0: %llx  %s\n", (unsigned long long) addr, disasm);
#endif
			// mmStrata wants to suppress warnings on the PUSH
			//  instructions that precede the LocalVarsAllocInstr
			//  (i.e. the PUSHes of callee-saved regs).
			if ((!AllocSeen || !NeedsFrame) && this->MDIsPushInstr()) {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL NoWarn %s \n",
						(unsigned long long) addr, -3, disasm);
				NoWarnFlag = true;
			}
			else {
				SDTInstrumentation = true;
			}
			break;
		}

		case 1:  // nothing for SDT to do
		{	SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n",
					(unsigned long long) addr, -1, OptExplanation[OptType], disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			break;
		}

		case 4:  // INC, DEC, etc.: no SDT work unless MemDest
		{	if (MemDest || MemSrc) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL Always1stSrc %s \n",
					(unsigned long long) addr, -1, disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			break;
		}

		case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
		{	if (MemDest || MemSrc) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			if (SecondSrcOperandImmNum 
				&& !this->MDIsFrameAllocInstr()
#if SPECIAL_CASE_CARRY_BORROW
				&& (this->GetIDAOpcode() != STARS_NN_adc)
				&& (this->GetIDAOpcode() != STARS_NN_sbb)
#endif
				) { // treat as category 1
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n",
						(unsigned long long) addr, -1, OptExplanation[OptType], disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			else {
				SDTInstrumentation = true;
			}
			break;
		}

		case 6: // Only OS code should include these; problem for SDT
		{	if (MemDest) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL AlwaysPTR %s \n",
					(unsigned long long) addr, -OptType, disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			break;
		}

		case 8: // Implicitly writes to EDX:EAX, always numeric.
		{	SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
					(unsigned long long) addr, -2, OptExplanation[OptType], disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			SDTInstrumentation = true;
			break;
		}

		case 9:  // Either writes to FP reg (cat. 1) or memory (cat. 0)
		{	if (MemDest) {
#if SMP_DEBUG2
				// MemDest seems to happen too much.
				SMP_msg("Floating point MemDest: %s \n", disasm);
#endif
				SDTInstrumentation = true;
				break; // treat as category 0
			}
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n",
					(unsigned long long) addr, -1, OptExplanation[OptType], disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			break;
		}

		case 10: // Implicitly writes to EDX:EAX and ECX, always numeric.
		{	SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ECX ZZ %s %s \n",
					(unsigned long long) addr, -2, OptExplanation[OptType], disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			SDTInstrumentation = true;
			break;
		}

		default: // 2,3,7: Optimization possibilities depend on operands
		{ 
#if SMP_DEBUG2
			if (OptType ==  3) {  // MOV instr class
				if (MemDest) {
					SMP_msg("MemDest on MOV: %s\n", disasm);
				}
				else if (!SecondSrcOperandNum) {
					SMP_msg("MOV: not 2nd op numeric: %s\n", disasm);
						this->PrintOperands();
				}
			}
#endif
			SDTInstrumentation = true;
			if (MemDest) {
#if SMP_DEBUG_XOR
				if (this->GetOptType() == 2)
					SMP_msg("MemDest on OptType 2: %s\n", disasm);
#endif
				break;  // treat as category 0
			}
			if ((this->GetOptType() == 2) || (this->GetOptType() == 7) || SecondSrcOperandImmNum) {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s %s %s \n",
					(unsigned long long) addr, -2, this->DestString(this->GetOptType()),
						OptExplanation[this->GetOptType()], disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			break;
		}
	} // end switch (OptType)

	// always emit stack constant annotations, in case strata is 
	// instrumenting all instructions, or trying to verify speculative annotations. 
	this->AnnotateStackConstants(UseFP, AnnotFile);
	
	// If mmStrata is going to have to deal with the
	//  instruction, then we can annotate EBP and ESP
	//  relative constant offsets. If we have emitted
	//  an annotation of type -1, there is no point
	//  in telling mmStrata about these constants.
	// Likewise, we can tell mmStrata if a MemDest is an
	//  non-directly-accessed child object.
	if (SDTInstrumentation || NoWarnFlag || CallInst || IndirJumpAnalyzed) {
		if (this->DeadRegsBitmap.any()) {
			// Optimize by informing mmStrata of dead registers. It can avoid saving
			//  and restoring dead state. This is particularly important for EFLAGS,
			//  as restoring the flags is a pipeline serializing instruction.
			this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm);
		}
#if SMP_CHILDACCESS_ALL_CODE
		int ChildOffset, ChildSize;
		if (MemDest && !OrphanCode
			&& ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr,
			ChildOffset, ChildSize)) {
			SMP_fprintf(AnnotFile, "%18llx %6zu INSTR CHILDACCESS %d %d ZZ %s \n",
				(unsigned long long) addr, this->GetSize(), ChildOffset, ChildSize, disasm);
		}
#endif
	}

	if ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || (RETURN == DataFlowType))  {
		this->EmitCallReturnStatus(CurrProg);
	}

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

/**
 * Emits Safe Returns
 * Mark the type of  the annotation as "-4". Currently  the SDT is ignoring this
 * annotation. 
 */ 
void SMPInstr::EmitSafeReturn(FILE *AnnotFile)
{
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
	SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL SafeReturn %s\n",
		(unsigned long long) this->GetAddr(), -4, disasm);
}

// Emit all annotations for the instruction using RTL type inference.
void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile) {
	STARS_ea_t addr = this->GetAddr();
	int TypeGroup = SMPTypeCategory[this->GetIDAOpcode()];
	SMPitype DataFlowType = this->GetDataFlowType();
#if 0  // wait on INDIR_CALL until we have good targets and sound analysis
	bool CallInst = ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall());
#else
	bool CallInst = ((CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall());
#endif
	bool IndirJumpInst = (INDIR_JUMP == DataFlowType);
	bool IndirJumpAnalyzed = IndirJumpInst && (!this->GetBlock()->GetFunc()->HasUnresolvedIndirectJumps());
	bool NumericDEFs = this->AllDefsNumeric();  // all DEFs are NUMERIC or CODEPTR
	bool ProfiledDEFs = this->AnyDefsProfiled();  // Some DEFs come from the profiler
	bool UnusedMetadata = this->AllDefMetadataUnused();
	bool MemDest = this->HasDestMemoryOperand();
	bool MemSrc = this->HasSourceMemoryOperand();
	bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(); // assumes 2nd source is imm or not-numeric??
	bool NoWarnFlag = false; // NOWARN annotation emitted?
	bool CarryBorrow = ((this->GetIDAOpcode() == STARS_NN_adc) || (this->GetIDAOpcode() == STARS_NN_sbb));
	// Do we have the special case in which a non-NUMERIC comes into
	//  an add with carry or subtract with borrow and the result
	//  has been inferred to be NUMERIC?
	bool TypeChange = CarryBorrow && (!IsNumeric(this->AddSubDefUseType)) && NumericDEFs;
	SMPMetadataType DefMetadataType = this->GetDefMetadataType();
	ProfilerInformation *ProfInfo;
	ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());

	global_STARS_program->IncrementOptCount(this->GetOptType()); // keep count for debugging info

	if (this->IsNop())
		TypeGroup = 1; // no-op idioms need their category reset

	// Emit appropriate optimization annotations.
	bool SDTInstrumentation = false;

#if 1
	// Find moves of code or data pointer constants.
	bool ValueFound = false;
	STARS_uval_t ConstValue;
	if (this->MDIsSimpleAssignment(ValueFound, ConstValue)) {
		if (ValueFound && (0 != ConstValue)) {
			// Assignment of constant.
			STARSDefUseIter DefIter = this->GetFirstDef();
			assert(DefIter != this->GetLastDef());
			SMPOperandType DefType = DefIter->GetType();
			if (IsCodePtr(DefType)) {
				SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR CODEPTR %llx %s\n",
					(uint64_t) addr, this->GetSize(), (uint64_t) ConstValue, disasm);
			}
			else if (IsDataPtr(DefType)) {
				SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR DATAPTR %llx %s\n",
					(uint64_t) addr, this->GetSize(), (uint64_t) ConstValue, disasm);
			}
		}
	}
#endif

	// In case we short circuit this function due to redundant or unused metadata, etc.,
	//  perform analyses that are useful to integer error annotations.

#if SMP_ANNOTATE_ALL_MEMORY_OPERANDS
	// Emit informational annotations for memory operands.
	if (MemSrc) {
		STARSOpndTypePtr MemSrcOp = this->MDGetMemUseOp();
		std::size_t SrcBitWidth = 8 * MemSrcOp->GetByteWidth();
		STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemSrcOp, UseFP);
		// Need to unnormalize stack memory DEFs and USEs before printing annotations.
		this->MDGetUnnormalizedOp(AnnotDefOp);
		SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSRC %zu", (unsigned long long) addr, this->GetSize(), SrcBitWidth);
		AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit());
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	}
	if (MemDest) {
		STARSOpndTypePtr MemDestOp = this->MDGetMemDefOp();
		std::size_t DestBitWidth = 8 * MemDestOp->GetByteWidth();
		STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemDestOp, UseFP);
		// Need to unnormalize stack memory DEFs and USEs before printing annotations.
		this->MDGetUnnormalizedOp(AnnotDefOp);
		SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMDEF %zu", (unsigned long long) addr, this->GetSize(), DestBitWidth);
		AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit());
		SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
	}
#endif

	// If the instruction is a CALL (or INDIR_CALL that has been resolved to
	//  a single target address), then we need to see if the call is to a 
	//  function that has been forbidden by a security policy. If so, we
	//  need to output a security alert.
	// In the near future, we will output SPRI instrumentation to prevent
	//  the system/library call from executing.
	if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) {
		// We have a resolved call target address, either via direct or indirect call.
		string FuncName = this->GetTrimmedCalledFunctionName();
		ZST_SysCallType FuncCallType = global_STARS_program->GetCallTypeFromFuncName(FuncName);
		ZST_Policy FuncCallPolicy = global_STARS_program->GetPolicyFromCallType(FuncCallType);
		if (ZST_DISALLOW == FuncCallPolicy) {
			SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM: Call to %s will be disallowed at %llx in %s\n",
				FuncName.c_str(), (unsigned long long) this->GetAddr(), this->GetBlock()->GetFunc()->GetFuncName());
			SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]);
			SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR SECURITYCALL Disallow 1 1 %s \n",
				(unsigned long long) addr, this->GetSize(), disasm);
		}
		if (global_STARS_program->ShouldSTARSPerformConstantPropagation()) {
			// See if we propagated constants to any outgoing args for the CALL.
			if (global_STARS_program->ShouldSTARSMaximizeCFGImprovement()) {
				this->EmitConstOutArgAnnotations(InfoAnnotFile);
			}
		}
	}

	if ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || (RETURN == DataFlowType))  {
		this->EmitCallReturnStatus();
	}

	// If the DEF metadata is all unused, mmStrata can skip the instruction.
	//  We omit this for groups 1 and 14, so that the metadata analysis
	//  does not get statistical credit for instructions that were already
	//  getting -1 annotations without analysis.
	// We also cannot skip STARS_NN_adc and STARS_NN_sbb instructions that change the
	//  type of the incoming register.
	if ((1 != TypeGroup) && (14 != TypeGroup) && (!this->IsInterruptCall())
		&& !TypeChange) {
		if (UnusedMetadata) {
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL MetadataUnused %s \n",
						(unsigned long long) addr, -1, disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm);
			return;
		}
		else if (DEF_METADATA_REDUNDANT == DefMetadataType) {
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL MetadataRedundant %s \n",
						(unsigned long long) addr, -1, disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm);
			return;
		}
		else if (DEF_METADATA_PROF_REDUNDANT == DefMetadataType) {
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL MetadataRedundant %s \n",
						(unsigned long long) addr, -257, disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			// Profiler annotations could be backed off due to false
			//  positives, in which case we will need stack constant
			//  annotations.
			this->AnnotateStackConstants(UseFP, AnnotFile);
			this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm);
			return;
		}
	}

	switch (TypeGroup) {
		case 0:  // SDT will have to handle these
		case 11: // PUSH/POP  **!!** What if we push/pop NUMERIC type? Optimize?

			// --jdh
			// pop numeric's can be optimized with a numericdef annotation.
			// numeric push's can't immediately be optimized, but if the stack location
			// can be proven as dead metadata, then perhaps optimize.
			// --jdh

			// mmStrata wants to suppress warnings on the PUSH
			//  instructions that precede the LocalVarsAllocInstr
			//  (i.e. the PUSHes of callee-saved regs).
			if ((!AllocSeen || !NeedsFrame) && this->MDIsPushInstr()) {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL NoWarn %s \n",
						(unsigned long long) addr, -3, disasm);
				NoWarnFlag = true;
			}
			else if (this->MDIsPopInstr() && NumericDEFs) {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n",
						(unsigned long long) addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->GetOptType()),
						disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			else {
				SDTInstrumentation = true;
			}
			break;

		case 1:  // nothing for SDT to do
		case 14:
			if (MemDest) {
				SMP_msg("ERROR: MemDest in Type Category 1 or 14: %llx %s\n", (unsigned long long) addr, disasm);
				SDTInstrumentation = true;
				break;
			}
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n",
					(unsigned long long) addr, -1, OptExplanation[this->GetOptType()], disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			break;

		case 4:  // INC, DEC, etc.: no SDT work unless MemDest
			if (MemDest || MemSrc) { // pretty conservative here?
						// could be more aggressive if we know there's no overflow. -- jdh
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL Always1stSrc %s \n",
					(unsigned long long) addr, -1, disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			break;

		case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
#if 1
			if (MemDest) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
#endif
			if (SecondSrcOperandImmNum 
				&& !this->MDIsFrameAllocInstr()
				&& !TypeChange
#if SPECIAL_CASE_CARRY_BORROW
				&& (!CarryBorrow)
#endif
				) {
				// treat as category 1
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n",
						(unsigned long long) addr, -1, OptExplanation[this->GetOptType()], disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			else if (IsEqType(NUMERIC, this->AddSubSourceType)
				&& !this->MDIsFrameAllocInstr()
				&& !TypeChange
#if SPECIAL_CASE_CARRY_BORROW
				&& (!CarryBorrow)
#endif
				) {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL 2ndSrcNumeric %s \n",
						(unsigned long long) addr, -1, disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			else if (NumericDEFs) {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n",
					(unsigned long long) addr, ProfiledDEFs ? -256 - 2 : -2, this->DestString(this->GetOptType()), disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
#if SMP_OPTIMIZE_ADD_TO_NUMERIC
			else if ((STARS_NN_add == this->GetIDAOpcode()) && (!MemSrc)
				&& IsNumeric(this->AddSubDefUseType)) {
				// reg1 := reg1 + reg2, where reg1 comes in as NUMERIC,
				//  means that reg1 will get DEFed to the type of reg2,
				//  whatever it is. If reg2 were known to be NUMERIC,
				//  we would have hit one of the annotation cases above.
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s := %s ZZ AddToNumeric %s \n",
					(unsigned long long) addr, -5, MDGetRegName(this->GetDefUseAddSubOp()),
					MDGetRegName(this->GetUseOnlyAddSubOp()), disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
#endif
			else {
				SDTInstrumentation = true;
			}
			break;

		case 6: // Only OS code should include these; problem for SDT
			if (MemDest) {
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL AlwaysPTR %s \n",
				(unsigned long long) addr, -(this->GetOptType()), disasm);
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			break;

		case 8: // Implicitly writes to EDX:EAX, always numeric.
			if (this->GetOptType() == 10) { // writes to ECX also
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ECX ZZ %s %s \n",
					(unsigned long long) addr, -2, OptExplanation[this->GetOptType()], disasm);
			}
			else {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
					(unsigned long long) addr, -2, OptExplanation[this->GetOptType()], disasm);
			}
			global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			SDTInstrumentation = true;
			break;

		case 9:  // Either writes to FP reg (cat. 1) or memory (cat. 0)
			if (MemDest) {
				SDTInstrumentation = true;
#if 0
				if (NumericDEFs) {
					SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n",
						(unsigned long long) addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->GetOptType()), disasm);
					global_STARS_program->IncrementAnnotationCount(this->GetOptType());
				}
#endif
			}
			else {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n",
					(unsigned long long) addr, -1, OptExplanation[this->GetOptType()], disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			break;

		case 10: // AND, OR, etc.: If all DEFs have been inferred to be
				 //  NUMERIC, then output optimizing annotation.
			SDTInstrumentation = true;
			if (MemDest) { // **!!** optimize with numeric annotation in future
				break;  // treat as category 0
			}
			else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n",
					(unsigned long long) addr, ProfiledDEFs ? -256 - 2 : -2, this->DestString(this->GetOptType()), disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			break;

		case 12: // Exchange, exchange and add, conditional exchange: All NUMERIC
				 //  sources ==> NUMERIC DEFs, so nothing for mmStrata to do.
			if (MemDest) { // **!!** optimize with numeric annotation in future
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr,
						ProfiledDEFs ? -256-1 : -1, OptExplanation[TypeGroup], disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			else 
				SDTInstrumentation = true;
			break;

		case 13:
		case 15: // Floating point, NUMERIC, possible memory destination.
				 //  If not memory destination, fpreg dest, so nothing for mmStrata to do.
			if (MemDest) { // **!!** optimize with numeric annotation in future
				SDTInstrumentation = true;
				break;  // treat as category 0
			}
			else { // NUMERIC floating register result; these regs are always NUMERIC
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr,
						-1, OptExplanation[TypeGroup], disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			break;

		default: // 2,3,7: Optimization possibilities depend on operands 
			SDTInstrumentation = true;
			if (MemDest) {
				break;  // treat as category 0
			}

			if ((this->GetOptType() == 2) || (this->GetOptType() == 7) || SecondSrcOperandImmNum) {
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s %s %s \n",
						(unsigned long long) addr, -2, this->DestString(this->GetOptType()), 
						OptExplanation[this->GetOptType()], disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			else if (NumericDEFs) { // NUMERIC move instruction
				SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n",
						(unsigned long long) addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->GetOptType()), disasm);
				global_STARS_program->IncrementAnnotationCount(this->GetOptType());
			}
			break;
	} // end switch (OptType)
	

	// always annotate stack constants for the profiler, etc.
	this->AnnotateStackConstants(UseFP, AnnotFile);

	// If mmStrata is going to have to deal with the
	//  instruction, then we can annotate EBP and ESP
	//  relative constant offsets. If we have emitted
	//  an annotation of type -1, there is no point
	//  in telling mmStrata about these constants.
	// Likewise, we can tell mmStrata if a MemDest is an
	//  non-directly-accessed child object.
	if (SDTInstrumentation || NoWarnFlag || CallInst || IndirJumpAnalyzed) {
		// Optimize by informing mmStrata of dead registers. It can avoid saving
		//  and restoring dead state. This is particularly important for EFLAGS,
		//  as restoring the flags is a pipeline serializing instruction.
		this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm);

		int ChildOffset, ChildSize;
		if (MemDest && ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr,
			ChildOffset, ChildSize)) {
			SMP_fprintf(AnnotFile, "%18llx %6zu INSTR CHILDACCESS %d %d ZZ %s \n",
				(unsigned long long) addr, this->GetSize(), ChildOffset, ChildSize, disasm);
		}
#if SMP_IDENTIFY_POINTER_ADDRESS_REG
		// WARNING: This old code was written prior to the normalization of stack operands.
		if (MemDest) {
			assert(this->HasDestMemoryOperand());
			set<DefOrUse, LessDefUse>::iterator PtrUse;
			PtrUse = this->GetPointerAddressReg(this->DEFMemOp);
			if (PtrUse != this->GetLastUse()) { // found POINTER addr reg USE
				if (PtrUse->GetOp()->GetOpType()->IsRegOp()) {
					SMP_fprintf(AnnotFile, "%18llx %6zu INSTR POINTER reg %s ZZ %s \n",
						(unsigned long long) addr, this->GetSize(), MDGetRegName(PtrUse->GetOp()), disasm);
				}
			}
		}
#endif
	}
	else if (this->HasReturnOpcode()) {
		// In case we have a COMPLETE return target set, emit DEADREGS annotation for return inst.
		this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm);
	}
	else {
		// Experiment with emitting DEADREGS for every inst, even direct jumps.
		this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm);
	}
	return;
} // end of SMPInstr::EmitTypeAnnotations()

// emit DEADREGS annotation using DeadRegsBitmap.
void SMPInstr::EmitDeadRegsAnnotation(FILE *AnnotFile, bool IndirJumpAnalyzed, char *disasm) {
	if (this->DeadRegsBitmap.any() && (NULL != this->GetBlock()) && (!this->GetBlock()->GetFunc()->IsMultiEntry())) {
		// Ensure that the only dead regs are not floating-point 8087 regs, which are not
		//  useful as scratch registers for instrumentation, and whose deadness we don't
		//  fully trust, so we won't print them in PrintDeadRegs(), anyway.
		bool RelevantDeadReg = false;
		for (int i = 0; i < MD_LAST_REG_NO; ++i) {
			if (!STARS_x86_is_FP8087_reg(i)) {
				if (this->DeadRegsBitmap[i]) {
					RelevantDeadReg = true;
					break;
				}
			}
		}
		
		if (RelevantDeadReg) {
			// Optimize by informing mmStrata of dead registers. It can avoid saving
			//  and restoring dead state. This is particularly important for EFLAGS,
			//  as restoring the flags is a pipeline serializing instruction.
			SMP_fprintf(AnnotFile, "%18llx %6zu INSTR DEADREGS  ",
				(unsigned long long) this->GetAddr(), this->GetSize());
			this->PrintDeadRegs(AnnotFile);
			SMP_fprintf(AnnotFile, " %s \n", disasm);
			if (IndirJumpAnalyzed && (!this->DeadRegsBitmap[MD_FLAGS_REG])) {
				// Unusual case: Switch table has live flags into cases.
				SMP_msg("INFO: IndirJump at %18llx has live flags register: Successor blocks: ", (unsigned long long) this->GetAddr());
				for (list<SMPBasicBlock *>::iterator SuccIter = this->GetBlock()->GetFirstSucc(); SuccIter != this->GetBlock()->GetLastSucc(); ++SuccIter) {
					SMP_msg("%18llx ", (unsigned long long) (*SuccIter)->GetFirstAddr());
				}
				SMP_msg("\n");
			}
		}
	}
	return;
} // end of SMPInstr::EmitDeadRegsAnnotation()

// emit constant outgoing arg annotations for CALL instructions
void SMPInstr::EmitConstOutArgAnnotations(FILE *InfoAnnotFile) {
	// Iterate through the argument regs for this program's ABI
	//  and see if any of them are USEs in the CALL instruction
	//  and also have constants determined in the SCCP analysis.
	std::list<STARS_regnum_t>::iterator ArgRegIter;
	for (ArgRegIter = global_STARS_program->GetFirstArgumentReg(); ArgRegIter != global_STARS_program->GetLastArgumentReg(); ++ArgRegIter) {
		STARS_regnum_t ArgRegNo = *ArgRegIter;
		STARSOpndTypePtr ArgRegOp = this->MakeRegOpnd(ArgRegNo);
		STARSDefUseIter UseIter = this->FindUse(ArgRegOp);
		if (UseIter != this->GetLastUse()) {
			// Look up argument reg + SSA number in SCCP hash table
			int UseSSANum = UseIter->GetSSANum();
			SMPBasicBlock *CurrBlock = this->GetBlock();
			int UseHashIndex = HashGlobalNameAndSSA(ArgRegOp, UseSSANum);
			bool LocalName = CurrBlock->IsLocalName(ArgRegOp);
			STARSSCCPMapIter ConstIter;
			bool ConstFound = CurrBlock->GetFunc()->FindSCCPConstIter(CurrBlock, UseHashIndex, LocalName,
				ConstIter);
			if (ConstFound) { // found an SCCP const entry of type STARS_CONST_HAS_VALUE
				++SCCPConstantOutgoingArgWriteCount;
				STARS_uval_t ConstVal = (*ConstIter).second.ConstValue;
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu CALL CONSTARG %s %llx ZZ \n",
					(uint64_t) this->GetAddr(), this->GetSize(), MDGetRegName(ArgRegOp),
					(uint64_t) ConstVal);
			}
		}
	} // end for all argument regs

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

// union of sign masks from 2 reg USEs for binary arithmetic
unsigned short SMPInstr::SignMaskUnionFromUseRegs(void) {
	unsigned short UnionMask = 0;
	unsigned short UseSignMask, DefSignMask;
	set<DefOrUse, LessDefUse>::iterator UseIter;
	std::size_t RegOpCount = 0;
	int UseHashValue;
	struct FineGrainedInfo UseFGInfo, DefFGInfo;
	bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();

	if (this->HasSourceMemoryOperand()) {
		// Don't have binary arithmetic on just registers.
		return UnionMask;
	}

	for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
		STARSOpndTypePtr UseOp = UseIter->GetOp();
		if (MDIsGeneralPurposeReg(UseOp) && (!MDIsStackPtrReg(UseOp->GetReg(), UseFP))) {
			++RegOpCount;
			UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum());
			bool LocalUseName = this->BasicBlock->IsLocalName(UseOp);

			if (LocalUseName) {
				// Local name, find in basic block maps.
				UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue);
			}
			else { // Global name, find in global maps.
				UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
			}
			UseSignMask = (FG_MASK_SIGNEDNESS_BITS & UseFGInfo.SignMiscInfo);
			if (0 == UseSignMask) {
				// Try to get signedness from DEF.
				if (LocalUseName) {
					// Local name, find in basic block maps.
					DefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue);
				}
				else { // Global name, find in global maps.
					DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue);
				}
				DefSignMask = (FG_MASK_SIGNEDNESS_BITS & DefFGInfo.SignMiscInfo);
				UnionMask |= DefSignMask;
			}
			else {
				UnionMask |= UseSignMask;
			}
		}
	}

	if (2 > RegOpCount) { // only interested in binary arithmetic on two registers
		UnionMask = 0;
	}
	return UnionMask;
} // SMPInstr::SignMaskUnionFromUseRegs()

// emit check annotations for signedness, overflow, truncation, etc.
void SMPInstr::EmitIntegerErrorAnnotations(FILE *InfoAnnotFile, list<std::size_t> &LoopList) {
	set<DefOrUse, LessDefUse>::iterator UseIter, DefIter;
	STARSOpndTypePtr UseOp = nullptr, DefOp = nullptr;
	unsigned short UseWidthInfo, DefWidthInfo, SourceDefWidthInfo;
	unsigned short DefSignInfo, SourceDefSignInfo;
	unsigned short UseSignMask, DefSignMask, SourceDefSignMask;
	struct FineGrainedInfo UseFGInfo, DefFGInfo, SourceDefFGInfo;
	std::size_t UseBitWidth, DefBitWidth, UseMaxBitWidth, SourceDefBitWidth, DefMaxBitWidth;
	STARS_ea_t DefAddr;
	int UseHashValue, DefHashValue, SSANum, DefSSANum, UseSSANum;
	int IdiomCode = 0; // records code pattern number causing suppression of annotation.
	bool OverflowOpcode = this->MDIsOverflowingOpcode();
	bool UnderflowOpcode = this->MDIsUnderflowingOpcode();
	bool CheckForOverflow;
	bool UseIsSigned, DefIsSigned, UseIsUnsigned, DefIsUnsigned, SourceDefIsSigned, SourceDefIsUnsigned;
	bool UseSignMixed, SourceDefSignMixed; // inconsistent signedness
	bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
	bool SuppressSignednessCheck = false; // If we are not confident in check, set to true.
	bool PartialStore; // Store is fewer bits than is defined for the target, e.g. overwriting last 8 bits
					   //  of an int or a pointer. Cannot have signedness error in that case, as sign bit
					   //  is not affected.


	bool cases1and2 = (OverflowOpcode || UnderflowOpcode);
	bool case3 = this->MDIsMultiply();
	bool cases4and5 = ((3 == this->GetOptType()) && this->GetMoveSource()->IsRegOp());
	bool case6 = ((this->MDIsLoadEffectiveAddressInstr()) && (!(this->IsNop() || this->IsRegClearIdiom())));
	bool case7 = this->MDDoublesWidth();
	bool case8 = ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump()));  // possible memset() call

	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
	string SinkString("");

	if (this->IsNumericAnnotationSuppressed()) {
		return; // Cannot figure out IdiomCode; suppressed from earlier instruction's analyses
	}

	// If the instruction is the beginning of an infinite loop, we want no annotations other than
	//  the infinite loop annotation.
	if (this->IsFirstInBlock()) {
		if (this->GetBlock()->IsInfiniteSelfLoop()) {
			SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR INFINITELOOP %s \n",
					(unsigned long long) this->GetAddr(), this->GetSize(), disasm);
			return;
		}
	}

	if (!(cases1and2 || case3 || cases4and5 || case6 || case7 || case8)) {
		return;
	}

	bool HasIntErrorSink = false;
	DefIter = this->GetFirstNonFlagsDef();
	if (!case8 && (DefIter != this->GetLastDef())) {
		DefOp = DefIter->GetOp();
		SSANum = DefIter->GetSSANum();
		bool FoundAnyCall = false;
		HasIntErrorSink = this->GetBlock()->GetFunc()->HasIntErrorCallSink(DefOp, SSANum, this->GetAddr(), SinkString, FoundAnyCall);

#if STARS_USE_NUMERIC_ERROR_BLACKLISTING
		if (!(HasIntErrorSink || this->HasPEASOUPBlacklistSink(FoundAnyCall))) {
			return;
		}
#endif
	}

	// Case 1: Overflow on addition.
	// Case 2: Underflow on subtraction.
	if (OverflowOpcode || UnderflowOpcode) {
		// If the flags register DEF is dead, we need a CHECK OVERFLOW/UNDERFLOW annotation.
		STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);
		DefIter = this->FindDef(FlagsOp);
		assert(DefIter != this->GetLastDef());
		if (this->BasicBlock->IsDefDead(this->GetAddr(), FlagsOp)) {
			DefIter = this->GetFirstNonFlagsDef();
			assert(DefIter != this->GetLastDef());
			DefOp = DefIter->GetOp();
			SSANum = DefIter->GetSSANum();
			SMPOperandType DefType = DefIter->GetType();
			SMPOperandType MemType;
			SMPOperandType DefUseType = UNINIT; // type of USE that is also the DEF of the instruction
			SMPMetadataType DefMetaStatus = DefIter->GetMetadataStatus();
			bool DefUnusedMetadata = (DEF_METADATA_UNUSED == DefMetaStatus);
			bool IgnoreOverflow = this->IsBenignOverflow(IdiomCode);
			STARS_uval_t ConstValue = 0;
			// NOTE: We no longer suppress the IgnoreOverflow annotations. Instead, we print
			//  them with an IdiomCode so that suppression can happen downstream, along with
			//  customized continuation policies, statistical summarizing, etc.
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			if (IgnoreOverflow)
				++BenignOverflowInstCount;
#endif
			// Don't worry about stack space allocation instructions. The
			//  program will crash long before the stack pointer underflows
			//  below zero.
			if (!((DefOp->IsRegOp()) && DefOp->MatchesReg(MD_STACK_POINTER_REG))) {
				if (!IgnoreOverflow && (this->GetBlock()->IsBenignOverflowDEF(DefOp, SSANum, this->GetAddr(), UnderflowOpcode, IdiomCode))) {
					IgnoreOverflow = true;
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
					++BenignOverflowDefCount;
#endif
				}
				if (DefOp->IsRegOp()) {
					DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum);
					if (this->BasicBlock->IsLocalName(DefOp)) {
						// Local name, find in basic block maps.
						DefFGInfo = this->BasicBlock->GetDefFGInfo(DefHashValue);
					}
					else { // Global name, find in global maps.
						DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
					}
				}
				else if (MDIsDirectStackAccessOpnd(DefOp, UseFP)) {
					bool success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), DefOp, DefFGInfo);
					assert(success);
				}
				else { // non-stack memory address; we know nothing about it.
					DefFGInfo.SignMiscInfo = 0;
					DefFGInfo.SizeInfo = 0;
				}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
				++NumericAnnotationsCount12;
#endif
				DefSignInfo = DefFGInfo.SignMiscInfo;
				DefSignMask = DefSignInfo & FG_MASK_SIGNEDNESS_BITS;
				DefWidthInfo = DefFGInfo.SizeInfo;
				DefBitWidth = LargestBitWidthFromMask(DefWidthInfo);
				if (0 == DefBitWidth) {
					// Could happen for non-stack memory operands, for example.
					DefBitWidth = MD_NORMAL_MACHINE_BITWIDTH;
				}
				if (DefSignMask == 0) {
					// If no sign info from DEF, see if we can get it from the USE regs.
					DefSignMask = this->SignMaskUnionFromUseRegs();
				}
				if ((0 == IdiomCode) && (DefSignMask == FG_MASK_UNSIGNED)) {
					// UNSIGNED is often unreliable because compilers zero-extend values
					//  just so they can avoid having undefined register bits. Later, only
					//  the lower bits get stored. We already detect this pattern as a benign
					//  truncation, but we need to back off on the certainty of our UNSIGNED
					//  inference on overflow/underflow operations along the path.
					UseIter = this->FindUse(DefOp);
					if (UseIter != this->GetLastUse()) {
						UseOp = UseIter->GetOp();
						UseSSANum = UseIter->GetSSANum();
						DefUseType = UseIter->GetType();
						if (MDIsDataFlowOpnd(UseOp, UseFP)) {
							if (this->IsOpSourceZeroExtendedMove(UseOp, UseSSANum, false)) {
								if (this->GetBlock()->IsOpDestTruncatedWrite(DefOp, SSANum, this->GetAddr())) {
									// Operand source was reduced-width, zero-extended; ultimate use is to store
									//  only the lower bits. The zero extension is no longer a reliable source of 
									//  inference for UNSIGNEDness.
									DefSignMask = FG_MASK_INCONSISTENT_SIGN;
								}
							}
							else if (UnderflowOpcode && this->IsOpSourceSmallPositiveConstant(UseOp, UseSSANum)) {
								// subtract from small positive, danger of UNSIGNED UNDERFLOW. Most likely, the
								//  inference of UNSIGNED is unreliable.
								DefSignMask = FG_MASK_INCONSISTENT_SIGN;
							}
						}
					}
				}
				if (OverflowOpcode) {
					if ((17 == IdiomCode) && (FG_MASK_UNSIGNED == DefSignMask)) {
						// An IdiomCode of 17 means not a benign overflow, but an addition that
						//  produces a jump table offset, which can be an addition of mixed signedness
						//  that produces false positives if treated as UNSIGNED. See discussion in
						//  SMPBasicBlock::IsBenignOverflowDEF().
						DefSignMask = FG_MASK_INCONSISTENT_SIGN;
					}
					else if (this->IsAdditionOfLargeConstant(ConstValue, DefSignMask)) {
						IgnoreOverflow = true;
						IdiomCode = 11;
					}

					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu ",
						(unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[DefSignMask], DefBitWidth);
				}
				else { // must be UnderflowOpcode
					// (1) Two more benign case to exclude: 
					//   movzx eax, byte ptr [esp+37] ; get char, with misleading zero-extension
					//   sub eax,0x65   ; subtract 'A' to see if char is in letter range
					//   cmp eax,25     ; there are 26 capital letters
					//   ja nextcheck   ; not in range of 'A' to 'Z'
					//   return true    ; found an alphanumeric
					// These operations make eax look UNSIGNED. But it is an ASCII char, and the subtraction
					//  will underflow whenever the char is less than 'A'. Similar checks occur for 'a'
					//  and the digit '0' quite often. We do not want false positives on underflow checks.
					//
					// (2) sub eax,[large constant value]
					//  We might have to follow the subtrahend operand back to its origin. A subtraction of a
					//  number that has a very large absolute value tends to indicate that underflow is benign
					//  and is being ignored.
					if (!IgnoreOverflow) {
						if ((DefSignMask == FG_MASK_UNSIGNED) && (this->SubtractsImmedASCII())) {
							IgnoreOverflow = true;
							IdiomCode = 9;
						}
						else if ((DefSignMask == FG_MASK_UNSIGNED) || (DefSignMask == FG_MASK_SIGNED)) {
							if (this->IsSubtractionOfLargeConstant(ConstValue, DefSignMask)) {
								IgnoreOverflow = true;
								IdiomCode = 11;
							}
						}
					}
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK UNDERFLOW %s %zu ",
							(unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[DefSignMask], DefBitWidth);
				}
				STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(DefOp, UseFP);
				if (! DefOp->IsRegOp()) {
					// Need to unnormalize stack memory DEFs and USEs before printing annotations.
					this->MDGetUnnormalizedOp(AnnotDefOp);
				}
				AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit());
				if (!IgnoreOverflow) {
					// See if we made a special detection of an operation involved in a hash function, which can
					//  be expected to overflow benignly.
					if (this->IsHashOperation()) {
						IgnoreOverflow = true;
						IdiomCode = 15;
					}
					else if (IsDataPtr(DefType) || IsDataPtr(DefUseType)) {
						// IDIOM 18 says to let C7 (buffer overflow/underflow) defenses handle the issues if it is a pointer.
						IgnoreOverflow = true;
						IdiomCode = 18;						
					}
					else if (!LoopList.empty()) { // Limit search for address-reg-only case to loops for now.
						list<std::size_t>::iterator LoopIter;
						for (LoopIter = LoopList.begin(); LoopIter != LoopList.end(); ++LoopIter) {
							std::size_t Counter = 0;
							std::size_t LoopNum = (*LoopIter);
							MemType = UNINIT;
							this->GetBlock()->GetFunc()->ResetProcessedBlocks();
							bool AddrRegOnly = this->GetBlock()->IsDefOnlyUsedAsAddressReg(this->GetAddr(), DefOp, LoopNum, Counter, MemType);
							if (AddrRegOnly && (0 < Counter)) {
								// Similarly, let C7 (buffer overflow/underflow) defenses handle the issues if it is only an index register.
								DefType = MemType;
								IgnoreOverflow = true;
								IdiomCode = 18;
								break; // Don't need to look at next loop
							}
						}
					}
				}
				if (IgnoreOverflow) {
					if (11 == IdiomCode) {
						SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d CONST %lu %s \n", IdiomCode, (unsigned long) ConstValue, disasm);
					}
					else if (18 == IdiomCode) {
						// Need a tag field telling what kind of pointer.
						if (IsEqType(DefType, STACKPTR) || IsEqType(DefUseType, STACKPTR)) {
							SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d STACKMEMSINK %s \n", IdiomCode, disasm);
						}
						else if (IsEqType(DefType, HEAPPTR) || IsEqType(DefUseType, HEAPPTR)) {
							SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d HEAPMEMSINK %s \n", IdiomCode, disasm);
						}
						else if (IsEqType(DefType, GLOBALPTR) || IsEqType(DefUseType, GLOBALPTR)) {
							SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d GLOBALMEMSINK %s \n", IdiomCode, disasm);
						}
						else { // must be unrefined POINTER type.
							SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d MEMORYSINK %s \n", IdiomCode, disasm);
						}
					}
					else {
						SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d %s \n", IdiomCode, disasm);
					}
				}
				else if (HasIntErrorSink) {
					SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
				}
			} // end if (!(DEF is stack ptr register))
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			else {
				++SuppressStackPtrOverflowCount;
			}
#endif

		} // end if flags reg is dead
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
		else {
			++SuppressLiveFlagsOverflowCount;
		}
#endif

	} // end cases 1-2

	// Case 3: Overflow on multiplication with upper bits discarded.
	if (case3) {
		// There are five overflow sub-cases for x86: (A) the multiplication result
		//  can go into EDX:EAX for 32x32=>64 bit multiplication; (A2) RDX:RAX gets
		//  result of 64x64=>128-bit multiplication in x86-64; (B) the result
		//  can go into DX:AX for 16x16=>32 bit; (C) the result can be in AX
		//  for 8x8=>16 bit; (D) see below. The latter case (C) will be detected most easily
		//  as a truncation in a later instruction, i.e. if only AL gets stored
		//  later, then we check the AH bits at that time for a truncation
		//  error. Because our SSA numbering lumps AL, AH, AX, and EAX into
		//  a single canonicalized register, we would have a hard time using
		//  SSA-based def-use chains to determine if AH is dead.
		// For the other three sub-cases, the question is whether EDX becomes dead
		//  starting with the DEF of EDX in the multiply instruction.
		// Case (D) is where the multiply instruction discards the upper bits
		//  of the multiply.
		// Sub-cases A&B are detected by checking if EDX is dead, and if so, then
		//  emitting an annotation to check for the overflow flag. The x86 sets
		//  overflow and carry flags on multiplication instructions based on whether
		//  the result carries out of the lower half of the result to the upper half.
		// Sub-case D is also detected using flags, but we don't need to check whether EDX
		//  is dead. We just need to detect that EDX is not in the DEF set in the
		//  first place. We have a private member flag for that case.
		CheckForOverflow = false;
		if (this->AreMultiplicationBitsDiscarded()) { // Sub-case D
			CheckForOverflow = true;
			assert(this->RTL.GetCount() > 0);
			DefOp = this->RTL.GetRT(0)->GetLeftOperand();
			DefIter = this->FindDef(DefOp);
			assert(DefIter != this->GetLastDef());
			DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
		}
		else {
			// If the instruction were EDX:=EDX*foo, then it would be
			//  the multiplication bits discarded case and would not
			//  reach this else clause. Therefore, if we find EDX in
			//  the DEF set, it is holding upper result bits of the
			//  multiplication and we have the potential for sub-cases A&B
			//  but not sub-case C. So, we check to see if the DEF of EDX
			//  is dead.
			DefOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx);
			DefIter = this->FindDef(DefOp);
			if (DefIter != this->GetLastDef()) {
				// We found DEF of EDX, so it is not AX:=AL*op8 sub-case C.
				// Now, is DEF of EDX dead (i.e. no uses?)
				CheckForOverflow = this->BasicBlock->IsDefDead(this->GetAddr(), DefOp);
				if (CheckForOverflow) {
					DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
				}
			}
		} // end if sub-case D else if sub-case A or B

		if (CheckForOverflow) { // need an annotation
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			++NumericAnnotationsCount3;
#endif
			if (this->BasicBlock->IsLocalName(DefOp)) {
				// Local name, find in basic block maps.
				DefFGInfo = this->BasicBlock->GetDefFGInfo(DefHashValue);
			}
			else { // Global name, find in global maps.
				DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
			}

			DefWidthInfo = DefFGInfo.SizeInfo;
			DefBitWidth = LargestBitWidthFromMask(DefWidthInfo);

			DefSignMask = (DefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
			if (DefSignMask == 0) {
				// If no sign info from DEF, see if we can get it from the USE regs.
				DefSignMask = this->SignMaskUnionFromUseRegs();
			}

			// Next two statements exclude the inconsistent sign case and the no sign info known case.
			DefIsSigned = (FG_MASK_SIGNED == DefSignMask);  // exact, not bit-mask-AND
			DefIsUnsigned = (FG_MASK_UNSIGNED == DefSignMask);  // exact, not bit-mask-AND

			STARS_uval_t ConstValue = 0;
			IdiomCode = 0;
			bool UnsignedAnnot = (this->MDIsUnsignedArithmetic() || DefIsUnsigned);
			bool SignedAnnot = (this->MDIsSignedArithmetic() || DefIsSigned);
			if (0 == DefSignMask) {
				// Prepare DefSignMask for use by IsMultiplyByLargeConst(),
				//  as it is of no more use in case3.
				if (UnsignedAnnot)
					DefSignMask = FG_MASK_UNSIGNED;
				else if (SignedAnnot)
					DefSignMask = FG_MASK_SIGNED;
			}
			if (this->IsMultiplyByLargeConstant(ConstValue, DefSignMask)) {
				IdiomCode = 10;
			}

			if (this->AreMultiplicationBitsDiscarded() && (!SignedAnnot)) {
				IdiomCode = 33;
			}
			if (UnsignedAnnot) {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW UNSIGNED %zu %s ZZ",
					(unsigned long long) this->GetAddr(), this->GetSize(), DefBitWidth, MDGetRegName(DefOp));
			}
			else if (SignedAnnot) {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW SIGNED %zu %s ZZ",
					(unsigned long long) this->GetAddr(), this->GetSize(), DefBitWidth, MDGetRegName(DefOp));
			}
			else {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW UNKNOWNSIGN %zu %s ZZ",
					(unsigned long long) this->GetAddr(), this->GetSize(), DefBitWidth, MDGetRegName(DefOp));
			}
			if (33 == IdiomCode) {
				SMP_fprintf(InfoAnnotFile, " IDIOM %d %s \n", IdiomCode, disasm);
			}
			else if (0 < IdiomCode) {
				SMP_fprintf(InfoAnnotFile, " IDIOM %d CONST %lu %s \n", IdiomCode, (unsigned long) ConstValue, disasm);
			}
			else {
				SMP_fprintf(InfoAnnotFile, " %s \n", disasm);
			}
		} // end if (CheckForOverflow)
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
		else {
			++LiveMultiplyBitsCount;
		}
#endif
	} // end of case 3

	// Case 4: Signedness error on move.
	// Case 5: Truncation error on move.
	IdiomCode = 0;
	if (cases4and5) {
		int TruncationIdiomCode = 0;
		bool SuppressTruncation = this->IsBenignTruncation(TruncationIdiomCode);
		// Possibilities for a move: reg to reg, mem to reg, or reg to mem. If we load
		//  from memory into a register, we cannot track signedness in memory unless it
		//  is a stack location. In that case, we record the signedness in the stack
		//  map and transfer it to the reg DEF in SMPInstr.MDSetWidthSignInfo(). That
		//  determines the signedness of the reg DEF and it cannot be in conflict with
		//  the stack memory USE. The load from stack to reg also determines width
		//  of the stack operand and we cannot have a truncation. So, we can restrict
		//  our analysis of cases 4-5 to register-source move instructions, as we
		//  have done in the condition above.
		//
		//  Similarly, we cannot detect a signedness conflict if the destination is a 
		//  memory location that is not known to be a particular stack offset location.
		//
		// So, we only concern ourselves with signedness errors
		//  when the USE operand of the move is a register, and the destination is another
		//  register or a stack location.
		//
		// We can have a truncation error and a signedness error on a single instruction, so
		//  we group them into common code. For example, move the lower half of a 32-bit unsigned
		//  into a 16-bit signed destination. Upper bits set to 1 and discarded would be a 
		//  truncation, and setting the sign bit of the 16-bit signed destination would be a
		//  signedness error.
		//
		// NOTE: Signedness errors are different from overflow and truncation errors. We
		//  can have incomplete knowledge about an instruction's operands and still determine
		//  that truncation occurred. For example, if we do not know whether register EAX
		//  is signed or unsigned, we can still say that storing only AX is a truncation error
		//  if the upper half of EAX is a mixture of one and zero bits. If EAX is unsigned,
		//  we could be more specific and insist that the upper half be all zero bits; if EAX
		//  is signed, we could insist that the upper half of EAX be the sign-extension of AX.
		//  We can avoid false positives by only declaring a truncation error when the upper
		//  half of EAX is not all zero bits or all one bits. This approach allows a few
		//  potential false negatives. With signedness, if we don't know the signedness
		//  of one of the operands, we can only avoid false positives by doing no checks at
		//  all.
		UseOp = this->GetMoveSource();
		UseBitWidth = 8 * UseOp->GetByteWidth();
		STARSOpndTypePtr SearchOp = UseOp->clone();  // clone because we can call SearchOp->SetByteWidth(8) below
		// Canonicalize sub-regs for searching DEFs and USEs.
		CanonicalizeOpnd(SearchOp);
		UseIter = this->FindUse(SearchOp);
		assert(UseIter != this->GetLastUse());

		// Now, the question is: Are we storing fewer bits than
		//  we were using in our computations in this DEF-USE chain?
		//  E.g. if we computed using 32 bits and then only store 16,
		//  we have potential truncation error. But if we computed
		//  using 16 bits all along, we have already checked for 16-bit
		//  overflows on arithmetic in the DU chain and there can be no
		//  truncation on this store.
		UseSSANum = UseIter->GetSSANum();
		UseHashValue = HashGlobalNameAndSSA(SearchOp, UseSSANum);

		bool LocalSearchOp = this->BasicBlock->IsLocalName(SearchOp);
		if (LocalSearchOp) {
			// Local name, find in basic block maps.
			SourceDefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue);
			UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue);
		}
		else { // Global name, find in global maps.
			SourceDefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue);
			UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
		}

		SourceDefWidthInfo = SourceDefFGInfo.SizeInfo;
		UseWidthInfo = UseFGInfo.SizeInfo;
		SourceDefBitWidth = LargestBitWidthFromMask(SourceDefWidthInfo);
		UseMaxBitWidth = LargestBitWidthFromMask(UseWidthInfo);
		UseSignMask = (UseFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
		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)) {
			if (this->GetBlock()->GetFunc()->IsLiveIn(SearchOp)) {
				SuppressTruncation = true;
				TruncationIdiomCode = 26;
			}
			else {
				STARS_ea_t DefAddr;
				if (LocalSearchOp) {
					if (0 == this->GetBlock()->GetNumber()) { // first block
						DefAddr = this->GetBlock()->GetDefAddrFromUseAddr(SearchOp, this->GetAddr(), 0, true);
					}
					else {
						DefAddr = STARS_BADADDR;
					}
				}
				else {
					DefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(SearchOp, 0);
				}
				if ((STARS_BADADDR != DefAddr) && (DefAddr < STARS_PSEUDO_ID_MIN)) {
					// We have the address of a defining instruction for SearchOp+UseSSANum==0.
					//  See if the reg was defined by a move from an incoming arg. If so, the
					//  incoming arg probably has full width, but that does not prove that it
					//  was always full width in the caller, because args are passed full-width on the stack.
					SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr);
					if (DefInst->MDIsMoveInstr()) {
						STARSOpndTypePtr MoveSourceOp = DefInst->GetMoveSource();
						if (this->GetBlock()->GetFunc()->IsInIncomingArgsRegion(DefInst, MoveSourceOp)) {
							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
		//  SourceDefSignMask as our signedness info. This is because of
		//  simple instruction sequences in which no signedness can be inferred
		//  from the use, e.g.:
		//
		//  imul eax,ebx  ; eax := eax*ebx and eax&ebx are signed
		//  mov [ebp-8],al  ; store al on stack
		//
		//  If we don't know the signedness of stack location [ebp-8],
		//   then we will end up in the S->? case below and we will emit
		//   a CHECK TRUNCATION UNKNOWNSIGN annotation. This discards the
		//   knowledge we have that EAX is signed, from the IMUL opcode.
		if (0 == UseSignMask) {
			UseSignMask = SourceDefSignMask;
		}
#endif

		// Next six statements exclude the inconsistent sign case and the no sign info known case.
		UseIsSigned = (FG_MASK_SIGNED == UseSignMask);  // exact, not bit-mask-AND
		UseIsUnsigned = (FG_MASK_UNSIGNED == UseSignMask);  // exact, not bit-mask-AND
		SourceDefIsSigned = (FG_MASK_SIGNED == SourceDefSignMask);  // exact, not bit-mask-AND
		SourceDefIsUnsigned = (FG_MASK_UNSIGNED == SourceDefSignMask);  // exact, not bit-mask-AND
		UseSignMixed = (FG_MASK_INCONSISTENT_SIGN == UseSignMask); // exclude uninit sign case
		SourceDefSignMixed = (FG_MASK_INCONSISTENT_SIGN == SourceDefSignMask); // exclude uninit sign case

		// Not only the CHECK SIGNEDNESS annotations depend on the signedness of the
		//  source and destination operands. The CHECK TRUNCATION annotations come
		//  in SIGNED, UNSIGNED, and UNKNOWNSIGN variants, so we need to get the
		//  signedness of the destination operand before we proceeed.
		DefOp = this->RTL.GetRT(0)->GetLeftOperand(); // RTL must be dest := rhs
		STARSOpndTypePtr DestSearchOp = CloneIfSubwordReg(DefOp);
		bool StackDestination = false;
		// Outargs locations are reused for different function calls, so no inference of their
		//  signedness is valid. We maintain a flag to suppress signedness checks on writes to
		//  outargs locations on the stack. We make an exception for the known unsigned args to
		//  certain library functions.
		bool OutArgsWrite = false;
		bool IgnoreOutArgsWrite = false;
		bool NonStackMemDestination = false;
		if (DestSearchOp->IsRegOp()) {
			StackDestination = false;
			CanonicalizeOpnd(DestSearchOp);
		}
		else if (!(MDIsDirectStackAccessOpnd(DefOp, UseFP))) {
			// If destination of move is not a register and is not
			//  a stack location, we cannot track its signedness and width.
			NonStackMemDestination = true;
		}
		else {
			StackDestination = true;
		}
		DefIter = this->FindDef(DestSearchOp);
		DefSSANum = DefIter->GetSSANum();

		if (StackDestination) {
			// Fetch FG info from stack map.
			bool success = this->GetBlock()->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), DefOp, DefFGInfo);
			assert(success);
			OutArgsWrite = this->GetBlock()->GetFunc()->IsInOutgoingArgsRegion(DefOp);
			IgnoreOutArgsWrite = OutArgsWrite && (!(this->IsUnsignedArg())); // ignore out args write iff not a known unsigned argument
		}
		else if (NonStackMemDestination) {
			// We can check truncation of USE operand, but we know nothing about
			//  the DEF operand.
			DefFGInfo.SignMiscInfo = 0;
			DefFGInfo.SizeInfo = 0;
		}
		else {
			// Fetch FG info from register FG info maps.
			DefHashValue = HashGlobalNameAndSSA(DestSearchOp, DefSSANum);
			if (this->BasicBlock->IsLocalName(DestSearchOp)) {
				// Local name, find in basic block maps.
				DefFGInfo = this->BasicBlock->GetDefFGInfo(DefHashValue);
			}
			else { // Global name, find in global maps.
				DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
			}
		}

		DefSignMask = (DefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
		// Next two statements exclude the inconsistent sign case and the no sign info known case.
		DefIsSigned = (FG_MASK_SIGNED == DefSignMask);  // exact, not bit-mask-AND
		DefIsUnsigned = (FG_MASK_UNSIGNED == DefSignMask);  // exact, not bit-mask-AND
		// Get the Def bit width and maximum bit width for special cases.
		DefWidthInfo = DefFGInfo.SizeInfo;
		DefMaxBitWidth = LargestBitWidthFromMask(DefWidthInfo); // max width over all defs
		DefBitWidth = 8 * DefOp->GetByteWidth(); // width of def in current instruction
		PartialStore = (DefBitWidth < DefMaxBitWidth);

		if (StackDestination) {
			// We only do signedness checks in limited, safe analysis cases on stack writes.
			SuppressSignednessCheck = this->SkipSignednessCheckOnStackWrite(DefSSANum, UseIsSigned);
			if (SuppressSignednessCheck) {
				IdiomCode = 7;
			}
		}
		else {
			// Check signedness on regs, but not on non-stack memory DEFs.
			SuppressSignednessCheck = NonStackMemDestination;
		}

		// If we set the (source) DEF bit width to 0, it means we wanted to have the USEs determine
		//  the width. This happens on sign-extended and zero-extended loads. If we zero-extend
		//  a 16-bit value to 32 bits, then immediately store the lower 16 bits to a 16-bit location,
		//  then the upper bits cannot have any overflow info yet. But if we do 32-bit arithmetic
		//  on the zero-extended value, and then store the lower 16 bits, we need to check for
		//  truncation. So, the key is whether the value ever got used as a 32-bit value. If it
		//  did, check for truncation; if not, there is no need to check.
		if ((SourceDefBitWidth > UseBitWidth) 
			|| ((SourceDefBitWidth == 0) && (UseMaxBitWidth > UseBitWidth))) {
			// Original DEF (or subsequent USE) was wider than what we are storing now.
			if (SourceDefBitWidth == 0) { // Convert for printing annotation.
				SourceDefBitWidth = 8 * SearchOp->GetByteWidth();
			}
			if ((SourceDefBitWidth == 64) && (SearchOp->GetByteWidth() < 8)) {
				// 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->SetByteWidth(8);
			}

			// 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.
			//  Each operand can be signed, unsigned, or of unknown sign (and we lump the
			//  inconsistent sign case into the unknown sign case). So, we have a set of 3x3=9
			//  possible combinations of signedness. 
			// Now we have the DefSignMask to compare to the UseSignMask. The nine possible
			//  combinations, and the annotations we want to emit for each, are shown below.
			//  S = SIGNED, U = UNSIGNED, and ? = unknown or inconsistent sign.
			//  S => U indicates a SIGNED being stored into an UNSIGNED, for example.
			//  Assume without loss of generality that register EAX is the source of
			//   all the move instructions, and that only subword register AX is being stored.
			//   We can perform all truncation and signedness checks on EAX just prior to
			//   the move instruction, which is cheaper than performing checks on the 
			//   destination if the destination is in memory.
			//
			//  U => U
			//  U => S
			//  S => U
			//  U => ?
			//  ? => U
			//
			//  In these first five cases, EAX must be the zero-extension of AX else there is
			//   a truncation error. In the three cases in which the source (EAX/AX) is UNSIGNED,
			//   discarding upper bits that are not zero is obviously truncation. In the case
			//   of S => U, if the upper bits of EAX are not all zeroes, then we either have
			//   a large positive value of EAX that is being truncated, or EAX is negative and
			//   the lower bits will be misinterpreted in the unsigned destination. Finally,
			//   the ? => U case must be either U => U or S => U, and these two cases already
			//   share the demand that EAX be the zero-extension of AX. So, these five cases
			//   will receive the annotation: CHECK TRUNCATION UNSIGNED 32 EAX 16 AX which
			//   means that EAX is tested against AX to see if it is the 32-bit zero-extension
			//   of 16-bit reg AX.
			//  In the U => S case, we can have a signedness error as well as truncation. Even
			//   if the truncation check passes (all upper half bits of EAX are zero), the top
			//   bit of AX might be 1, and this will be misinterpreted as a sign bit in the
			//   destination. So, this case receives a second annotation: CHECK SIGNEDNESS SIGNED 16 AX.
			//  In the two cases that involve signedness uncertainty, there are possible signedness
			//   errors that we are not checking at tun-time, because we do not have enough information
			//   to perform the checks without generating many more false positives than true positives.
			//   As a result, false negatives on signedness can occur.
			//
			// On to more of the 9 combinations:
			//
			// S => S
			//
			// In this case, EAX must be the sign-extension of AX. Because the destination is also
			//  signed, nothing is lost if the sign-extension bits (all zeroes or all ones) are dropped.
			//  We emit a CHECK TRUNCATION SIGNED 32 EAX 16 AX annotation to test EAX == sign-extended AX.
			//
			// S => ?
			// ? => S
			// ? => ?
			//
			// These final three cases all involve at least one operand of unknown signedness, and no
			//  operands that are known to be unsigned. In each case, there are two possibilities:
			//  either EAX must be the sign-extension of AX, or EAX must be the zero-extension of AX.
			//  Because of the uncertainty that is represented by the question marks, we are not sure
			//  which of these two cases we are dealing with. However, rather than just give up and
			//  perform no run-time checks (to avoid false positives), we can still perform a run-time
			//  check that will catch (perhaps most) true positives while causing no false positives.
			//  We can insist that EAX must be EITHER the sign-extension or the zero-extension of AX.
			//  To be neither type of extension of AX implies that some sort of truncation is happening.
			//  So, we emit a CHECK TRUNCATION UNKNOWNSIGN 32 EAX 16 AX annotation, and the Strata
			//  instrumentation will check for either EAX == sign-extended AX or EAX == zero-extended AX
			//  being true. If neither is true, we raise a true positive alert. False negatives on
			//  signedness errors are the result of the uncertainty, but all truncations are detected
			//  for all nine cases.

			bool HasSinkString = HasIntErrorSink;
			if (DefIsUnsigned || UseIsUnsigned) {
				// First five cases above: any UNSIGNED operand leads to CHECK TRUNCATION UNSIGNED annotation.
				if (!SuppressTruncation) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION UNSIGNED %zu %s %zu %s",
						(unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth,
						MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp));
					if (HasSinkString) {
						SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
					}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
					++TruncationAnnotationsCount;
#endif
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION UNSIGNED %zu %s %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth,
						MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp), TruncationIdiomCode, disasm);
				}
				if (UseIsUnsigned && DefIsSigned && !OutArgsWrite && !PartialStore) {
					if (!SuppressSignednessCheck && (0 == IdiomCode)) {
						unsigned short DummySignMask;
						if ((0 != TruncationIdiomCode) && this->MDIsSignedLoad(DummySignMask)) {
							// No truncation, extended load, so signedness check is unreliable.
							IdiomCode = 20;
							SuppressSignednessCheck = true;
						}
					}
					if (SuppressSignednessCheck && (0 == IdiomCode)) {
						;
					}
					else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ IDIOM %d %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
					}
				}
			}
			else if (DefIsSigned && UseIsSigned) {
				// S => S case above. Emit CHECK TRUNCATION SIGNED annotation.
				if (!SuppressTruncation) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION SIGNED %zu %s %zu %s",
						(unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth,
						MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp));
						if (HasSinkString) {
							SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm);
						}
						else {
							SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
						}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
					++TruncationAnnotationsCount;
#endif
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION SIGNED %zu %s %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth,
						MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp), TruncationIdiomCode, disasm);
				}
			}
			else {
				// S => ?, ? => S, ? => ? cases above: CHECK TRUNCATION UNKNOWNSIGN annotation.
				if (!SuppressTruncation) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION UNKNOWNSIGN %zu %s %zu %s",
						(unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth,
						MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp));
					if (HasSinkString) {
						SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
					}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
						++TruncationAnnotationsCount;
#endif
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR CHECK TRUNCATION UNKNOWNSIGN %6zu %s %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth,
						MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp), TruncationIdiomCode, disasm);
				}
			}
#if 1
			// Now check for signedness conflicts between the UseOp USEs and its DEF.
			if (!OutArgsWrite && !PartialStore) { // Inferred signedness of outargs location is invalid anyway
				if (!SuppressSignednessCheck && (0 == IdiomCode)) {
					unsigned short DummySignMask;
					if ((0 != TruncationIdiomCode) && this->MDIsSignedLoad(DummySignMask)) {
						// No reliable truncation, extended load, so signedness check is unreliable.
						IdiomCode = 20;
						SuppressSignednessCheck = true;
					}
				}
				if (UseIsSigned && SourceDefIsUnsigned) {
					if (SuppressSignednessCheck && (0 == IdiomCode)) {
						;
					}
					else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
					}
				}
				else if (UseIsUnsigned && SourceDefIsSigned) {
					// Currently same annotation, but might differ in the future for better forensics
					//  and more precise diagnostic messages.
					if (SuppressSignednessCheck && (0 == IdiomCode)) {
						;
					}
					else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
					}
				}
				else if ((!SourceDefSignMixed) && UseSignMixed) {
					// DEF has consistent and known signedness, USE is inconsistent.
					if (SuppressSignednessCheck && (0 == IdiomCode)) {
						;
					}
					else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS %s %zu %s ZZ %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[SourceDefSignMask], 
							UseBitWidth, MDGetRegName(UseOp), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS %s %zu %s ZZ IDIOM %d %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[SourceDefSignMask], 
							UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
					}
				}
			}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			if (SuppressSignednessCheck || (0 < IdiomCode)) {
				++SuppressSignednessOnTruncation;
			}
#endif
#endif
		} // end if truncation
		else if (!IgnoreOutArgsWrite && !PartialStore) { // still need to check for signedness errors even if no truncation
			if (!SuppressSignednessCheck && (0 == IdiomCode)) {
				unsigned short DummySignMask;
				if (this->MDIsSignedLoad(DummySignMask)) {
					// No truncation, extended load, so signedness check is unreliable.
					IdiomCode = 20;
					SuppressSignednessCheck = true;
				}
			}
			if (this->IsUnsignedArg()) {
				DefIsUnsigned = true;
			}
			if (UseIsSigned && DefIsUnsigned) {
				if (SuppressSignednessCheck && (0 == IdiomCode)) {
					;
				}
				else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
				}
			}
			else if (UseIsUnsigned && DefIsSigned) {
				// Currently UNSIGNED and SIGNED annotations for signedness differ only in the
				//  arithmetic saturation value applied as a recovery action. UNSIGNED means
				//  left-hand-side is UNSIGNED so saturate a negative right-hand-side up to 0,
				//  while SIGNED means lhs is SIGNED so saturate large rhs to 0x7fff....
				//  For inconsistent sign cases we default to SIGNED.
				if (SuppressSignednessCheck && (0 == IdiomCode)) {
					;
				}
				else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
				}
			}
			else if (UseIsSigned && SourceDefIsUnsigned) {
				if (SuppressSignednessCheck && (0 == IdiomCode)) {
					;
				}
				else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
				}
			}
			else if (UseIsUnsigned && SourceDefIsSigned) {
				// Currently same annotation, but might differ in the future for better forensics
				//  and more precise diagnostic messages.
				if (SuppressSignednessCheck && (0 == IdiomCode)) {
					;
				}
				else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm);
				}
			}
#if 0
			else if ((!SourceDefSignMixed) && UseSignMixed) {
				// source DEF has consistent and known signedness, source USE is inconsistent.
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %u %s ZZ %s \n",
					(unsigned long long)this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm);
			}
#endif
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			if (SuppressSignednessCheck && (0 == IdiomCode)) {
				;
			}
			else if (!SuppressSignednessCheck && (0 == IdiomCode)) {
				++SignednessWithoutTruncationCount;
			}
			else {
				++SuppressSignednessOnTruncation;
			}
#endif
		} // end if truncation else check signedness
	} // end of cases 4-5, (3 == OptType) checking for TRUNCATION and SIGNEDNESS errors
	else if (case6) {
		// Case 6: Load Effective Address opcodes can do arithmetic that silently overflows.
		this->MDEmitLeaOpcodeOverflowAnnotations(InfoAnnotFile, LoopList);
	} // end of case 6, LoadEffectiveAddress instruction
	else if (case7) {
		// case 7: half of register is sign-extended into the full register.
		//  Potential truncation error if entire register was DEFed first, because
		//  only the lower half is used. That also makes a potential signedness
		//  error, because the "sign bit" that is being extended is really a data bit,
		//  not a sign bit.
		DefIter = this->GetFirstNonFlagsDef();
		assert(DefIter != this->GetLastDef());
		DefOp = DefIter->GetOp();
		assert(DefOp->IsRegOp());
		SSANum = DefIter->GetSSANum();
		DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum);
		UseIter = this->GetFirstUse();
		assert(UseIter != this->GetLastUse());
		UseOp = UseIter->GetOp();
		assert(UseOp->IsRegOp());
		SSANum = UseIter->GetSSANum();
		UseHashValue = HashGlobalNameAndSSA(UseOp, SSANum);
		if (this->GetBlock()->IsLocalName(DefOp)) {
			DefFGInfo = this->GetBlock()->GetDefFGInfo(DefHashValue);
			SourceDefFGInfo = this->GetBlock()->GetDefFGInfo(UseHashValue);
		}
		else {
			DefFGInfo = this->GetBlock()->GetFunc()->GetDefFGInfo(DefHashValue);
			SourceDefFGInfo = this->GetBlock()->GetFunc()->GetDefFGInfo(UseHashValue);
		}
		DefWidthInfo = DefFGInfo.SizeInfo;
		DefMaxBitWidth = LargestBitWidthFromMask(DefWidthInfo); // max width over all defs
		SourceDefWidthInfo = SourceDefFGInfo.SizeInfo;
		SourceDefBitWidth = LargestBitWidthFromMask(SourceDefWidthInfo); // max width over all defs
		// Was the USE in the width-doubling instruction originally DEFed to have more bits
		//  than are used in the width-doubling instruction? If so, we have truncation and
		//  signedness errors to check at run time.
		UseBitWidth = (DefMaxBitWidth / 2); // USE should have been DEFed with this bit width
		if (SourceDefBitWidth > UseBitWidth) {
			// Make checks signed, because of the implications of sign extension by these opcodes.
			SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR CHECK TRUNCATION SIGNED %zu %s %zu %s ZZ %s \n",
				(unsigned long long) this->GetAddr(), this->GetSize(), DefMaxBitWidth,
					MDGetRegName(DefOp), UseBitWidth, MDGetRegName(UseOp), disasm);
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			++WidthDoublingTruncationCount;
#endif
		}
	} // end of case 7, doubles width inside register
	else if (case8) {
		// PEASOUP wants info on memset() calls.
		string FuncName = this->GetTrimmedCalledFunctionName();
		if (0 == FuncName.compare("memset")) {
			STARSOpndTypePtr MemSetTarget;
			std::size_t MemSetSize;
			int StackOffset;
			bool FPRelativeTarget = false; // original target before stack delta normalization
			if (this->GetBlock()->AnalyzeMemSet(this->GetAddr(), MemSetTarget, MemSetSize, StackOffset, FPRelativeTarget)) {
				if (0 < MemSetSize) {
					// Emit annotation.
					// NOTE: We want the unnormalized stack operand, so that Strata and SPRI will get
					//  annotations that match what is seen in the assembly language.
					if (FPRelativeTarget) {
						// Must be negative offset from EBP.
						assert(UseFP);
						StackOffset -= (int) this->GetBlock()->GetFunc()->GetFramePtrStackDelta();
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSET STACKOFFSET_EBP %d SIZE %zu ZZ %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), StackOffset, MemSetSize, disasm);
					}
					else {
						// Must be non-negative offset from ESP.
						StackOffset -= this->GetStackPtrOffset();
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSET STACKOFFSET_ESP %d SIZE %zu ZZ %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), StackOffset, MemSetSize, disasm);
					}
				}
			}
		}
	} // end of memset() case

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

#define MAX_OFFSET_STR_LEN 40

// Emit overflow annotations for lea opcodes that perform arithmetic that
//  can overflow without affecting the flags.
void SMPInstr::MDEmitLeaOpcodeOverflowAnnotations(FILE *InfoAnnotFile, list<std::size_t> &LoopList) {
	set<DefOrUse, LessDefUse>::iterator UseIter, DefIter;
	std::size_t OpNum;
	int BaseReg;
	int IndexReg;
	uint16_t ScaleFactor;
	STARS_ea_t offset;
	int SignedOffset;
	bool ScaledIndexReg;
	bool SourceFound = false;
	bool DataPointer = false;
	int SSANum;
	SMPOperandType DefType, UseType;
	int UseHashValue;
	int IdiomCode = 0;
	struct FineGrainedInfo UseFGInfo, SourceDefFGInfo;
	unsigned short UseSignMask, SourceDefSignMask, BaseRegSignMask, TempSignMask;
	unsigned short BaseRegWidthInfo, UseBitWidthInfo;
	std::size_t BaseRegMaxWidth, IndexRegMaxWidth, TempMaxWidth;
	char OffsetString[MAX_OFFSET_STR_LEN];
	STARSOpndTypePtr TempOp = nullptr, DefOp = nullptr;

	for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
		TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			if (TempOp->IsMemOp()) {
				MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);
				SignedOffset = (int) offset; // IDA Pro makes offset unsigned for some reason.
				SourceFound = true;
				break;
			}
		}
	}
	assert(SourceFound);
	if (MDIsStackAccessOpnd(TempOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
		// If the lea operand is something like lea ebx,[esp+4] we do not want to waste
		//  time checking for overflow, because stack pointers and frame pointers
		//  are kept within integer bounds (and if not, something big and terrible will
		//  happen long before integer bounds are overflowed or underflowed).
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
		++SuppressStackPtrOverflowCount;
#endif
		return;
	}
	else { // Check for the benign overflow cases we want to ignore.
		DefIter = this->GetFirstNonFlagsDef();
		assert(DefIter != this->GetLastDef());
		DefOp = DefIter->GetOp();
		SSANum = DefIter->GetSSANum();
		DefType = DefIter->GetType();
		DataPointer = IsDataPtr(DefType);
		if (this->IsHashOperation()) {
			IdiomCode = 15;
		}
		else if (this->GetBlock()->IsBenignOverflowDEF(DefOp, SSANum, this->GetAddr(), this->MDIsUnderflowingOpcode(), IdiomCode)) {
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			++BenignOverflowDefCount;
#endif
			;
		}
	}

	if (0 == IdiomCode) {
		// Any overflow or underflow producing a PTROFFSET type should be suppressed.
		for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
			DefType = DefIter->GetType();
			if (IsEqType(DefType, PTROFFSET)) {
				IdiomCode = 19;
				break;
			}
			else if (IsEqType(DefType, NEGATEDPTR)) {
				IdiomCode = 13;
				break;
			}
		}
	}
	if (0 == IdiomCode) {
		// Any overflow or underflow using a PTROFFSET type should be suppressed.
		for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
			UseType = UseIter->GetType();
			if (IsEqType(UseType, PTROFFSET)) {
				IdiomCode = 19;
				break;
			}
			else if (IsEqType(UseType, NEGATEDPTR)) {
				IdiomCode = 13;
				break;
			}
		}
	}

	char *disasm = DisAsmText.GetDisAsm(this->GetAddr());

	ScaledIndexReg = (0 < ScaleFactor);
	if (0 != SignedOffset) {
		(void) SMP_snprintf(OffsetString, MAX_OFFSET_STR_LEN-2, "%d", SignedOffset);
	}

	// Build up the computational string one operation at a time and emit
	//  CHECK OVERFLOW annotations after each step.
	string CurrString("");
	const char *ScaleStrings[4] = {"", "*2", "*4", "*8"};
	string PtrString("");
	if (IdiomCode == 0) {
		if (!DataPointer && (1 == LoopList.size())) { // Start with simple case of blocks only present in one loop
			SMPOperandType MemType = UNINIT;
			std::size_t Counter = 0;
			std::size_t LoopNum = LoopList.front();
			this->GetBlock()->GetFunc()->ResetProcessedBlocks();
			bool AddrRegOnly = this->GetBlock()->IsDefOnlyUsedAsAddressReg(this->GetAddr(), DefOp, LoopNum, Counter, MemType);
			if (AddrRegOnly && (0 < Counter)) {
				// Similarly, let C7 (buffer overflow/underflow) defenses handle the issues if it is only an index register.
				DefType = MemType;					
				DataPointer = true;
			}
		}
		if (DataPointer) {
			if (IsEqType(STACKPTR, DefType))
				PtrString = "STACKMEMSINK";
			else if (IsEqType(HEAPPTR, DefType))
				PtrString = "HEAPMEMSINK";
			else if (IsEqType(GLOBALPTR, DefType))
				PtrString = "GLOBALMEMSINK";
			else
				PtrString = "MEMORYSINK";
			IdiomCode = 18;
		}
		else {
			// Any overflow or underflow using a POINTER type should be suppressed.
			for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
				UseType = UseIter->GetType();
				if (IsDataPtr(UseType)) {
					if (IsEqType(STACKPTR, UseType))
						PtrString = "STACKMEMSINK";
					else if (IsEqType(HEAPPTR, UseType))
						PtrString = "HEAPMEMSINK";
					else if (IsEqType(GLOBALPTR, UseType))
						PtrString = "GLOBALMEMSINK";
					else
						PtrString = "MEMORYSINK";
					IdiomCode = 18;
					break;
				}
			}
		}
	}

	// Gather signedness info about BaseReg, if any, that will be used in multiple cases below.
	if (STARS_x86_R_none != BaseReg) {
		STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg));
		if (this->MDIsAddressing64bit()) {
			RegOp->SetByteWidth(8);
		}
		UseIter = this->FindUse(RegOp);
		assert(UseIter != this->GetLastUse());
		UseHashValue = HashGlobalNameAndSSA(RegOp, UseIter->GetSSANum());
		if (this->BasicBlock->IsLocalName(RegOp)) {
			// Local name, find in basic block maps.
			SourceDefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue);
			UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue);
		}
		else { // Global name, find in global maps.
			SourceDefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue);
			UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
		}
		UseSignMask = (UseFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
		SourceDefSignMask = (SourceDefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
		if (UseSignMask == 0) {
			// Get signedness info wherever it is available.
			UseSignMask = SourceDefSignMask;
		}
		BaseRegSignMask = UseSignMask;
		if ((17 == IdiomCode) && (FG_MASK_UNSIGNED == BaseRegSignMask)) {
			// An IdiomCode of 17 means not a benign overflow, but an addition that
			//  produces a jump table offset, which can be an addition of mixed signedness
			//  that produces false positives if treated as UNSIGNED. See discussion in
			//  SMPBasicBlock::IsBenignOverflowDEF().
			BaseRegSignMask = FG_MASK_INCONSISTENT_SIGN;
		}
		BaseRegWidthInfo = (UseFGInfo.SizeInfo & FG_MASK_BITWIDTH_FIELDS);
		if (0 == BaseRegWidthInfo) {
			BaseRegWidthInfo = (SourceDefFGInfo.SizeInfo & FG_MASK_BITWIDTH_FIELDS);
		}
		BaseRegMaxWidth = LargestBitWidthFromMask(BaseRegWidthInfo);
	}
	else {
		BaseRegMaxWidth = 0;
		BaseRegSignMask = 0;
	}

	if (STARS_x86_R_none != IndexReg) {
		// Get signedness info for IndexReg.
		STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg));
		if (this->MDIsAddressing64bit()) {
			RegOp->SetByteWidth(8);
		}
		UseIter = this->FindUse(RegOp);
		assert(UseIter != this->GetLastUse());
		UseHashValue = HashGlobalNameAndSSA(RegOp, UseIter->GetSSANum());
		if (this->BasicBlock->IsLocalName(RegOp)) {
			// Local name, find in basic block maps.
			SourceDefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue);
			UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue);
		}
		else { // Global name, find in global maps.
			SourceDefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue);
			UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
		}
		UseSignMask = (UseFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
		SourceDefSignMask = (SourceDefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
		if (UseSignMask == 0) {
			// Get signedness info wherever it is available.
			UseSignMask = SourceDefSignMask;
		}
		if ((17 == IdiomCode) && (FG_MASK_UNSIGNED == UseSignMask)) {
			// An IdiomCode of 17 means not a benign overflow, but an addition that
			//  produces a jump table offset, which can be an addition of mixed signedness
			//  that produces false positives if treated as UNSIGNED. See discussion in
			//  SMPBasicBlock::IsBenignOverflowDEF().
			UseSignMask = FG_MASK_INCONSISTENT_SIGN;
			IdiomCode = 0; // reset; not a benign code idiom
		}
		UseBitWidthInfo = (UseFGInfo.SizeInfo & FG_MASK_BITWIDTH_FIELDS);
		IndexRegMaxWidth = LargestBitWidthFromMask(UseBitWidthInfo);
		TempSignMask = (BaseRegSignMask | UseSignMask);
		TempMaxWidth = (BaseRegMaxWidth >= IndexRegMaxWidth) ? BaseRegMaxWidth : IndexRegMaxWidth;

		if (ScaledIndexReg) {
			assert((ScaleFactor >= 1) && (ScaleFactor <= 3));
			assert((IndexReg >= STARS_x86_R_ax) && (IndexReg <= STARS_x86_R_bh));
			CurrString += MDGetRegName(RegOp);
			CurrString += ScaleStrings[ScaleFactor];
			if (IdiomCode > 0) {
				if (IdiomCode == 18) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[UseSignMask], 
						IndexRegMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[UseSignMask], 
						IndexRegMaxWidth, CurrString.c_str(), IdiomCode, disasm);
				}
			}
			else {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n",
					(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[UseSignMask], 
					IndexRegMaxWidth, CurrString.c_str(), disasm);
			}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			++LeaInstOverflowCount;
#endif
			if (STARS_x86_R_none != BaseReg) {
				// Have BaseReg+IndexReg*ScaleFactor
				string TempStr(CurrString);
				CurrString.clear();
				STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg));
				if (this->MDIsAddressing64bit()) {
					RegOp->SetByteWidth(8);
				}
				CurrString += MDGetRegName(RegOp);
				CurrString += "+";
				CurrString += TempStr;
				if (IdiomCode > 0) {
					if (IdiomCode == 18) {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
							TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
							TempMaxWidth, CurrString.c_str(), IdiomCode, disasm);
					}
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
						TempMaxWidth, CurrString.c_str(), disasm);
				}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
				++LeaInstOverflowCount;
#endif
			}
			if (0 != SignedOffset) {
				// We have  [ BaseReg + ] IndexReg*ScaleFactor+offset [BaseReg or not]
				//  CurrString has everything through the end of the scalefactor in either case.
#if 0 // easier for instrumentation to always use ADD, even for negative offsets
				if (0 < SignedOffset)
#endif
					CurrString += "+";

				CurrString += OffsetString;
				if (IdiomCode > 0) {
					if (IdiomCode == 18) {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
							TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
							TempMaxWidth, CurrString.c_str(), IdiomCode, disasm);
					}
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
						TempMaxWidth, CurrString.c_str(), disasm);
				}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
				++LeaInstOverflowCount;
#endif
			}
		}
		else if (STARS_x86_R_none != BaseReg) {
			// We have BaseReg+IndexReg, unscaled.
			STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg));
			if (this->MDIsAddressing64bit()) {
				RegOp->SetByteWidth(8);
			}
			CurrString += MDGetRegName(RegOp);
			CurrString += "+";
			STARSOpndTypePtr IndexOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg));
			if (this->MDIsAddressing64bit()) {
				IndexOp->SetByteWidth(8);
			}
			CurrString += MDGetRegName(IndexOp);
			if (IdiomCode > 0) {
				if (IdiomCode == 18) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
						TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
						TempMaxWidth, CurrString.c_str(), IdiomCode, disasm);
				}
			}
			else {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n",
					(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
					TempMaxWidth, CurrString.c_str(), disasm);
			}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			++LeaInstOverflowCount;
#endif
			if (0 != SignedOffset) {
				// We have BaseReg + IndexReg + offset
#if 0 // easier for instrumentation to always use ADD, even for negative offsets
				if (0 < SignedOffset)
#endif
					CurrString += "+";

				CurrString += OffsetString;
				if (IdiomCode > 0) {
					if (IdiomCode == 18) {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
							TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm);
					}
					else {
						SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n",
							(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
							TempMaxWidth, CurrString.c_str(), IdiomCode, disasm);
					}
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
						TempMaxWidth, CurrString.c_str(), disasm);
				}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
				++LeaInstOverflowCount;
#endif
			}
		}
		else if (0 != SignedOffset) {
			// We have just IndexReg+offset.
			STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg));
			if (this->MDIsAddressing64bit()) {
				RegOp->SetByteWidth(8);
			}
			CurrString += MDGetRegName(RegOp);
#if 0 // easier for instrumentation to always use ADD, even for negative offsets
			if (0 < SignedOffset)
#endif
				CurrString += "+";

			CurrString += OffsetString;
			if (IdiomCode > 0) {
				if (IdiomCode == 18) {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
						TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm);
				}
				else {
					SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n",
						(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
						TempMaxWidth, CurrString.c_str(), IdiomCode, disasm);
				}
			}
			else {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n",
					(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], 
					TempMaxWidth, CurrString.c_str(), disasm);
			}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
			++LeaInstOverflowCount;
#endif
		}
		else {
			// Just IndexReg, no BaseReg or offset, so nothing to do.
			;
		}
	}
	else if ((STARS_x86_R_none != BaseReg) && (SignedOffset != 0)) {
		// No index reg, scaled or otherwise. Just BaseReg+offset
		STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg));
		if (this->MDIsAddressing64bit()) {
			RegOp->SetByteWidth(8);
		}
		CurrString += MDGetRegName(RegOp);
		if (17 == IdiomCode) {
			IdiomCode = 0; // reset; not a benign code idiom
		}
#if 0 // easier for instrumentation to always use ADD, even for negative offsets
		if (0 < SignedOffset)
#endif
			CurrString += "+";

		CurrString += OffsetString;
		if (IdiomCode > 0) {
			if (IdiomCode == 18) {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n",
					(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[BaseRegSignMask], 
					BaseRegMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm);
			}
			else {
				SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n",
					(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[BaseRegSignMask], 
					BaseRegMaxWidth, CurrString.c_str(), IdiomCode, disasm);
			}
		}
		else {
			SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n",
				(unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[BaseRegSignMask], 
				BaseRegMaxWidth, CurrString.c_str(), disasm);
		}
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
		++LeaInstOverflowCount;
#endif
	}
	else {
		// Either just a BaseReg, or just an offset. Nothing to do.
		;
	}

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

// Get the immediate value used in the instruction. Return zero
//  if no immediate was used.
int SMPInstr::MDGetImmedUse(void) {
	int ImmedVal = 0;
	set<DefOrUse, LessDefUse>::iterator CurrUse;
	for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
		STARSOpndTypePtr UseOp = CurrUse->GetOp();
		if (UseOp->IsImmedOp()) {
			assert(sizeof(int) <= sizeof(uintptr_t));
			ImmedVal = (int) UseOp->GetImmedValue();
			break;
		}
	}
	return ImmedVal;
} // end of SMPInstr::MDGetImmedUse()

// See which particular SCCP flags (carry flag, zero flag, etc.) are USEd
void SMPInstr::MDGetFlagsUsed(set<int> &UsedFlags) {
	pair<set<int>::iterator, bool> InsertResult;
	switch (this->GetIDAOpcode()) {
		case STARS_NN_adc:                 // Add with Carry
		case STARS_NN_daa:                 // Decimal Adjust AL after Addition
		case STARS_NN_das:                 // Decimal Adjust AL after Subtraction
		case STARS_NN_jae:                 // Jump if Above or Equal (CF=0)
		case STARS_NN_jb:                  // Jump if Below (CF=1)
		case STARS_NN_jc:                  // Jump if Carry (CF=1)
		case STARS_NN_jnae:                // Jump if Not Above or Equal (CF=1)
		case STARS_NN_jnb:                 // Jump if Not Below (CF=0)
		case STARS_NN_jnc:                 // Jump if Not Carry (CF=0)
		case STARS_NN_rcl:                 // Rotate Through Carry Left
		case STARS_NN_rcr:                 // Rotate Through Carry Right
		case STARS_NN_sbb:                 // Integer Subtraction with Borrow
		case STARS_NN_setae:               // Set Byte if Above or Equal (CF=0)
		case STARS_NN_setb:                // Set Byte if Below (CF=1)
		case STARS_NN_setc:                // Set Byte if Carry (CF=1)
		case STARS_NN_setnae:              // Set Byte if Not Above or Equal (CF=1)
		case STARS_NN_setnb:               // Set Byte if Not Below (CF=0)
		case STARS_NN_setnc:               // Set Byte if Not Carry (CF=0)
		case STARS_NN_cmovb:               // Move if Below (CF=1)
		case STARS_NN_cmovnb:              // Move if Not Below (CF=0)
		case STARS_NN_fcmovb:              // Floating Move if Below
		case STARS_NN_fcmovnb:             // Floating Move if Not Below
		case STARS_NN_setalc:              // Set AL to Carry Flag
		case STARS_NN_adcx:                 // Unsigned Integer Addition of Two Operands with Carry Flag
			InsertResult = UsedFlags.insert(MD_CARRY_FLAG);
			break;

		case STARS_NN_into:                // Call to Interrupt Procedure if Overflow Flag = 1
		case STARS_NN_jno:                 // Jump if Not Overflow (OF=0)
		case STARS_NN_jo:                  // Jump if Overflow (OF=1)
		case STARS_NN_setno:               // Set Byte if Not Overflow (OF=0)
		case STARS_NN_seto:                // Set Byte if Overflow (OF=1)
		case STARS_NN_cmovno:              // Move if Not Overflow (OF=0)
		case STARS_NN_cmovo:               // Move if Overflow (OF=1)
		case STARS_NN_adox:                 // Unsigned Integer Addition of Two Operands with Overflow Flag
			InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG);
			break;

		case STARS_NN_ja:                  // Jump if Above (CF=0 & ZF=0)
		case STARS_NN_jbe:                 // Jump if Below or Equal (CF=1 | ZF=1)
		case STARS_NN_jna:                 // Jump if Not Above (CF=1 | ZF=1)
		case STARS_NN_jnbe:                // Jump if Not Below or Equal (CF=0 & ZF=0) a.k.a. ja
		case STARS_NN_seta:                // Set Byte if Above (CF=0 & ZF=0)
		case STARS_NN_setbe:               // Set Byte if Below or Equal (CF=1 | ZF=1)
		case STARS_NN_setna:               // Set Byte if Not Above (CF=1 | ZF=1)
		case STARS_NN_setnbe:              // Set Byte if Not Below or Equal (CF=0 & ZF=0)
		case STARS_NN_cmova:               // Move if Above (CF=0 & ZF=0)
		case STARS_NN_cmovbe:              // Move if Below or Equal (CF=1 | ZF=1)
		case STARS_NN_fcmovbe:             // Floating Move if Below or Equal
		case STARS_NN_fcmovnbe:            // Floating Move if Not Below or Equal
			InsertResult = UsedFlags.insert(MD_CARRY_FLAG);
			InsertResult = UsedFlags.insert(MD_ZERO_FLAG);
			break;

		case STARS_NN_ins:                 // Input string; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used
		case STARS_NN_je:                  // Jump if Equal (ZF=1)
		case STARS_NN_jne:                 // Jump if Not Equal (ZF=0)
		case STARS_NN_jnz:                 // Jump if Not Zero (ZF=0)  a.k.a. jne
		case STARS_NN_jz:                  // Jump if Zero (ZF=1)
		case STARS_NN_lods:                // Load string; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used
		case STARS_NN_loopwe:              // Loop while CX != 0 and ZF=1
		case STARS_NN_loope:               // Loop while rCX != 0 and ZF=1
		case STARS_NN_loopde:              // Loop while ECX != 0 and ZF=1
		case STARS_NN_loopqe:              // Loop while RCX != 0 and ZF=1
		case STARS_NN_loopwne:             // Loop while CX != 0 and ZF=0
		case STARS_NN_loopne:              // Loop while rCX != 0 and ZF=0
		case STARS_NN_loopdne:             // Loop while ECX != 0 and ZF=0
		case STARS_NN_loopqne:             // Loop while RCX != 0 and ZF=0
		case STARS_NN_movs:                // Move Byte(s) from String to String; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used
		case STARS_NN_outs:                // Output string; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used
		case STARS_NN_repe:                // Repeat String Operation while ZF=1
		case STARS_NN_repne:               // Repeat String Operation while ZF=0
		case STARS_NN_scas:                // Scan String; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used
		case STARS_NN_sete:                // Set Byte if Equal (ZF=1)
		case STARS_NN_setne:               // Set Byte if Not Equal (ZF=0)
		case STARS_NN_setnz:               // Set Byte if Not Zero (ZF=0)
		case STARS_NN_setz:                // Set Byte if Zero (ZF=1)
		case STARS_NN_stos:                // Store String; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used
		case STARS_NN_cmovnz:              // Move if Not Zero (ZF=0)
		case STARS_NN_cmovz:               // Move if Zero (ZF=1)
		case STARS_NN_fcmove:              // Floating Move if Equal
		case STARS_NN_fcmovne:             // Floating Move if Not Equal
			InsertResult = UsedFlags.insert(MD_ZERO_FLAG);
			break;

		case STARS_NN_jge:                 // Jump if Greater or Equal (SF=OF)
		case STARS_NN_jl:                  // Jump if Less (SF!=OF)
		case STARS_NN_jnge:                // Jump if Not Greater or Equal (SF != OF) **
		case STARS_NN_jnl:                 // Jump if Not Less (SF=OF) a.k.a. jge
		case STARS_NN_setge:               // Set Byte if Greater or Equal (SF=OF)
		case STARS_NN_setl:                // Set Byte if Less (SF!=OF)
		case STARS_NN_setnge:				 // Set Byte if Not Greater or Equal (SF!=OF)
		case STARS_NN_setnl:               // Set Byte if Not Less (SF=OF)
		case STARS_NN_cmovge:              // Move if Greater or Equal (SF=OF)
		case STARS_NN_cmovl:               // Move if Less (SF!=OF)
			InsertResult = UsedFlags.insert(MD_SIGN_FLAG);
			InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG);
			break;

		case STARS_NN_jg:                  // Jump if Greater (ZF=0 & SF=OF)
		case STARS_NN_jle:                 // Jump if Less or Equal (ZF=1 | SF!=OF)
		case STARS_NN_jng:                 // Jump if Not Greater (ZF=1 | SF!=OF) a.k.a. jle
		case STARS_NN_jnle:                // Jump if Not Less or Equal (ZF=0 & SF=OF) a.k.a. jg
		case STARS_NN_setg:                // Set Byte if Greater (ZF=0 & SF=OF)
		case STARS_NN_setle:               // Set Byte if Less or Equal (ZF=1 | SF!=OF)
		case STARS_NN_setng:               // Set Byte if Not Greater (ZF=1 | SF!=OF)
		case STARS_NN_setnle:              // Set Byte if Not Less or Equal (ZF=0 & SF=OF)
		case STARS_NN_cmovg:               // Move if Greater (ZF=0 & SF=OF)
		case STARS_NN_cmovle:              // Move if Less or Equal (ZF=1 | SF!=OF)
			InsertResult = UsedFlags.insert(MD_ZERO_FLAG);
			InsertResult = UsedFlags.insert(MD_SIGN_FLAG);
			InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG);
			break;

		case STARS_NN_jns:                 // Jump if Not Sign (SF=0)
		case STARS_NN_js:                  // Jump if Sign (SF=1)
		case STARS_NN_setns:               // Set Byte if Not Sign (SF=0)
		case STARS_NN_sets:                // Set Byte if Sign (SF=1)
		case STARS_NN_cmovns:              // Move if Not Sign (SF=0)
		case STARS_NN_cmovs:               // Move if Sign (SF=1)
			InsertResult = UsedFlags.insert(MD_SIGN_FLAG);
			break;

		case STARS_NN_jnp:                 // Jump if Not Parity (PF=0)
		case STARS_NN_jp:                  // Jump if Parity (PF=1)
			InsertResult = UsedFlags.insert(MD_PARITY_FLAG);
			break;

		case STARS_NN_lahf:                // Load Flags into AH Register
			InsertResult = UsedFlags.insert(MD_CARRY_FLAG);
			InsertResult = UsedFlags.insert(MD_ZERO_FLAG);
			InsertResult = UsedFlags.insert(MD_SIGN_FLAG);
			break;

		case STARS_NN_pushfw:              // Push Flags Register onto the Stack
		case STARS_NN_pushf:               // Push Flags Register onto the Stack
		case STARS_NN_pushfd:              // Push Flags Register onto the Stack (use32)
		case STARS_NN_pushfq:              // Push Flags Register onto the Stack (use64)
			InsertResult = UsedFlags.insert(MD_CARRY_FLAG);
			InsertResult = UsedFlags.insert(MD_ZERO_FLAG);
			InsertResult = UsedFlags.insert(MD_SIGN_FLAG);
			InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG);
			break;

		default:
			if (SMPUsesFlags[this->GetIDAOpcode()]) {
				SMP_msg("ERROR: SCCP: Unknown flags USEd in instruction opcode at %llx : %s\n", (unsigned long long) this->GetAddr(),
					DisAsmText.GetDisAsm(this->GetAddr()));
			}
			break;
	} // end switch on opcode
	return;
} // end of SMPInstr::MDGetFlagsUsed()

// Get funcname from call inst and remove "." and "_" prefices.
//  Asserts if this is not a call instruction.
string SMPInstr::GetTrimmedCalledFunctionName(void) {
	SMPitype DFType = this->GetDataFlowType();
	assert((CALL == DFType) || (INDIR_CALL == DFType) || this->IsTailCall());
	STARS_ea_t FuncAddr = this->GetCallTarget();
	char IDA_func_name[STARS_MAXSTR];
	std::size_t SkipCount;
	char *TempFuncName;

	if (CALL == DFType) {
		// We should have a good call target for direct calls.
		if (STARS_BADADDR != FuncAddr) {
			(void) SMP_get_func_name(FuncAddr, IDA_func_name, (std::size_t)(STARS_MAXSTR - 1));
			SkipCount = strspn(IDA_func_name, "._");
			TempFuncName = &(IDA_func_name[SkipCount]);
			string FuncName(TempFuncName);
			return FuncName;
		}
		else {
			string FuncName("syscall");
			return FuncName;
		}
	}
	else { // INDIR_CALL
		// We might have a resolved call target for indirect calls.
		if (STARS_BADADDR != FuncAddr) {
			// We have a resolved address for the indirect call.
			(void) SMP_get_func_name(FuncAddr, IDA_func_name, (std::size_t)(STARS_MAXSTR - 1));
			SkipCount = strspn(IDA_func_name, "._");
			TempFuncName = &(IDA_func_name[SkipCount]);
			string IndirFuncName(TempFuncName);
			return IndirFuncName;
		}
		else { // INDIR_CALL, no resolved target.
			string DummyFuncName("ZST_NEVER_MATCH_THIS_FUNC_NAME");
			return DummyFuncName;
		}
	}
} // end of SMPInstr::GetTrimmedCalledFunctionName()

// Build the RTL for an instruction with a unary opcode
bool SMPInstr::BuildUnaryRTL(SMPoperator UnaryOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool WidthDoubler = this->MDDoublesWidth();
	unsigned short opcode = this->GetIDAOpcode();
	SMPRegTransfer *TempRT = NULL;

	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
	STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG);
	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);

	// Handle special cases first
	if (SMP_UNARY_FLOATING_ARITHMETIC == UnaryOp) {
		// Use of the floating register stack top is implicit
		DestFound = true;
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(FPRegOp);
		TempRT->SetOperator(SMP_ASSIGN);
		SMPRegTransfer *RightRT = new SMPRegTransfer;
		RightRT->SetParentInst(this);
		RightRT->SetLeftOperand(FPRegOp);
		RightRT->SetOperator(UnaryOp);
		RightRT->SetRightOperand(VoidOp);
		TempRT->SetRightTree(RightRT);
		this->RTL.push_back(TempRT);
	}
	else if ((STARS_NN_clc == opcode) || (STARS_NN_cld == opcode) || (STARS_NN_cmc == opcode) || (STARS_NN_stc == opcode) || (STARS_NN_std == opcode)) {
		// Flags register is implicit destination.
		DestFound = true;
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(FlagsOp);
		TempRT->SetOperator(SMP_ASSIGN);
		SMPRegTransfer *RightRT = new SMPRegTransfer;
		RightRT->SetParentInst(this);
		if (STARS_NN_cmc == opcode) { // complement carry flag USEs old carry flag
			RightRT->SetLeftOperand(FlagsOp);
			RightRT->SetOperator(SMP_BITWISE_NOT);
		}
		else {
			RightRT->SetLeftOperand(VoidOp);
			RightRT->SetOperator(UnaryOp);
		}
		RightRT->SetRightOperand(VoidOp);
		TempRT->SetRightTree(RightRT);
		this->RTL.push_back(TempRT);
	}

	for (OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		STARSOpndTypePtr LeftOp;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);

				if (WidthDoubler) {
					// Opcodes that sign-extend a byte to a word, or a word to a dword, 
					//  have only one operand. It is implicit, and it is the shorter USE.
					//  That means the DEF op will have the same width as the USE op, e.g. if
					//  we are sign-extending AX to EAX, the USE op and DEF op will both be AX
					//  without a special fix. We fix this problem with the DEF operand now.
					LeftOp = TempOp->clone();
					uint16_t CurrByteWidth = LeftOp->GetByteWidth();
					if ((1 == CurrByteWidth) || (2 == CurrByteWidth) || (4 == CurrByteWidth)) {
						LeftOp->DoubleRegWidth();
					}
					else {
						SMP_msg("ERROR: Instruction operand %zu not 1,2, or 4 bytes at %llx ; Width: %u\n",
							OpNum, (unsigned long long) this->GetAddr(), LeftOp->GetByteWidth());
					}
				}
				else { // No need to clone; we won't alter the operand by doubling it
					LeftOp = TempOp;
				}

				TempRT->SetLeftOperand(LeftOp);

				TempRT->SetOperator(SMP_ASSIGN);
				SMPRegTransfer *RightRT = new SMPRegTransfer;
				RightRT->SetParentInst(this);
				RightRT->SetLeftOperand(TempOp);
				RightRT->SetOperator(UnaryOp);
				RightRT->SetRightOperand(VoidOp);
				TempRT->SetRightTree(RightRT);
				this->RTL.push_back(TempRT);
			}
		}
	} // end for (OpNum = 0; ...)

#if SMP_DEBUG_BUILD_RTL
	if (!DestFound) {
		SMP_msg("ERROR: Could not find unary operand at %llx for %s\n", 
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
	}
#endif
	return DestFound;
} // end of SMPInstr::BuildUnaryRTL()

#if 0
// Cleaner, no special-case version of BuildUnary2OpndRTL()
// Build the RTL for an instruction of the form dest := unary_operator(src), with src != dest
bool SMPInstr::BuildUnaryTwoOperandRTL(SMPoperator UnaryOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SrcFound = false;
	STARSOpndTypePtr DestOp = nullptr, SrcOp = nullptr;
	SMPRegTransfer *TempRT = NULL;

	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();

	for (OpNum = 0; (!(DestFound && SourceFound)) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				DestOp = TempOp;
			}
		}
		else { // not dest, see if valid source
			if (MDKnownOperandType(TempOp)) {
				SourceFound = true;
				SrcOp = TempOp;
			}
		}
	} // end for (OpNum = 0; ...)

	if (DestFound && SourceFound) {
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(DestOp);
		TempRT->SetOperator(SMP_ASSIGN);
		SMPRegTransfer *RightRT = new SMPRegTransfer;
		RightRT->SetParentInst(this);
		RightRT->SetLeftOperand(SrcOp);
		RightRT->SetOperator(UnaryOp);
		RightRT->SetRightOperand(VoidOp);
		TempRT->SetRightTree(RightRT);
		this->RTL.push_back(TempRT);
	}
#if SMP_DEBUG_BUILD_RTL
	else {
		SMP_msg("ERROR: Could not find unary operand at %llx for %s\n", 
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
	}
#endif
	return DestFound;
} // end of SMPInstr::BuildUnaryTwoOperandRTL()
#endif

// Build the RTL for an instruction with a binary arithmetic opcode
bool SMPInstr::BuildBinaryRTL(SMPoperator BinaryOp, bool HiddenFPStackOp) {
	std::size_t OpNum;
	unsigned short opcode = this->GetIDAOpcode();
	bool DestFound = false;
	bool SourceFound = false;
	bool MemSrc = this->HasSourceMemoryOperand();
	bool MemDest = this->HasDestMemoryOperand();
	// Work around IDA pro error; they assumed that the pcmpeq/ne/gt/ge/lt/le
	//  families of instructions were just compares, so they do not tag
	//  either operand as a DEF. Actually, the first operand has byte or
	//  word or dword fields set to all 1's or all 0's based on the result
	//  of the comparison.
	bool SrcIsReallyDest = ((SMP_COMPARE_EQ_AND_SET <= BinaryOp) 
		&& (SMP_COMPARE_LE_AND_SET >= BinaryOp));
	bool StackPointerModification = false; // SP := SP SMP_BITWISE_AND operand
	bool NeedsGuard = ((STARS_NN_arpl == opcode) || (STARS_NN_bound == opcode));
	bool BuildOnlySignalRT = (STARS_NN_bound == opcode);
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	SMPGuard *Guard1 = NULL;
	RightRT->SetParentInst(this);

	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();

	STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG);
	// floating point register stack

	// Handle special cases first
	if (NeedsGuard) {
		// Need a guard in the RTL.
		Guard1 = new SMPGuard;
		Guard1->SetOperator(SMP_U_COMPARE);
	}
	else if (HiddenFPStackOp) {
		// Use of the floating register stack top is implicit
		DestFound = true;
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(FPRegOp);
		TempRT->SetOperator(SMP_ASSIGN);
		RightRT->SetLeftOperand(FPRegOp);
		RightRT->SetOperator(BinaryOp);
		RightRT->SetRightOperand(VoidOp);
		TempRT->SetRightTree(RightRT);
	}

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if ((this->STARSInstPtr->IsDefOpnd(OpNum))
			|| (SrcIsReallyDest && (0 == OpNum))) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				// See comments just below for floating point sources. FP stores
				//  are analogous to FP loads.
				if (!MemDest || (IsMemOperand(TempOp))) {
					DestFound = true;
					TempRT = new SMPRegTransfer;
					TempRT->SetParentInst(this);
					if (!BuildOnlySignalRT) {
						TempRT->SetLeftOperand(TempOp);
						TempRT->SetOperator(SMP_ASSIGN);
					}
					if (this->IsRegClearIdiom()) {
						STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);
						TempRT->SetRightOperand(ZeroOp);
						SourceFound = true; // cause loop exit
					}
					else {
						if (!BuildOnlySignalRT) {
							RightRT->SetLeftOperand(TempOp);
							RightRT->SetOperator(BinaryOp);
							TempRT->SetRightTree(RightRT);
							if (TempOp->MatchesReg(MD_STACK_POINTER_REG) && (SMP_BITWISE_AND == BinaryOp)) {
								StackPointerModification = true; // searching for SP := SP AND immediate
							}
						}
						if (NeedsGuard) {
							Guard1->SetLeftOperand(TempOp);
							TempRT->SetGuard(Guard1);
						}
					}
				}
				else {
					;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					SMP_msg("WARNING: Skipping DEF operand: ");
					PrintOperand(TempOp);
					SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				}
			}
			else if (DestFound && (!HiddenFPStackOp)) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found two DEF operands: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		}
		else { // USE
			if (!SourceFound && MDKnownOperandType(TempOp)) {
				// If this is a floating point instruction with the fpregs listed as
				//  a USE and a memory operand also listed as a USE, then we want to
				//  ignore the irrelevant USE of the fpreg stack.
				// Note that MemDest AND MemSrc means something like add mem,reg is being
				//  processed, where the memory operand is both DEF and USE.
				if (!MemSrc || MemDest || (IsMemOperand(TempOp))) {
					SourceFound = true;
					if (!BuildOnlySignalRT) {
						RightRT->SetRightOperand(TempOp);
						if (StackPointerModification && (TempOp->IsImmedOp())) {
							this->SetStackAlignmentInst();
						}
					}
				}
				else {
					SMP_msg("ERROR: Operand not processed as USE: ");
					PrintOperand(TempOp);
					SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
				}
				if (NeedsGuard) {
					Guard1->SetRightOperand(TempOp);
				}
			}
			if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: Operand neither DEF nor USE: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		} // end if DEF ... else ...
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound) {
		assert(NULL != RightRT);
		if (DestFound && (NULL != TempRT))
			delete TempRT;
		else
			delete RightRT;
#if SMP_DEBUG_BUILD_RTL
		if (!DestFound) {
			SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		else {
			SMP_msg("ERROR: Could not find binary operand at %llx for %s\n", 
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#endif
	}
	else {
		if (BuildOnlySignalRT) {
			TempRT->SetLeftOperand(VoidOp);
			TempRT->SetRightOperand(VoidOp);
			TempRT->SetOperator(SMP_SIGNAL);
			delete RightRT;
		}
		this->RTL.push_back(TempRT);
		// The "p" at the end of the opcode indicates that the floating point
		//  register stack gets popped.
		if ((STARS_NN_fstp == opcode) || (STARS_NN_fbstp == opcode) || (STARS_NN_fistp == opcode)) {
			this->RTL.ExtraKills.push_back(FPRegOp);
		}
	}
	return (DestFound && SourceFound);
} // end of SMPInstr::BuildBinaryRTL()

// helper for BuildRTL(); dest := src1 oper src2
bool SMPInstr::BuildBinary3OpndRTL(SMPoperator BinaryOp) {
	std::size_t OpNum;
	unsigned short opcode = this->GetIDAOpcode();
	bool DestFound = false;
	bool Source1Found = false;
	bool Source2Found = false;
	bool MemSrc = this->HasSourceMemoryOperand();
	bool MemDest = this->HasDestMemoryOperand();
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);

	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();

	for (OpNum = 0; !(DestFound && Source1Found && Source2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				if (!MemDest || (IsMemOperand(TempOp))) {
					DestFound = true;
					TempRT = new SMPRegTransfer;
					TempRT->SetParentInst(this);
					TempRT->SetLeftOperand(TempOp);
					TempRT->SetOperator(SMP_ASSIGN);
					if (this->IsRegClearIdiom()) {
						STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);
						TempRT->SetRightOperand(ZeroOp);
						Source1Found = Source2Found = true; // cause loop exit
					}
					else {
						RightRT->SetOperator(BinaryOp);
						TempRT->SetRightTree(RightRT);
					}
				}
				else {
					;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					SMP_msg("WARNING: Skipping DEF operand: ");
					PrintOperand(TempOp);
					SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				}
			}
			else if (DestFound) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found two DEF operands: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		}
		// Fall through from DEF to USE check, as an operand could be both in a three-operand opcode.
		if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			if (!Source1Found && MDKnownOperandType(TempOp)) {
				Source1Found = true;
				RightRT->SetLeftOperand(TempOp);
			}
			else if (!Source2Found && Source1Found && MDKnownOperandType(TempOp)) {
				Source2Found = true;
				RightRT->SetRightOperand(TempOp);
			}
		} // end if DEF ... else ...
	} // end for (OpNum = 0; ...)

	if (!DestFound || !Source1Found || !Source2Found) {
		assert(NULL != RightRT);
		if (DestFound && (NULL != TempRT))
			delete TempRT;
		else
			delete RightRT;
#if SMP_DEBUG_BUILD_RTL
		if (!DestFound) {
			SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		else {
			SMP_msg("ERROR: Could not find binary operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}
	return (DestFound && Source1Found && Source2Found);
} // end of SMPInstr::BuildBinary3OpndRTL()

// helper for BuildRTL(); dest := (src1 * src2) +/- src3
bool SMPInstr::BuildMultAddOrSub4OpndRTL(SMPoperator BinaryOp1, SMPoperator BinaryOp2) {
	bool DestFound = false;
	bool Source1Found = false;
	bool Source2Found = false;
	bool Source3Found = false;

	// RTL shape will be dest := (src3 SMP_ADD (src1 * src2)) or (src3 SMP_NEGATE_AND_ADD (src1 * src2))
	//  where the first operator is whatever is in BinaryOp2 and * is whatever is in BinaryOp1.
	//  The SMP_NEGATE_AND_ADD is needed because the RTL shape must grow with right tree and no left trees.
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	SMPRegTransfer *RightRightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	RightRightRT->SetParentInst(this);

	for (size_t OpNum = 0; !(DestFound && Source1Found && Source2Found && Source3Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				RightRT->SetOperator(BinaryOp2);
				TempRT->SetRightTree(RightRT);
				RightRightRT->SetOperator(BinaryOp1);
				RightRT->SetRightTree(RightRightRT);
			}
			else if (DestFound) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found two DEF operands: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		} // end if DEF ...
		else if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			if (!Source1Found && MDKnownOperandType(TempOp)) {
				Source1Found = true;
				RightRightRT->SetLeftOperand(TempOp);
			}
			else if (!Source2Found && Source1Found && MDKnownOperandType(TempOp)) {
				Source2Found = true;
				RightRightRT->SetRightOperand(TempOp);
			}
			else if (!Source3Found && Source2Found && MDKnownOperandType(TempOp)) {
				Source3Found = true;
				RightRT->SetLeftOperand(TempOp);
			}
		}
		else {
			;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
			SMP_msg("WARNING: Operand neither DEF nor USE: ");
			PrintOperand(TempOp);
			SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
		} // end if USE ... else ...
	} // end for (OpNum = 0; ...)

	if (!DestFound || !Source1Found || !Source2Found || !Source3Found) {
		assert(NULL != RightRT);
		if (DestFound && (NULL != TempRT))
			delete TempRT;
		else
			delete RightRT;
#if SMP_DEBUG_BUILD_RTL
		if (!DestFound) {
			SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		else {
			SMP_msg("ERROR: Could not find binary operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}

	return (DestFound && Source1Found && Source2Found && Source3Found);
} // end of SMPInstr::BuildMultAddOrSub4OpndRTL()

// Build the RTL for a signal/exception raised based on a guarded comparison of operands
bool SMPInstr::BuildGuardedSignalRTL(SMPoperator SignalOp) {
	std::size_t OpNum;
	bool Source1Found = false;
	bool Source2Found = false;
	SMPRegTransfer *TempRT = NULL;
	SMPGuard *Guard1 = new SMPGuard;

	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();

	Guard1->SetOperator(SMP_U_COMPARE);

	for (OpNum = 0; !(Source1Found && Source2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
					;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				SMP_msg("WARNING: Skipping DEF operand: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif

			}
		}
		else { // USE
			if (!Source1Found && MDKnownOperandType(TempOp)) {
				Source1Found = true;
				Guard1->SetLeftOperand(TempOp);
			}
			else if ((!Source2Found) && MDKnownOperandType(TempOp)) {
				Source2Found = true;
				Guard1->SetRightOperand(TempOp);
			}
			if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: Operand neither DEF nor USE: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		} // end if DEF ... else ...
	} // end for (OpNum = 0; ...)

	if (!Source1Found || !Source2Found) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		if (!Source1Found) {
			SMP_msg("ERROR: Could not find first USE operand for BOUND at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		else {
			SMP_msg("ERROR: Could not find second USE operand for BOUND at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		this->PrintOperands();
#endif
		delete Guard1;
	}
	else {
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(VoidOp);
		TempRT->SetRightOperand(VoidOp);
		TempRT->SetOperator(SignalOp);
		TempRT->SetGuard(Guard1);
		this->RTL.push_back(TempRT);
	}
	return (Source1Found && Source2Found);
} // end of SMPInstr::BuildGuardedSignalRTL()

// bool BuildUnary2OpndPlusImmedRTL(SMPoperator UnaryOp, SMPoperator ImmedOp); // helper for BuildRTL()

// Build the RTL for an instruction with a binary arithmetic opcode plus an operator to apply to
//  the two source-only operands, one of which is an immediate value.
bool SMPInstr::BuildBinaryPlusImmedRTL(SMPoperator BinaryOp, SMPoperator ImmedOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool ImmedFound = false;
	bool MemSrc = this->HasSourceMemoryOperand();
	bool MemDest = this->HasDestMemoryOperand();
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	SMPRegTransfer *ImmedRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	ImmedRT->SetParentInst(this);

	for (OpNum = 0; !(DestFound && SourceFound && ImmedFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				if (!MemDest || (IsMemOperand(TempOp))) {
					DestFound = true;
					TempRT = new SMPRegTransfer;
					TempRT->SetParentInst(this);
					TempRT->SetLeftOperand(TempOp);
					TempRT->SetOperator(SMP_ASSIGN);
					RightRT->SetLeftOperand(TempOp);
					RightRT->SetOperator(BinaryOp);
					TempRT->SetRightTree(RightRT);
				}
				else {
					;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					SMP_msg("WARNING: Skipping DEF operand: ");
					PrintOperand(TempOp);
					SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				}
			}
			else if (DestFound) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found two DEF operands: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		}
		else { // USE
			if (!SourceFound && MDKnownOperandType(TempOp)) {
				if (!MemSrc || (IsMemOperand(TempOp))) {
					SourceFound = true;
					ImmedRT->SetLeftOperand(TempOp);
				}
			}
			else if (!ImmedFound && (TempOp->IsImmedOp())) {
				ImmedFound = true;
				ImmedRT->SetRightOperand(TempOp);
				ImmedRT->SetOperator(ImmedOp);
				RightRT->SetRightTree(ImmedRT);
			}
			if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: Operand neither DEF nor USE: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		} // end if DEF ... else ...
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound || !ImmedFound) {
		assert(NULL != RightRT);
		if (DestFound && (NULL != TempRT))
			delete TempRT;
		else {
			delete RightRT;
			if (!ImmedFound)
				delete ImmedRT;
		}
#if SMP_DEBUG_BUILD_RTL
		if (!DestFound) {
			SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		else if (!ImmedFound) {
			SMP_msg("ERROR: Could not find immediate operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
		else {
			SMP_msg("ERROR: Could not find binary USE operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}
	return (DestFound && SourceFound && ImmedFound);
} // end of SMPInstr::BuildBinaryPlusImmedRTL()

// Build the RTL for an instruction with a binary arithmetic opcode, ignoring a third operand
//  which is an immediate value which is a control word for packed operations (e.g. SSE, XMM).
bool SMPInstr::BuildBinaryIgnoreImmedRTL(SMPoperator BinaryOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool ImmedFound = false;
	bool MemSrc = this->HasSourceMemoryOperand();
	bool MemDest = this->HasDestMemoryOperand();
	unsigned short opcode = this->GetIDAOpcode();
	bool ECXDest = ((STARS_NN_pcmpestri == opcode) || (STARS_NN_pcmpistri == opcode));
	bool XMM0Dest = ((STARS_NN_pcmpestrm == opcode) || (STARS_NN_pcmpistrm == opcode));
	bool SrcIsReallyDest = (ECXDest || XMM0Dest); // Dest is implicit, so ASM only has source operand
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);

	for (OpNum = 0; !(DestFound && SourceFound && ImmedFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if ((this->STARSInstPtr->IsDefOpnd(OpNum))
			|| (SrcIsReallyDest && (0 == OpNum))) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				if (!MemDest || (IsMemOperand(TempOp))) {
					DestFound = true;
					TempRT = new SMPRegTransfer;
					TempRT->SetParentInst(this);
					if (ECXDest) {
						STARSOpndTypePtr ECXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
						TempRT->SetLeftOperand(ECXOp);
					}
					else if (XMM0Dest) {
						STARSOpndTypePtr XMMOp = this->STARSInstPtr->MakeXMMRegOpnd(STARS_x86_R_xmm0);
						TempRT->SetLeftOperand(XMMOp);
					}
					else {
						TempRT->SetLeftOperand(TempOp);
					}
					TempRT->SetOperator(SMP_ASSIGN);
					RightRT->SetLeftOperand(TempOp);
					RightRT->SetOperator(BinaryOp);
					TempRT->SetRightTree(RightRT);
				}
				else {
					;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					SMP_msg("WARNING: Skipping DEF operand: ");
					PrintOperand(TempOp);
					SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				}
			}
			else if (DestFound) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found two DEF operands: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		}
		else { // USE
			if (!SourceFound && MDKnownOperandType(TempOp)) {
				if (!MemSrc || (IsMemOperand(TempOp))) {
					SourceFound = true;
					RightRT->SetRightOperand(TempOp);
				}
			}
			else if (!ImmedFound && (TempOp->IsImmedOp())) {
				ImmedFound = true;
			}
			if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: Operand neither DEF nor USE: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		} // end if DEF ... else ...
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound || !ImmedFound) {
		assert(NULL != RightRT);
		if (DestFound && (NULL != TempRT))
			delete TempRT;
		else
			delete RightRT;
#if SMP_DEBUG_BUILD_RTL
		if (!DestFound) {
			SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		else if (!ImmedFound) {
			SMP_msg("ERROR: Could not find immediate operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
		else {
			SMP_msg("ERROR: Could not find binary USE operand at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}
	return (DestFound && SourceFound && ImmedFound);
} // end of SMPInstr::BuildBinaryIgnoreImmedRTL()

// Build the RTL for a load-effective-address instruction.
bool SMPInstr::BuildLeaRTL(void) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool EIPRelativeAddr = false;
	STARSOpndTypePtr DefOp = nullptr;
	STARSOpndTypePtr UseOp = nullptr;
	SMPRegTransfer *AssignRT = NULL;
	int BaseReg;
	int IndexReg;
	uint16_t ScaleFactor;
	STARS_ea_t offset;
	bool ScaledIndexReg;

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			DefOp = TempOp;
			DestFound = true;
			assert(DefOp->IsRegOp());
		}
		else { // USE
			if (!SourceFound && MDKnownOperandType(TempOp)) {
				if (IsMemOperand(TempOp)) {
					SourceFound = true;
					UseOp = TempOp;
					MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);
					if (TempOp->GetSegReg() == STARS_x86_R_cs) {
						EIPRelativeAddr = true;
#if 0
						// Special case of PC-relative addressing, e.g. lea edx,[eip+offset]
						//  which is encoded by IDA Pro with no basereg but CS segreg.
						if (STARS_x86_R_none == BaseReg) {
							BaseReg = MD_INSTRUCTION_POINTER_REG;
						}
#endif
					}
				}
				else {
					;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
					SMP_msg("WARNING: Skipping USE operand: ");
					PrintOperand(TempOp);
					SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				}
			}

			if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: Operand neither DEF nor USE: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		} // end if DEF ... else ...
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound) {
#if SMP_DEBUG_BUILD_RTL
		if (!DestFound) {
			SMP_msg("ERROR: Could not find lea DEF operand at %llx for %s\n", (unsigned long long) this->GetAddr(),
				DisAsmText.GetDisAsm(this->GetAddr()));
		}
		else {
			SMP_msg("ERROR: Could not find lea USE operand at %llx for %s\n", (unsigned long long) this->GetAddr(),
				DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#endif
	}
	else { // Ready to build the RTL
		// We build the RTL down to the right, in reverse order, with any multiplication
		//  of the index register by a scale factor at the bottom of the RTL tree.
		// Note that almost any combination of BaseReg, IndexReg, and offset can be present
		//  or absent.
		AssignRT = new SMPRegTransfer;
		AssignRT->SetParentInst(this);
		AssignRT->SetLeftOperand(DefOp);
		AssignRT->SetOperator(SMP_ASSIGN);

		ScaledIndexReg = ((ScaleFactor > 0) && (IndexReg != STARS_x86_R_none));
		STARSOpndTypePtr BaseOp = nullptr;
		size_t ProgramBitWidth = global_STARS_program->GetSTARS_ISA_Bitwidth();
		bool DefaultToMachineWidth = ((ProgramBitWidth == 64) && this->MDIsAddressing64bit())
			|| ((ProgramBitWidth == 32) && this->MDIsAddressing32bit());
		if (BaseReg != STARS_x86_R_none)
			BaseOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg, DefaultToMachineWidth);
		STARSOpndTypePtr IndexOp = nullptr;
		if (IndexReg != STARS_x86_R_none)
			IndexOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg, DefaultToMachineWidth);
		STARSOpndTypePtr OffsetOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) offset);
		STARSOpndTypePtr ScaleOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) ScaleFactor);

		if (ScaledIndexReg) {
			// First, build the subtree to scale the IndexReg.
			SMPRegTransfer *MultRT = new SMPRegTransfer;
			MultRT->SetParentInst(this);
			MultRT->SetLeftOperand(IndexOp);
			MultRT->SetOperator(SMP_U_LEFT_SHIFT);
			MultRT->SetRightOperand(ScaleOp);
			// Now, case on the possibilities for existence of the other address fields.
			if (0 != offset) {
				// Add the offset to the scaled index subtree.
				SMPRegTransfer *AddOffRT = new SMPRegTransfer;
				AddOffRT->SetParentInst(this);
				AddOffRT->SetLeftOperand(OffsetOp);
				AddOffRT->SetOperator(SMP_ADD);
				AddOffRT->SetRightTree(MultRT);
				// Add a BaseReg, if any.
				if (STARS_x86_R_none != BaseReg) {
					SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
					AddBaseRT->SetParentInst(this);
					AddBaseRT->SetLeftOperand(BaseOp);
					AddBaseRT->SetOperator(SMP_ADD);
					AddBaseRT->SetRightTree(AddOffRT);
					// Link into assignment root tree.
					AssignRT->SetRightTree(AddBaseRT);
				}
				else { // no BaseReg
					AssignRT->SetRightTree(AddOffRT);
				}
			} // end if nonzero offset
			else { // no offset to add
				// Add a BaseReg, if any.
				if (STARS_x86_R_none != BaseReg) {
					SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
					AddBaseRT->SetParentInst(this);
					AddBaseRT->SetLeftOperand(BaseOp);
					AddBaseRT->SetOperator(SMP_ADD);
					AddBaseRT->SetRightTree(MultRT);
					// Link into assignment root tree.
					AssignRT->SetRightTree(AddBaseRT);
				}
				else { // no BaseReg
					AssignRT->SetRightTree(MultRT);
				}
			}
		} // end if ScaleIndexReg
		else { // no scaled index register
			if (0 != offset) {
				if (STARS_x86_R_none != IndexReg) {
					SMPRegTransfer *AddOffRT = new SMPRegTransfer;
					AddOffRT->SetParentInst(this);
					AddOffRT->SetLeftOperand(OffsetOp);
					AddOffRT->SetOperator(SMP_ADD);
					AddOffRT->SetRightOperand(IndexOp);
					// Add BaseReg, if any.
					if (STARS_x86_R_none != BaseReg) {
						SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
						AddBaseRT->SetParentInst(this);
						AddBaseRT->SetLeftOperand(BaseOp);
						AddBaseRT->SetOperator(SMP_ADD);
						AddBaseRT->SetRightTree(AddOffRT);
						// Link into assignment root tree.
						AssignRT->SetRightTree(AddBaseRT);
					}
					else { // no BaseReg
						AssignRT->SetRightTree(AddOffRT);
					}
				} // end if valid IndexReg
				else { // no IndexReg
					// Add BaseReg, if any.
					if (STARS_x86_R_none != BaseReg) {
						SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
						AddBaseRT->SetParentInst(this);
						AddBaseRT->SetLeftOperand(BaseOp);
						AddBaseRT->SetOperator(SMP_ADD);
						AddBaseRT->SetRightOperand(OffsetOp);
						// Link into assignment root tree.
						AssignRT->SetRightTree(AddBaseRT);
					}
					else { // no BaseReg, no IndexReg, just offset?
						if (!UseOp->IsStaticMemOp()) {
							SMP_msg("WARNING: lea used as move at %llx for %s\n", (unsigned long long) this->GetAddr(),
								DisAsmText.GetDisAsm(this->GetAddr()));
						}
						AssignRT->SetRightOperand(OffsetOp);
					}
				}
			} // end if nonzero offset
			else { // no offset
				if ((STARS_x86_R_none == BaseReg) || (STARS_x86_R_none == IndexReg)) {
					SMP_msg("WARNING: lea used as move at %llx for %s\n", (unsigned long long) this->GetAddr(),
						DisAsmText.GetDisAsm(this->GetAddr()));
					if (STARS_x86_R_none != BaseReg) {
						AssignRT->SetRightOperand(BaseOp);
					}
					else {
						if (STARS_x86_R_none == IndexReg) { // Should be RegClearIdiom in this case, no longer Lea RTL
							assert(this->IsRegClearIdiom());
							STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);
							AssignRT->SetRightOperand(ZeroOp);
						}
						else {
							AssignRT->SetRightOperand(IndexOp);
						}
					}
				}
				else { // we have a BaseReg and an IndexReg, unscaled, no offset
					SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
					AddBaseRT->SetParentInst(this);
					AddBaseRT->SetLeftOperand(BaseOp);
					AddBaseRT->SetOperator(SMP_ADD);
					AddBaseRT->SetRightOperand(IndexOp);
					// Link into assignment root tree.
					AssignRT->SetRightTree(AddBaseRT);
				}
			} // end if nonzero offset ... else ...
		} // end if (ScaledIndexReg) ... else ...
		this->RTL.push_back(AssignRT);
	}
	return (DestFound && SourceFound);
} // end of SMPInstr::BuildLeaRTL()

// Build the RTL for an double-word shift instruction
bool SMPInstr::BuildDoubleShiftRTL(SMPoperator BinaryOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool CountFound = false;
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	SMPRegTransfer *LowerRightRT = new SMPRegTransfer;
	LowerRightRT->SetParentInst(this);

	// The doubleword shifts operate as follows: shift the DEF register right or left by
	//  the number of bits specified by the count, and shift in bits from the USE register,
	//  but do not change the USE register. This is hard to represent accurately in an RTL,
	//  so we create an RTL as follows:
	//
	//         ASSIGN
	//         /     \                                       tree 
	//        DEF    SHIFT
	//               /    \                                  tree
	//              DEF   SHIFT
	//                    /    \                             tree RTL
	//                   USE   count
	//
	// This records all the operands, but it makes it look like the result of the
	//  lower shift is the counter for the upper shift, which is unintentional and
	//  will have to be special cased. In all single word shifts, the lower shift
	//  subtree would be replaced by a single count operand. The presence of a sub-tree
	//  instead of an operand is the identifying marker for double-word shifts.

	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);

	for (OpNum = 0; !(DestFound && SourceFound && CountFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				RightRT->SetLeftOperand(TempOp);
				RightRT->SetOperator(BinaryOp);
				TempRT->SetRightTree(RightRT);
				LowerRightRT->SetOperator(BinaryOp);
				RightRT->SetRightTree(LowerRightRT);
			}
		}
		else { // USE
			if (MDKnownOperandType(TempOp)) {
				if (!SourceFound) {
					SourceFound = true;
					LowerRightRT->SetLeftOperand(TempOp);
				}
				else {
					CountFound = true;
					LowerRightRT->SetRightOperand(TempOp);
				}
			}
		}
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound || !CountFound) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find double-shift operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		this->RTL.push_back(TempRT);
		// The carry flag gets the last shifted out bit.
		this->RTL.ExtraKills.push_back(FlagsOp);
	}
	return (DestFound && SourceFound && CountFound);
} // end of SMPInstr::BuildDoubleShiftRTL()

// Build the RTL for a multiply or divide, which can have implicit EAX and/or EDX operands
bool SMPInstr::BuildMultiplyDivideRTL(SMPoperator BinaryOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool x86ImulCase = (BinaryOp == SMP_S_MULTIPLY);
	bool ThreeOperandCase = false;
	bool DivisionCase = ((BinaryOp == SMP_S_DIVIDE) || (BinaryOp == SMP_U_DIVIDE));
	bool ImplicitDEFs = false;
	bool InvisibleOperand = false;
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);

	if (x86ImulCase) {
		// Detect three-operand case of x86 imul, with reg1 := reg2 * immediate.
		for (OpNum = 0; (!ThreeOperandCase) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
			STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
			if ((nullptr == TempOp) || TempOp->IsVoidOp()) // finished processing operands
				break;
			ThreeOperandCase = TempOp->IsImmedOp();
		}
	}

	bool FinishedOperands = false;
	bool ImmedFound = false;
	bool ByteSourceOperand = false;
	for (OpNum = 0; (!FinishedOperands) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if ((nullptr == TempOp) || TempOp->IsVoidOp()) {
			// finished processing operands
			break;
		}
		if (!TempOp->IsVisible()) { // hidden operand
			InvisibleOperand = true;
		}
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			// Three-operand case: opnd1 := opnd2 * immed
			// Two-operand case: opnd1 := opnd1 * opnd2, overflow bits to RDX or discarded
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				if (!ThreeOperandCase) {
					RightRT->SetLeftOperand(TempOp);
				}
				RightRT->SetOperator(BinaryOp);
				TempRT->SetRightTree(RightRT);
			}
		}
		if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			if (MDKnownOperandType(TempOp)) {
				SourceFound = true;
				if (TempOp->IsImmedOp()) {
					assert(ThreeOperandCase);
					ImmedFound = true;
					RightRT->SetRightOperand(TempOp);
				}
				else {
					ByteSourceOperand = (1 == TempOp->GetByteWidth());
					if (ThreeOperandCase) {
						RightRT->SetLeftOperand(TempOp);
					}
					else if ((0 == OpNum) && DestFound) {
						// e.g. RAX := RAX / RCX; processing RAX as both DEF and USE
						RightRT->SetLeftOperand(TempOp);
						SourceFound = false; // keep looking for divisor or multiplier
					}
					else {
						RightRT->SetRightOperand(TempOp);
					}
				}
			}
		}
		// x86ImulCase can have three operands, need to see VoidOp in order to be sure we saw all operands.
		FinishedOperands = (ThreeOperandCase) ? (DestFound && SourceFound && ImmedFound) : (DestFound && SourceFound);
	} // end for (OpNum = 0; ...)

	if (!FinishedOperands) {
		assert(NULL != RightRT);
		if (DestFound && (NULL != TempRT))
			delete TempRT;
		else
			delete RightRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find multiply/divide operand at %p for %s\n",
			this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		// See the x86 ISA manuals for DIV, IDIV, IMUL, MUL opcodes to see all the cases.
		ImplicitDEFs = x86ImulCase ? (!ByteSourceOperand && InvisibleOperand) : (!ByteSourceOperand);
		// IRDB does not have the invisible operands, but it has an implicit DEFs field.
		if (!ImplicitDEFs) {
			ImplicitDEFs = this->STARSInstPtr->HasImplicitlyModifiedRegs();
		}
		this->RTL.push_back(TempRT);
		if (ImplicitDEFs) {
			// Need another effect for EDX, which was implicit.
			//  Make a deep copy from existing EAX effect and change EAX dest to EDX.
			//  For divisions, we also deep copy EAX effect and change EAX source to EDX.
			SMPRegTransfer *EDXRT = new SMPRegTransfer;
			EDXRT->SetParentInst(this);
			SMPRegTransfer *EDXRightRT = new SMPRegTransfer;
			EDXRightRT->SetParentInst(this);
			STARSOpndTypePtr EDXOp = TempRT->GetLeftOperand()->clone();
			size_t SourceByteWidth = EDXOp->GetByteWidth();
			EDXRT->SetOperator(SMP_ASSIGN);
			assert(EDXOp->MatchesReg(STARS_x86_R_ax));
			EDXOp->SetReg(STARS_x86_R_dx);
			EDXOp->SetByteWidth(SourceByteWidth); // undo possible width change in SetReg()
			EDXRT->SetLeftOperand(EDXOp);
			STARSOpndTypePtr SourceOp = RightRT->GetLeftOperand();
			if ((STARS_NN_div == this->GetIDAOpcode()) || (STARS_NN_idiv == this->GetIDAOpcode())) {
				// Need to change left operand of RightRT to EDX. i.e. we are
				//  changing the effect from eax := eax DIV foo to edx := edx DIV foo.
				assert(SourceOp->MatchesReg(STARS_x86_R_ax));
				EDXRightRT->SetLeftOperand(EDXOp);
			}
			else { // just use same source operands for multiplies
				EDXRightRT->SetLeftOperand(SourceOp);
			}
			EDXRightRT->SetOperator(BinaryOp);
			EDXRightRT->SetRightOperand(RightRT->GetRightOperand());
			EDXRT->SetRightTree(EDXRightRT);
			this->RTL.push_back(EDXRT);
			this->ResetMultiplicationBitsDiscarded();
		}
		else { // No implicit EDX effect.
			// If we had 8x8=>16 bit multiply with AL*op8=>AX there
			//  is no discarding of result bits, else there is discarding.
			if (!ByteSourceOperand)
				this->SetMultiplicationBitsDiscarded();
		}
	}
	return (FinishedOperands);
} // end of SMPInstr::BuildMultiplyDivideRTL()

// Build the RTL for an instruction with a tertiary arithmetic opcode applied to
//  two operands plus an implied FLAGS operand, e.g. add with carry adds the carry bit
//  and two operands together; rotate through carry, etc.
bool SMPInstr::BuildBinaryPlusFlagsRTL(SMPoperator BinaryOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	SMPRegTransfer *TempRT = NULL;

	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);

	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	SMPRegTransfer *FlagsRightRT = new SMPRegTransfer;
	FlagsRightRT->SetParentInst(this);

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				RightRT->SetLeftOperand(TempOp);
				RightRT->SetOperator(BinaryOp);
				TempRT->SetRightTree(RightRT);
			}
		}
		else { // USE
			if (MDKnownOperandType(TempOp)) {
				SourceFound = true;
				FlagsRightRT->SetLeftOperand(TempOp);
				FlagsRightRT->SetOperator(BinaryOp);
				FlagsRightRT->SetRightOperand(FlagsOp);
				RightRT->SetRightTree(FlagsRightRT);
			}
		}
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound) {
		if (DestFound)
			delete TempRT;   // also deletes linked in RightRT
		else
			delete RightRT;  // will also delete FlagsRightRT if SourceFound is true
		if (!SourceFound) // FlagsRightRT not linked into RightRT yet
			delete FlagsRightRT; // .. so delete FlagsRightRT separately
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find binary operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}
	return (DestFound && SourceFound);
} // end of SMPInstr::BuildBinaryPlusFlagsRTL()

#define SMP_FIRST_SET_OPCODE  STARS_NN_seta
#define SMP_LAST_SET_OPCODE   STARS_NN_setz
// Build RTL for setting 0 or 1 into a register based on flags.
bool SMPInstr::BuildSetFlagIntoRegRTL(SMPoperator GuardOp, SMPoperator InvertedGuardOp) {
	unsigned short opcode = this->GetIDAOpcode();
	assert((SMP_FIRST_SET_OPCODE <= opcode) && (SMP_LAST_SET_OPCODE >= opcode));

	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	SMPRegTransfer *InvertedRT = new SMPRegTransfer;
	InvertedRT->SetParentInst(this);

	bool DestFound = false;
	for (size_t OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
			}
		}
	} // end for (OpNum = 0; ...)

	if (!DestFound) {
		if (NULL != TempRT)
			delete TempRT;
		if (NULL != InvertedRT)
			delete InvertedRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find SETcc destination operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		// Finish the RTLs.
		STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);
		STARSOpndTypePtr OneOp = this->STARSInstPtr->MakeImmediateOpnd(1);
		TempRT->SetRightOperand(OneOp);  // e.g. setz al  =>  al := 1 if GuardOp
		InvertedRT->SetRightOperand(ZeroOp); // e.g. setz al  =>  al := 0 if InvertedGuardOp

		// As the set is conditional, set the guard expressions.
		assert(SMP_NULL_OPERATOR != GuardOp);
		assert(SMP_NULL_OPERATOR != InvertedGuardOp);
		STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);
		SMPGuard *Guard1 = new SMPGuard;
		Guard1->SetLeftOperand(FlagsOp);
		Guard1->SetOperator(GuardOp);
		Guard1->SetRightOperand(ZeroOp);
		TempRT->SetGuard(Guard1);
		this->RTL.push_back(TempRT);

		SMPGuard *Guard2 = new SMPGuard;
		Guard2->SetLeftOperand(FlagsOp);
		Guard2->SetOperator(InvertedGuardOp);
		Guard2->SetRightOperand(ZeroOp);
		InvertedRT->SetGuard(Guard2);
		this->RTL.push_back(InvertedRT);
	}

	return (DestFound);
} // end of SMPInstr::BuildSetFlagIntoRegRTL()

// Build the RTL for an instruction of form dest := unary_operator(source), dest != source
bool SMPInstr::BuildUnary2OpndRTL(SMPoperator UnaryOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	unsigned short opcode = this->GetIDAOpcode();
	bool ExtendedMove = ((STARS_NN_movsx == opcode) || (STARS_NN_movzx == opcode) || (STARS_NN_movsxd == opcode));

	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);
	STARSOpndTypePtr PortNumOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx);
	PortNumOp->SetByteWidth(2); // always DX, 16-bit
	STARSOpndTypePtr PortDataOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax);

	// Handle special cases first.
	if ((SMP_FIRST_SET_OPCODE <= opcode) && (SMP_LAST_SET_OPCODE >= opcode)) {
		// Set instructions implicitly use the flags register.
		SourceFound = true;
		RightRT->SetLeftOperand(FlagsOp);
	}

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				if (STARS_NN_in == opcode) {
#if 0
					SMP_msg("ERROR: Explicit DEF for IN from port opcode at %x : ", this->GetAddr());
					PrintOperand(TempOp);
					SMP_msg("\n");
#endif
					TempRT->SetLeftOperand(TempOp);
					TempRT->SetOperator(UnaryOp);
				}
				else if (STARS_NN_out == opcode) {
					TempRT->SetLeftOperand(TempOp);
					TempRT->SetOperator(UnaryOp);
				}
				else {
					TempRT->SetLeftOperand(TempOp);
					TempRT->SetOperator(SMP_ASSIGN);
					RightRT->SetRightOperand(VoidOp);
					RightRT->SetOperator(UnaryOp);
					TempRT->SetRightTree(RightRT);
				}
			}
		}
		else { // USE
			if (MDKnownOperandType(TempOp)) {
				SourceFound = true;
				if (STARS_NN_in == opcode) {
					TempRT->SetRightOperand(TempOp);
				}
				else if (STARS_NN_out == opcode) {
#if 0
					SMP_msg("ERROR: Explicit USE for OUT to port opcode at %x : ", this->GetAddr());
					PrintOperand(TempOp);
					SMP_msg("\n");
#endif
					TempRT->SetRightOperand(TempOp);
				}
				else {
					RightRT->SetLeftOperand(TempOp);
					if (ExtendedMove)
						this->MoveSource = CloneIfNecessary(TempOp, true);
				}
			}
		}
	} // end for (OpNum = 0; ...)

	if (!SourceFound && (STARS_NN_in == opcode)) {
		// Input from port is implicitly from port # in DX register if not
		//  specified with an immediate operand.
		SourceFound = true;
		TempRT->SetRightOperand(PortNumOp);
	}
	if (!DestFound && (STARS_NN_in == opcode)) {
		// Input from port is implicitly to register AL, AX, or EAX
		//  depending on the opcode and bit width mode.
		// NOTE: Two different machine codes for 8-bit and 32-bit widths.
		//  We should check and set dtyp field accordingly.
		DestFound = true;
		TempRT->SetLeftOperand(PortDataOp);
		TempRT->SetOperator(UnaryOp);
	}
	if (!DestFound && (STARS_NN_out == opcode)) {
		// Output to port is implicitly to port # in DX register if not
		//  specified with an immediate operand.
		// NOTE: Two different machine codes for 8-bit and 32-bit widths.
		//  We should check and set dtyp field accordingly.
		DestFound = true;
		TempRT->SetLeftOperand(PortNumOp);
		TempRT->SetOperator(SMP_ASSIGN);
	}
	if (!SourceFound && (STARS_NN_out == opcode)) {
		// Output to port is implicitly from register AL, AX, or EAX
		//  depending on the opcode and bit width mode.
		SourceFound = true;
		TempRT->SetRightOperand(PortDataOp);
	}

	if (!DestFound || !SourceFound) {
		if (!DestFound)
			delete RightRT; // never linked in to TempRT
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find unary operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		this->RTL.push_back(TempRT);
		if ((STARS_NN_in == opcode) || (STARS_NN_out == opcode))
			delete RightRT;  // unused for port I/O
	}
	return (DestFound && SourceFound);
} // end of SMPInstr::BuildUnary2OpndRTL()

// Build the RTL for an instruction of form: dec ECX, loop to address with optional condition code guard
bool SMPInstr::BuildLoopRTL(SMPoperator GuardOp) {
	std::size_t OpNum;
	bool SourceFound = false;
	bool EqFlag = false; // loopeq variants
	bool NeqFlag = false; // loopne variants
	uint16_t CounterByteWidth; // width of loop counter reg (RCX, ECX, CX, CL)

	SMPRegTransfer *LoopRT = new SMPRegTransfer;
	LoopRT->SetParentInst(this);
	SMPRegTransfer *DecCounterRT = new SMPRegTransfer;
	DecCounterRT->SetParentInst(this);

	STARSOpndTypePtr OneOp = this->STARSInstPtr->MakeImmediateOpnd(1);
	STARSOpndTypePtr CountOp = nullptr;

	switch (this->GetIDAOpcode()) {
	case STARS_NN_loopw:               // Loop while ECX != 0
		CounterByteWidth = 4;
		break;

	case STARS_NN_loop:                // Loop while CX != 0
		CounterByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
		break;

	case STARS_NN_loopd:               // Loop while ECX != 0
		CounterByteWidth = 4;
		break;

	case STARS_NN_loopq:               // Loop while RCX != 0
		CounterByteWidth = 8;
		break;

	case STARS_NN_loopwe:              // Loop while CX != 0 and ZF=1
		CounterByteWidth = 2;
		EqFlag = true;
		break;

	case STARS_NN_loope:               // Loop while rCX != 0 and ZF=1
		CounterByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
		EqFlag = true;
		break;

	case STARS_NN_loopde:              // Loop while ECX != 0 and ZF=1
		CounterByteWidth = 4;
		EqFlag = true;
		break;

	case STARS_NN_loopqe:              // Loop while RCX != 0 and ZF=1
		CounterByteWidth = 8;
		EqFlag = true;
		break;

	case STARS_NN_loopwne:             // Loop while CX != 0 and ZF=0
		CounterByteWidth = 2;
		NeqFlag = true;
		break;

	case STARS_NN_loopne:              // Loop while rCX != 0 and ZF=0
		CounterByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth();
		NeqFlag = true;
		break;

	case STARS_NN_loopdne:             // Loop while ECX != 0 and ZF=0
		CounterByteWidth = 4;
		NeqFlag = true;
		break;

	case STARS_NN_loopqne:             // Loop while RCX != 0 and ZF=0
		CounterByteWidth = 8;
		NeqFlag = true;
		break;

	default:
		SMP_msg("ERROR: Unknown loop instruction opcode at %llx in BuildLoopRTL.\n", (unsigned long long) this->GetAddr());
		CounterByteWidth = 4;
		break;
	}

	OneOp->SetByteWidth(CounterByteWidth);
	if (CounterByteWidth == 1) {
		CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cl);
	}
	else {
		CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
		CountOp->SetByteWidth(CounterByteWidth);
	}

	STARSOpndTypePtr EIPOp = this->STARSInstPtr->MakeRegOpnd(MD_INSTRUCTION_POINTER_REG);

	// All x86 loop instructions behave as follows:
	//  1. Decrement RCX/ECX/CX depending on 64/32/16-bit mode of CPU.
	//  2. If counter decremented to zero, fall through to next instruction.
	//  3. For condition code variants, fall through if zero flag is 1 or 0, depending on variant.
	//  4. Otherwise, loop back by adding a signed 8-bit offset to the instruction counter.
	//
	// So, for LOOP, it is simply decrement ECX and loop back if ECX did not become zero.
	//  For LOOPE a.k.a. LOOPZ, it is decrement ECX and loop back if ECX != 0 and ZF == 1, which means
	//   that ZF (zero flag) was set to 1 by an instruction before the LOOPE instruction, not by the
	//   decrement of ECX within the microcode for LOOPE.
	//  For LOOPNE a.k.a. LOOPNZ, change ZF == 1 to ZF == 0 in above description.
	//
	// For RTLs, this means we need an RTL to decrement ECX, and a guarded RTL to add an immediate to the EIP reg.
	//  The guard can be simple (ECX != 0) or compound ((ECX != 0) AND (ZF is 0 or 1)). However, because RTs in
	//  an RTL happen in parallel, we compare ECX to 1 because the comparison happens before it is decremented by
	//  another RT in the RTL. Note also that IDA Pro has converted the signed 8-bit relative offset to a near address
	//  in the operand list.

	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
	DecCounterRT->SetLeftOperand(CountOp);
	DecCounterRT->SetOperator(SMP_DECREMENT);
	DecCounterRT->SetRightOperand(VoidOp);

	for (OpNum = 0; (!SourceFound && (OpNum < STARS_UA_MAXOP)); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
			SMP_msg("WARNING: Unexpected DEF Operand in LOOP instruction: ");
			PrintOperand(TempOp);
			SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			;
		}
		if (!SourceFound && (this->STARSInstPtr->IsUseOpnd(OpNum)) && MDKnownOperandType(TempOp)) {
			if (TempOp->IsNearPointer()) {
				LoopRT->SetLeftOperand(EIPOp);
				LoopRT->SetOperator(SMP_ASSIGN);
				LoopRT->SetRightOperand(TempOp);
				SourceFound = true;
			}
		}
	} // end for (OpNum = 0; ...)

	if (!SourceFound) {
		if (NULL != LoopRT)
			delete LoopRT;
		if (NULL != DecCounterRT)
			delete DecCounterRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find loop operand at %llx for %s\n", 
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		// If the move is conditional, set the guard expression.
		// NOTE: We do not want to complicate the SMPGuard class to handle compound expressions yet.
		//  If the need arises, we can do so. For now, just treat all loop instructions as a simple LOOP
		//  even if it is LOOPE or LOOPNE.
		SMPGuard *Guard1 = new SMPGuard;
		Guard1->SetLeftOperand(CountOp);
		Guard1->SetOperator(SMP_EQUAL);
		Guard1->SetRightOperand(OneOp);
		LoopRT->SetGuard(Guard1);
		this->RTL.push_back(LoopRT);
		this->RTL.push_back(DecCounterRT);
	}
	return (SourceFound);
} // end of SMPInstr::BuildLoopRTL()

// Build the RTL for an instruction of form dest := source, where dest != source
bool SMPInstr::BuildMoveRTL(SMPoperator GuardOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool MemSrc = this->HasSourceMemoryOperand();
	bool MemDest = this->HasDestMemoryOperand();
	bool AltersRSI = false; // for string operations
	bool AltersRDI = false; // for string operations
	unsigned short opcode = this->GetIDAOpcode();

	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);

	STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax);
	STARSOpndTypePtr ALOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_al);
	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);
	STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG);
	STARSOpndTypePtr PortNumOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx);
	STARSOpndTypePtr PortDataOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax);

#if SMP_DEBUG_BUILD_RTL
	if (MemSrc && MemDest && (STARS_NN_movs != opcode) && (STARS_NN_movss != opcode) && (STARS_NN_movsd != opcode)) {
		if ((STARS_NN_stos != opcode) && (STARS_NN_outs != opcode)) {
			SMP_msg("ERROR: IDA Pro error: MemDest and MemSrc in move at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#if 1
		else {  // IDA incorrectly lists [EDI] as both DEF and USE, because reg EDI
				//  is both DEF and USE in STARS_NN_stos.
			SMP_msg("WARNING: Ignoring IDA Pro error: MemDest and MemSrc in move at %llx for %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
			this->PrintOperands();
		}
#endif
	}
#endif

	// First, handle special cases with implicit operands
	if (STARS_NN_lahf == opcode) {  // load AH from flags
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(EAXOp);
		TempRT->SetRightOperand(FlagsOp);
		this->RTL.push_back(TempRT);
		return true;
	}
	if (STARS_NN_sahf == opcode) {  // store AH to flags
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(FlagsOp);
		TempRT->SetRightOperand(EAXOp);
		this->RTL.push_back(TempRT);
		return true;
	}
	if ((STARS_NN_movs == opcode) || (STARS_NN_stos == opcode) || (STARS_NN_ins == opcode) || (STARS_NN_outs == opcode)) {
		// The ESI and EDI registers get incremented or decremented, depending
		//  on the direction flag DF, for MOVS; only EDI for STOS and INS;
		//  only ESI for OUTS.
		// This is true with or without a repeat prefix.
		STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si);
		STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di);
		STARSOpndTypePtr ESIMemOp = this->STARSInstPtr->MakeMemPhraseOpnd(STARS_x86_R_si, STARS_x86_R_none, 0);  // [esi]
		STARSOpndTypePtr EDIMemOp = this->STARSInstPtr->MakeMemPhraseOpnd(STARS_x86_R_di, STARS_x86_R_none, 0);  // [edi]
		if (STARS_NN_movs == opcode) {
			AltersRSI = true;
			AltersRDI = true;
			TempRT->SetOperator(SMP_ASSIGN);
			TempRT->SetLeftOperand(EDIMemOp);
			TempRT->SetRightOperand(ESIMemOp);
			DestFound = true;
			SourceFound = true;
		}
		else if (STARS_NN_stos == opcode) {
			AltersRDI = true;
			TempRT->SetOperator(SMP_ASSIGN);
			TempRT->SetLeftOperand(EDIMemOp);
			TempRT->SetRightOperand(ALOp); // default in case we don't find source later
			DestFound = true;
		}
		else if (STARS_NN_ins == opcode) {
			AltersRDI = true;
			TempRT->SetOperator(SMP_INPUT);
			TempRT->SetLeftOperand(EDIMemOp);
			TempRT->SetRightOperand(PortNumOp);
			DestFound = true;
			SourceFound = true;
		}
		else if (STARS_NN_outs == opcode) {
			AltersRSI = true;
			TempRT->SetOperator(SMP_OUTPUT);
			TempRT->SetLeftOperand(ESIMemOp);
			TempRT->SetRightOperand(PortNumOp);
			DestFound = true;
			SourceFound = true;
		}
	}

	// Some floating point instructions use the floating point register stack top as
	//  an implicit source or destination, but the other operand of the load or store
	//  is explicit, so we set the implicit operand and let control flow pass to the
	//  main processing loop below.
	if ((STARS_NN_fld == opcode) || (STARS_NN_fbld == opcode) || (STARS_NN_fild == opcode)) {
		// Loads implicitly use the floating point stack top as destination.
		TempRT->SetLeftOperand(FPRegOp);
		TempRT->SetOperator(SMP_ASSIGN);
		DestFound =  true;
	}
	else if ((STARS_NN_fst == opcode) || (STARS_NN_fstp == opcode) || (STARS_NN_fbstp == opcode)
		|| (STARS_NN_fist == opcode) || (STARS_NN_fistp == opcode)) {
		// Stores implicitly use the floating point stack top as source
		TempRT->SetRightOperand(FPRegOp);
		SourceFound = true;
		// The "p" at the end of the opcode indicates that the floating point
		//  register stack gets popped.
		if ((STARS_NN_fstp == opcode) || (STARS_NN_fbstp == opcode) || (STARS_NN_fistp == opcode)) {
			this->RTL.ExtraKills.push_back(FPRegOp);
		}
	}
	else if ((STARS_NN_ldmxcsr == opcode) || (STARS_NN_vldmxcsr == opcode)) {
		// The MMX Control & Status Register is used implicitly.
		STARSOpndTypePtr MXCSROp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_mxcsr);  // MMX Control & Status Register
		TempRT->SetLeftOperand(MXCSROp);
		DestFound = true;
	}
	else if ((STARS_NN_stmxcsr == opcode) || (STARS_NN_vstmxcsr == opcode)) {
		// The MMX Control & Status Register is used implicitly.
		STARSOpndTypePtr MXCSROp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_mxcsr);  // MMX Control & Status Register
		TempRT->SetRightOperand(MXCSROp);
		SourceFound = true;
	}
	else if (STARS_NN_fldcw == opcode) {
		// The FP control Register is used implicitly.
		STARSOpndTypePtr FPControlOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_fpctrl);  // FP control Register
		TempRT->SetRightOperand(FPControlOp);
		DestFound = true;
	}
	else if ((STARS_NN_fstcw == opcode) || (STARS_NN_fnstcw == opcode)) {
		// The FP control Register is used implicitly.
		STARSOpndTypePtr FPControlOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_fpctrl);  // FP control Register
		TempRT->SetRightOperand(FPControlOp);
		SourceFound = true;
	}
	else if ((STARS_NN_fstsw == opcode) || (STARS_NN_fnstsw == opcode)) {
		// The FP Status Register is used implicitly.
		STARSOpndTypePtr FPStatusOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_fpstat);  // FP Status Register
		TempRT->SetRightOperand(FPStatusOp);
		SourceFound = true;
	}

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (!DestFound && MDKnownOperandType(TempOp)) {
				// See comments just below for floating point sources. FP stores
				//  are analogous to FP loads.
				if (!MemDest || (IsMemOperand(TempOp))) {
					DestFound = true;
					TempRT->SetLeftOperand(TempOp);
					TempRT->SetOperator(SMP_ASSIGN);
				}
			}
		}
		else { // USE
			if (!SourceFound && MDKnownOperandType(TempOp)) {
				// If this is a floating point instruction with the fpregs listed as
				//  a USE and a memory operand also listed as a USE, then we want to
				//  ignore the irrelevant USE of the fpreg stack.
				// Note that MemDest AND MemSrc means something like stosb is being
				//  processed, where the memory operand is both DEF and USE to IDA
				//  for mysterious reasons.
				if (!MemSrc || MemDest || (IsMemOperand(TempOp))) {
					SourceFound = true;
					TempRT->SetRightOperand(TempOp);
					this->MoveSource = CloneIfNecessary(TempOp, true);
				}
			}
			if (!this->STARSInstPtr->IsUseOpnd(OpNum)) {
				;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: Operand neither DEF nor USE: ");
				PrintOperand(TempOp);
				SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		}
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find move operand at %llx for %s\n", 
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		// If the move is conditional, set the guard expression.
		if (SMP_NULL_OPERATOR != GuardOp) {
			STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);
			SMPGuard *Guard1 = new SMPGuard;
			Guard1->SetLeftOperand(FlagsOp);
			Guard1->SetOperator(GuardOp);
			Guard1->SetRightOperand(ZeroOp);
			TempRT->SetGuard(Guard1);
		}
		this->RTL.push_back(TempRT);
		// Now, create the repeat prefix effects
		STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
		STARSOpndTypePtr FirstOpnd = this->GetOperand(0);
		uint16_t ByteWidth = FirstOpnd->GetByteWidth();
		STARSOpndTypePtr IncrementOp = this->MakeImmediateOpnd((STARS_uval_t) ByteWidth);
		bool HasRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix();
		if (HasRepeatPrefix) { // Must be MOVS or STOS or INS or OUTS
			// The repeat causes USE and DEF of ECX as a counter
			STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
			SMPRegTransfer *CounterRT = new SMPRegTransfer;
			CounterRT->SetParentInst(this);
			SMPRegTransfer *RightRT = new SMPRegTransfer;
			RightRT->SetParentInst(this);
			CounterRT->SetLeftOperand(CountOp);
			CounterRT->SetOperator(SMP_ASSIGN);
			RightRT->SetLeftOperand(CountOp);
			RightRT->SetOperator(SMP_DECREMENT);
			RightRT->SetRightOperand(VoidOp);
			CounterRT->SetRightTree(RightRT);
			this->RTL.push_back(CounterRT);
		}
		// Depending on the opcode, we increment or decrement RSI, RDI, or both.
		if (AltersRSI) {
			STARSOpndTypePtr AddrOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si);
			SMPRegTransfer *AddrRT = new SMPRegTransfer;
			AddrRT->SetParentInst(this);
			SMPRegTransfer *RightRT = new SMPRegTransfer;
			RightRT->SetParentInst(this);
			AddrRT->SetLeftOperand(AddrOp);
			AddrRT->SetOperator(SMP_ASSIGN);
			RightRT->SetLeftOperand(AddrOp);
			// NOTE: SMP_ADD assumes default setting of DirectionFlag.
			RightRT->SetOperator(SMP_ADD);
			RightRT->SetRightOperand(IncrementOp);
			AddrRT->SetRightTree(RightRT);
			this->RTL.push_back(AddrRT);
		}
		if (AltersRDI) {
			STARSOpndTypePtr AddrOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di);
			SMPRegTransfer *AddrRT = new SMPRegTransfer;
			AddrRT->SetParentInst(this);
			SMPRegTransfer *RightRT = new SMPRegTransfer;
			RightRT->SetParentInst(this);
			AddrRT->SetLeftOperand(AddrOp);
			AddrRT->SetOperator(SMP_ASSIGN);
			RightRT->SetLeftOperand(AddrOp);
			// NOTE: SMP_ADD assumes default setting of DirectionFlag.
			RightRT->SetOperator(SMP_ADD);
			RightRT->SetRightOperand(IncrementOp);
			AddrRT->SetRightTree(RightRT);
			this->RTL.push_back(AddrRT);
		}
	}
	return (DestFound && SourceFound);
} // end of SMPInstr::BuildMoveRTL()

// Build the RTL for a load string instruction, which loads from DS:ESI into EAX
//  (or into AX or AL) and increments or decrements ESI based on the direction flag DF.
bool SMPInstr::BuildLoadStringRTL(void) {
	bool DestFound = false;
	unsigned short ByteSize = 0;

	STARSOpndTypePtr DestOp = nullptr;

	for (std::size_t OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (MDKnownOperandType(TempOp)) {
			if ((TempOp->IsRegOp()) && (this->STARSInstPtr->IsDefOpnd(OpNum))) { // DEF
				DestFound = true;
				if (TempOp->MatchesReg(STARS_x86_R_al)) {					
					ByteSize = 1;
					DestOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_al);
				}
				else if (TempOp->MatchesReg(STARS_x86_R_ax)) {
					ByteSize = global_STARS_program->GetSTARS_ISA_Bytewidth();
					DestOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax);
				}
				else {
					SMP_msg("ERROR: Load string destination operand is neither AL nor EAX at %llx\n", 
						(unsigned long long) this->GetAddr());
					ByteSize = 1; // default to AL destination
					DestOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_al);
				}
			}
		}
	} // end for (OpNum = 0; ...)

	// Return false if we did not find a destination
	if (!DestFound) {
		return false;
	}

	STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);
	STARSOpndTypePtr OneOp = this->STARSInstPtr->MakeImmediateOpnd(1);
	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);
	STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si);
	STARSOpndTypePtr DerefESIOp = this->STARSInstPtr->MakeMemPhraseOpnd(STARS_x86_R_si, STARS_x86_R_none, 0);

	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	SMPRegTransfer *GuardedIncRT = new SMPRegTransfer;
	GuardedIncRT->SetParentInst(this);
	SMPRegTransfer *GuardedDecRT = new SMPRegTransfer;
	GuardedDecRT->SetParentInst(this);
	SMPRegTransfer *RightIncRT = new SMPRegTransfer;
	RightIncRT->SetParentInst(this);
	SMPRegTransfer *RightDecRT = new SMPRegTransfer;
	RightDecRT->SetParentInst(this);

	// Build the load string RTL. Ignore DS segment register for now.
	// Load string is:  AL := [ESI]; if (DF == 0) ESI += 1 else ESI -= 1;
	//  for the 8-bit case, and EAX := [ESI]; if (DF == 0) ESI += 4 else ESI -= 4;
	//  for the 32-bit case.

	// AL := [ESI] or EAX := [ESI]
	TempRT->SetLeftOperand(DestOp);
	TempRT->SetOperator(SMP_ASSIGN);
	TempRT->SetRightOperand(DerefESIOp);

	this->RTL.push_back(TempRT);

	// Guarded increment RTL: If the DF (Direction Flag) in EFLAGS is 0, increment ESI
	//  by ByteSize.
	STARSOpndTypePtr IncDecOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) ByteSize);

	SMPGuard *Guard1 = new SMPGuard;
	Guard1->SetLeftOperand(FlagsOp);
	Guard1->SetOperator(SMP_U_COMPARE);
	Guard1->SetRightOperand(ZeroOp);
	GuardedIncRT->SetGuard(Guard1);
	GuardedIncRT->SetLeftOperand(ESIOp);
	GuardedIncRT->SetOperator(SMP_ASSIGN);
	RightIncRT->SetLeftOperand(ESIOp);
	RightIncRT->SetOperator(SMP_ADD);
	RightIncRT->SetRightOperand(IncDecOp);
	GuardedIncRT->SetRightTree(RightIncRT);

	this->RTL.push_back(GuardedIncRT);

	// Guarded decrement RTL: If the DF (Direction Flag) in EFLAGS is 1, decrement ESI
	//  by ByteSize.
	SMPGuard *Guard2 = new SMPGuard;
	Guard2->SetLeftOperand(FlagsOp);
	Guard2->SetOperator(SMP_U_COMPARE);
	Guard2->SetRightOperand(OneOp);
	GuardedDecRT->SetGuard(Guard2);
	GuardedDecRT->SetLeftOperand(ESIOp);
	GuardedDecRT->SetOperator(SMP_ASSIGN);
	RightDecRT->SetLeftOperand(ESIOp);
	RightDecRT->SetOperator(SMP_SUBTRACT);
	RightDecRT->SetRightOperand(IncDecOp);
	GuardedDecRT->SetRightTree(RightDecRT);

	this->RTL.push_back(GuardedDecRT);

	return true;
} // end of SMPInstr::BuildLoadStringRTL()

// Build the RTL for a compare string instruction, possibly with repeat prefix.
bool SMPInstr::BuildCompareStringRTL(void) {
	std::size_t OpNum;
	bool Src1Found = false;
	bool Src2Found = false;

	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);

	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);

	for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (MDKnownOperandType(TempOp)) {
			if (!Src1Found) {
				Src1Found = true;
				TempRT->SetLeftOperand(FlagsOp);
				TempRT->SetOperator(SMP_ASSIGN);
				RightRT->SetLeftOperand(TempOp);
				RightRT->SetOperator(SMP_U_COMPARE);
				TempRT->SetRightTree(RightRT);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF
					SMP_msg("CMPS 1st opnd is DEF\n");
				else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE
					SMP_msg("CMPS 1st opnd is USE\n");
				else
					SMP_msg("ERROR: CMPS 1st opnd neither DEF nor USE\n");
#endif
			}
			else {
				Src2Found = true;
				RightRT->SetRightOperand(TempOp);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF
					SMP_msg("CMPS 2nd opnd is DEF\n");
				else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE
					SMP_msg("CMPS 2nd opnd is USE\n");
				else
					SMP_msg("ERROR: CMPS 2nd opnd neither DEF nor USE\n");
#endif
			}
		}
	} // end for (OpNum = 0; ...)

	if (!Src1Found || !Src2Found) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find CMPS operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		this->RTL.push_back(TempRT);
		// Now, create the repeat prefix effects
		bool HasRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix();
		if (HasRepeatPrefix) {
			// The repeat causes USE and DEF of ECX as a counter
			SMPRegTransfer *CounterRT = new SMPRegTransfer;
			CounterRT->SetParentInst(this);
			SMPRegTransfer *RightRT = new SMPRegTransfer;
			RightRT->SetParentInst(this);
			STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
			STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
			CounterRT->SetLeftOperand(CountOp);
			CounterRT->SetOperator(SMP_ASSIGN);
			RightRT->SetLeftOperand(CountOp);
			RightRT->SetOperator(SMP_UNARY_NUMERIC_OPERATION);
			RightRT->SetRightOperand(VoidOp);
			CounterRT->SetRightTree(RightRT);
			this->RTL.push_back(CounterRT);
		}
	}
	return (Src1Found && Src2Found);
} // end of SMPInstr::BuildCompareStringRTL()

// Build the RTL for an instruction of form dest := source, source := dest
bool SMPInstr::BuildExchangeRTL(void) {
	std::size_t OpNum;
	bool Src1Found = false;
	bool Src2Found = false;
	SMPRegTransfer *TempRT = new SMPRegTransfer;  // second effect, src := dest
	TempRT->SetParentInst(this);

	for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (MDKnownOperandType(TempOp)) {
			if (!Src1Found) {
				Src1Found = true;
				TempRT->SetRightOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF
					SMP_msg("CORRECT: XCHG 1st opnd is DEF\n");
				else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE
					SMP_msg("WARNING: XCHG 1st opnd is USE\n");
				else
					SMP_msg("ERROR: XCHG 1st opnd neither DEF nor USE\n");
#endif
			}
			else {
				Src2Found = true;
				TempRT->SetLeftOperand(TempOp);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF
					SMP_msg("WARNING: XCHG 2nd opnd is DEF\n");
				else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE
					SMP_msg("CORRECT: XCHG 2nd opnd is USE\n");
				else
					SMP_msg("ERROR: XCHG 2nd opnd neither DEF nor USE\n");
#endif
			}
		}
	} // end for (OpNum = 0; ...)

	if (!Src1Found || !Src2Found) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find XCHG operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		// Create the first effect, dest := src
		SMPRegTransfer *FirstRT = new SMPRegTransfer;
		FirstRT->SetParentInst(this);
		FirstRT->SetLeftOperand(TempRT->GetRightOperand());
		FirstRT->SetRightOperand(TempRT->GetLeftOperand());
		FirstRT->SetOperator(SMP_ASSIGN);
		this->RTL.push_back(FirstRT);
		// Push the second effect on the list, src := dest
		this->RTL.push_back(TempRT);
	}
	return (Src1Found && Src2Found);
} // end of SMPInstr::BuildExchangeRTL()

// Build the RTL for an instruction of form dest := dest + source, source := dest
bool SMPInstr::BuildExchangeAddRTL(void) {
	std::size_t OpNum;
	bool Src1Found = false;
	bool Src2Found = false;

	SMPRegTransfer *TempRT = new SMPRegTransfer;  // second effect, src := dest
	TempRT->SetParentInst(this);

	for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (MDKnownOperandType(TempOp)) {
			if (!Src1Found) {
				Src1Found = true;
				TempRT->SetRightOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF
					SMP_msg("CORRECT: XADD 1st opnd is DEF\n"); // should be the case
				else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE
					SMP_msg("WARNING: XADD 1st opnd is USE\n");
				else
					SMP_msg("ERROR: XADD 1st opnd neither DEF nor USE\n");
#endif
			}
			else {
				Src2Found = true;
				TempRT->SetLeftOperand(TempOp);
#if SMP_VERBOSE_DEBUG_BUILD_RTL
				if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF
					SMP_msg("WARNING: XADD 2nd opnd is DEF\n");
				else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE
					SMP_msg("CORRECT: XADD 2nd opnd is USE\n"); // should be the case
				else
					SMP_msg("ERROR: XADD 2nd opnd neither DEF nor USE\n");
#endif
			}
		}
	} // end for (OpNum = 0; ...)

	if (!Src1Found || !Src2Found) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find XADD operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		// Create the first effect, dest := dest + src
		SMPRegTransfer *FirstRT = new SMPRegTransfer;
		FirstRT->SetParentInst(this);
		SMPRegTransfer *AddRT = new SMPRegTransfer;
		AddRT->SetParentInst(this);
		AddRT->SetLeftOperand(TempRT->GetRightOperand());
		AddRT->SetOperator(SMP_ADD);
		AddRT->SetRightOperand(TempRT->GetLeftOperand());
		FirstRT->SetLeftOperand(TempRT->GetRightOperand());
		FirstRT->SetRightTree(AddRT);
		FirstRT->SetOperator(SMP_ASSIGN);
		this->RTL.push_back(FirstRT);
		// Push the second effect on the list, src := dest
		this->RTL.push_back(TempRT);
	}
	return (Src1Found && Src2Found);
} // end of SMPInstr::BuildExchangeAddRTL()

// Build the RTL for an instruction of form:
//  if (dest==EAX) dest := source  else  EAX := dest
bool SMPInstr::BuildCompareExchangeRTL(void) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	STARSOpndTypePtr DestOp = nullptr;
	STARSOpndTypePtr SourceOp = nullptr;
	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);

	for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (MDKnownOperandType(TempOp)) {
			if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
				if (!DestFound) {
					DestFound = true;
					DestOp = TempOp;
				}
				else {
					SMP_msg("ERROR: CMPXCHG has two DEF operands.\n");
				}
			}
			else if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
				if (!SourceFound) {
					SourceFound = true;
					SourceOp = TempOp;
				}
				else {
					SMP_msg("ERROR: CMPXCHG has two USE operands.\n");
				}
			}
		}
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find CMPXCHG operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		// Create the first effect, if (dest == EAX) dest := src
		SMPGuard *Guard1 = new SMPGuard;
		STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax);
		Guard1->SetLeftOperand(DestOp);
		Guard1->SetOperator(SMP_EQUAL);
		Guard1->SetRightOperand(EAXOp);
		SMPRegTransfer *FirstRT = new SMPRegTransfer;
		FirstRT->SetParentInst(this);
		FirstRT->SetLeftOperand(DestOp);
		FirstRT->SetRightOperand(SourceOp);
		FirstRT->SetOperator(SMP_ASSIGN);
		FirstRT->SetGuard(Guard1);
		this->RTL.push_back(FirstRT);
		// Push the second effect on the list, if (dest!=EAX) dest := EAX
		SMPGuard *Guard2 = new SMPGuard;
		Guard2->SetLeftOperand(DestOp);
		Guard2->SetOperator(SMP_EQUAL);
		Guard2->SetRightOperand(EAXOp);
		TempRT->SetLeftOperand(DestOp);
		TempRT->SetRightOperand(EAXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetGuard(Guard2);
		this->RTL.push_back(TempRT);
	}
	return (DestFound && SourceFound);
} // end of SMPInstr::BuildCompareExchangeRTL()

// Build the RTL for an extended FP concatenate and shift instruction
bool SMPInstr::BuildPackShiftRTL(SMPoperator PackOp, SMPoperator ShiftOp) {
	std::size_t OpNum;
	bool DestFound = false;
	bool SourceFound = false;
	bool CountFound = false;
	SMPRegTransfer *TempRT = NULL;
	SMPRegTransfer *ShiftRT = new SMPRegTransfer;
	ShiftRT->SetParentInst(this);
	SMPRegTransfer *PackRT = new SMPRegTransfer;
	PackRT->SetParentInst(this);

	// RTL structure: top operator is assignment, next right operator is a reverse
	//  shift with the shift count as its left operand, and lowest right operator
	//  is the concatenation operator. Sequence of operations is pack, shift, assign.
	for (OpNum = 0; !(DestFound && SourceFound && CountFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				PackRT->SetLeftOperand(TempOp);
				PackRT->SetOperator(PackOp);
				ShiftRT->SetOperator(ShiftOp);
				ShiftRT->SetRightTree(PackRT);
				TempRT->SetRightTree(ShiftRT);
			}
		}
		else { // USE
			if (MDKnownOperandType(TempOp)) {
				if (!SourceFound) {
					SourceFound = true;
					PackRT->SetRightOperand(TempOp);
				}
				else {
					CountFound = true;
					ShiftRT->SetLeftOperand(TempOp);
				}
			}
		}
	} // end for (OpNum = 0; ...)

	if (!DestFound || !SourceFound || !CountFound) {
		if (NULL != TempRT)
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find MMX/XMM pack and shift operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}
	return (DestFound && SourceFound && CountFound);
} // end of SMPInstr::BuildPackShiftRTL()

// Build the RTL for a compare or test instruction with an implicit EFLAGS destination operand
bool SMPInstr::BuildFlagsDestBinaryRTL(SMPoperator BinaryOp) {
	std::size_t OpNum;
	unsigned short opcode = this->GetIDAOpcode();
	bool Source1Found = false;
	bool Source2Found = false;
	bool NoOperandsRequired = ((STARS_NN_scas == opcode) || (STARS_NN_cmps == opcode));

	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);

	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);

	// Some floating point instructions use the floating point register stack top as
	//  an implicit source or destination, but the other operand of the load or store
	//  is explicit, so we set the implicit operand and let control flow pass to the
	//  main processing loop below.
	if ((STARS_NN_fcomi == opcode) || (STARS_NN_fucomi == opcode) || (STARS_NN_fcomip == opcode)
		|| (STARS_NN_fucomip == opcode)) {
		// Compares implicitly use the floating point stack top as destination.
		STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG);
		TempRT->SetLeftOperand(FlagsOp);
		TempRT->SetOperator(SMP_ASSIGN);
		RightRT->SetLeftOperand(FPRegOp);
		RightRT->SetOperator(BinaryOp);
		TempRT->SetRightTree(RightRT);
		Source1Found = true;
		// The "p" at the end of the opcode indicates that the floating point
		//  register stack gets popped.
		if ((STARS_NN_fcomip == opcode) || (STARS_NN_fucomip == opcode)) {
			this->RTL.ExtraKills.push_back(FPRegOp);
		}
	}

	for (OpNum = 0; !(Source1Found && Source2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
#if SMP_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found destination for compare or test at %llx : %s\n",
					(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
				PrintOperand(TempOp);
				SMP_msg("\n");
#endif
			}
		}
		else { // USE
			if (MDKnownOperandType(TempOp)) {
				if (!Source1Found) {
					Source1Found = true;
					TempRT->SetLeftOperand(FlagsOp);
					TempRT->SetOperator(SMP_ASSIGN);
					RightRT->SetLeftOperand(TempOp);
					RightRT->SetOperator(BinaryOp);
					TempRT->SetRightTree(RightRT);
				}
				else {
					assert(!Source2Found);
					Source2Found = true;
					RightRT->SetRightOperand(TempOp);
				}
			}
		}
	} // end for (OpNum = 0; ...)

	// The compare string instruction always uses DS:ESI and ES:EDI as its source
	//  operands, regardless of the explicit operands given, and might not have
	//  explicit operands; explicit operands are just for documentation.
	// The scan string instruction uses EAX/AX/AH/AL and ES:EDI as its source
	//  operands and might not have any explicit operands at all.
	if ((!NoOperandsRequired) && (!Source1Found || !Source2Found)) {
		if (!Source1Found)
			delete RightRT;
		else
			delete TempRT;
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find CMP/TEST operand at %llx for %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		this->RTL.push_back(TempRT);
		// Now, create the repeat prefix effects
		bool HasRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix();
		if (HasRepeatPrefix) { // Must be CMPS or SCAS
			// The repeat causes USE and DEF of ECX as a counter
			SMPRegTransfer *CounterRT = new SMPRegTransfer;
			CounterRT->SetParentInst(this);
			SMPRegTransfer *RightRT = new SMPRegTransfer;
			RightRT->SetParentInst(this);
			STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
			CounterRT->SetLeftOperand(CountOp);
			CounterRT->SetOperator(SMP_ASSIGN);
			RightRT->SetLeftOperand(CountOp);
			RightRT->SetOperator(SMP_UNARY_NUMERIC_OPERATION);
			STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
			RightRT->SetRightOperand(VoidOp);
			CounterRT->SetRightTree(RightRT);
			this->RTL.push_back(CounterRT);
		}
		if ((STARS_NN_cmps == opcode) || (STARS_NN_scas == opcode)) {
			// The ESI and EDI registers get incremented or decremented, depending
			//  on the direction flag DF, for CMPS; only EDI for SCAS.
			// This is true with or without a repeat prefix.
			if (STARS_NN_cmps == opcode) {
				STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si);
				this->RTL.ExtraKills.push_back(ESIOp);
			}
			STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di);
			this->RTL.ExtraKills.push_back(EDIOp);
		}
	}
	return (NoOperandsRequired || (Source1Found && Source2Found));
} // end of SMPInstr::BuildFlagsDestBinaryRTL()

// Build the RTL for a direct or indirect call instruction
bool SMPInstr::BuildCallRTL(void) {
	std::size_t OpNum;
	bool SourceFound = false;
	uint16_t opcode = this->GetIDAOpcode();
	bool ParameterlessCall = ((opcode == STARS_NN_syscall) || (opcode == STARS_NN_sysenter)
		|| (opcode == STARS_NN_into) || (opcode == STARS_NN_int3));
	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
	SMPRegTransfer *TempRT = NULL;

	if (ParameterlessCall) {
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(VoidOp);
		TempRT->SetOperator(SMP_CALL);
		STARSOpndTypePtr TargetOp = this->STARSInstPtr->MakeNearPointerOpnd(STARS_BADADDR);
		TempRT->SetRightOperand(TargetOp);
	}
	else {
		for (OpNum = 0; !SourceFound && (OpNum < STARS_UA_MAXOP); ++OpNum) {
			STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
			if (nullptr == TempOp) // finished processing operands
				break;
			if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
				if (MDKnownOperandType(TempOp)) {
#if SMP_DEBUG_BUILD_RTL
					SMP_msg("ERROR: Found destination operand for call at %llx : %s\n",
						(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				}
			}
			else { // USE
				if (MDKnownOperandType(TempOp)) {
					SourceFound = true;
					TempRT = new SMPRegTransfer;
					TempRT->SetParentInst(this);
					TempRT->SetLeftOperand(VoidOp);
					TempRT->SetOperator(SMP_CALL);
					TempRT->SetRightOperand(TempOp);
				}
			}
		} // end for (OpNum = 0; ...)
	}

	if (!SourceFound && !ParameterlessCall) {
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find CALL operand at %llx for %s\n", 
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		this->RTL.push_back(TempRT);
	}
	return (SourceFound || ParameterlessCall);
} // end of SMPInstr::BuildCallRTL()

// Build the RTL for a return instruction, with or without extra bytes popped off stack
bool SMPInstr::BuildReturnRTL(void) {
	std::size_t OpNum;
	STARS_uval_t PopBytes = (STARS_uval_t) global_STARS_program->GetSTARS_ISA_Bytewidth();  // default: pop off return address

	switch (this->GetIDAOpcode()) {
		// Returns modified by operand size prefixes
		case STARS_NN_retnw:               // Return Near from Procedure (use16)
		case STARS_NN_retfw:               // Return Far from Procedure (use16)
			PopBytes = 2;
			break;

		case STARS_NN_retnd:               // Return Near from Procedure (use32)
		case STARS_NN_retfd:               // Return Far from Procedure (use32)
			PopBytes = 4;
			break;

		case STARS_NN_retnq:               // Return Near from Procedure (use64)
		case STARS_NN_retfq:               // Return Far from Procedure (use64)
			PopBytes = 8;
			break;
	}

	for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
#if SMP_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found destination operand for RET at %llx : %s\n",
					(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		}
		else { // USE
			if (MDKnownOperandType(TempOp)) {
				if (TempOp->IsImmedOp()) {
					PopBytes += TempOp->GetImmedValue();
				}
				else {
#if SMP_DEBUG_BUILD_RTL
					if (!(this->IsTailCall())) {
						SMP_msg("ERROR: Found unexpected operand for return at %llx : %s\n",
							(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
					}
#endif
				}
			}
		}
	} // end for (OpNum = 0; ...)

	this->AddToStackPointer(PopBytes);
	this->SetHasReturnOpcode();
	return true;
} // end of SMPInstr::BuildReturnRTL()

// Build the RTL for an ENTER instruction
bool SMPInstr::BuildEnterRTL(void) {
	// An "ENTER k,0" instruction with allocation k and nesting level 0 does the following:
	//  push ebp
	//  mov ebp,esp
	//  sub esp,k
	// This can be modeled by the parallel effects:
	//  [esp-4] := ebp; ebp := esp - 4; esp := esp - (k + 4)
	// If nesting level is greater than zero, we have a block structure language with
	//  nested procedures, in which additional frame pointers are saved:
	// "ENTER k,n" pushes n additional frame pointers on the stack. We will only model
	//  the change in the stack pointer here, and not attempt to transfer the display
	//  pointers. A warning will be issued to the log file. Parallel effects are:
	//  [esp-4] := ebp; ebp := esp - 4; esp := esp - (((k + n)*4)+4)
	// Note that k and n are immediate values so the final expression can be computed.
	std::size_t OpNum;
	STARS_uval_t NestingLevel = 0;
	STARS_uval_t AllocBytes = 0;
	bool AllocFound = false;
	bool NestingLevelFound = false;

	STARSOpndTypePtr StackPointerOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG);
	STARSOpndTypePtr FramePointerOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG);
	STARSOpndTypePtr ImmedWordSizeOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) global_STARS_program->GetSTARS_ISA_Bytewidth());

	STARSOpndTypePtr SavedEBP = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, (-((STARS_ea_t) global_STARS_program->GetSTARS_ISA_Bytewidth())));
	// [ESP-4 or 8], location of saved EBP

	for (OpNum = 0; !(AllocFound && NestingLevelFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
#if SMP_DEBUG_BUILD_RTL
				SMP_msg("ERROR: Found destination operand for ENTER at %llx : %s\n",
					(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
			}
		}
		else { // USE
			if (MDKnownOperandType(TempOp)) {
				if (TempOp->IsImmedOp()) {
					if (!AllocFound) {
						AllocBytes = TempOp->GetImmedValue();
						AllocFound = true;
					}
					else {
						NestingLevel = TempOp->GetImmedValue();
						NestingLevelFound = true;
					}
				}
				else {
#if SMP_DEBUG_BUILD_RTL
					SMP_msg("ERROR: Found unexpected operand for ENTER at %llx : %s\n",
						(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				}
			}
		}
	} // end for (OpNum = 0; ...)

	if (!AllocFound) {
#if SMP_DEBUG_BUILD_RTL
		SMP_msg("ERROR: Could not find allocation operand for ENTER at %llx : %s\n",
			(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
#endif
	}
	else {
		SMPRegTransfer *TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);

		// Add first effect: [esp - wordsize] := ebp
		TempRT->SetLeftOperand(SavedEBP);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(FramePointerOp);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// Add second effect: ebp := esp - wordsize
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(FramePointerOp);
		TempRT->SetOperator(SMP_ASSIGN);
		SMPRegTransfer *RightRT = new SMPRegTransfer;
		RightRT->SetParentInst(this);
		RightRT->SetLeftOperand(StackPointerOp);
		RightRT->SetOperator(SMP_SUBTRACT);
		RightRT->SetRightOperand(ImmedWordSizeOp);
		TempRT->SetRightTree(RightRT);
		this->RTL.push_back(TempRT);
		TempRT = NULL;
		RightRT = NULL;

		// Add final effect on stack pointer
		AllocBytes += (global_STARS_program->GetSTARS_ISA_Bytewidth() * (NestingLevel + 1));
		if (0 != NestingLevel) {
			SMP_msg("WARNING: Nested procedures in ENTER instruction at %llx : %s\n",
				(unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
		}
		this->SubFromStackPointer(AllocBytes);
	}
	return AllocFound;
} // end of SMPInstr::BuildEnterRTL()

// Build the RTL for a LEAVE instruction
bool SMPInstr::BuildLeaveRTL(void) {
	// A LEAVE instruction simulates the following instructions:
	//  mov ebp into esp (deallocates stack frame)
	//  pop saved ebp off stack into ebp
	// We want to model these two instructions with three parallel effects:
	//  esp := ebp; ebp := [ebp+0]; esp = esp + wordsize;
	// There cannot be two definitions of esp in the list of effects, so we do:
	//  esp := ebp + wordsize; ebp := [ebp+0] as our two parallel effects
	STARSOpndTypePtr StackPointerOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG);
	STARSOpndTypePtr FramePointerOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG);
	STARSOpndTypePtr ImmedWordSizeOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) global_STARS_program->GetSTARS_ISA_Bytewidth());
	STARSOpndTypePtr SavedEBP = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_FRAME_POINTER_REG, STARS_x86_R_none, 0, 0);

	// Build first effect:  ESP := EBP + wordsize
	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	TempRT->SetLeftOperand(StackPointerOp);
	TempRT->SetOperator(SMP_ASSIGN);
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	RightRT->SetOperator(SMP_ADD);
	RightRT->SetLeftOperand(FramePointerOp);
	RightRT->SetRightOperand(ImmedWordSizeOp);
	TempRT->SetRightTree(RightRT);
	this->RTL.push_back(TempRT);
	TempRT = NULL;
	RightRT = NULL;

	// Build second effect: EBP := [EBP+0]
	TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	TempRT->SetLeftOperand(FramePointerOp);
	TempRT->SetOperator(SMP_ASSIGN);
	TempRT->SetRightOperand(SavedEBP);
	this->RTL.push_back(TempRT);
	TempRT = NULL;

	return true;
} // end of SMPInstr::BuildLeaveRTL()

// Build OptCategory 8 RTLs, which set system info into EDX:EAX.
bool SMPInstr::BuildOptType8RTL(void) {
	STARSOpndTypePtr DestOp1 = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx);
	STARSOpndTypePtr DestOp2 = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax);
	STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd();
	STARSOpndTypePtr LeftOp = nullptr;
	if (STARS_NN_xgetbv == this->GetIDAOpcode()) {
		// AMD xgetbv opcode gets control register number to read out of ECX.
		LeftOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
	}
	else {
		LeftOp = VoidOp;
	}

	// Create the effect on EDX.
	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	TempRT->SetLeftOperand(DestOp1);
	TempRT->SetOperator(SMP_ASSIGN);
	SMPRegTransfer *RightRT =  new SMPRegTransfer;
	RightRT->SetParentInst(this);
	RightRT->SetLeftOperand(LeftOp);
	RightRT->SetOperator(SMP_SYSTEM_OPERATION);
	RightRT->SetRightOperand(VoidOp);
	TempRT->SetRightTree(RightRT);
	this->RTL.push_back(TempRT);

	// Create the effect on EAX.
	TempRT = NULL;
	RightRT = NULL;
	TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	TempRT->SetLeftOperand(DestOp2);
	TempRT->SetOperator(SMP_ASSIGN);
	RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	RightRT->SetLeftOperand(LeftOp);
	RightRT->SetOperator(SMP_SYSTEM_OPERATION);
	RightRT->SetRightOperand(VoidOp);
	TempRT->SetRightTree(RightRT);
	this->RTL.push_back(TempRT);

	return true;
} // end of BuildOptType8RTL()

// Build the RTL for a direct or indirect jump instruction
bool SMPInstr::BuildJumpRTL(SMPoperator CondBranchOp) {
	std::size_t OpNum;
	bool TargetFound = false;
	SMPRegTransfer *TempRT = NULL;
	STARSOpndTypePtr EIPOp = this->STARSInstPtr->MakeRegOpnd(MD_INSTRUCTION_POINTER_REG);
	STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx);
	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG);
	STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0);

#if 0
	if (this->IsTailCall())
		return this->BuildReturnRTL();
#endif

	for (OpNum = 0; !TargetFound && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			if (MDKnownOperandType(TempOp)) {
				TargetFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetLeftOperand(EIPOp);
				TempRT->SetOperator(SMP_ASSIGN);
				TempRT->SetRightOperand(TempOp);
				if (CondBranchOp != SMP_NULL_OPERATOR) {
					// Set up a guard expression comparing EFLAGS to zero.
					// NOTE: This is imprecise for value-set purposes, but OK for types.
					SMPGuard *BranchCondition = new SMPGuard;
					BranchCondition->SetOperator(CondBranchOp);
					// The conditional jumps on ECX==0 compare to ECX, not EFLAGS.
					if ((STARS_NN_jcxz <= this->GetIDAOpcode()) && (STARS_NN_jrcxz >= this->GetIDAOpcode()))
						BranchCondition->SetLeftOperand(CountOp);
					else
						BranchCondition->SetLeftOperand(FlagsOp);
					BranchCondition->SetRightOperand(ZeroOp);
					TempRT->SetGuard(BranchCondition);
				}
				this->RTL.push_back(TempRT);
			}
		}
	} // end for (OpNum = 0; ...)

#if SMP_DEBUG_BUILD_RTL
	if (!TargetFound) {
		SMP_msg("ERROR: Could not find jump target at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
	}
#endif
	return TargetFound;
} // end of SMPInstr::BuildJumpRTL()

// Add to the stack pointer to deallocate stack space, e.g. for a pop instruction.
void SMPInstr::AddToStackPointer(STARS_uval_t delta) {
	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
	STARSOpndTypePtr DeltaOp = this->STARSInstPtr->MakeImmediateOpnd(delta);

	TempRT->SetLeftOperand(StackOp);    // ESP := RightRT
	TempRT->SetOperator(SMP_ASSIGN); 
	RightRT->SetLeftOperand(StackOp); // ESP + delta
	RightRT->SetOperator(SMP_ADD);
	RightRT->SetRightOperand(DeltaOp);
	TempRT->SetRightTree(RightRT);
	this->RTL.push_back(TempRT);
	return;
} // end of SMPInstr::AddToStackPointer()

// Subtract from the stack pointer to allocate stack space, e.g. for a push instruction.
void SMPInstr::SubFromStackPointer(STARS_uval_t delta) {
	SMPRegTransfer *TempRT = new SMPRegTransfer;
	TempRT->SetParentInst(this);
	SMPRegTransfer *RightRT = new SMPRegTransfer;
	RightRT->SetParentInst(this);
	STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
	STARSOpndTypePtr DeltaOp = this->STARSInstPtr->MakeImmediateOpnd(delta);

	TempRT->SetLeftOperand(StackOp);    // ESP := RightRT
	TempRT->SetOperator(SMP_ASSIGN);
	RightRT->SetLeftOperand(StackOp); // ESP - delta
	RightRT->SetOperator(SMP_SUBTRACT);
	RightRT->SetRightOperand(DeltaOp);
	TempRT->SetRightTree(RightRT);
	this->RTL.push_back(TempRT);
	return;
} // end of SMPInstr::SubFromStackPointer()

#define SMP_FIRST_POP_FLAGS  STARS_NN_popfw
#define SMP_LAST_POP_FLAGS  STARS_NN_popfq
#define SMP_FIRST_POP_ALL  STARS_NN_popaw
#define SMP_LAST_POP_ALL  STARS_NN_popaq
// Build the RTL for a pop instruction
bool SMPInstr::BuildPopRTL(void) {
	std::size_t OpNum, OpSize;
	bool DestFound = false;
	SMPRegTransfer *TempRT = NULL;

	// Handle special cases first.
	if ((SMP_FIRST_POP_FLAGS <= this->GetIDAOpcode()) && (SMP_LAST_POP_FLAGS >= this->GetIDAOpcode())) {
		STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 0); // [ESP+0]
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(FlagsOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp);
		this->RTL.push_back(TempRT);
		TempRT = NULL;
		// Now create the stack pointer increment effect.
		this->AddToStackPointer(global_STARS_program->GetSTARS_ISA_Bytewidth());
		return true;
	}

	if ((SMP_FIRST_POP_ALL <= this->GetIDAOpcode()) && (SMP_LAST_POP_ALL >= this->GetIDAOpcode())) {
		// We pop off 7 registers from the 8 that were pushed on the stack.
		//  The pushed stack pointer is ignored. Instead, the stack pointer value is
		//  adjusted at the end, per the Intel instruction manuals.

		// EDI comes from [ESP+0]
		STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp0 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
			((STARS_ea_t) 0 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(EDIOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp0);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// ESI comes from [ESP+4 or 8]
		STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp1 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
			((STARS_ea_t) 1 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(ESIOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp1);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// EBP comes from [ESP+8 or 16]
		STARSOpndTypePtr EBPOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp2 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
			((STARS_ea_t) 2 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(EBPOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp2);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// Skip over saved ESP at [ESP+12 or 24]

		// EBX comes from [ESP+16 or 32]
		STARSOpndTypePtr EBXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_bx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp4 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
			((STARS_ea_t) 4 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(EBXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp4);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// EDX comes from [ESP+20 or 40]
		STARSOpndTypePtr EDXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp5 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
			((STARS_ea_t) 5 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(EDXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp5);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// ECX comes from [ESP+24 or 48]
		STARSOpndTypePtr ECXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp6 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
			((STARS_ea_t) 6 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(ECXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp6);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// EAX comes from [ESP+28 or 56]
		STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp7 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
			((STARS_ea_t) 7 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetLeftOperand(EAXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetRightOperand(StackOp7);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// Now create the stack pointer increment effect.
		this->AddToStackPointer(8*global_STARS_program->GetSTARS_ISA_Bytewidth());
		return true;
	} // end for "pop all" instructions

	// If we reach this point, we have a simple POP instruction.
	for (OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF
			if (MDKnownOperandType(TempOp)) {
				DestFound = true;
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetLeftOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				OpSize = TempOp->GetByteWidth();
				STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 0);
				StackOp->SetByteWidth(OpSize);
				TempRT->SetRightOperand(StackOp);
				this->RTL.push_back(TempRT);
				// Now create the stack pointer increment effect.
				this->AddToStackPointer((STARS_uval_t) OpSize);
			}
		}
	} // end for (OpNum = 0; ...)

#if SMP_DEBUG_BUILD_RTL
	if (!DestFound) {
		SMP_msg("ERROR: Could not find pop operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
	}
#endif
	return DestFound;
} // end of SMPInstr::BuildPopRTL()

#define SMP_FIRST_PUSH_FLAGS  STARS_NN_pushfw
#define SMP_LAST_PUSH_FLAGS  STARS_NN_pushfq
#define SMP_FIRST_PUSH_ALL  STARS_NN_pushaw
#define SMP_LAST_PUSH_ALL  STARS_NN_pushaq
// Build the RTL for a push instruction
bool SMPInstr::BuildPushRTL(void) {
	std::size_t OpNum, OpSize;
	bool SourceFound = false;
	SMPRegTransfer *TempRT = NULL;

	// Handle special cases first.
	if ((SMP_FIRST_PUSH_FLAGS <= this->GetIDAOpcode()) && (SMP_LAST_PUSH_FLAGS >= this->GetIDAOpcode())) {
		STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(FlagsOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp);
		this->RTL.push_back(TempRT);
		// Now create the stack pointer increment effect.
		this->SubFromStackPointer(global_STARS_program->GetSTARS_ISA_Bytewidth());
		return true;
	}

	if ((SMP_FIRST_PUSH_ALL <= this->GetIDAOpcode()) && (SMP_LAST_PUSH_ALL >= this->GetIDAOpcode())) {
		// EDI goes to [ESP-32 or 64]
		STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp8 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) 8 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(EDIOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp8);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// ESI goes to [ESP-28 or 56]
		STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp7 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) 7 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(ESIOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp7);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// EBP goes to [ESP-24 or 48]
		STARSOpndTypePtr EBPOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp6 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) 6 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(EBPOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp6);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// ESP goes to [ESP-20 or 40]
		STARSOpndTypePtr ESPOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp5 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) 5 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(ESPOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp5);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// EBX goes to [ESP-16 or 32]
		STARSOpndTypePtr EBXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_bx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp4 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) 4 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(EBXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp4);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// EDX goes to [ESP-12 or 24]
		STARSOpndTypePtr EDXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp3 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) 3 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(EDXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp3);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// ECX goes to [ESP-8 or 16]
		STARSOpndTypePtr ECXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp2 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
			-((STARS_ea_t) 2 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(ECXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp2);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// EAX goes to [ESP-4]
		STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
		STARSOpndTypePtr StackOp1 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 
												   -((STARS_ea_t) 1 * global_STARS_program->GetSTARS_ISA_Bytewidth()));
		TempRT = new SMPRegTransfer;
		TempRT->SetParentInst(this);
		TempRT->SetRightOperand(EAXOp);
		TempRT->SetOperator(SMP_ASSIGN);
		TempRT->SetLeftOperand(StackOp1);
		this->RTL.push_back(TempRT);
		TempRT = NULL;

		// Now create the stack pointer increment effect.
		this->SubFromStackPointer((STARS_uval_t) 8 * global_STARS_program->GetSTARS_ISA_Bytewidth());
		return true;
	} // end for "pop all" instructions

	// If we reach this point, we have a simple PUSH instruction.
	for (OpNum = 0; !SourceFound && (OpNum < STARS_UA_MAXOP); ++OpNum) {
		STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum);
		if (nullptr == TempOp) // finished processing operands
			break;
		if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE
			if (MDKnownOperandType(TempOp)) {
				SourceFound = true;
				OpSize = TempOp->GetByteWidth();
				TempRT = new SMPRegTransfer;
				TempRT->SetParentInst(this);
				TempRT->SetRightOperand(TempOp);
				TempRT->SetOperator(SMP_ASSIGN);
				OpSize = TempRT->MDSignExtend64RightOpIfNeeded();
				STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0,
					-((STARS_ea_t) OpSize));
				StackOp->SetByteWidth(OpSize);
				TempRT->SetLeftOperand(StackOp);
				this->RTL.push_back(TempRT);
				TempRT = NULL;
				// Now create the stack pointer increment effect.
				this->SubFromStackPointer((STARS_uval_t) OpSize);
#if 0
				this->RTL.Dump();
#endif
			}
		}
	} // end for (OpNum = 0; ...)

#if SMP_DEBUG_BUILD_RTL
	if (!SourceFound) {
		SMP_msg("ERROR: Could not find push operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
	}
#endif
	return SourceFound;
} // end of SMPInstr::BuildPushRTL()

// Build RTL trees from the SMPcmd info.
bool SMPInstr::BuildRTL(void) {
	STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64));
	SMPRegTransfer *NopRT = NULL;  // no-op register transfer

	// We don't want to explicitly represent the various no-ops except as NULL operations.
	//  E.g. mov esi,esi should not generate DEF and USE of esi, because esi does not change.
	if (this->IsNop()) {
		NopRT = new SMPRegTransfer;
		NopRT->SetParentInst(this);
		NopRT->SetOperator(SMP_NULL_OPERATOR);
		this->RTL.push_back(NopRT);
		NopRT = NULL;
		return true;
	}

	switch (this->GetIDAOpcode()) {
		case STARS_NN_aaa:                 // ASCII Adjust after Addition
		case STARS_NN_aad:                 // ASCII Adjust AX before Division
		case STARS_NN_aam:                 // ASCII Adjust AX after Multiply
		case STARS_NN_aas:                 // ASCII Adjust AL after Subtraction
			return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION);

		case STARS_NN_adc:                 // Add with Carry
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
			return this->BuildBinaryPlusFlagsRTL(SMP_ADD_CARRY);
#else
			return this->BuildBinaryRTL(SMP_ADD_CARRY);
#endif

		case STARS_NN_add:                 // Add
			return this->BuildBinaryRTL(SMP_ADD);

		case STARS_NN_and:                 // Logical AND
			return this->BuildBinaryRTL(SMP_BITWISE_AND);

		case STARS_NN_arpl:                // Adjust RPL Field of Selector
			return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_bound:               // Check Array Index Against Bounds
			return this->BuildGuardedSignalRTL(SMP_SIGNAL);

		case STARS_NN_bsf:                 // Bit Scan Forward
		case STARS_NN_bsr:                 // Bit Scan Reverse
			return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION);

		case STARS_NN_bt:                  // Bit Test
			return this->BuildFlagsDestBinaryRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_btc:                 // Bit Test and Complement
		case STARS_NN_btr:                 // Bit Test and Reset
		case STARS_NN_bts:                 // Bit Test and Set
			// Has effects on both the carry flag and the first operand
			this->RTL.ExtraKills.push_back(FlagsOp);
			return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_call:                // Call Procedure
		case STARS_NN_callfi:              // Indirect Call Far Procedure
		case STARS_NN_callni:              // Indirect Call Near Procedure
			return this->BuildCallRTL();

		case STARS_NN_cbw:                 // AL -> AX (with sign)
		case STARS_NN_cwde:                // AX -> EAX (with sign)
		case STARS_NN_cdqe:                // EAX -> RAX (with sign)
			return this->BuildUnaryRTL(SMP_SIGN_EXTEND);

		case STARS_NN_clc:                 // Clear Carry Flag
		case STARS_NN_cld:                 // Clear Direction Flag
			return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION);

		case STARS_NN_cli:                 // Clear Interrupt Flag
		case STARS_NN_clts:                // Clear Task-Switched Flag in CR0
			// We don't track the interrupt flag or the special registers,
			//  so we can just consider these to be no-ops.
			// NOTE: Shouldn't we killthe EFLAGS register on STARS_NN_cli ??!!??!!
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_cmc:                 // Complement Carry Flag
			return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION);

		case STARS_NN_cmp:                 // Compare Two Operands
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);

		case STARS_NN_cmps:                // Compare Strings
			// Why do we no longer use BuildCompareStringRTL()?  ****!!!!**** Test it!
			return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE);

		case STARS_NN_cwd:                 // AX -> DX:AX (with sign)
		case STARS_NN_cdq:                 // EAX -> EDX:EAX (with sign)
		case STARS_NN_cqo:                 // RAX -> RDX:RAX (with sign)
			return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND);

		case STARS_NN_daa:                 // Decimal Adjust AL after Addition
		case STARS_NN_das:                 // Decimal Adjust AL after Subtraction
			return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION);

		case STARS_NN_dec:                 // Decrement by 1
			return this->BuildUnaryRTL(SMP_DECREMENT);

		case STARS_NN_div:                 // Unsigned Divide
			return this->BuildMultiplyDivideRTL(SMP_U_DIVIDE);

		case STARS_NN_enterw:              // Make Stack Frame for Procedure Parameters
		case STARS_NN_enter:               // Make Stack Frame for Procedure Parameters
		case STARS_NN_enterd:              // Make Stack Frame for Procedure Parameters
		case STARS_NN_enterq:              // Make Stack Frame for Procedure Parameters
			return this->BuildEnterRTL();

		case STARS_NN_hlt:                 // Halt
			// Treat as a no-op
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_idiv:                // Signed Divide
			return this->BuildMultiplyDivideRTL(SMP_S_DIVIDE);

		case STARS_NN_imul:                // Signed Multiply
			return this->BuildMultiplyDivideRTL(SMP_S_MULTIPLY);

		case STARS_NN_in:                  // Input from Port
			return this->BuildUnary2OpndRTL(SMP_INPUT);

		case STARS_NN_inc:                 // Increment by 1
			return this->BuildUnaryRTL(SMP_INCREMENT);

		case STARS_NN_ins:                 // Input Byte(s) from Port to String
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_int:                 // Call to Interrupt Procedure
		case STARS_NN_into:                // Call to Interrupt Procedure if Overflow Flag = 1
		case STARS_NN_int3:                // Trap to Debugger
			return this->BuildCallRTL();

		case STARS_NN_iretw:               // Interrupt Return
		case STARS_NN_iret:                // Interrupt Return
		case STARS_NN_iretd:               // Interrupt Return (use32)
		case STARS_NN_iretq:               // Interrupt Return (use64)
			return this->BuildReturnRTL();

		case STARS_NN_ja:                  // Jump if Above (CF=0 & ZF=0)
			return this->BuildJumpRTL(SMP_ABOVE);

		case STARS_NN_jae:                 // Jump if Above or Equal (CF=0)
			return this->BuildJumpRTL(SMP_ABOVE_EQUAL);

		case STARS_NN_jb:                  // Jump if Below (CF=1)
			return this->BuildJumpRTL(SMP_BELOW);

		case STARS_NN_jbe:                 // Jump if Below or Equal (CF=1 | ZF=1)
			return this->BuildJumpRTL(SMP_BELOW_EQUAL);

		case STARS_NN_jc:                  // Jump if Carry (CF=1)
			return this->BuildJumpRTL(SMP_BELOW);

		case STARS_NN_jcxz:                // Jump if CX is 0
		case STARS_NN_jecxz:               // Jump if ECX is 0
		case STARS_NN_jrcxz:               // Jump if RCX is 0
			return this->BuildJumpRTL(SMP_EQUAL); // special case in BuildJumpRTL()

		case STARS_NN_je:                  // Jump if Equal (ZF=1)
			return this->BuildJumpRTL(SMP_EQUAL);

		case STARS_NN_jg:                  // Jump if Greater (ZF=0 & SF=OF)
			return this->BuildJumpRTL(SMP_GREATER_THAN);

		case STARS_NN_jge:                 // Jump if Greater or Equal (SF=OF)
			return this->BuildJumpRTL(SMP_GREATER_EQUAL);

		case STARS_NN_jl:                  // Jump if Less (SF!=OF)
			return this->BuildJumpRTL(SMP_LESS_THAN);

		case STARS_NN_jle:                 // Jump if Less or Equal (ZF=1 | SF!=OF)
			return this->BuildJumpRTL(SMP_LESS_EQUAL);

		case STARS_NN_jna:                 // Jump if Not Above (CF=1 | ZF=1)
			return this->BuildJumpRTL(SMP_BELOW_EQUAL);

		case STARS_NN_jnae:                // Jump if Not Above or Equal (CF=1)
			return this->BuildJumpRTL(SMP_BELOW);

		case STARS_NN_jnb:                 // Jump if Not Below (CF=0)
			return this->BuildJumpRTL(SMP_ABOVE_EQUAL);

		case STARS_NN_jnbe:                // Jump if Not Below or Equal (CF=0 & ZF=0) a.k.a. ja
			return this->BuildJumpRTL(SMP_ABOVE);

		case STARS_NN_jnc:                 // Jump if Not Carry (CF=0)
			return this->BuildJumpRTL(SMP_ABOVE_EQUAL);

		case STARS_NN_jne:                 // Jump if Not Equal (ZF=0)
			return this->BuildJumpRTL(SMP_NOT_EQUAL);

		case STARS_NN_jng:                 // Jump if Not Greater (ZF=1 | SF!=OF) a.k.a. jle
			return this->BuildJumpRTL(SMP_LESS_EQUAL);

		case STARS_NN_jnge:                // Jump if Not Greater or Equal (SF != OF) **
			return this->BuildJumpRTL(SMP_LESS_THAN);

		case STARS_NN_jnl:                 // Jump if Not Less (SF=OF) a.k.a. jge
			return this->BuildJumpRTL(SMP_GREATER_EQUAL);

		case STARS_NN_jnle:                // Jump if Not Less or Equal (ZF=0 & SF=OF) a.k.a. jg
			return this->BuildJumpRTL(SMP_GREATER_THAN);

		case STARS_NN_jno:                 // Jump if Not Overflow (OF=0)
		case STARS_NN_jnp:                 // Jump if Not Parity (PF=0)
		case STARS_NN_jns:                 // Jump if Not Sign (SF=0)
			return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_jnz:                 // Jump if Not Zero (ZF=0)  a.k.a. jne
			return this->BuildJumpRTL(SMP_NOT_EQUAL);

		case STARS_NN_jo:                  // Jump if Overflow (OF=1)
		case STARS_NN_jp:                  // Jump if Parity (PF=1)
		case STARS_NN_jpe:                 // Jump if Parity Even (PF=1)
		case STARS_NN_jpo:                 // Jump if Parity Odd  (PF=0)
		case STARS_NN_js:                  // Jump if Sign (SF=1)
			return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_jz:                  // Jump if Zero (ZF=1)
			return this->BuildJumpRTL(SMP_EQUAL);

		case STARS_NN_jmp:                 // Jump
		case STARS_NN_jmpfi:               // Indirect Far Jump
		case STARS_NN_jmpni:               // Indirect Near Jump
		case STARS_NN_jmpshort:            // Jump Short (not used)
			return this->BuildJumpRTL(SMP_NULL_OPERATOR);

		case STARS_NN_lahf:                // Load Flags into AH Register
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_lar:                 // Load Access Right Byte
			return false;
			break;

		case STARS_NN_lea:                 // Load Effective Address
			return this->BuildLeaRTL();
			break;

		case STARS_NN_leavew:              // High Level Procedure Exit
		case STARS_NN_leave:               // High Level Procedure Exit
		case STARS_NN_leaved:              // High Level Procedure Exit
		case STARS_NN_leaveq:              // High Level Procedure Exit
			return this->BuildLeaveRTL();
			break;

		case STARS_NN_lgdt:                // Load Global Descriptor Table Register
		case STARS_NN_lidt:                // Load Interrupt Descriptor Table Register
			return false;
			break;

		case STARS_NN_lgs:                 // Load Full Pointer to GS:xx
		case STARS_NN_lss:                 // Load Full Pointer to SS:xx
		case STARS_NN_lds:                 // Load Full Pointer to DS:xx
		case STARS_NN_les:                 // Load Full Pointer to ES:xx
		case STARS_NN_lfs:                 // Load Full Pointer to FS:xx
			// These instructions differ from STARS_NN_lea only in setting
			//  a segment register in addition to a pointer. We are
			//  not yet tracking segment registers.
			return this->BuildLeaRTL();
			break;

		case STARS_NN_lldt:                // Load Local Descriptor Table Register
		case STARS_NN_lmsw:                // Load Machine Status Word
			return false;
			break;

		case STARS_NN_lock:                // Assert LOCK# Signal Prefix  NOTE: This is now a no-op
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_lods:                // Load String
			return this->BuildLoadStringRTL();
			break;

		case STARS_NN_loopw:               // Loop while ECX != 0
		case STARS_NN_loop:                // Loop while CX != 0
		case STARS_NN_loopd:               // Loop while ECX != 0
		case STARS_NN_loopq:               // Loop while RCX != 0
		case STARS_NN_loopwe:              // Loop while CX != 0 and ZF=1
		case STARS_NN_loope:               // Loop while rCX != 0 and ZF=1
		case STARS_NN_loopde:              // Loop while ECX != 0 and ZF=1
		case STARS_NN_loopqe:              // Loop while RCX != 0 and ZF=1
		case STARS_NN_loopwne:             // Loop while CX != 0 and ZF=0
		case STARS_NN_loopne:              // Loop while rCX != 0 and ZF=0
		case STARS_NN_loopdne:             // Loop while ECX != 0 and ZF=0
		case STARS_NN_loopqne:             // Loop while RCX != 0 and ZF=0
			return this->BuildLoopRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_lsl:                 // Load Segment Limit
		case STARS_NN_ltr:                 // Load Task Register
			return false;
			break;

		case STARS_NN_mov:                 // Move Data
		case STARS_NN_movsp:               // Move to/from Special Registers
		case STARS_NN_movs:                // Move Byte(s) from String to String
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_movsx:               // Move with Sign-Extend
			return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND);

		case STARS_NN_movzx:               // Move with Zero-Extend
			return this->BuildUnary2OpndRTL(SMP_ZERO_EXTEND);

		case STARS_NN_mul:                 // Unsigned Multiplication of AL or AX
			return this->BuildMultiplyDivideRTL(SMP_U_MULTIPLY);

		case STARS_NN_neg:                 // Two's Complement Negation
			return this->BuildUnaryRTL(SMP_NEGATE);

		case STARS_NN_nop:                 // No Operation
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_not:                 // One's Complement Negation
			return this->BuildUnaryRTL(SMP_BITWISE_NOT);

		case STARS_NN_or:                  // Logical Inclusive OR
			return this->BuildBinaryRTL(SMP_BITWISE_OR);

		case STARS_NN_out:                 // Output to Port
			return this->BuildUnary2OpndRTL(SMP_OUTPUT);

		case STARS_NN_outs:                // Output Byte(s) to Port
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_pop:                 // Pop a word from the Stack
		case STARS_NN_popaw:               // Pop all General Registers
		case STARS_NN_popa:                // Pop all General Registers
		case STARS_NN_popad:               // Pop all General Registers (use32)
		case STARS_NN_popaq:               // Pop all General Registers (use64)
		case STARS_NN_popfw:               // Pop Stack into Flags Register
		case STARS_NN_popf:                // Pop Stack into Flags Register
		case STARS_NN_popfd:               // Pop Stack into Eflags Register
		case STARS_NN_popfq:               // Pop Stack into Rflags Register
			return this->BuildPopRTL();

		case STARS_NN_push:                // Push Operand onto the Stack
		case STARS_NN_pushaw:              // Push all General Registers
		case STARS_NN_pusha:               // Push all General Registers
		case STARS_NN_pushad:              // Push all General Registers (use32)
		case STARS_NN_pushaq:              // Push all General Registers (use64)
		case STARS_NN_pushfw:              // Push Flags Register onto the Stack
		case STARS_NN_pushf:               // Push Flags Register onto the Stack
		case STARS_NN_pushfd:              // Push Flags Register onto the Stack (use32)
		case STARS_NN_pushfq:              // Push Flags Register onto the Stack (use64)
			return this->BuildPushRTL();

		case STARS_NN_rcl:                 // Rotate Through Carry Left
			return this->BuildBinaryPlusFlagsRTL(SMP_ROTATE_LEFT_CARRY);

		case STARS_NN_rcr:                 // Rotate Through Carry Right
			return this->BuildBinaryPlusFlagsRTL(SMP_ROTATE_RIGHT_CARRY);

		case STARS_NN_rol:                 // Rotate Left
			return this->BuildBinaryRTL(SMP_ROTATE_LEFT);

		case STARS_NN_ror:                 // Rotate Right
			return this->BuildBinaryRTL(SMP_ROTATE_RIGHT);

		case STARS_NN_rep:                 // Repeat String Operation
		case STARS_NN_repe:                // Repeat String Operation while ZF=1
		case STARS_NN_repne:               // Repeat String Operation while ZF=0
			return false;
			break;

		case STARS_NN_retn:                // Return Near from Procedure
		case STARS_NN_retf:                // Return Far from Procedure
			return this->BuildReturnRTL();

		case STARS_NN_sahf:                // Store AH into Flags Register
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_sal:                 // Shift Arithmetic Left
			return this->BuildBinaryRTL(SMP_S_LEFT_SHIFT);

		case STARS_NN_sar:                 // Shift Arithmetic Right
			return this->BuildBinaryRTL(SMP_S_RIGHT_SHIFT);

		case STARS_NN_shl:                 // Shift Logical Left
			return this->BuildBinaryRTL(SMP_U_LEFT_SHIFT);

		case STARS_NN_shr:                 // Shift Logical Right
			return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT);

		case STARS_NN_sbb:                 // Integer Subtraction with Borrow
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
			return this->BuildBinaryPlusFlagsRTL(SMP_SUBTRACT_BORROW);
#else
			return this->BuildBinaryRTL(SMP_SUBTRACT_BORROW);
#endif

		case STARS_NN_scas:                // Scan String
			return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE);

		case STARS_NN_seta:                // Set Byte if Above (CF=0 & ZF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_ABOVE, SMP_BELOW_EQUAL);

		case STARS_NN_setae:               // Set Byte if Above or Equal (CF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_ABOVE_EQUAL, SMP_BELOW);

		case STARS_NN_setb:                // Set Byte if Below (CF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_BELOW, SMP_ABOVE_EQUAL);

		case STARS_NN_setbe:               // Set Byte if Below or Equal (CF=1 | ZF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_BELOW_EQUAL, SMP_ABOVE);

		case STARS_NN_setc:                // Set Byte if Carry (CF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_CARRY, SMP_NOT_CARRY);

		case STARS_NN_sete:                // Set Byte if Equal (ZF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_EQUAL, SMP_NOT_EQUAL);

		case STARS_NN_setg:                // Set Byte if Greater (ZF=0 & SF=OF)
			return this->BuildSetFlagIntoRegRTL(SMP_GREATER_THAN, SMP_LESS_EQUAL);

		case STARS_NN_setge:               // Set Byte if Greater or Equal (SF=OF)
			return this->BuildSetFlagIntoRegRTL(SMP_GREATER_EQUAL, SMP_LESS_THAN);

		case STARS_NN_setl:                // Set Byte if Less (SF!=OF)
			return this->BuildSetFlagIntoRegRTL(SMP_LESS_THAN, SMP_GREATER_EQUAL);

		case STARS_NN_setle:               // Set Byte if Less or Equal (ZF=1 | SF!=OF)
			return this->BuildSetFlagIntoRegRTL(SMP_LESS_EQUAL, SMP_GREATER_THAN);

		case STARS_NN_setna:               // Set Byte if Not Above (CF=1 | ZF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_BELOW_EQUAL, SMP_ABOVE);

		case STARS_NN_setnae:              // Set Byte if Not Above or Equal (CF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_BELOW, SMP_ABOVE_EQUAL);

		case STARS_NN_setnb:               // Set Byte if Not Below (CF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_ABOVE_EQUAL, SMP_BELOW);

		case STARS_NN_setnbe:              // Set Byte if Not Below or Equal (CF=0 & ZF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_ABOVE, SMP_BELOW_EQUAL);

		case STARS_NN_setnc:               // Set Byte if Not Carry (CF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_NOT_CARRY, SMP_CARRY);

		case STARS_NN_setne:               // Set Byte if Not Equal (ZF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_NOT_EQUAL, SMP_EQUAL);

		case STARS_NN_setng:               // Set Byte if Not Greater (ZF=1 | SF!=OF)
			return this->BuildSetFlagIntoRegRTL(SMP_LESS_EQUAL, SMP_GREATER_THAN);

		case STARS_NN_setnge:              // Set Byte if Not Greater or Equal (ZF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_LESS_THAN, SMP_GREATER_EQUAL);

		case STARS_NN_setnl:               // Set Byte if Not Less (SF=OF)
			return this->BuildSetFlagIntoRegRTL(SMP_GREATER_EQUAL, SMP_LESS_THAN);

		case STARS_NN_setnle:              // Set Byte if Not Less or Equal (ZF=0 & SF=OF)
			return this->BuildSetFlagIntoRegRTL(SMP_GREATER_THAN, SMP_LESS_EQUAL);

		case STARS_NN_setno:               // Set Byte if Not Overflow (OF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_NOT_OVERFLOW, SMP_OVERFLOW);

		case STARS_NN_setnp:               // Set Byte if Not Parity (PF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_NOT_PARITY, SMP_PARITY);

		case STARS_NN_setns:               // Set Byte if Not Sign (SF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_NOT_SIGN_BIT_SET, SMP_SIGN_BIT_SET);

		case STARS_NN_setnz:               // Set Byte if Not Zero (ZF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_NOT_EQUAL, SMP_EQUAL);

		case STARS_NN_seto:                // Set Byte if Overflow (OF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_OVERFLOW, SMP_NOT_OVERFLOW);

		case STARS_NN_setp:                // Set Byte if Parity (PF=1)
		case STARS_NN_setpe:               // Set Byte if Parity Even (PF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_PARITY, SMP_NOT_PARITY);

		case STARS_NN_setpo:               // Set Byte if Parity Odd  (PF=0)
			return this->BuildSetFlagIntoRegRTL(SMP_NOT_PARITY, SMP_PARITY);

		case STARS_NN_sets:                // Set Byte if Sign (SF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_SIGN_BIT_SET, SMP_NOT_SIGN_BIT_SET);

		case STARS_NN_setz:                // Set Byte if Zero (ZF=1)
			return this->BuildSetFlagIntoRegRTL(SMP_EQUAL, SMP_NOT_EQUAL);

		case STARS_NN_sgdt:                // Store Global Descriptor Table Register
		case STARS_NN_sidt:                // Store Interrupt Descriptor Table Register
			return false;
			break;

		case STARS_NN_shld:                // Double Precision Shift Left
			return this->BuildDoubleShiftRTL(SMP_U_LEFT_SHIFT);

		case STARS_NN_shrd:                // Double Precision Shift Right
			return this->BuildDoubleShiftRTL(SMP_U_RIGHT_SHIFT);

		case STARS_NN_sldt:                // Store Local Descriptor Table Register
		case STARS_NN_smsw:                // Store Machine Status Word
			return false;
			break;

		case STARS_NN_stc:                 // Set Carry Flag
		case STARS_NN_std:                 // Set Direction Flag
			return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION);

		case STARS_NN_sti:                 // Set Interrupt Flag
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_stos:                // Store String
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_str:                 // Store Task Register
			return false;
			break;

		case STARS_NN_sub:                 // Integer Subtraction
			return this->BuildBinaryRTL(SMP_SUBTRACT);

		case STARS_NN_test:                // Logical Compare
			return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE);

		case STARS_NN_verr:                // Verify a Segment for Reading
		case STARS_NN_verw:                // Verify a Segment for Writing
		case STARS_NN_wait:                // Wait until BUSY# Pin is Inactive (HIGH)
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			if (STARS_NN_wait != this->GetIDAOpcode())
				this->RTL.ExtraKills.push_back(FlagsOp);
			return true;

		case STARS_NN_xchg:                // Exchange Register/Memory with Register
			return this->BuildExchangeRTL();

		case STARS_NN_xlat:                // Table Lookup Translation
			return false;
			break;

		case STARS_NN_xor:                 // Logical Exclusive OR
			return this->BuildBinaryRTL(SMP_BITWISE_XOR);


		//
		//      486 instructions
		//

		case STARS_NN_cmpxchg:             // Compare and Exchange
			return this->BuildCompareExchangeRTL();

		case STARS_NN_bswap:               // Swap bits in EAX
			return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION);

		case STARS_NN_xadd:                // t<-dest; dest<-src+dest; src<-t
			return this->BuildExchangeAddRTL();

		case STARS_NN_invd:                // Invalidate Data Cache
		case STARS_NN_wbinvd:              // Invalidate Data Cache (write changes)
		case STARS_NN_invlpg:              // Invalidate TLB entry
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		//
		//      Pentium instructions
		//

		case STARS_NN_rdmsr:               // Read Machine Status Register
			return this->BuildOptType8RTL();

		case STARS_NN_wrmsr:               // Write Machine Status Register
			return false;
			break;

		case STARS_NN_cpuid:               // Get CPU ID
			return this->BuildOptType8RTL();

		case STARS_NN_cmpxchg8b:           // Compare and Exchange Eight Bytes
			return false;
			break;

		case STARS_NN_rdtsc:               // Read Time Stamp Counter
			return this->BuildOptType8RTL();

		case STARS_NN_rsm:                 // Resume from System Management Mode
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;


		//
		//      Pentium Pro instructions
		//

		case STARS_NN_cmova:               // Move if Above (CF=0 & ZF=0)
			return this->BuildMoveRTL(SMP_ABOVE);

		case STARS_NN_cmovb:               // Move if Below (CF=1)
			return this->BuildMoveRTL(SMP_BELOW);

		case STARS_NN_cmovbe:              // Move if Below or Equal (CF=1 | ZF=1)
			return this->BuildMoveRTL(SMP_BELOW_EQUAL);

		case STARS_NN_cmovg:               // Move if Greater (ZF=0 & SF=OF)
			return this->BuildMoveRTL(SMP_GREATER_THAN);

		case STARS_NN_cmovge:              // Move if Greater or Equal (SF=OF)
			return this->BuildMoveRTL(SMP_GREATER_EQUAL);

		case STARS_NN_cmovl:               // Move if Less (SF!=OF)
			return this->BuildMoveRTL(SMP_LESS_THAN);

		case STARS_NN_cmovle:              // Move if Less or Equal (ZF=1 | SF!=OF)
			return this->BuildMoveRTL(SMP_LESS_EQUAL);

		case STARS_NN_cmovnb:              // Move if Not Below (CF=0)
			return this->BuildMoveRTL(SMP_ABOVE_EQUAL);

		case STARS_NN_cmovno:              // Move if Not Overflow (OF=0)
		case STARS_NN_cmovnp:              // Move if Not Parity (PF=0)
		case STARS_NN_cmovns:              // Move if Not Sign (SF=0)
			return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_cmovnz:              // Move if Not Zero (ZF=0)
			return this->BuildMoveRTL(SMP_NOT_EQUAL);

		case STARS_NN_cmovo:               // Move if Overflow (OF=1)
		case STARS_NN_cmovp:               // Move if Parity (PF=1)
		case STARS_NN_cmovs:               // Move if Sign (SF=1)
			return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_cmovz:               // Move if Zero (ZF=1)
			return this->BuildMoveRTL(SMP_EQUAL);

		case STARS_NN_fcmovb:              // Floating Move if Below
			return this->BuildMoveRTL(SMP_BELOW);

		case STARS_NN_fcmove:              // Floating Move if Equal
			return this->BuildMoveRTL(SMP_EQUAL);

		case STARS_NN_fcmovbe:             // Floating Move if Below or Equal
			return this->BuildMoveRTL(SMP_BELOW_EQUAL);

		case STARS_NN_fcmovu:              // Floating Move if Unordered
			return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_fcmovnb:             // Floating Move if Not Below
			return this->BuildMoveRTL(SMP_ABOVE_EQUAL);

		case STARS_NN_fcmovne:             // Floating Move if Not Equal
			return this->BuildMoveRTL(SMP_NOT_EQUAL);

		case STARS_NN_fcmovnbe:            // Floating Move if Not Below or Equal
			return this->BuildMoveRTL(SMP_ABOVE);

		case STARS_NN_fcmovnu:             // Floating Move if Not Unordered
			return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION);


		case STARS_NN_fcomi:               // FP Compare: result in EFLAGS
		case STARS_NN_fucomi:              // FP Unordered Compare: result in EFLAGS
		case STARS_NN_fcomip:              // FP Compare: result in EFLAGS: pop stack
		case STARS_NN_fucomip:             // FP Unordered Compare: result in EFLAGS: pop stack
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);
			break;

		case STARS_NN_rdpmc:               // Read Performance Monitor Counter
			return this->BuildOptType8RTL();

		//
		//      FPP instructions
		//

		case STARS_NN_fld:                 // Load Real
		case STARS_NN_fst:                 // Store Real
		case STARS_NN_fstp:                // Store Real and Pop
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_fxch:                // Exchange Registers
			// FP registers remain NUMERIC anyway, so this is a no-op to our type system.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_fild:                // Load Integer
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_fist:                // Store Integer
		case STARS_NN_fistp:               // Store Integer and Pop
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);

		case STARS_NN_fbld:                // Load BCD
		case STARS_NN_fbstp:               // Store BCD and Pop
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_fadd:                // Add Real
		case STARS_NN_faddp:               // Add Real and Pop
		case STARS_NN_fiadd:               // Add Integer
		case STARS_NN_fsub:                // Subtract Real
		case STARS_NN_fsubp:               // Subtract Real and Pop
		case STARS_NN_fisub:               // Subtract Integer
		case STARS_NN_fsubr:               // Subtract Real Reversed
		case STARS_NN_fsubrp:              // Subtract Real Reversed and Pop
		case STARS_NN_fisubr:              // Subtract Integer Reversed
		case STARS_NN_fmul:                // Multiply Real
		case STARS_NN_fmulp:               // Multiply Real and Pop
		case STARS_NN_fimul:               // Multiply Integer
		case STARS_NN_fdiv:                // Divide Real
		case STARS_NN_fdivp:               // Divide Real and Pop
		case STARS_NN_fidiv:               // Divide Integer
		case STARS_NN_fdivr:               // Divide Real Reversed
		case STARS_NN_fdivrp:              // Divide Real Reversed and Pop
		case STARS_NN_fidivr:              // Divide Integer Reversed
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC, true);

		case STARS_NN_fsqrt:               // Square Root
		case STARS_NN_fscale:              // Scale:  st(0) <- st(0) * 2^st(1)
		case STARS_NN_fprem:               // Partial Remainder
		case STARS_NN_frndint:             // Round to Integer
		case STARS_NN_fxtract:             // Extract exponent and significand
		case STARS_NN_fabs:                // Absolute value
		case STARS_NN_fchs:                // Change Sign
			return this->BuildUnaryRTL(SMP_UNARY_FLOATING_ARITHMETIC);

		case STARS_NN_fcom:                // Compare Real
		case STARS_NN_fcomp:               // Compare Real and Pop
		case STARS_NN_fcompp:              // Compare Real and Pop Twice
		case STARS_NN_ficom:               // Compare Integer
		case STARS_NN_ficomp:              // Compare Integer and Pop
		case STARS_NN_ftst:                // Test
		case STARS_NN_fxam:                // Examine
			// Floating comparison instructions use FP reg stack locations
			//  as sources and set only the FP flags. All of these are numeric
			//  type and we don't track any of them, so all such instructions
			//  can be considered to be no-ops.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_fptan:               // Partial tangent
		case STARS_NN_fpatan:              // Partial arctangent
		case STARS_NN_f2xm1:               // 2^x - 1
		case STARS_NN_fyl2x:               // Y * lg2(X)
		case STARS_NN_fyl2xp1:             // Y * lg2(X+1)
			// We can consider it a unary operation when both arguments come
			//  off the floating point register stack, unless we ever start
			//  modeling the different locations in the FP register stack.
			return this->BuildUnaryRTL(SMP_UNARY_FLOATING_ARITHMETIC);

		case STARS_NN_fldz:                // Load +0.0
		case STARS_NN_fld1:                // Load +1.0
		case STARS_NN_fldpi:               // Load PI=3.14...
		case STARS_NN_fldl2t:              // Load lg2(10)
		case STARS_NN_fldl2e:              // Load lg2(e)
		case STARS_NN_fldlg2:              // Load lg10(2)
		case STARS_NN_fldln2:              // Load ln(2)
		case STARS_NN_finit:               // Initialize Processor
		case STARS_NN_fninit:              // Initialize Processor (no wait)
		case STARS_NN_fsetpm:              // Set Protected Mode
			// Floating point stack and control word and flags operations
			//  with no memory operands are no-ops to us.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_fldcw:               // Load Control Word
		case STARS_NN_fstcw:               // Store Control Word
		case STARS_NN_fnstcw:              // Store Control Word (no wait)
		case STARS_NN_fstsw:               // Store Status Word
		case STARS_NN_fnstsw:              // Store Status Word (no wait)
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);

		case STARS_NN_fclex:               // Clear Exceptions
		case STARS_NN_fnclex:              // Clear Exceptions (no wait)
			// Floating point stack and control word and flags operations
			//  with no memory operands are no-ops to us.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_fstenv:              // Store Environment
		case STARS_NN_fnstenv:             // Store Environment (no wait)
		case STARS_NN_fldenv:              // Load Environment
		case STARS_NN_fsave:               // Save State
		case STARS_NN_fnsave:              // Save State (no wait)
		case STARS_NN_frstor:              // Restore State
		case STARS_NN_fincstp:             // Increment Stack Pointer
		case STARS_NN_fdecstp:             // Decrement Stack Pointer
		case STARS_NN_ffree:               // Free Register
			// Floating point stack and control word and flags operations
			//  with no memory operands are no-ops to us.
			// NOTE: We might want to deal with the memory operands in some
			//  of these opcodes later.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_fnop:                // No Operation
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_feni:                // (8087 only)
		case STARS_NN_fneni:               // (no wait) (8087 only)
		case STARS_NN_fdisi:               // (8087 only)
		case STARS_NN_fndisi:              // (no wait) (8087 only)
			return false;
			break;


		//
		//      80387 instructions
		//

		case STARS_NN_fprem1:              // Partial Remainder ( < half )
		case STARS_NN_fsincos:             // t<-cos(st); st<-sin(st); push t
		case STARS_NN_fsin:                // Sine
		case STARS_NN_fcos:                // Cosine
		case STARS_NN_fucom:               // Compare Unordered Real
		case STARS_NN_fucomp:              // Compare Unordered Real and Pop
		case STARS_NN_fucompp:             // Compare Unordered Real and Pop Twice
			// Floating point stack and control word and flags operations
			//  with no memory operands are no-ops to us.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;


		//
		//      Instructions added 28.02.96
		//

		case STARS_NN_setalc:              // Set AL to Carry Flag
		case STARS_NN_svdc:                // Save Register and Descriptor
		case STARS_NN_rsdc:                // Restore Register and Descriptor
		case STARS_NN_svldt:               // Save LDTR and Descriptor
		case STARS_NN_rsldt:               // Restore LDTR and Descriptor
		case STARS_NN_svts:                // Save TR and Descriptor
		case STARS_NN_rsts:                // Restore TR and Descriptor
		case STARS_NN_icebp:               // ICE Break Point
		case STARS_NN_loadall:             // Load the entire CPU state from ES:EDI
			return false;
			break;

		//
		//      MMX instructions
		//

		case STARS_NN_emms:                // Empty MMX state
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;
			break;

		case STARS_NN_movd:                // Move 32 bits
		case STARS_NN_movq:                // Move 64 bits
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_packsswb:            // Pack with Signed Saturation (Word->Byte)
		case STARS_NN_packssdw:            // Pack with Signed Saturation (Dword->Word)
			return this->BuildBinaryRTL(SMP_PACK_S);
			break;

		case STARS_NN_packuswb:            // Pack with Unsigned Saturation (Word->Byte)
			return this->BuildBinaryRTL(SMP_PACK_U);
			break;

		case STARS_NN_paddb:               // Packed Add Byte
		case STARS_NN_paddw:               // Packed Add Word
		case STARS_NN_paddd:               // Packed Add Dword
		case STARS_NN_paddsb:              // Packed Add with Saturation (Byte)
		case STARS_NN_paddsw:              // Packed Add with Saturation (Word)
		case STARS_NN_paddusb:             // Packed Add Unsigned with Saturation (Byte)
		case STARS_NN_paddusw:             // Packed Add Unsigned with Saturation (Word)
			return this->BuildBinaryRTL(SMP_ADD);
			break;

		case STARS_NN_pand:                // Bitwise Logical And
			return this->BuildBinaryRTL(SMP_BITWISE_AND);
			break;

		case STARS_NN_pandn:               // Bitwise Logical And Not
			return this->BuildBinaryRTL(SMP_BITWISE_AND_NOT);
			break;

		case STARS_NN_pcmpeqb:             // Packed Compare for Equal (Byte)
		case STARS_NN_pcmpeqw:             // Packed Compare for Equal (Word)
		case STARS_NN_pcmpeqd:             // Packed Compare for Equal (Dword)
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_pcmpgtb:             // Packed Compare for Greater Than (Byte)
		case STARS_NN_pcmpgtw:             // Packed Compare for Greater Than (Word)
		case STARS_NN_pcmpgtd:             // Packed Compare for Greater Than (Dword)
			return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_pmaddwd:             // Packed Multiply and Add
			return this->BuildBinaryRTL(SMP_MULTIPLY_AND_ADD);
			break;

		case STARS_NN_pmulhw:              // Packed Multiply High
		case STARS_NN_pmullw:              // Packed Multiply Low
			return this->BuildBinaryRTL(SMP_U_MULTIPLY);
			break;

		case STARS_NN_por:                 // Bitwise Logical Or
			return this->BuildBinaryRTL(SMP_BITWISE_OR);
			break;

		case STARS_NN_psllw:               // Packed Shift Left Logical (Word)
		case STARS_NN_pslld:               // Packed Shift Left Logical (Dword)
		case STARS_NN_psllq:               // Packed Shift Left Logical (Qword)
			return this->BuildBinaryRTL(SMP_U_LEFT_SHIFT);
			break;

		case STARS_NN_psraw:               // Packed Shift Right Arithmetic (Word)
		case STARS_NN_psrad:               // Packed Shift Right Arithmetic (Dword)
			return this->BuildBinaryRTL(SMP_S_RIGHT_SHIFT);
			break;

		case STARS_NN_psrlw:               // Packed Shift Right Logical (Word)
		case STARS_NN_psrld:               // Packed Shift Right Logical (Dword)
		case STARS_NN_psrlq:               // Packed Shift Right Logical (Qword)
			return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT);
			break;

		case STARS_NN_psubb:               // Packed Subtract Byte
		case STARS_NN_psubw:               // Packed Subtract Word
		case STARS_NN_psubd:               // Packed Subtract Dword
			return this->BuildBinaryRTL(SMP_SUBTRACT);
			break;

		case STARS_NN_psubsb:              // Packed Subtract with Saturation (Byte)
		case STARS_NN_psubsw:              // Packed Subtract with Saturation (Word)
			return this->BuildBinaryRTL(SMP_SUBTRACT);
			break;

		case STARS_NN_psubusb:             // Packed Subtract Unsigned with Saturation (Byte)
		case STARS_NN_psubusw:             // Packed Subtract Unsigned with Saturation (Word)
			return this->BuildBinaryRTL(SMP_SUBTRACT);
			break;

		case STARS_NN_punpckhbw:           // Unpack High Packed Data (Byte->Word)
		case STARS_NN_punpckhwd:           // Unpack High Packed Data (Word->Dword)
		case STARS_NN_punpckhdq:           // Unpack High Packed Data (Dword->Qword)
		case STARS_NN_punpcklbw:           // Unpack Low Packed Data (Byte->Word)
		case STARS_NN_punpcklwd:           // Unpack Low Packed Data (Word->Dword)
		case STARS_NN_punpckldq:           // Unpack Low Packed Data (Dword->Qword)
			return this->BuildBinaryRTL(SMP_INTERLEAVE);
			break;

		case STARS_NN_pxor:                // Bitwise Logical Exclusive Or
			return this->BuildBinaryRTL(SMP_BITWISE_XOR);
			break;

		//
		//      Undocumented Deschutes processor instructions
		//

		case STARS_NN_fxsave:              // Fast save FP context
		case STARS_NN_fxrstor:             // Fast restore FP context
			return false;
			break;

		//      Pentium II instructions

		case STARS_NN_sysenter:            // Fast Transition to System Call Entry Point
		case STARS_NN_sysexit:             // Fast Transition from System Call Entry Point
			return false;
			break;

		//      3DNow! instructions

		case STARS_NN_pavgusb:             // Packed 8-bit Unsigned Integer Averaging
			return this->BuildBinaryRTL(SMP_AVERAGE_U);
			break;

		case STARS_NN_pfadd:               // Packed Floating-Point Addition
			return this->BuildBinaryRTL(SMP_ADD);
			break;

		case STARS_NN_pfsub:               // Packed Floating-Point Subtraction
		case STARS_NN_pfsubr:              // Packed Floating-Point Reverse Subtraction   !!!!****!!!! Fix this reversal if we care about the details
			return this->BuildBinaryRTL(SMP_SUBTRACT);
			break;

		case STARS_NN_pfacc:               // Packed Floating-Point Accumulate
			return this->BuildBinaryRTL(SMP_ADD);
			break;

		case STARS_NN_pfcmpge:             // Packed Floating-Point Comparison: Greater or Equal
			return this->BuildBinaryRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_pfcmpgt:             // Packed Floating-Point Comparison: Greater
			return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_pfcmpeq:             // Packed Floating-Point Comparison: Equal
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_pfmin:               // Packed Floating-Point Minimum
			return this->BuildBinaryRTL(SMP_MIN_S);
			break;

		case STARS_NN_pfmax:               // Packed Floating-Point Maximum
			return this->BuildBinaryRTL(SMP_MAX_S);
			break;

		case STARS_NN_pi2fd:               // Packed 32-bit Integer to Floating-Point
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_pf2id:               // Packed Floating-Point to 32-bit Integer
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_pfrcp:               // Packed Floating-Point Reciprocal Approximation
		case STARS_NN_pfrsqrt:             // Packed Floating-Point Reciprocal Square Root Approximation
			return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_pfmul:               // Packed Floating-Point Multiplication
			return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY);
			break;

		case STARS_NN_pfrcpit1:            // Packed Floating-Point Reciprocal First Iteration Step
		case STARS_NN_pfrsqit1:            // Packed Floating-Point Reciprocal Square Root First Iteration Step
		case STARS_NN_pfrcpit2:            // Packed Floating-Point Reciprocal Second Iteration Step
			return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_pmulhrw:             // Packed Floating-Point 16-bit Integer Multiply with rounding
			return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY);
			break;

		case STARS_NN_femms:               // Faster entry/exit of the MMX or floating-point state
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;
			break;

		case STARS_NN_prefetch:            // Prefetch at least a 32-byte line into L1 data cache
		case STARS_NN_prefetchw:           // Prefetch processor cache line into L1 data cache (mark as modified)
			// Prefetch opcodes are no-ops to us.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		//      Pentium III instructions

		case STARS_NN_addps:               // Packed Single-FP Add
		case STARS_NN_addss:               // Scalar Single-FP Add
			return this->BuildBinaryRTL(SMP_FLOATING_ADD);
			break;

		case STARS_NN_andnps:              // Bitwise Logical And Not for Single-FP
		case STARS_NN_andps:               // Bitwise Logical And for Single-FP
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_cmpps:               // Packed Single-FP Compare
		case STARS_NN_cmpss:               // Scalar Single-FP Compare
			return this->BuildBinaryPlusImmedRTL(SMP_GENERAL_COMPARE, SMP_CREATE_MASK);
			break;

		case STARS_NN_comiss:              // Scalar Ordered Single-FP Compare and Set EFLAGS
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);
			break;

		case STARS_NN_cvtpi2ps:            // Packed signed INT32 to Packed Single-FP conversion
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_cvtps2pi:            // Packed Single-FP to Packed INT32 conversion
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_cvtsi2ss:            // Scalar signed INT32 to Single-FP conversion
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_cvtss2si:            // Scalar Single-FP to signed INT32 conversion
		case STARS_NN_cvttps2pi:           // Packed Single-FP to Packed INT32 conversion (truncate)
		case STARS_NN_cvttss2si:           // Scalar Single-FP to signed INT32 conversion (truncate)
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_divps:               // Packed Single-FP Divide
		case STARS_NN_divss:               // Scalar Single-FP Divide
			return this->BuildBinaryRTL(SMP_FLOATING_DIVIDE);
			break;

		case STARS_NN_ldmxcsr:             // Load Streaming SIMD Extensions Technology Control/Status Register
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_maxps:               // Packed Single-FP Maximum
		case STARS_NN_maxss:               // Scalar Single-FP Maximum
			return this->BuildBinaryRTL(SMP_MAX_S);
			break;

		case STARS_NN_minps:               // Packed Single-FP Minimum
		case STARS_NN_minss:               // Scalar Single-FP Minimum
			return this->BuildBinaryRTL(SMP_MIN_S);
			break;

		case STARS_NN_movaps:              // Move Aligned Four Packed Single-FP
		case STARS_NN_movhlps:             // Move High to Low Packed Single-FP
		case STARS_NN_movhps:              // Move High Packed Single-FP
		case STARS_NN_movlhps:             // Move Low to High Packed Single-FP
		case STARS_NN_movlps:              // Move Low Packed Single-FP
		case STARS_NN_movmskps:            // Move Mask to Register
		case STARS_NN_movss:               // Move Scalar Single-FP
		case STARS_NN_movups:              // Move Unaligned Four Packed Single-FP
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_mulps:               // Packed Single-FP Multiply
		case STARS_NN_mulss:               // Scalar Single-FP Multiply
			return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY);
			break;

		case STARS_NN_orps:                // Bitwise Logical OR for Single-FP Data
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_rcpps:               // Packed Single-FP Reciprocal
		case STARS_NN_rcpss:               // Scalar Single-FP Reciprocal
		case STARS_NN_rsqrtps:             // Packed Single-FP Square Root Reciprocal
		case STARS_NN_rsqrtss:             // Scalar Single-FP Square Root Reciprocal
			return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_shufps:              // Shuffle Single-FP
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_sqrtps:              // Packed Single-FP Square Root
		case STARS_NN_sqrtss:              // Scalar Single-FP Square Root
			return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_stmxcsr:             // Store Streaming SIMD Extensions Technology Control/Status Register
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_subps:               // Packed Single-FP Subtract
		case STARS_NN_subss:               // Scalar Single-FP Subtract
			return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT);
			break;

		case STARS_NN_ucomiss:             // Scalar Unordered Single-FP Compare and Set EFLAGS
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);
			break;

		case STARS_NN_unpckhps:            // Unpack High Packed Single-FP Data
		case STARS_NN_unpcklps:            // Unpack Low Packed Single-FP Data
			return this->BuildBinaryRTL(SMP_INTERLEAVE);
			break;

		case STARS_NN_xorps:               // Bitwise Logical XOR for Single-FP Data
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_pavgb:               // Packed Average (Byte)
		case STARS_NN_pavgw:               // Packed Average (Word)
			return this->BuildBinaryRTL(SMP_AVERAGE_U);
			break;

		case STARS_NN_pextrw:              // Extract Word
			return this->BuildBinaryPlusImmedRTL(SMP_EXTRACT_ZERO_EXTEND, SMP_CREATE_MASK);
			break;

		case STARS_NN_pinsrw:              // Insert Word
			return this->BuildBinaryPlusImmedRTL(SMP_BITWISE_AND, SMP_CREATE_MASK);
			break;

		case STARS_NN_pmaxsw:              // Packed Signed Integer Word Maximum
			return this->BuildBinaryRTL(SMP_MAX_S);
			break;

		case STARS_NN_pmaxub:              // Packed Unsigned Integer Byte Maximum
			return this->BuildBinaryRTL(SMP_MAX_U);
			break;

		case STARS_NN_pminsw:              // Packed Signed Integer Word Minimum
			return this->BuildBinaryRTL(SMP_MIN_S);
			break;

		case STARS_NN_pminub:              // Packed Unsigned Integer Byte Minimum
			return this->BuildBinaryRTL(SMP_MIN_U);
			break;

		case STARS_NN_pmovmskb:            // Move Byte Mask to Integer
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_pmulhuw:             // Packed Multiply High Unsigned
			return this->BuildBinaryRTL(SMP_U_MULTIPLY);
			break;

		case STARS_NN_psadbw:              // Packed Sum of Absolute Differences
			return this->BuildBinaryRTL(SMP_SUM_OF_DIFFS);
			break;

		case STARS_NN_pshufw:              // Packed Shuffle Word
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_maskmovq:            // Byte Mask write
			return false;
			break;

		case STARS_NN_movntps:             // Move Aligned Four Packed Single-FP Non Temporal
		case STARS_NN_movntq:              // Move 64 Bits Non Temporal
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_prefetcht0:          // Prefetch to all cache levels
		case STARS_NN_prefetcht1:          // Prefetch to all cache levels
		case STARS_NN_prefetcht2:          // Prefetch to L2 cache
		case STARS_NN_prefetchnta:         // Prefetch to L1 cache
		case STARS_NN_sfence:              // Store Fence
			// Cache prefetch and store fence opcodes are no-ops to us.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		// Pentium III Pseudo instructions

		case STARS_NN_cmpeqps:             // Packed Single-FP Compare EQ
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_cmpltps:             // Packed Single-FP Compare LT
			return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_cmpleps:             // Packed Single-FP Compare LE
			return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_cmpunordps:          // Packed Single-FP Compare UNORD
			return this->BuildBinaryRTL(SMP_GENERAL_COMPARE);
			break;

		case STARS_NN_cmpneqps:            // Packed Single-FP Compare NOT EQ
			return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_cmpnltps:            // Packed Single-FP Compare NOT LT
			return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_cmpnleps:            // Packed Single-FP Compare NOT LE
			return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_cmpordps:            // Packed Single-FP Compare ORDERED
			return this->BuildBinaryRTL(SMP_GENERAL_COMPARE);
			break;

		case STARS_NN_cmpeqss:             // Scalar Single-FP Compare EQ
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_cmpltss:             // Scalar Single-FP Compare LT
			return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_cmpless:             // Scalar Single-FP Compare LE
			return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_cmpunordss:          // Scalar Single-FP Compare UNORD
			return this->BuildBinaryRTL(SMP_GENERAL_COMPARE);
			break;

		case STARS_NN_cmpneqss:            // Scalar Single-FP Compare NOT EQ
			return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_cmpnltss:            // Scalar Single-FP Compare NOT LT
			return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_cmpnless:            // Scalar Single-FP Compare NOT LE
			return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_cmpordss:            // Scalar Single-FP Compare ORDERED
			return this->BuildBinaryRTL(SMP_GENERAL_COMPARE);
			break;

		// AMD K7 instructions

		case STARS_NN_pf2iw:               // Packed Floating-Point to Integer with Sign Extend
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_pfnacc:              // Packed Floating-Point Negative Accumulate
		case STARS_NN_pfpnacc:             // Packed Floating-Point Mixed Positive-Negative Accumulate
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_pi2fw:               // Packed 16-bit Integer to Floating-Point
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_pswapd:              // Packed Swap Double Word
			return this->BuildExchangeRTL();
			break;

		// Undocumented FP instructions (thanks to norbert.juffa@adm.com)

		case STARS_NN_fstp1:               // Alias of Store Real and Pop
		case STARS_NN_fcom2:               // Alias of Compare Real
		case STARS_NN_fcomp3:              // Alias of Compare Real and Pop
		case STARS_NN_fxch4:               // Alias of Exchange Registers
		case STARS_NN_fcomp5:              // Alias of Compare Real and Pop
			return false;
			break;

		case STARS_NN_ffreep:              // Free Register and Pop; used in mplayer binary
			// Floating point stack and control word and flags operations
			//  with no memory operands are no-ops to us.
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;


		case STARS_NN_fxch7:               // Alias of Exchange Registers
		case STARS_NN_fstp8:               // Alias of Store Real and Pop
		case STARS_NN_fstp9:               // Alias of Store Real and Pop
			return false;
			break;

		// Pentium 4 instructions

		case STARS_NN_addpd:               // Add Packed Double-Precision Floating-Point Values
		case STARS_NN_addsd:               // Add Scalar Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_FLOATING_ADD);
			break;

		case STARS_NN_andnpd:              // Bitwise Logical AND NOT of Packed Double-Precision Floating-Point Values
		case STARS_NN_andpd:               // Bitwise Logical AND of Packed Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_clflush:             // Flush Cache Line
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;
			break;

		case STARS_NN_cmppd:               // Compare Packed Double-Precision Floating-Point Values
		case STARS_NN_cmpsd:               // Compare Scalar Double-Precision Floating-Point Values
			return this->BuildBinary3OpndRTL(SMP_GENERAL_COMPARE);
			break;

		case STARS_NN_comisd:              // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);
			break;

		case STARS_NN_cvtdq2pd:            // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values
		case STARS_NN_cvtdq2ps:            // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_cvtpd2dq:            // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_cvtpd2pi:            // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_cvtpd2ps:            // Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;


		case STARS_NN_cvtpi2pd:            // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_cvtps2dq:            // Convert Packed Single-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_cvtps2pd:            // Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values
		case STARS_NN_cvtsd2si:            // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer
		case STARS_NN_cvtsd2ss:            // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_cvtsi2sd:            // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_cvtss2sd:            // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value
		case STARS_NN_cvttpd2dq:           // Convert With Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_cvttpd2pi:           // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_cvttps2dq:           // Convert With Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_cvttsd2si:           // Convert with Truncation Scalar Double-Precision Floating-Point Value to Doubleword Integer
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_divpd:               // Divide Packed Double-Precision Floating-Point Values
		case STARS_NN_divsd:               // Divide Scalar Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_FLOATING_DIVIDE);
			break;

		case STARS_NN_lfence:              // Load Fence
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_maskmovdqu:          // Store Selected Bytes of Double Quadword
			return false;
			break;

		case STARS_NN_maxpd:               // Return Maximum Packed Double-Precision Floating-Point Values
		case STARS_NN_maxsd:               // Return Maximum Scalar Double-Precision Floating-Point Value
			return this->BuildBinaryRTL(SMP_MAX_S);
			break;

		case STARS_NN_mfence:              // Memory Fence
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_minpd:               // Return Minimum Packed Double-Precision Floating-Point Values
		case STARS_NN_minsd:               // Return Minimum Scalar Double-Precision Floating-Point Value
			return this->BuildBinaryRTL(SMP_MIN_S);
			break;

		case STARS_NN_movapd:              // Move Aligned Packed Double-Precision Floating-Point Values
		case STARS_NN_movdq2q:             // Move Quadword from XMM to MMX Register
		case STARS_NN_movdqa:              // Move Aligned Double Quadword
		case STARS_NN_movdqu:              // Move Unaligned Double Quadword
		case STARS_NN_movhpd:              // Move High Packed Double-Precision Floating-Point Values
		case STARS_NN_movlpd:              // Move Low Packed Double-Precision Floating-Point Values
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_movmskpd:            // Extract Packed Double-Precision Floating-Point Sign Mask
			return false;
			break;

		case STARS_NN_movntdq:             // Store Double Quadword Using Non-Temporal Hint
		case STARS_NN_movnti:              // Store Doubleword Using Non-Temporal Hint
		case STARS_NN_movntpd:             // Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint
		case STARS_NN_movq2dq:             // Move Quadword from MMX to XMM Register
		case STARS_NN_movsd:               // Move Scalar Double-Precision Floating-Point Values
		case STARS_NN_movupd:              // Move Unaligned Packed Double-Precision Floating-Point Values
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_mulpd:               // Multiply Packed Double-Precision Floating-Point Values
		case STARS_NN_mulsd:               // Multiply Scalar Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY);
			break;

		case STARS_NN_orpd:                // Bitwise Logical OR of Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_paddq:               // Add Packed Quadword Integers
			return this->BuildBinaryRTL(SMP_ADD);
			break;

		case STARS_NN_pause:               // Spin Loop Hint
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		case STARS_NN_pmuludq:             // Multiply Packed Unsigned Doubleword Integers
			return this->BuildBinaryRTL(SMP_U_MULTIPLY);
			break;

		case STARS_NN_pshufd:              // Shuffle Packed Doublewords
		case STARS_NN_pshufhw:             // Shuffle Packed High Words
		case STARS_NN_pshuflw:             // Shuffle Packed Low Words
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_pslldq:              // Shift Double Quadword Left Logical
			return this->BuildBinaryRTL(SMP_U_LEFT_SHIFT);
			break;

		case STARS_NN_psrldq:              // Shift Double Quadword Right Logical
			return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT);
			break;

		case STARS_NN_psubq:               // Subtract Packed Quadword Integers
			return this->BuildBinaryRTL(SMP_SUBTRACT);
			break;

		case STARS_NN_punpckhqdq:          // Unpack High Data
		case STARS_NN_punpcklqdq:          // Unpack Low Data
			return this->BuildBinaryRTL(SMP_INTERLEAVE);
			break;

		case STARS_NN_shufpd:              // Shuffle Packed Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_sqrtpd:              // Compute Square Roots of Packed Double-Precision Floating-Point Values
		case STARS_NN_sqrtsd:              // Compute Square Rootof Scalar Double-Precision Floating-Point Value
			return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_subpd:               // Subtract Packed Double-Precision Floating-Point Values
		case STARS_NN_subsd:               // Subtract Scalar Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT);
			break;

		case STARS_NN_ucomisd:             // Unordered Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);
			break;

		case STARS_NN_unpckhpd:            // Unpack and Interleave High Packed Double-Precision Floating-Point Values
		case STARS_NN_unpcklpd:            // Unpack and Interleave Low Packed Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_INTERLEAVE);
			break;

		case STARS_NN_xorpd:               // Bitwise Logical OR of Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		// AMD syscall/sysret instructions

		case STARS_NN_syscall:             // Low latency system call
			return this->BuildCallRTL();

		case STARS_NN_sysret:              // Return from system call

		// AMD64 instructions

		case STARS_NN_swapgs:              // Exchange GS base with KernelGSBase MSR
			return false;
			break;

		// New Pentium instructions (SSE3)

		case STARS_NN_movddup:             // Move One Double-FP and Duplicate
		case STARS_NN_movshdup:            // Move Packed Single-FP High and Duplicate
		case STARS_NN_movsldup:            // Move Packed Single-FP Low and Duplicate
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		// Missing AMD64 instructions : NOTE: Also found in Intel manual -- clc

		case STARS_NN_movsxd:              // Move with Sign-Extend Doubleword
			return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND);

		case STARS_NN_cmpxchg16b:          // Compare and Exchange 16 Bytes
			return false;
			break;

		// SSE3 instructions

		case STARS_NN_addsubpd:            // Add /Sub packed DP FP numbers
		case STARS_NN_addsubps:            // Add /Sub packed SP FP numbers
		case STARS_NN_haddpd:              // Add horizontally packed DP FP numbers
		case STARS_NN_haddps:              // Add horizontally packed SP FP numbers
		case STARS_NN_hsubpd:              // Sub horizontally packed DP FP numbers
		case STARS_NN_hsubps:              // Sub horizontally packed SP FP numbers
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_monitor:             // Set up a linear address range to be monitored by hardware
		case STARS_NN_mwait:               // Wait until write-back store performed within the range specified by the MONITOR instruction
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;
			break;

		case STARS_NN_fisttp:              // Store ST in intXX (chop) and pop
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_lddqu:               // Load unaligned integer 128-bit
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		// SSSE3 instructions

		case STARS_NN_psignb:              // Packed SIGN Byte
		case STARS_NN_psignw:              // Packed SIGN Word
		case STARS_NN_psignd:              // Packed SIGN Doubleword
		case STARS_NN_pshufb:              // Packed Shuffle Bytes
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_pmulhrsw:            // Packed Multiply High with Round and Scale
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_pmaddubsw:           // Multiply and Add Packed Signed and Unsigned Bytes
			return this->BuildBinaryRTL(SMP_MULTIPLY_AND_ADD);
			break;

		case STARS_NN_phsubsw:             // Packed Horizontal Subtract and Saturate
			return this->BuildBinaryRTL(SMP_SUBTRACT);
			break;

		case STARS_NN_phaddsw:             // Packed Horizontal Add and Saturate
			return this->BuildBinaryRTL(SMP_ADD);
			break;

		case STARS_NN_phaddw:              // Packed Horizontal Add Word
		case STARS_NN_phaddd:              // Packed Horizontal Add Doubleword
			return this->BuildBinaryRTL(SMP_ADD);
			break;

		case STARS_NN_phsubw:              // Packed Horizontal Subtract Word
		case STARS_NN_phsubd:              // Packed Horizontal Subtract Doubleword
			return this->BuildBinaryRTL(SMP_SUBTRACT);
			break;

		case STARS_NN_palignr:             // Packed Align Right
			return this->BuildPackShiftRTL(SMP_CONCATENATE, SMP_REVERSE_SHIFT_U);
			break;

		case STARS_NN_pabsb:               // Packed Absolute Value Byte
		case STARS_NN_pabsw:               // Packed Absolute Value Word
		case STARS_NN_pabsd:               // Packed Absolute Value Doubleword
			return this->BuildUnary2OpndRTL(SMP_ABSOLUTE_VALUE);
			break;

		// VMX instructions

		case STARS_NN_vmcall:              // Call to VM Monitor
		case STARS_NN_vmclear:             // Clear Virtual Machine Control Structure
		case STARS_NN_vmlaunch:            // Launch Virtual Machine
		case STARS_NN_vmresume:            // Resume Virtual Machine
		case STARS_NN_vmptrld:             // Load Pointer to Virtual Machine Control Structure
		case STARS_NN_vmptrst:             // Store Pointer to Virtual Machine Control Structure
		case STARS_NN_vmread:              // Read Field from Virtual Machine Control Structure
		case STARS_NN_vmwrite:             // Write Field from Virtual Machine Control Structure
		case STARS_NN_vmxoff:              // Leave VMX Operation
		case STARS_NN_vmxon:               // Enter VMX Operation
			return false;
			break;



		case STARS_NN_ud2:                 // Undefined Instruction
			// Should be unreachable, so make it a nop so the whole func can be analyzed
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

		// Added with x86-64

		case STARS_NN_rdtscp:             // Read Time-Stamp Counter and Processor ID
			return false;
			break;

		// Geode LX 3DNow! extensions

		case STARS_NN_pfrcpv:              // Reciprocal Approximation for a Pair of 32-bit Floats
		case STARS_NN_pfrsqrtv:            // Reciprocal Square Root Approximation for a Pair of 32-bit Floats
			return this->BuildUnaryRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		// SSE2 pseudoinstructions

		case STARS_NN_cmpeqpd:             // Packed Double-FP Compare EQ
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_cmpltpd:             // Packed Double-FP Compare LT
			return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_cmplepd:             // Packed Double-FP Compare LE
			return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_cmpunordpd:          // Packed Double-FP Compare UNORD
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_cmpneqpd:            // Packed Double-FP Compare NOT EQ
			return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_cmpnltpd:            // Packed Double-FP Compare NOT LT
			return this->BuildBinaryRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_cmpnlepd:            // Packed Double-FP Compare NOT LE
			return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_cmpordpd:            // Packed Double-FP Compare ORDERED
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_cmpeqsd:             // Scalar Double-FP Compare EQ
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_cmpltsd:             // Scalar Double-FP Compare LT
			return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_cmplesd:             // Scalar Double-FP Compare LE
			return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_cmpunordsd:          // Scalar Double-FP Compare UNORD
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_cmpneqsd:            // Scalar Double-FP Compare NOT EQ
			return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_cmpnltsd:            // Scalar Double-FP Compare NOT LT
			return this->BuildBinaryRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_cmpnlesd:            // Scalar Double-FP Compare NOT LE
			return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_cmpordsd:            // Scalar Double-FP Compare ORDERED
			return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		// SSSE4.1 instructions

		case STARS_NN_blendpd:              // Blend Packed Double Precision Floating-Point Values
		case STARS_NN_blendps:              // Blend Packed Single Precision Floating-Point Values
		case STARS_NN_blendvpd:             // Variable Blend Packed Double Precision Floating-Point Values
		case STARS_NN_blendvps:             // Variable Blend Packed Single Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_dppd:                 // Dot Product of Packed Double Precision Floating-Point Values
		case STARS_NN_dpps:                 // Dot Product of Packed Single Precision Floating-Point Values
			return this->BuildBinaryPlusImmedRTL(SMP_BINARY_FLOATING_ARITHMETIC, SMP_CREATE_MASK);
			break;

		case STARS_NN_extractps:            // Extract Packed Single Precision Floating-Point Value
		case STARS_NN_insertps:             // Insert Packed Single Precision Floating-Point Value
		case STARS_NN_movntdqa:             // Load Double Quadword Non-Temporal Aligned Hint
		case STARS_NN_mpsadbw:              // Compute Multiple Packed Sums of Absolute Difference
			return false;
			break;

		case STARS_NN_packusdw:             // Pack with Unsigned Saturation
			return this->BuildBinaryRTL(SMP_PACK_U);
			break;

		case STARS_NN_pblendvb:             // Variable Blend Packed Bytes
		case STARS_NN_pblendw:              // Blend Packed Words
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_pcmpeqq:              // Compare Packed Qword Data for Equal
			return false;
			break;

		case STARS_NN_pextrb:               // Extract Byte
		case STARS_NN_pextrd:               // Extract Dword
		case STARS_NN_pextrq:               // Extract Qword
			return this->BuildBinaryPlusImmedRTL(SMP_EXTRACT_ZERO_EXTEND, SMP_CREATE_MASK);

		case STARS_NN_phminposuw:           // Packed Horizontal Word Minimum
			return false;
			break;

		case STARS_NN_pinsrb:               // Insert Byte 
		case STARS_NN_pinsrd:               // Insert Dword
		case STARS_NN_pinsrq:               // Insert Qword
			return this->BuildBinaryPlusImmedRTL(SMP_BITWISE_AND, SMP_CREATE_MASK);
			break;

		case STARS_NN_pmaxsb:               // Maximum of Packed Signed Byte Integers
		case STARS_NN_pmaxsd:               // Maximum of Packed Signed Dword Integers
			return this->BuildBinaryRTL(SMP_MAX_S);
			break;

		case STARS_NN_pmaxud:               // Maximum of Packed Unsigned Dword Integers
		case STARS_NN_pmaxuw:               // Maximum of Packed Word Integers
			return this->BuildBinaryRTL(SMP_MAX_U);
			break;

		case STARS_NN_pminsb:               // Minimum of Packed Signed Byte Integers
		case STARS_NN_pminsd:               // Minimum of Packed Signed Dword Integers
			return this->BuildBinaryRTL(SMP_MIN_S);
			break;

		case STARS_NN_pminud:               // Minimum of Packed Unsigned Dword Integers
		case STARS_NN_pminuw:               // Minimum of Packed Word Integers
			return this->BuildBinaryRTL(SMP_MIN_U);
			break;

		case STARS_NN_pmovsxbw:             // Packed Move with Sign Extend
		case STARS_NN_pmovsxbd:             // Packed Move with Sign Extend
		case STARS_NN_pmovsxbq:             // Packed Move with Sign Extend
		case STARS_NN_pmovsxwd:             // Packed Move with Sign Extend
		case STARS_NN_pmovsxwq:             // Packed Move with Sign Extend
		case STARS_NN_pmovsxdq:             // Packed Move with Sign Extend
			return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND);
			break;

		case STARS_NN_pmovzxbw:             // Packed Move with Zero Extend
		case STARS_NN_pmovzxbd:             // Packed Move with Zero Extend
		case STARS_NN_pmovzxbq:             // Packed Move with Zero Extend
		case STARS_NN_pmovzxwd:             // Packed Move with Zero Extend
		case STARS_NN_pmovzxwq:             // Packed Move with Zero Extend
		case STARS_NN_pmovzxdq:             // Packed Move with Zero Extend
			return this->BuildUnary2OpndRTL(SMP_ZERO_EXTEND);
			break;

		case STARS_NN_pmuldq:               // Multiply Packed Signed Dword Integers
		case STARS_NN_pmulld:               // Multiply Packed Signed Dword Integers and Store Low Result
			return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY);
			break;

		case STARS_NN_ptest:                // Logical Compare
			return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE);

		case STARS_NN_roundpd:              // Round Packed Double Precision Floating-Point Values
		case STARS_NN_roundps:              // Round Packed Single Precision Floating-Point Values
		case STARS_NN_roundsd:              // Round Scalar Double Precision Floating-Point Values
		case STARS_NN_roundss:              // Round Scalar Single Precision Floating-Point Values
			return this->BuildBinaryPlusImmedRTL(SMP_UNARY_FLOATING_ARITHMETIC, SMP_CREATE_MASK);
			break;

		// SSSE4.2 instructions
		case STARS_NN_crc32:                // Accumulate CRC32 Value
			return false;
			break;

		case STARS_NN_pcmpestri:            // Packed Compare Explicit Length Strings, Return Index
		case STARS_NN_pcmpestrm:            // Packed Compare Explicit Length Strings, Return Mask
		case STARS_NN_pcmpistri:            // Packed Compare Implicit Length Strings, Return Index
		case STARS_NN_pcmpistrm:            // Packed Compare Implicit Length Strings, Return Mask
			return BuildBinaryIgnoreImmedRTL(SMP_GENERAL_COMPARE);
			break;

		case STARS_NN_pcmpgtq:              // Compare Packed Data for Greater Than
			return false;
			break;

		case STARS_NN_popcnt:               // Return the Count of Number of Bits Set to 1
			return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION);

		// AMD SSE4a instructions

		case STARS_NN_extrq:                // Extract Field From Register
		case STARS_NN_insertq:              // Insert Field
		case STARS_NN_movntsd:              // Move Non-Temporal Scalar Double-Precision Floating-Point
		case STARS_NN_movntss:              // Move Non-Temporal Scalar Single-Precision Floating-Point
		case STARS_NN_lzcnt:                // Leading Zero Count
			return false;
			break;

		// xsave/xrstor instructions

		case STARS_NN_xgetbv:               // Get Value of Extended Control Register
			return this->BuildOptType8RTL();

		case STARS_NN_xrstor:               // Restore Processor Extended States
		case STARS_NN_xsave:                // Save Processor Extended States
		case STARS_NN_xsetbv:               // Set Value of Extended Control Register
			return false;
			break;

		// Intel Safer Mode Extensions (SMX)

		case STARS_NN_getsec:               // Safer Mode Extensions (SMX) Instruction
			return false;
			break;

		// AMD-V Virtualization ISA Extension

		case STARS_NN_clgi:                 // Clear Global Interrupt Flag
		case STARS_NN_invlpga:              // Invalidate TLB Entry in a Specified ASID
		case STARS_NN_skinit:               // Secure Init and Jump with Attestation
		case STARS_NN_stgi:                 // Set Global Interrupt Flag
		case STARS_NN_vmexit:               // Stop Executing Guest, Begin Executing Host
		case STARS_NN_vmload:               // Load State from VMCB
		case STARS_NN_vmmcall:              // Call VMM
		case STARS_NN_vmrun:                // Run Virtual Machine
		case STARS_NN_vmsave:               // Save State to VMCB
			return false;
			break;

		// VMX+ instructions

		case STARS_NN_invept:               // Invalidate Translations Derived from EPT
		case STARS_NN_invvpid:              // Invalidate Translations Based on VPID
			return false;
			break;

		// Intel Atom instructions

		case STARS_NN_movbe:                // Move Data After Swapping Bytes
			return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION);

		// Intel AES instructions

		case STARS_NN_aesenc:                // Perform One Round of an AES Encryption Flow
		case STARS_NN_aesenclast:            // Perform the Last Round of an AES Encryption Flow
		case STARS_NN_aesdec:                // Perform One Round of an AES Decryption Flow
		case STARS_NN_aesdeclast:            // Perform the Last Round of an AES Decryption Flow
		case STARS_NN_aesimc:                // Perform the AES InvMixColumn Transformation
		case STARS_NN_aeskeygenassist:       // AES Round Key Generation Assist
			return this->BuildBinaryRTL(SMP_ENCRYPTION_OPERATION);
			break;

		// Carryless multiplication

		case STARS_NN_pclmulqdq:            // Carry-Less Multiplication Quadword
			return BuildBinaryIgnoreImmedRTL(SMP_U_MULTIPLY);
			break;

// Returns modified by operand size prefixes

		case STARS_NN_retnw:               // Return Near from Procedure (use16)
		case STARS_NN_retnd:               // Return Near from Procedure (use32)
		case STARS_NN_retnq:               // Return Near from Procedure (use64)
		case STARS_NN_retfw:               // Return Far from Procedure (use16)
		case STARS_NN_retfd:               // Return Far from Procedure (use32)
		case STARS_NN_retfq:               // Return Far from Procedure (use64)
			return this->BuildReturnRTL();

// RDRAND support

		case STARS_NN_rdrand:              // Read Random Number
			return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION);

// new GPR instructions

		case STARS_NN_adcx:                 // Unsigned Integer Addition of Two Operands with Carry Flag
		case STARS_NN_adox:                 // Unsigned Integer Addition of Two Operands with Overflow Flag
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
			return this->BuildBinaryPlusFlagsRTL(SMP_ADD_CARRY);
#else
			return this->BuildBinaryRTL(SMP_ADD_CARRY);
#endif
		case STARS_NN_andn:                 // Logical AND NOT
		case STARS_NN_bextr:                // Bit Field Extract
		case STARS_NN_blsi:                 // Extract Lowest Set Isolated Bit
		case STARS_NN_blsmsk:               // Get Mask Up to Lowest Set Bit
		case STARS_NN_blsr:                 // Reset Lowest Set Bit
		case STARS_NN_bzhi:                 // Zero High Bits Starting with Specified Bit Position
			return this->BuildBinaryPlusFlagsRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_clac:                 // Clear AC Flag in EFLAGS Register
			return false;

		case STARS_NN_mulx:                 // Unsigned Multiply Without Affecting Flags
			return this->BuildBinaryRTL(SMP_U_MULTIPLY);

		case STARS_NN_pdep:                 // Parallel Bits Deposit
		case STARS_NN_pext:                 // Parallel Bits Extract
			return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_rorx:                 // Rotate Right Logical Without Affecting Flags
			return this->BuildBinaryRTL(SMP_ROTATE_RIGHT);

		case STARS_NN_sarx:                 // Shift Arithmetically Right Without Affecting Flags
			return this->BuildBinaryRTL(SMP_S_RIGHT_SHIFT);

		case STARS_NN_shlx:                 // Shift Logically Left Without Affecting Flags

		case STARS_NN_shrx:                 // Shift Logically Right Without Affecting Flags
			return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT);

		case STARS_NN_stac:                 // Set AC Flag in EFLAGS Register
			return false;

		case STARS_NN_tzcnt:                // Count the Number of Trailing Zero Bits
			return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_xsaveopt:             // Save Processor Extended States Optimized
		case STARS_NN_invpcid:              // Invalidate Processor Context ID
			return false;

		case STARS_NN_rdseed:               // Read Random Seed
			return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION);

		case STARS_NN_rdfsbase:             // Read FS Segment Base
		case STARS_NN_rdgsbase:             // Read GS Segment Base
		case STARS_NN_wrfsbase:             // Write FS Segment Base
		case STARS_NN_wrgsbase:             // Write GS Segment Base
			return false;

// new AVX instructions

		case STARS_NN_vaddpd:               // Add Packed Double-Precision Floating-Point Values
		case STARS_NN_vaddps:               // Packed Single-FP Add
		case STARS_NN_vaddsd:               // Add Scalar Double-Precision Floating-Point Values
		case STARS_NN_vaddss:               // Scalar Single-FP Add
			return this->BuildBinary3OpndRTL(SMP_FLOATING_ADD);
			break;

		case STARS_NN_vaddsubpd:            // Add /Sub packed DP FP numbers
		case STARS_NN_vaddsubps:            // Add /Sub packed SP FP numbers
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vaesdec:              // Perform One Round of an AES Decryption Flow
		case STARS_NN_vaesdeclast:          // Perform the Last Round of an AES Decryption Flow
		case STARS_NN_vaesenc:              // Perform One Round of an AES Encryption Flow
		case STARS_NN_vaesenclast:          // Perform the Last Round of an AES Encryption Flow
		case STARS_NN_vaesimc:              // Perform the AES InvMixColumn Transformation
		case STARS_NN_vaeskeygenassist:     // AES Round Key Generation Assist
			return this->BuildBinaryRTL(SMP_ENCRYPTION_OPERATION);
			break;

		case STARS_NN_vandnpd:              // Bitwise Logical AND NOT of Packed Double-Precision Floating-Point Values
		case STARS_NN_vandnps:              // Bitwise Logical And Not for Single-FP
		case STARS_NN_vandpd:               // Bitwise Logical AND of Packed Double-Precision Floating-Point Values
		case STARS_NN_vandps:               // Bitwise Logical And for Single-FP
			return this->BuildBinary3OpndRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vblendpd:             // Blend Packed Double Precision Floating-Point Values
		case STARS_NN_vblendps:             // Blend Packed Single Precision Floating-Point Values
		case STARS_NN_vblendvpd:            // Variable Blend Packed Double Precision Floating-Point Values
		case STARS_NN_vblendvps:            // Variable Blend Packed Single Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_vbroadcastf128:       // Broadcast 128 Bits of Floating-Point Data
		case STARS_NN_vbroadcasti128:       // Broadcast 128 Bits of Integer Data
		case STARS_NN_vbroadcastsd:         // Broadcast Double-Precision Floating-Point Element
		case STARS_NN_vbroadcastss:         // Broadcast Single-Precision Floating-Point Element
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vcmppd:               // Compare Packed Double-Precision Floating-Point Values
		case STARS_NN_vcmpps:               // Packed Single-FP Compare
		case STARS_NN_vcmpsd:               // Compare Scalar Double-Precision Floating-Point Values
		case STARS_NN_vcmpss:               // Scalar Single-FP Compare
			return false;
			break;

		case STARS_NN_vcomisd:              // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
		case STARS_NN_vcomiss:              // Scalar Ordered Single-FP Compare and Set EFLAGS
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);
			break;

		case STARS_NN_vcvtdq2pd:            // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values
		case STARS_NN_vcvtdq2ps:            // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_vcvtpd2dq:            // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_vcvtpd2ps:            // Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values
		case STARS_NN_vcvtph2ps:            // Convert 16-bit FP Values to Single-Precision FP Values
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vcvtps2dq:            // Convert Packed Single-Precision Floating-Point Values to Packed Doubleword Integers
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_vcvtps2pd:            // Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values
		case STARS_NN_vcvtps2ph:            // Convert Single-Precision FP value to 16-bit FP value
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vcvtsd2si:            // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_vcvtsd2ss:            // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vcvtsi2sd:            // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value
		case STARS_NN_vcvtsi2ss:            // Scalar signed INT32 to Single-FP conversion
			return this->BuildBinary3OpndRTL(SMP_CONVERT_INT_TO_FP);
			break;

		case STARS_NN_vcvtss2sd:            // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vcvtss2si:            // Scalar Single-FP to signed INT32 conversion
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_vcvttpd2dq:           // Convert With Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_vcvttps2dq:           // Convert With Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers
		case STARS_NN_vcvttsd2si:           // Convert with Truncation Scalar Double-Precision Floating-Point Value to Doubleword Integer
		case STARS_NN_vcvttss2si:           // Scalar Single-FP to signed INT32 conversion (truncate)
			return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT);
			break;


		case STARS_NN_vdivpd:               // Divide Packed Double-Precision Floating-Point Values
		case STARS_NN_vdivps:               // Packed Single-FP Divide
		case STARS_NN_vdivsd:               // Divide Scalar Double-Precision Floating-Point Values
		case STARS_NN_vdivss:               // Scalar Single-FP Divide
			return this->BuildBinary3OpndRTL(SMP_FLOATING_DIVIDE);
			break;

		case STARS_NN_vdppd:                // Dot Product of Packed Double Precision Floating-Point Values
		case STARS_NN_vdpps:                // Dot Product of Packed Single Precision Floating-Point Values
			return false;
			break;

		case STARS_NN_vextractf128:         // Extract Packed Floating-Point Values
		case STARS_NN_vextracti128:         // Extract Packed Integer Values
		case STARS_NN_vextractps:           // Extract Packed Floating-Point Values
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vfmadd132pd:          // Fused Multiply-Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmadd132ps:          // Fused Multiply-Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmadd132sd:          // Fused Multiply-Add of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfmadd132ss:          // Fused Multiply-Add of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfmadd213pd:          // Fused Multiply-Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmadd213ps:          // Fused Multiply-Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmadd213sd:          // Fused Multiply-Add of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfmadd213ss:          // Fused Multiply-Add of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfmadd231pd:          // Fused Multiply-Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmadd231ps:          // Fused Multiply-Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmadd231sd:          // Fused Multiply-Add of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfmadd231ss:          // Fused Multiply-Add of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfmaddsub132pd:       // Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmaddsub132ps:       // Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmaddsub213pd:       // Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmaddsub213ps:       // Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmaddsub231pd:       // Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmaddsub231ps:       // Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmsub132pd:          // Fused Multiply-Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmsub132ps:          // Fused Multiply-Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmsub132sd:          // Fused Multiply-Subtract of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfmsub132ss:          // Fused Multiply-Subtract of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfmsub213pd:          // Fused Multiply-Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmsub213ps:          // Fused Multiply-Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmsub213sd:          // Fused Multiply-Subtract of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfmsub213ss:          // Fused Multiply-Subtract of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfmsub231pd:          // Fused Multiply-Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmsub231ps:          // Fused Multiply-Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmsub231sd:          // Fused Multiply-Subtract of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfmsub231ss:          // Fused Multiply-Subtract of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfmsubadd132pd:       // Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmsubadd132ps:       // Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmsubadd213pd:       // Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmsubadd213ps:       // Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfmsubadd231pd:       // Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfmsubadd231ps:       // Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfnmadd132pd:         // Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfnmadd132ps:         // Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfnmadd132sd:         // Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfnmadd132ss:         // Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfnmadd213pd:         // Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfnmadd213ps:         // Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfnmadd213sd:         // Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfnmadd213ss:         // Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfnmadd231pd:         // Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfnmadd231ps:         // Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfnmadd231sd:         // Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfnmadd231ss:         // Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfnmsub132pd:         // Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfnmsub132ps:         // Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfnmsub132sd:         // Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfnmsub132ss:         // Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfnmsub213pd:         // Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfnmsub213ps:         // Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfnmsub213sd:         // Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfnmsub213ss:         // Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values
		case STARS_NN_vfnmsub231pd:         // Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values
		case STARS_NN_vfnmsub231ps:         // Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values
		case STARS_NN_vfnmsub231sd:         // Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values
		case STARS_NN_vfnmsub231ss:         // Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vgatherdps:           // Gather Packed SP FP Values Using Signed Dword Indices
		case STARS_NN_vgatherdpd:           // Gather Packed DP FP Values Using Signed Dword Indices
		case STARS_NN_vgatherqps:           // Gather Packed SP FP Values Using Signed Qword Indices
		case STARS_NN_vgatherqpd:           // Gather Packed DP FP Values Using Signed Qword Indices
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vhaddpd:              // Add horizontally packed DP FP numbers
		case STARS_NN_vhaddps:              // Add horizontally packed SP FP numbers
			return this->BuildBinaryRTL(SMP_FLOATING_ADD);
			break;

		case STARS_NN_vhsubpd:              // Sub horizontally packed DP FP numbers
		case STARS_NN_vhsubps:              // Sub horizontally packed SP FP numbers
			return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT);
			break;

		case STARS_NN_vinsertf128:          // Insert Packed Floating-Point Values
		case STARS_NN_vinserti128:          // Insert Packed Integer Values
		case STARS_NN_vinsertps:            // Insert Packed Single Precision Floating-Point Value
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vlddqu:               // Load Unaligned Packed Integer Values
			return false;
			break;

		case STARS_NN_vldmxcsr:             // Load Streaming SIMD Extensions Technology Control/Status Register
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vmaskmovdqu:          // Store Selected Bytes of Double Quadword with NT Hint
		case STARS_NN_vmaskmovpd:           // Conditionally Load Packed Double-Precision Floating-Point Values
		case STARS_NN_vmaskmovps:           // Conditionally Load Packed Single-Precision Floating-Point Values
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vmaxpd:               // Return Maximum Packed Double-Precision Floating-Point Values
		case STARS_NN_vmaxps:               // Packed Single-FP Maximum
		case STARS_NN_vmaxsd:               // Return Maximum Scalar Double-Precision Floating-Point Value
		case STARS_NN_vmaxss:               // Scalar Single-FP Maximum
		case STARS_NN_vminpd:               // Return Minimum Packed Double-Precision Floating-Point Values
		case STARS_NN_vminps:               // Packed Single-FP Minimum
		case STARS_NN_vminsd:               // Return Minimum Scalar Double-Precision Floating-Point Value
		case STARS_NN_vminss:               // Scalar Single-FP Minimum
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vmovapd:              // Move Aligned Packed Double-Precision Floating-Point Values
		case STARS_NN_vmovaps:              // Move Aligned Four Packed Single-FP
		case STARS_NN_vmovd:                // Move 32 bits
		case STARS_NN_vmovddup:             // Move One Double-FP and Duplicate
		case STARS_NN_vmovdqa:              // Move Aligned Double Quadword
		case STARS_NN_vmovdqu:              // Move Unaligned Double Quadword
		case STARS_NN_vmovhlps:             // Move High to Low Packed Single-FP
		case STARS_NN_vmovhpd:              // Move High Packed Double-Precision Floating-Point Values
		case STARS_NN_vmovhps:              // Move High Packed Single-FP
		case STARS_NN_vmovlhps:             // Move Low to High Packed Single-FP
		case STARS_NN_vmovlpd:              // Move Low Packed Double-Precision Floating-Point Values
		case STARS_NN_vmovlps:              // Move Low Packed Single-FP
		case STARS_NN_vmovmskpd:            // Extract Packed Double-Precision Floating-Point Sign Mask
		case STARS_NN_vmovmskps:            // Move Mask to Register
		case STARS_NN_vmovntdq:             // Store Double Quadword Using Non-Temporal Hint
		case STARS_NN_vmovntdqa:            // Load Double Quadword Non-Temporal Aligned Hint
		case STARS_NN_vmovntpd:             // Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint
		case STARS_NN_vmovntps:             // Move Aligned Four Packed Single-FP Non Temporal
#if (IDA_SDK_VERSION < 700)      // Incredibly, these opcodes were removed in IDA Pro 7.0
		case STARS_NN_vmovntsd:             // Move Non-Temporal Scalar Double-Precision Floating-Point
		case STARS_NN_vmovntss:             // Move Non-Temporal Scalar Single-Precision Floating-Point
#endif
		case STARS_NN_vmovq:                // Move 64 bits
		case STARS_NN_vmovsd:               // Move Scalar Double-Precision Floating-Point Values
		case STARS_NN_vmovshdup:            // Move Packed Single-FP High and Duplicate
		case STARS_NN_vmovsldup:            // Move Packed Single-FP Low and Duplicate
		case STARS_NN_vmovss:               // Move Scalar Single-FP
		case STARS_NN_vmovupd:              // Move Unaligned Packed Double-Precision Floating-Point Values
		case STARS_NN_vmovups:              // Move Unaligned Four Packed Single-FP
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vmpsadbw:             // Compute Multiple Packed Sums of Absolute Difference
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vmulpd:               // Multiply Packed Double-Precision Floating-Point Values
		case STARS_NN_vmulps:               // Packed Single-FP Multiply
		case STARS_NN_vmulsd:               // Multiply Scalar Double-Precision Floating-Point Values
		case STARS_NN_vmulss:               // Scalar Single-FP Multiply
			return this->BuildBinary3OpndRTL(SMP_FLOATING_MULTIPLY);
			break;

		case STARS_NN_vorpd:                // Bitwise Logical OR of Double-Precision Floating-Point Values
		case STARS_NN_vorps:                // Bitwise Logical OR for Single-FP Data
		case STARS_NN_vpabsb:               // Packed Absolute Value Byte
		case STARS_NN_vpabsd:               // Packed Absolute Value Doubleword
		case STARS_NN_vpabsw:               // Packed Absolute Value Word
		case STARS_NN_vpackssdw:            // Pack with Signed Saturation (Dword->Word)
		case STARS_NN_vpacksswb:            // Pack with Signed Saturation (Word->Byte)
		case STARS_NN_vpackusdw:            // Pack with Unsigned Saturation
		case STARS_NN_vpackuswb:            // Pack with Unsigned Saturation (Word->Byte)
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vpaddb:               // Packed Add Byte
		case STARS_NN_vpaddd:               // Packed Add Dword
		case STARS_NN_vpaddq:               // Add Packed Quadword Integers
		case STARS_NN_vpaddsb:              // Packed Add with Saturation (Byte)
		case STARS_NN_vpaddsw:              // Packed Add with Saturation (Word)
		case STARS_NN_vpaddusb:             // Packed Add Unsigned with Saturation (Byte)
		case STARS_NN_vpaddusw:             // Packed Add Unsigned with Saturation (Word)
		case STARS_NN_vpaddw:               // Packed Add Word
			return this->BuildBinaryRTL(SMP_FLOATING_ADD);
			break;

		case STARS_NN_vpalignr:             // Packed Align Right
		case STARS_NN_vpand:                // Bitwise Logical And
		case STARS_NN_vpandn:               // Bitwise Logical And Not
		case STARS_NN_vpavgb:               // Packed Average (Byte)
		case STARS_NN_vpavgw:               // Packed Average (Word)
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vpblendd:             // Blend Packed Dwords
		case STARS_NN_vpblendvb:            // Variable Blend Packed Bytes
		case STARS_NN_vpblendw:             // Blend Packed Words
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_vpbroadcastb:         // Broadcast a Byte Integer
		case STARS_NN_vpbroadcastd:         // Broadcast a Dword Integer
		case STARS_NN_vpbroadcastq:         // Broadcast a Qword Integer
		case STARS_NN_vpbroadcastw:         // Broadcast a Word Integer
		case STARS_NN_vpclmulqdq:           // Carry-Less Multiplication Quadword
		case STARS_NN_vpcmpeqb:             // Packed Compare for Equal (Byte)
		case STARS_NN_vpcmpeqd:             // Packed Compare for Equal (Dword)
		case STARS_NN_vpcmpeqq:             // Compare Packed Qword Data for Equal
		case STARS_NN_vpcmpeqw:             // Packed Compare for Equal (Word)
		case STARS_NN_vpcmpestri:           // Packed Compare Explicit Length Strings, Return Index
		case STARS_NN_vpcmpestrm:           // Packed Compare Explicit Length Strings, Return Mask
		case STARS_NN_vpcmpgtb:             // Packed Compare for Greater Than (Byte)
		case STARS_NN_vpcmpgtd:             // Packed Compare for Greater Than (Dword)
		case STARS_NN_vpcmpgtq:             // Compare Packed Data for Greater Than
		case STARS_NN_vpcmpgtw:             // Packed Compare for Greater Than (Word)
		case STARS_NN_vpcmpistri:           // Packed Compare Implicit Length Strings, Return Index
		case STARS_NN_vpcmpistrm:           // Packed Compare Implicit Length Strings, Return Mask
		case STARS_NN_vperm2f128:           // Permute Floating-Point Values
		case STARS_NN_vperm2i128:           // Permute Integer Values
		case STARS_NN_vpermd:               // Full Doublewords Element Permutation
		case STARS_NN_vpermilpd:            // Permute Double-Precision Floating-Point Values
		case STARS_NN_vpermilps:            // Permute Single-Precision Floating-Point Values
		case STARS_NN_vpermpd:              // Permute Double-Precision Floating-Point Elements
		case STARS_NN_vpermps:              // Permute Single-Precision Floating-Point Elements
		case STARS_NN_vpermq:               // Qwords Element Permutation
		case STARS_NN_vpextrb:              // Extract Byte
		case STARS_NN_vpextrd:              // Extract Dword
		case STARS_NN_vpextrq:              // Extract Qword
		case STARS_NN_vpextrw:              // Extract Word
		case STARS_NN_vpgatherdd:           // Gather Packed Dword Values Using Signed Dword Indices
		case STARS_NN_vpgatherdq:           // Gather Packed Qword Values Using Signed Dword Indices
		case STARS_NN_vpgatherqd:           // Gather Packed Dword Values Using Signed Qword Indices
		case STARS_NN_vpgatherqq:           // Gather Packed Qword Values Using Signed Qword Indices
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vphaddd:              // Packed Horizontal Add Doubleword
		case STARS_NN_vphaddsw:             // Packed Horizontal Add and Saturate
		case STARS_NN_vphaddw:              // Packed Horizontal Add Word
			return this->BuildBinaryRTL(SMP_FLOATING_ADD);
			break;

		case STARS_NN_vphminposuw:          // Packed Horizontal Word Minimum
			return false;
			break;

		case STARS_NN_vphsubd:              // Packed Horizontal Subtract Doubleword
		case STARS_NN_vphsubsw:             // Packed Horizontal Subtract and Saturate
		case STARS_NN_vphsubw:              // Packed Horizontal Subtract Word
			return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT);
			break;

		case STARS_NN_vpinsrb:              // Insert Byte
		case STARS_NN_vpinsrd:              // Insert Dword
		case STARS_NN_vpinsrq:              // Insert Qword
		case STARS_NN_vpinsrw:              // Insert Word
			return false;
			break;

		case STARS_NN_vpmaddubsw:           // Multiply and Add Packed Signed and Unsigned Bytes
		case STARS_NN_vpmaddwd:             // Packed Multiply and Add
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vpmaskmovd:           // Conditionally Store Dword Values Using Mask
		case STARS_NN_vpmaskmovq:           // Conditionally Store Qword Values Using Mask
			return false;
			break;

		case STARS_NN_vpmaxsb:              // Maximum of Packed Signed Byte Integers
		case STARS_NN_vpmaxsd:              // Maximum of Packed Signed Dword Integers
		case STARS_NN_vpmaxsw:              // Packed Signed Integer Word Maximum
			return this->BuildBinaryRTL(SMP_MAX_S);
			break;

		case STARS_NN_vpmaxub:              // Packed Unsigned Integer Byte Maximum
		case STARS_NN_vpmaxud:              // Maximum of Packed Unsigned Dword Integers
		case STARS_NN_vpmaxuw:              // Maximum of Packed Word Integers
			return this->BuildBinaryRTL(SMP_MAX_U);
			break;

		case STARS_NN_vpminsb:              // Minimum of Packed Signed Byte Integers
		case STARS_NN_vpminsd:              // Minimum of Packed Signed Dword Integers
		case STARS_NN_vpminsw:              // Packed Signed Integer Word Minimum
			return this->BuildBinaryRTL(SMP_MIN_S);
			break;

		case STARS_NN_vpminub:              // Packed Unsigned Integer Byte Minimum
		case STARS_NN_vpminud:              // Minimum of Packed Unsigned Dword Integers
		case STARS_NN_vpminuw:              // Minimum of Packed Word Integers
			return this->BuildBinaryRTL(SMP_MIN_U);
			break;

		case STARS_NN_vpmovmskb:            // Move Byte Mask to Integer
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vpmovsxbd:            // Packed Move with Sign Extend
		case STARS_NN_vpmovsxbq:            // Packed Move with Sign Extend
		case STARS_NN_vpmovsxbw:            // Packed Move with Sign Extend
		case STARS_NN_vpmovsxdq:            // Packed Move with Sign Extend
		case STARS_NN_vpmovsxwd:            // Packed Move with Sign Extend
		case STARS_NN_vpmovsxwq:            // Packed Move with Sign Extend
			return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND);
			break;

		case STARS_NN_vpmovzxbd:            // Packed Move with Zero Extend
		case STARS_NN_vpmovzxbq:            // Packed Move with Zero Extend
		case STARS_NN_vpmovzxbw:            // Packed Move with Zero Extend
		case STARS_NN_vpmovzxdq:            // Packed Move with Zero Extend
		case STARS_NN_vpmovzxwd:            // Packed Move with Zero Extend
		case STARS_NN_vpmovzxwq:            // Packed Move with Zero Extend
			return this->BuildUnary2OpndRTL(SMP_ZERO_EXTEND);
			break;

		case STARS_NN_vpmuldq:              // Multiply Packed Signed Dword Integers
		case STARS_NN_vpmulhrsw:            // Packed Multiply High with Round and Scale
		case STARS_NN_vpmulhuw:             // Packed Multiply High Unsigned
		case STARS_NN_vpmulhw:              // Packed Multiply High
		case STARS_NN_vpmulld:              // Multiply Packed Signed Dword Integers and Store Low Result
		case STARS_NN_vpmullw:              // Packed Multiply Low
		case STARS_NN_vpmuludq:             // Multiply Packed Unsigned Doubleword Integers
		case STARS_NN_vpor:                 // Bitwise Logical Or
		case STARS_NN_vpsadbw:              // Packed Sum of Absolute Differences
			return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY);
			break;

		case STARS_NN_vpshufb:              // Packed Shuffle Bytes
		case STARS_NN_vpshufd:              // Shuffle Packed Doublewords
		case STARS_NN_vpshufhw:             // Shuffle Packed High Words
		case STARS_NN_vpshuflw:             // Shuffle Packed Low Words
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_vpsignb:              // Packed SIGN Byte
		case STARS_NN_vpsignd:              // Packed SIGN Doubleword
		case STARS_NN_vpsignw:              // Packed SIGN Word
			return false;
			break;

		case STARS_NN_vpslld:               // Packed Shift Left Logical (Dword)
		case STARS_NN_vpslldq:              // Shift Double Quadword Left Logical
		case STARS_NN_vpsllq:               // Packed Shift Left Logical (Qword)
		case STARS_NN_vpsllvd:              // Variable Bit Shift Left Logical (Dword)
		case STARS_NN_vpsllvq:              // Variable Bit Shift Left Logical (Qword)
		case STARS_NN_vpsllw:               // Packed Shift Left Logical (Word)
		case STARS_NN_vpsrad:               // Packed Shift Right Arithmetic (Dword)
		case STARS_NN_vpsravd:              // Variable Bit Shift Right Arithmetic
		case STARS_NN_vpsraw:               // Packed Shift Right Arithmetic (Word)
		case STARS_NN_vpsrld:               // Packed Shift Right Logical (Dword)
		case STARS_NN_vpsrldq:              // Shift Double Quadword Right Logical (Qword)
		case STARS_NN_vpsrlq:               // Packed Shift Right Logical (Qword)
		case STARS_NN_vpsrlvd:              // Variable Bit Shift Right Logical (Dword)
		case STARS_NN_vpsrlvq:              // Variable Bit Shift Right Logical (Qword)
		case STARS_NN_vpsrlw:               // Packed Shift Right Logical (Word)
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vpsubb:               // Packed Subtract Byte
		case STARS_NN_vpsubd:               // Packed Subtract Dword
		case STARS_NN_vpsubq:               // Subtract Packed Quadword Integers
		case STARS_NN_vpsubsb:              // Packed Subtract with Saturation (Byte)
		case STARS_NN_vpsubsw:              // Packed Subtract with Saturation (Word)
		case STARS_NN_vpsubusb:             // Packed Subtract Unsigned with Saturation (Byte)
		case STARS_NN_vpsubusw:             // Packed Subtract Unsigned with Saturation (Word)
		case STARS_NN_vpsubw:               // Packed Subtract Word
			return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT);
			break;

		case STARS_NN_vptest:               // Logical Compare
			return false;
			break;

		case STARS_NN_vpunpckhbw:           // Unpack High Packed Data (Byte->Word)
		case STARS_NN_vpunpckhdq:           // Unpack High Packed Data (Dword->Qword)
		case STARS_NN_vpunpckhqdq:          // Unpack High Packed Data (Qword->Xmmword)
		case STARS_NN_vpunpckhwd:           // Unpack High Packed Data (Word->Dword)
		case STARS_NN_vpunpcklbw:           // Unpack Low Packed Data (Byte->Word)
		case STARS_NN_vpunpckldq:           // Unpack Low Packed Data (Dword->Qword)
		case STARS_NN_vpunpcklqdq:          // Unpack Low Packed Data (Qword->Xmmword)
		case STARS_NN_vpunpcklwd:           // Unpack Low Packed Data (Word->Dword)
			return this->BuildBinaryRTL(SMP_INTERLEAVE);
			break;

		case STARS_NN_vpxor:                // Bitwise Logical Exclusive Or
		case STARS_NN_vrcpps:               // Packed Single-FP Reciprocal
		case STARS_NN_vrcpss:               // Scalar Single-FP Reciprocal
			return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vroundpd:             // Round Packed Double Precision Floating-Point Values
		case STARS_NN_vroundps:             // Round Packed Single Precision Floating-Point Values
		case STARS_NN_vroundsd:             // Round Scalar Double Precision Floating-Point Values
		case STARS_NN_vroundss:             // Round Scalar Single Precision Floating-Point Values
			return this->BuildUnary2OpndRTL(SMP_CONVERT_FP_TO_INT);
			break;

		case STARS_NN_vrsqrtps:             // Packed Single-FP Square Root Reciprocal
		case STARS_NN_vrsqrtss:             // Scalar Single-FP Square Root Reciprocal
			return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vshufpd:              // Shuffle Packed Double-Precision Floating-Point Values
		case STARS_NN_vshufps:              // Shuffle Single-FP
			return this->BuildBinaryRTL(SMP_SHUFFLE);
			break;

		case STARS_NN_vsqrtpd:              // Compute Square Roots of Packed Double-Precision Floating-Point Values
		case STARS_NN_vsqrtps:              // Packed Single-FP Square Root
		case STARS_NN_vsqrtsd:              // Compute Square Rootof Scalar Double-Precision Floating-Point Value
		case STARS_NN_vsqrtss:              // Scalar Single-FP Square Root
			return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vstmxcsr:             // Store Streaming SIMD Extensions Technology Control/Status Register
			return this->BuildMoveRTL(SMP_NULL_OPERATOR);
			break;

		case STARS_NN_vsubpd:               // Subtract Packed Double-Precision Floating-Point Values
		case STARS_NN_vsubps:               // Packed Single-FP Subtract
		case STARS_NN_vsubsd:               // Subtract Scalar Double-Precision Floating-Point Values
		case STARS_NN_vsubss:               // Scalar Single-FP Subtract
			return this->BuildBinary3OpndRTL(SMP_FLOATING_SUBTRACT);
			break;

		case STARS_NN_vtestpd:              // Packed Double-Precision Floating-Point Bit Test
		case STARS_NN_vtestps:              // Packed Single-Precision Floating-Point Bit Test
		case STARS_NN_vucomisd:             // Unordered Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
		case STARS_NN_vucomiss:             // Scalar Unordered Single-FP Compare and Set EFLAGS
			return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE);
			break;

		case STARS_NN_vunpckhpd:            // Unpack and Interleave High Packed Double-Precision Floating-Point Values
		case STARS_NN_vunpckhps:            // Unpack High Packed Single-FP Data
		case STARS_NN_vunpcklpd:            // Unpack and Interleave Low Packed Double-Precision Floating-Point Values
		case STARS_NN_vunpcklps:            // Unpack Low Packed Single-FP Data
			return this->BuildBinary3OpndRTL(SMP_INTERLEAVE);
			break;

		case STARS_NN_vxorpd:               // Bitwise Logical OR of Double-Precision Floating-Point Values
		case STARS_NN_vxorps:               // Bitwise Logical XOR for Single-FP Data
			return this->BuildBinary3OpndRTL(SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vzeroall:             // Zero All YMM Registers
		case STARS_NN_vzeroupper:           // Zero Upper Bits of YMM Registers
			NopRT = new SMPRegTransfer;
			NopRT->SetParentInst(this);
			NopRT->SetOperator(SMP_NULL_OPERATOR);
			this->RTL.push_back(NopRT);
			NopRT = NULL;
			return true;

// Transactional Synchronization Extensions

		case STARS_NN_xabort:               // Transaction Abort
		case STARS_NN_xbegin:               // Transaction Begin
		case STARS_NN_xend:                 // Transaction End
		case STARS_NN_xtest:                // Test If In Transactional Execution
			return false;
			break;

// Virtual PC synthetic instructions

		case STARS_NN_vmgetinfo:            // Virtual PC - Get VM Information
		case STARS_NN_vmsetinfo:            // Virtual PC - Set VM Information
		case STARS_NN_vmdxdsbl:             // Virtual PC - Disable Direct Execution
		case STARS_NN_vmdxenbl:             // Virtual PC - Enable Direct Execution
		case STARS_NN_vmcpuid:              // Virtual PC - Virtualized CPU Information
		case STARS_NN_vmhlt:                // Virtual PC - Halt
		case STARS_NN_vmsplaf:              // Virtual PC - Spin Lock Acquisition Failed
		case STARS_NN_vmpushfd:             // Virtual PC - Push virtualized flags register
		case STARS_NN_vmpopfd:              // Virtual PC - Pop virtualized flags register
		case STARS_NN_vmcli:                // Virtual PC - Clear Interrupt Flag
		case STARS_NN_vmsti:                // Virtual PC - Set Interrupt Flag
		case STARS_NN_vmiretd:              // Virtual PC - Return From Interrupt
		case STARS_NN_vmsgdt:               // Virtual PC - Store Global Descriptor Table
		case STARS_NN_vmsidt:               // Virtual PC - Store Interrupt Descriptor Table
		case STARS_NN_vmsldt:               // Virtual PC - Store Local Descriptor Table
		case STARS_NN_vmstr:                // Virtual PC - Store Task Register
		case STARS_NN_vmsdte:               // Virtual PC - Store to Descriptor Table Entry
		case STARS_NN_vpcext:               // Virtual PC - ISA extension
			return false;
			break;

		// AMD FMA4
		case STARS_NN_vfmaddsubps:          // Multiply with Alternating Add/Subtract of Packed Single-Precision Floating-Point
		case STARS_NN_vfmaddsubpd:          // Multiply with Alternating Add/Subtract of Packed Double-Precision Floating-Point
		case STARS_NN_vfmsubaddps:          // Multiply with Alternating Subtract/Add of Packed Single-Precision Floating-Point
		case STARS_NN_vfmsubaddpd:          // Multiply with Alternating Subtract/Add of Packed Double-Precision Floating-Point
			return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_BINARY_FLOATING_ARITHMETIC);
			break;

		case STARS_NN_vfmaddps:             // Multiply and Add Packed Single-Precision Floating-Point
		case STARS_NN_vfmaddpd:             // Multiply and Add Packed Double-Precision Floating-Point
		case STARS_NN_vfmaddss:             // Multiply and Add Scalar Single-Precision Floating-Point
		case STARS_NN_vfmaddsd:             // Multiply and Add Scalar Double-Precision Floating-Point
			return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_FLOATING_ADD);
			break;

		case STARS_NN_vfmsubps:             // Multiply and Subtract Packed Single-Precision Floating-Point
		case STARS_NN_vfmsubpd:             // Multiply and Subtract Packed Double-Precision Floating-Point
		case STARS_NN_vfmsubss:             // Multiply and Subtract Scalar Single-Precision Floating-Point
		case STARS_NN_vfmsubsd:             // Multiply and Subtract Scalar Double-Precision Floating-Point
			return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_FLOATING_SUBTRACT);
			break;

		case STARS_NN_vfnmaddps:            // Negative Multiply and Add Packed Single-Precision Floating-Point
		case STARS_NN_vfnmaddpd:            // Negative Multiply and Add Packed Double-Precision Floating-Point
		case STARS_NN_vfnmaddss:            // Negative Multiply and Add Scalar Single-Precision Floating-Point
		case STARS_NN_vfnmaddsd:            // Negative Multiply and Add Double Single-Precision Floating-Point
		case STARS_NN_vfnmsubps:            // Negative Multiply and Subtract Packed Single-Precision Floating-Point
		case STARS_NN_vfnmsubpd:            // Negative Multiply and Subtract Packed Double-Precision Floating-Point
		case STARS_NN_vfnmsubss:            // Negative Multiply and Subtract Scalar Single-Precision Floating-Point
		case STARS_NN_vfnmsubsd:            // Negative Multiply and Subtract Double Single-Precision Floating-Point
			return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_FLOATING_NEGATE_AND_ADD);
			break;

		// Intel Memory Protection Extensions (MPX)

		case STARS_NN_bndmk:                // Make Bounds
		case STARS_NN_bndcl:                // Check Lower Bound
		case STARS_NN_bndcu:                // Check Upper Bound
		case STARS_NN_bndcn:                // Check Upper Bound
		case STARS_NN_bndmov:               // Move Bounds
		case STARS_NN_bndldx:               // Load Extended Bounds Using Address Translation
		case STARS_NN_bndstx:               // Store Extended Bounds Using Address Translation
			return false;
			break;

		// New xstate instructions

		case STARS_NN_xrstors:              // Restore Processor Extended States Supervisor
		case STARS_NN_xsavec:               // Save Processor Extended States with Compaction
		case STARS_NN_xsaves:               // Save Processor Extended States Supervisor
			return false;
			break;

		// PREFETCHWT1 support

		case STARS_NN_prefetchwt1:          // Prefetch Vector Data Into Caches with Intent to Write and T1 Hint
			return false;
			break;

		// Memory instructions

		case STARS_NN_clflushopt:           // Flush a Cache Line Optimized
		case STARS_NN_clwb:                 // Cache Line Write Back
		case STARS_NN_pcommit:              // Persistent Commit (deprecated by Intel)
			return false;
			break;

		// Protection Key Rights for User Pages

		case STARS_NN_rdpkru:               // Read Protection Key Rights for User Pages
		case STARS_NN_wrpkru:               // Write Data to User Page Key Register
			return false;
			break;

		// AVX comparison pseudo-ops

		case STARS_NN_vcmpeqpd:             // Compare Packed Double-Precision Floating-Point Values - Equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);

		case STARS_NN_vcmpltpd:             // Compare Packed Double-Precision Floating-Point Values - Less-than (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);

		case STARS_NN_vcmplepd:             // Compare Packed Double-Precision Floating-Point Values - Less-than-or-equal (ordered, signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);

		case STARS_NN_vcmpunordpd:          // Compare Packed Double-Precision Floating-Point Values - Unordered (non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);

		case STARS_NN_vcmpneqpd:            // Compare Packed Double-Precision Floating-Point Values - Not-equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);

		case STARS_NN_vcmpnltpd:            // Compare Packed Double-Precision Floating-Point Values - Not-less-than (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET);

		case STARS_NN_vcmpnlepd:            // Compare Packed Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered, signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET);

		case STARS_NN_vcmpordpd:            // Compare Packed Double-Precision Floating-Point Values - Ordered (non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);

		case STARS_NN_vcmpeq_uqpd:          // Compare Packed Double-Precision Floating-Point Values - Equal (unordered: non-signaling)
		case STARS_NN_vcmpngepd:            // Compare Packed Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered, signaling)
		case STARS_NN_vcmpngtpd:            // Compare Packed Double-Precision Floating-Point Values - Not-greater-than (unordered: signaling)
		case STARS_NN_vcmpfalsepd:          // Compare Packed Double-Precision Floating-Point Values - False (ordered, non-signaling)
		case STARS_NN_vcmpneq_oqpd:         // Compare Packed Double-Precision Floating-Point Values - Not-equal (ordered: non-signaling)
		case STARS_NN_vcmpgepd:             // Compare Packed Double-Precision Floating-Point Values - Greater-than-or-equal (ordered, signaling)
		case STARS_NN_vcmpgtpd:             // Compare Packed Double-Precision Floating-Point Values - Greater-than (ordered, signaling)
		case STARS_NN_vcmptruepd:           // Compare Packed Double-Precision Floating-Point Values - True (unordered, non-signaling)
		case STARS_NN_vcmpeq_ospd:          // Compare Packed Double-Precision Floating-Point Values - Equal (ordered: signaling)
		case STARS_NN_vcmplt_oqpd:          // Compare Packed Double-Precision Floating-Point Values - Less-than (ordered: non-signaling)
		case STARS_NN_vcmple_oqpd:          // Compare Packed Double-Precision Floating-Point Values - Less-than-or-equal (ordered, non-signaling)
		case STARS_NN_vcmpunord_spd:        // Compare Packed Double-Precision Floating-Point Values - Unordered (signaling)
		case STARS_NN_vcmpneq_uspd:         // Compare Packed Double-Precision Floating-Point Values - Not-equal (unordered: signaling)
		case STARS_NN_vcmpnlt_uqpd:         // Compare Packed Double-Precision Floating-Point Values - Not-less-than (unordered: non-signaling)
		case STARS_NN_vcmpnle_uqpd:         // Compare Packed Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered, non-signaling)
		case STARS_NN_vcmpord_spd:          // Compare Packed Double-Precision Floating-Point Values - Ordered (signaling)
		case STARS_NN_vcmpeq_uspd:          // Compare Packed Double-Precision Floating-Point Values - Equal (unordered: signaling)
		case STARS_NN_vcmpnge_uqpd:         // Compare Packed Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered, non-signaling)
		case STARS_NN_vcmpngt_uqpd:         // Compare Packed Double-Precision Floating-Point Values - Not-greater-than (unordered, non-signaling)
		case STARS_NN_vcmpfalse_ospd:       // Compare Packed Double-Precision Floating-Point Values - False (ordered, signaling)
		case STARS_NN_vcmpneq_ospd:         // Compare Packed Double-Precision Floating-Point Values - Not-equal (ordered: signaling)
		case STARS_NN_vcmpge_oqpd:          // Compare Packed Double-Precision Floating-Point Values - Greater-than-or-equal (ordered: non-signaling)
		case STARS_NN_vcmpgt_oqpd:          // Compare Packed Double-Precision Floating-Point Values - Greater-than (ordered, non-signaling)
		case STARS_NN_vcmptrue_uspd:        // Compare Packed Double-Precision Floating-Point Values - True (unordered, signaling)

		case STARS_NN_vcmpeqps:             // Packed Single-FP Compare - Equal (ordered, non-signaling)
		case STARS_NN_vcmpltps:             // Packed Single-FP Compare - Less-than (ordered: signaling)
		case STARS_NN_vcmpleps:             // Packed Single-FP Compare - Less-than-or-equal (ordered, signaling)
		case STARS_NN_vcmpunordps:          // Packed Single-FP Compare - Unordered (non-signaling)
		case STARS_NN_vcmpneqps:            // Packed Single-FP Compare - Not-equal (unordered, non-signaling)

		case STARS_NN_vcmpnltps:            // Packed Single-FP Compare - Not-less-than (unordered, signaling)
		case STARS_NN_vcmpnleps:            // Packed Single-FP Compare - Not-less-than-or-equal (unordered, signaling)
		case STARS_NN_vcmpordps:            // Packed Single-FP Compare - Ordered (non-signaling)
		case STARS_NN_vcmpeq_uqps:          // Packed Single-FP Compare - Equal (unordered, non-signaling)
		case STARS_NN_vcmpngeps:            // Packed Single-FP Compare - Not-greater-than-or-equal (unordered, signaling)
		case STARS_NN_vcmpngtps:            // Packed Single-FP Compare - Not-greater-than (unordered, signaling)
		case STARS_NN_vcmpfalseps:          // Packed Single-FP Compare - False (ordered, non-signaling)
		case STARS_NN_vcmpneq_oqps:         // Packed Single-FP Compare - Not-equal (ordered: non-signaling)
		case STARS_NN_vcmpgeps:             // Packed Single-FP Compare - Greater-than-or-equal (ordered: signaling)
		case STARS_NN_vcmpgtps:             // Packed Single-FP Compare - Greater-than (ordered: signaling)
		case STARS_NN_vcmptrueps:           // Packed Single-FP Compare - True (unordered: non-signaling)
		case STARS_NN_vcmpeq_osps:          // Packed Single-FP Compare - Equal (ordered: signaling)
		case STARS_NN_vcmplt_oqps:          // Packed Single-FP Compare - Less-than (ordered: non-signaling)
		case STARS_NN_vcmple_oqps:          // Packed Single-FP Compare - Less-than-or-equal (ordered: non-signaling)
		case STARS_NN_vcmpunord_sps:        // Packed Single-FP Compare - Unordered (signaling)
		case STARS_NN_vcmpneq_usps:         // Packed Single-FP Compare - Not-equal (unordered: signaling)
		case STARS_NN_vcmpnlt_uqps:         // Packed Single-FP Compare - Not-less-than (unordered: non-signaling)
		case STARS_NN_vcmpnle_uqps:         // Packed Single-FP Compare - Not-less-than-or-equal (unordered: non-signaling)
		case STARS_NN_vcmpord_sps:          // Packed Single-FP Compare - Ordered (signaling)
		case STARS_NN_vcmpeq_usps:          // Packed Single-FP Compare - Equal (unordered: signaling)
		case STARS_NN_vcmpnge_uqps:         // Packed Single-FP Compare - Not-greater-than-or-equal (unordered: non-signaling)
		case STARS_NN_vcmpngt_uqps:         // Packed Single-FP Compare - Not-greater-than (unordered: non-signaling)
		case STARS_NN_vcmpfalse_osps:       // Packed Single-FP Compare - False (ordered: signaling)
		case STARS_NN_vcmpneq_osps:         // Packed Single-FP Compare - Not-equal (ordered: signaling)
		case STARS_NN_vcmpge_oqps:          // Packed Single-FP Compare - Greater-than-or-equal (ordered: non-signaling)
		case STARS_NN_vcmpgt_oqps:          // Packed Single-FP Compare - Greater-than (ordered: non-signaling)
		case STARS_NN_vcmptrue_usps:        // Packed Single-FP Compare - True (unordered: signaling)
			return false;
			break;

		case STARS_NN_vcmpeqsd:             // Compare Scalar Double-Precision Floating-Point Values - Equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpltsd:             // Compare Scalar Double-Precision Floating-Point Values - Less-than (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmplesd:             // Compare Scalar Double-Precision Floating-Point Values - Less-than-or-equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpunordsd:          // Compare Scalar Double-Precision Floating-Point Values - Unordered (non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpneqsd:            // Compare Scalar Double-Precision Floating-Point Values - Not-equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpnltsd:            // Compare Scalar Double-Precision Floating-Point Values - Not-less-than (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmpnlesd:            // Compare Scalar Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpordsd:            // Compare Scalar Double-Precision Floating-Point Values - Ordered (non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpeq_uqsd:          // Compare Scalar Double-Precision Floating-Point Values - Equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpngesd:            // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmpngtsd:            // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpfalsesd:          // Compare Scalar Double-Precision Floating-Point Values - False (ordered: non-signaling)
			return false;
			break;

		case STARS_NN_vcmpneq_oqsd:         // Compare Scalar Double-Precision Floating-Point Values - Not-equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpgesd:             // Compare Scalar Double-Precision Floating-Point Values - Greater-than-or-equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_vcmpgtsd:             // Compare Scalar Double-Precision Floating-Point Values - Greater-than (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_vcmptruesd:           // Compare Scalar Double-Precision Floating-Point Values - True (unordered: non-signaling)
			return false;
			break;

		case STARS_NN_vcmpeq_ossd:          // Compare Scalar Double-Precision Floating-Point Values - Equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmplt_oqsd:          // Compare Scalar Double-Precision Floating-Point Values - Less-than (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmple_oqsd:          // Compare Scalar Double-Precision Floating-Point Values - Less-than-or-equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpunord_ssd:        // Compare Scalar Double-Precision Floating-Point Values - Unordered (signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpneq_ussd:         // Compare Scalar Double-Precision Floating-Point Values - Not-equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpnlt_uqsd:         // Compare Scalar Double-Precision Floating-Point Values - Not-less-than (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_vcmpnle_uqsd:         // Compare Scalar Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_vcmpord_ssd:          // Compare Scalar Double-Precision Floating-Point Values - Ordered (signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpeq_ussd:          // Compare Scalar Double-Precision Floating-Point Values - Equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpnge_uqsd:         // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmpngt_uqsd:         // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpfalse_ossd:       // Compare Scalar Double-Precision Floating-Point Values - False (ordered: signaling)
			return false;
			break;

		case STARS_NN_vcmpneq_ossd:         // Compare Scalar Double-Precision Floating-Point Values - Not-equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpge_oqsd:          // Compare Scalar Double-Precision Floating-Point Values - Greater-than-or-equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_vcmpgt_oqsd:          // Compare Scalar Double-Precision Floating-Point Values - Greater-than (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_vcmptrue_ussd:        // Compare Scalar Double-Precision Floating-Point Values - True (unordered: signaling)
			return false;
			break;

		case STARS_NN_vcmpeqss:             // Scalar Single-FP Compare - Equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpltss:             // Scalar Single-FP Compare - Less-than (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmpless:             // Scalar Single-FP Compare - Less-than-or-equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpunordss:          // Scalar Single-FP Compare - Unordered (non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpneqss:            // Scalar Single-FP Compare - Not-equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpnltss:            // Scalar Single-FP Compare - Not-less-than (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmpnless:            // Scalar Single-FP Compare - Not-less-than-or-equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpordss:            // Scalar Single-FP Compare - Ordered (non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpeq_uqss:          // Scalar Single-FP Compare - Equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpngess:            // Scalar Single-FP Compare - Not-greater-than-or-equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmpngtss:            // Scalar Single-FP Compare - Not-greater-than (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpfalsess:          // Scalar Single-FP Compare - False (ordered: non-signaling)
			return false;
			break;

		case STARS_NN_vcmpneq_oqss:         // Scalar Single-FP Compare - Not-equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpgess:             // Scalar Single-FP Compare - Greater-than-or-equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_vcmpgtss:             // Scalar Single-FP Compare - Greater-than (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_vcmptruess:           // Scalar Single-FP Compare - True (unordered: non-signaling)
			return true;
			break;

		case STARS_NN_vcmpeq_osss:          // Scalar Single-FP Compare - Equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmplt_oqss:          // Scalar Single-FP Compare - Less-than (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmple_oqss:          // Scalar Single-FP Compare - Less-than-or-equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpunord_sss:        // Scalar Single-FP Compare - Unordered (signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpneq_usss:         // Scalar Single-FP Compare - Not-equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpnlt_uqss:         // Scalar Single-FP Compare - Not-less-than (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_vcmpnle_uqss:         // Scalar Single-FP Compare - Not-less-than-or-equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_vcmpord_sss:          // Scalar Single-FP Compare - Ordered (signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpeq_usss:          // Scalar Single-FP Compare - Equal (unordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET);
			break;

		case STARS_NN_vcmpnge_uqss:         // Scalar Single-FP Compare - Not-greater-than-or-equal (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET);
			break;

		case STARS_NN_vcmpngt_uqss:         // Scalar Single-FP Compare - Not-greater-than (unordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET);
			break;

		case STARS_NN_vcmpfalse_osss:       // Scalar Single-FP Compare - False (ordered: signaling)
			return false;
			break;

		case STARS_NN_vcmpneq_osss:         // Scalar Single-FP Compare - Not-equal (ordered: signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET);
			break;

		case STARS_NN_vcmpge_oqss:          // Scalar Single-FP Compare - Greater-than-or-equal (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET);
			break;

		case STARS_NN_vcmpgt_oqss:          // Scalar Single-FP Compare - Greater-than (ordered: non-signaling)
			return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET);
			break;

		case STARS_NN_vcmptrue_usss:        // Scalar Single-FP Compare - True (unordered: signaling)
			return false;
			break;

		// AVX-512 instructions

		case STARS_NN_valignd:              // Align Doubleword Vectors
		case STARS_NN_valignq:              // Align Quadword Vectors
		case STARS_NN_vblendmpd:            // Blend Float64 Vectors Using an OpMask Control
		case STARS_NN_vblendmps:            // Blend Float32 Vectors Using an OpMask Control
		case STARS_NN_vpblendmb:            // Blend Byte Vectors Using an Opmask Control
		case STARS_NN_vpblendmw:            // Blend Word Vectors Using an Opmask Control
		case STARS_NN_vpblendmd:            // Blend Int32 Vectors Using an OpMask Control
		case STARS_NN_vpblendmq:            // Blend Int64 Vectors Using an OpMask Control
		case STARS_NN_vbroadcastf32x2:      // Load with Broadcast Floating-Point Data
		case STARS_NN_vbroadcastf32x4:      // Load with Broadcast Floating-Point Data
		case STARS_NN_vbroadcastf64x2:      // Load with Broadcast Floating-Point Data
		case STARS_NN_vbroadcastf32x8:      // Load with Broadcast Floating-Point Data
		case STARS_NN_vbroadcastf64x4:      // Load with Broadcast Floating-Point Data
		case STARS_NN_vbroadcasti32x2:      // Load Integer and Broadcast
		case STARS_NN_vbroadcasti32x4:      // Load Integer and Broadcast
		case STARS_NN_vbroadcasti64x2:      // Load Integer and Broadcast
		case STARS_NN_vbroadcasti32x8:      // Load Integer and Broadcast
		case STARS_NN_vbroadcasti64x4:      // Load Integer and Broadcast
		case STARS_NN_vcompresspd:          // Store Sparse Packed Double-Precision Floating-Point Values into Dense Memory
		case STARS_NN_vcompressps:          // Store Sparse Packed Single-Precision Floating-Point Values into Dense Memory
		case STARS_NN_vcvtpd2qq:            // Convert Packed Double-Precision Floating-Point Values to Packed Quadword Integers
		case STARS_NN_vcvtpd2udq:           // Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers
		case STARS_NN_vcvtpd2uqq:           // Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers
		case STARS_NN_vcvtps2udq:           // Convert Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values
		case STARS_NN_vcvtps2qq:            // Convert Packed Single Precision Floating-Point Values to Packed Singed Quadword Integer Values
		case STARS_NN_vcvtps2uqq:           // Convert Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values
		case STARS_NN_vcvtqq2pd:            // Convert Packed Quadword Integers to Packed Double-Precision Floating-Point Values
		case STARS_NN_vcvtqq2ps:            // Convert Packed Quadword Integers to Packed Single-Precision Floating-Point Values
		case STARS_NN_vcvtsd2usi:           // Convert Scalar Double-Precision Floating-Point Value to Unsigned Doubleword Integer
		case STARS_NN_vcvtss2usi:           // Convert Scalar Single-Precision Floating-Point Value to Unsigned Doubleword Integer
		case STARS_NN_vcvttpd2qq:           // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Quadword Integers
		case STARS_NN_vcvttpd2udq:          // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers
		case STARS_NN_vcvttpd2uqq:          // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers
		case STARS_NN_vcvttps2udq:          // Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values
		case STARS_NN_vcvttps2qq:           // Convert with Truncation Packed Single Precision Floating-Point Values to Packed Singed Quadword Integer Values
		case STARS_NN_vcvttps2uqq:          // Convert with Truncation Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values
		case STARS_NN_vcvttsd2usi:          // Convert with Truncation Scalar Double-Precision Floating-Point Value to Unsigned Integer
		case STARS_NN_vcvttss2usi:          // Convert with Truncation Scalar Single-Precision Floating-Point Value to Unsigned Integer
		case STARS_NN_vcvtudq2pd:           // Convert Packed Unsigned Doubleword Integers to Packed Double-Precision Floating-Point Values
		case STARS_NN_vcvtudq2ps:           // Convert Packed Unsigned Doubleword Integers to Packed Single-Precision Floating-Point Values
		case STARS_NN_vcvtuqq2pd:           // Convert Packed Unsigned Quadword Integers to Packed Double-Precision Floating-Point Values
		case STARS_NN_vcvtuqq2ps:           // Convert Packed Unsigned Quadword Integers to Packed Single-Precision Floating-Point Values
		case STARS_NN_vcvtusi2sd:           // Convert Unsigned Integer to Scalar Double-Precision Floating-Point Value
		case STARS_NN_vcvtusi2ss:           // Convert Unsigned Integer to Scalar Single-Precision Floating-Point Value
		case STARS_NN_vdbpsadbw:            // Double Block Packed Sum-Absolute-Differences (SAD) on Unsigned Bytes
		case STARS_NN_vexpandpd:            // Load Sparse Packed Double-Precision Floating-Point Values from Dense Memory
		case STARS_NN_vexpandps:            // Load Sparse Packed Single-Precision Floating-Point Values from Dense Memory
		case STARS_NN_vextractf32x4:        // Extract Packed Floating-Point Values
		case STARS_NN_vextractf64x2:        // Extract Packed Floating-Point Values
		case STARS_NN_vextractf32x8:        // Extract Packed Floating-Point Values
		case STARS_NN_vextractf64x4:        // Extract Packed Floating-Point Values
		case STARS_NN_vextracti32x4:        // Extract packed Integer Values
		case STARS_NN_vextracti64x2:        // Extract packed Integer Values
		case STARS_NN_vextracti32x8:        // Extract packed Integer Values
		case STARS_NN_vextracti64x4:        // Extract packed Integer Values
		case STARS_NN_vfixupimmpd:          // Fix Up Special Packed Float64 Values
		case STARS_NN_vfixupimmps:          // Fix Up Special Packed Float32 Values
		case STARS_NN_vfixupimmsd:          // Fix Up Special Scalar Float64 Value
		case STARS_NN_vfixupimmss:          // Fix Up Special Scalar Float32 Value
		case STARS_NN_vfpclasspd:           // Tests Types Of a Packed Float64 Values
		case STARS_NN_vfpclassps:           // Tests Types Of a Packed Float32 Values
		case STARS_NN_vfpclasssd:           // Tests Types Of a Scalar Float64 Values
		case STARS_NN_vfpclassss:           // Tests Types Of a Scalar Float32 Values
		case STARS_NN_vgetexppd:            // Convert Exponents of Packed DP FP Values to DP FP Values
		case STARS_NN_vgetexpps:            // Convert Exponents of Packed SP FP Values to SP FP Values
		case STARS_NN_vgetexpsd:            // Convert Exponents of Scalar DP FP Values to DP FP Value
		case STARS_NN_vgetexpss:            // Convert Exponents of Scalar SP FP Values to SP FP Value
		case STARS_NN_vgetmantpd:           // Extract Float64 Vector of Normalized Mantissas from Float64 Vector
		case STARS_NN_vgetmantps:           // Extract Float32 Vector of Normalized Mantissas from Float32 Vector
		case STARS_NN_vgetmantsd:           // Extract Float64 of Normalized Mantissas from Float64 Scalar
		case STARS_NN_vgetmantss:           // Extract Float32 Vector of Normalized Mantissa from Float32 Vector
		case STARS_NN_vinsertf32x4:         // Insert Packed Floating-Point Values
		case STARS_NN_vinsertf64x2:         // Insert Packed Floating-Point Values
		case STARS_NN_vinsertf32x8:         // Insert Packed Floating-Point Values
		case STARS_NN_vinsertf64x4:         // Insert Packed Floating-Point Values
		case STARS_NN_vinserti32x4:         // Insert Packed Integer Values
		case STARS_NN_vinserti64x2:         // Insert Packed Integer Values
		case STARS_NN_vinserti32x8:         // Insert Packed Integer Values
		case STARS_NN_vinserti64x4:         // Insert Packed Integer Values
		case STARS_NN_vmovdqa32:            // Move Aligned Packed Integer Values
		case STARS_NN_vmovdqa64:            // Move Aligned Packed Integer Values
		case STARS_NN_vmovdqu8:             // Move Unaligned Packed Integer Values
		case STARS_NN_vmovdqu16:            // Move Unaligned Packed Integer Values
		case STARS_NN_vmovdqu32:            // Move Unaligned Packed Integer Values
		case STARS_NN_vmovdqu64:            // Move Unaligned Packed Integer Values
		case STARS_NN_vpabsq:               // Packed Absolute Value
		case STARS_NN_vpandd:               // Logical AND
		case STARS_NN_vpandq:               // Logical AND
		case STARS_NN_vpandnd:              // Logical AND NOT
		case STARS_NN_vpandnq:              // Logical AND NOT
		case STARS_NN_vpbroadcastmb2q:      // Broadcast Mask to Vector Register
		case STARS_NN_vpbroadcastmw2d:      // Broadcast Mask to Vector Register
		case STARS_NN_vpcmpb:               // Compare Packed Byte Values Into Mask
		case STARS_NN_vpcmpub:              // Compare Packed Byte Values Into Mask
		case STARS_NN_vpcmpd:               // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpud:              // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpq:               // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpuq:              // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpw:               // Compare Packed Word Values Into Mask
		case STARS_NN_vpcmpuw:              // Compare Packed Word Values Into Mask
		case STARS_NN_vpcompressd:          // Store Sparse Packed Doubleword Integer Values into Dense Memory/Register
		case STARS_NN_vpcompressq:          // Store Sparse Packed Quadword Integer Values into Dense Memory/Register
		case STARS_NN_vpconflictd:          // Detect Conflicts Within a Vector of Packed Dword Values into Dense Memory/Register
		case STARS_NN_vpconflictq:          // Detect Conflicts Within a Vector of Packed Qword Values into Dense Memory/Register
		case STARS_NN_vpermb:               // Permute Packed Bytes Elements
		case STARS_NN_vpermw:               // Permute Packed Words Elements
		case STARS_NN_vpermi2b:             // Full Permute of Bytes From Two Tables Overwriting the Index
		case STARS_NN_vpermi2w:             // Full Permute From Two Tables Overwriting the Index
		case STARS_NN_vpermi2d:             // Full Permute From Two Tables Overwriting the Index
		case STARS_NN_vpermi2q:             // Full Permute From Two Tables Overwriting the Index
		case STARS_NN_vpermi2ps:            // Full Permute From Two Tables Overwriting the Index
		case STARS_NN_vpermi2pd:            // Full Permute From Two Tables Overwriting the Index
		case STARS_NN_vpermt2b:             // Full Permute of Bytes From Two Tables Overwriting a Table
		case STARS_NN_vpermt2w:             // Full Permute from Two Tables Overwriting one Table
		case STARS_NN_vpermt2d:             // Full Permute from Two Tables Overwriting one Table
		case STARS_NN_vpermt2q:             // Full Permute from Two Tables Overwriting one Table
		case STARS_NN_vpermt2ps:            // Full Permute from Two Tables Overwriting one Table
		case STARS_NN_vpermt2pd:            // Full Permute from Two Tables Overwriting one Table
		case STARS_NN_vpexpandd:            // Load Sparse Packed Doubleword Integer Values from Dense Memory/Register
		case STARS_NN_vpexpandq:            // Load Sparse Packed Quadword Integer Values from Dense Memory/Register
		case STARS_NN_vplzcntd:             // Count the Number of Leading Zero Bits for Packed Dword Values
		case STARS_NN_vplzcntq:             // Count the Number of Leading Zero Bits for Packed Qword Values
		case STARS_NN_vpmadd52luq:          // Packed Multiply of Unsigned 52-bit Integers and Add the Low 52-bit Products to Qword Accumulators
		case STARS_NN_vpmadd52huq:          // Packed Multiply of Unsigned 52-bit Unsigned Integers and Add High 52-bit Products to 64-bit Accumulators
		case STARS_NN_vpmaxsq:              // Maximum of Packed Signed Integers
		case STARS_NN_vpmaxuq:              // Maximum of Packed Unsigned Integers
		case STARS_NN_vpminsq:              // Minimum of Packed Signed Integers
		case STARS_NN_vpminuq:              // Minimum of Packed Unsigned Integers
		case STARS_NN_vpmovm2b:             // Convert a Mask Register to a Vector Register
		case STARS_NN_vpmovm2w:             // Convert a Mask Register to a Vector Register
		case STARS_NN_vpmovm2d:             // Convert a Mask Register to a Vector Register
		case STARS_NN_vpmovm2q:             // Convert a Mask Register to a Vector Register
		case STARS_NN_vpmovb2m:             // Convert a Vector Register to a Mask
		case STARS_NN_vpmovw2m:             // Convert a Vector Register to a Mask
		case STARS_NN_vpmovd2m:             // Convert a Vector Register to a Mask
		case STARS_NN_vpmovq2m:             // Convert a Vector Register to a Mask
		case STARS_NN_vpmovqb:              // Down Convert QWord to Byte
		case STARS_NN_vpmovsqb:             // Down Convert QWord to Byte
		case STARS_NN_vpmovusqb:            // Down Convert QWord to Byte
		case STARS_NN_vpmovqw:              // Down Convert QWord to Word
		case STARS_NN_vpmovsqw:             // Down Convert QWord to Word
		case STARS_NN_vpmovusqw:            // Down Convert QWord to Word
		case STARS_NN_vpmovqd:              // Down Convert QWord to DWord
		case STARS_NN_vpmovsqd:             // Down Convert QWord to DWord
		case STARS_NN_vpmovusqd:            // Down Convert QWord to DWord
		case STARS_NN_vpmovdb:              // Down Convert DWord to Byte
		case STARS_NN_vpmovsdb:             // Down Convert DWord to Byte
		case STARS_NN_vpmovusdb:            // Down Convert DWord to Byte
		case STARS_NN_vpmovdw:              // Down Convert DWord to Word
		case STARS_NN_vpmovsdw:             // Down Convert DWord to Word
		case STARS_NN_vpmovusdw:            // Down Convert DWord to Word
		case STARS_NN_vpmovwb:              // Down Convert Word to Byte
		case STARS_NN_vpmovswb:             // Down Convert Word to Byte
		case STARS_NN_vpmovuswb:            // Down Convert Word to Byte
		case STARS_NN_vpmullq:              // Multiply Packed Integers and Store Low Result
		case STARS_NN_vpmultishiftqb:       // Select Packed Unaligned Bytes from Quadword Sources
		case STARS_NN_vpord:                // Bitwise Logical Or
		case STARS_NN_vporq:                // Bitwise Logical Or
		case STARS_NN_vprold:               // Bit Rotate Left
		case STARS_NN_vprolvd:              // Bit Rotate Left
		case STARS_NN_vprolq:               // Bit Rotate Left
		case STARS_NN_vprolvq:              // Bit Rotate Left
		case STARS_NN_vprord:               // Bit Rotate Right
		case STARS_NN_vprorvd:              // Bit Rotate Right
		case STARS_NN_vprorq:               // Bit Rotate Right
		case STARS_NN_vprorvq:              // Bit Rotate Right
		case STARS_NN_vpscatterdd:          // Scatter Packed Dword with Signed Dword
		case STARS_NN_vpscatterdq:          // Scatter Packed Qword with Signed Qword Indices
		case STARS_NN_vpscatterqd:          // Scatter Packed Dword with Signed Dword
		case STARS_NN_vpscatterqq:          // Scatter Packed Qword with Signed Qword Indices
		case STARS_NN_vpsraq:               // Bit Shift Arithmetic Right
		case STARS_NN_vpsllvw:              // Variable Bit Shift Left Logical
		case STARS_NN_vpsrlvw:              // Variable Bit Shift Right Logical
		case STARS_NN_vptestnmb:            // Logical NAND and Set
		case STARS_NN_vptestnmw:            // Logical NAND and Set
		case STARS_NN_vptestnmd:            // Logical NAND and Set
		case STARS_NN_vptestnmq:            // Logical NAND and Set
		case STARS_NN_vshuff32x4:           // Shuffle Packed Values at 128-bit Granularity
		case STARS_NN_vshuff64x2:           // Shuffle Packed Values at 128-bit Granularity
		case STARS_NN_vshufi32x4:           // Shuffle Packed Values at 128-bit Granularity
		case STARS_NN_vshufi64x2:           // Shuffle Packed Values at 128-bit Granularity
		case STARS_NN_vpternlogd:           // Bitwise Ternary Logic
		case STARS_NN_vpternlogq:           // Bitwise Ternary Logic
		case STARS_NN_vptestmb:             // Logical AND and Set Mask
		case STARS_NN_vptestmw:             // Logical AND and Set Mask
		case STARS_NN_vptestmd:             // Logical AND and Set Mask
		case STARS_NN_vptestmq:             // Logical AND and Set Mask
		case STARS_NN_vpsravw:              // Variable Bit Shift Right Arithmetic
		case STARS_NN_vpsravq:              // Variable Bit Shift Right Arithmetic
		case STARS_NN_vpxord:               // Exclusive Or
		case STARS_NN_vpxorq:               // Exclusive Or
		case STARS_NN_vrangepd:             // Range Restriction Calculation For Packed Pairs of Float64 Values
		case STARS_NN_vrangeps:             // Range Restriction Calculation For Packed Pairs of Float32 Values
		case STARS_NN_vrangesd:             // Range Restriction Calculation From a pair of Scalar Float64 Values
		case STARS_NN_vrangess:             // Range Restriction Calculation From a Pair of Scalar Float32 Values
		case STARS_NN_vrcp14pd:             // Compute Approximate Reciprocals of Packed Float64 Values
		case STARS_NN_vrcp14sd:             // Compute Approximate Reciprocal of Scalar Float64 Value
		case STARS_NN_vrcp14ps:             // Compute Approximate Reciprocals of Packed Float32 Values
		case STARS_NN_vrcp14ss:             // Compute Approximate Reciprocal of Scalar Float32 Value
		case STARS_NN_vreducepd:            // Perform Reduction Transformation on Packed Float64 Values
		case STARS_NN_vreducesd:            // Perform a Reduction Transformation on a Scalar Float64 Value
		case STARS_NN_vreduceps:            // Perform Reduction Transformation on Packed Float32 Values
		case STARS_NN_vreducess:            // Perform a Reduction Transformation on a Scalar Float32 Value
		case STARS_NN_vrndscalepd:          // Round Packed Float64 Values To Include A Given Number Of Fraction Bits
		case STARS_NN_vrndscalesd:          // Round Scalar Float64 Value To Include A Given Number Of Fraction Bits
		case STARS_NN_vrndscaleps:          // Round Packed Float32 Values To Include A Given Number Of Fraction Bits
		case STARS_NN_vrndscaless:          // Round Scalar Float32 Value To Include A Given Number Of Fraction Bits
		case STARS_NN_vrsqrt14pd:           // Compute Approximate Reciprocals of Square Roots of Packed Float64 Values
		case STARS_NN_vrsqrt14sd:           // Compute Approximate Reciprocal of Square Root of Scalar Float64 Value
		case STARS_NN_vrsqrt14ps:           // Compute Approximate Reciprocals of Square Roots of Packed Float32 Values
		case STARS_NN_vrsqrt14ss:           // Compute Approximate Reciprocal of Square Root of Scalar Float32 Value
		case STARS_NN_vscalefpd:            // Scale Packed Float64 Values With Float64 Values
		case STARS_NN_vscalefsd:            // Scale Scalar Float64 Values With Float64 Values
		case STARS_NN_vscalefps:            // Scale Packed Float32 Values With Float32 Values
		case STARS_NN_vscalefss:            // Scale Scalar Float32 Value With Float32 Value
		case STARS_NN_vscatterdps:          // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices
		case STARS_NN_vscatterdpd:          // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices
		case STARS_NN_vscatterqps:          // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices
		case STARS_NN_vscatterqpd:          // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices

		case STARS_NN_vexp2pd:              // Approximation to the Exponential 2^x of Packed Double-Precision Floating-Point Values with Less Than 2^-23 Relative Error
		case STARS_NN_vexp2ps:              // Approximation to the Exponential 2^x of Packed Single-Precision Floating-Point Values with Less Than 2^-23 Relative Error
		case STARS_NN_vrcp28pd:             // Approximation to the Reciprocal of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error
		case STARS_NN_vrcp28sd:             // Approximation to the Reciprocal of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error
		case STARS_NN_vrcp28ps:             // Approximation to the Reciprocal of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error
		case STARS_NN_vrcp28ss:             // Approximation to the Reciprocal of Scalar Single-Precision Floating-Point Value with Less Than 2^-28 Relative Error
		case STARS_NN_vrsqrt28pd:           // Approximation to the Reciprocal Square Root of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error
		case STARS_NN_vrsqrt28sd:           // Approximation to the Reciprocal Square Root of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error
		case STARS_NN_vrsqrt28ps:           // Approximation to the Reciprocal Square Root of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error
		case STARS_NN_vrsqrt28ss:           // Approximation to the Reciprocal Square Root of Scalar Single-Precision Floating-Point Value with Less Than 2^-28 Relative Error

		case STARS_NN_vgatherpf0dps:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint
		case STARS_NN_vgatherpf0qps:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint
		case STARS_NN_vgatherpf0dpd:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint
		case STARS_NN_vgatherpf0qpd:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint
		case STARS_NN_vgatherpf1dps:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint
		case STARS_NN_vgatherpf1qps:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint
		case STARS_NN_vgatherpf1dpd:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint
		case STARS_NN_vgatherpf1qpd:        // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint
		case STARS_NN_vscatterpf0dps:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write
		case STARS_NN_vscatterpf0qps:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write
		case STARS_NN_vscatterpf0dpd:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write
		case STARS_NN_vscatterpf0qpd:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write
		case STARS_NN_vscatterpf1dps:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write
		case STARS_NN_vscatterpf1qps:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write
		case STARS_NN_vscatterpf1dpd:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write
		case STARS_NN_vscatterpf1qpd:       // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write
			return false;
			break;

		// AVX-512 comparison pseudo-ops

		case STARS_NN_vpcmpltd:             // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpled:             // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpneqd:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnltd:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnled:            // Compare Packed Integer Values into Mask

		case STARS_NN_vpcmpequd:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpltud:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpleud:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnequd:           // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnltud:           // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnleud:           // Compare Packed Integer Values into Mask

		case STARS_NN_vpcmpltq:             // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpleq:             // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpneqq:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnltq:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnleq:            // Compare Packed Integer Values into Mask

		case STARS_NN_vpcmpequq:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpltuq:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpleuq:            // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnequq:           // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnltuq:           // Compare Packed Integer Values into Mask
		case STARS_NN_vpcmpnleuq:           // Compare Packed Integer Values into Mask
			return false;
			break;

		// Opmask instructions

		case STARS_NN_kaddw:                // ADD Two Masks
		case STARS_NN_kaddb:                // ADD Two Masks
		case STARS_NN_kaddq:                // ADD Two Masks
		case STARS_NN_kaddd:                // ADD Two Masks
		case STARS_NN_kandw:                // Bitwise Logical AND Masks
		case STARS_NN_kandb:                // Bitwise Logical AND Masks
		case STARS_NN_kandq:                // Bitwise Logical AND Masks
		case STARS_NN_kandd:                // Bitwise Logical AND Masks
		case STARS_NN_kandnw:               // Bitwise Logical AND NOT Masks
		case STARS_NN_kandnb:               // Bitwise Logical AND NOT Masks
		case STARS_NN_kandnq:               // Bitwise Logical AND NOT Masks
		case STARS_NN_kandnd:               // Bitwise Logical AND NOT Masks
		case STARS_NN_kmovw:                // Move from and to Mask Registers
		case STARS_NN_kmovb:                // Move from and to Mask Registers
		case STARS_NN_kmovq:                // Move from and to Mask Registers
		case STARS_NN_kmovd:                // Move from and to Mask Registers
		case STARS_NN_kunpckbw:             // Unpack for Mask Registers
		case STARS_NN_kunpckwd:             // Unpack for Mask Registers
		case STARS_NN_kunpckdq:             // Unpack for Mask Registers
		case STARS_NN_knotw:                // NOT Mask Register
		case STARS_NN_knotb:                // NOT Mask Register
		case STARS_NN_knotq:                // NOT Mask Register
		case STARS_NN_knotd:                // NOT Mask Register
		case STARS_NN_korw:                 // Bitwise Logical OR Masks
		case STARS_NN_korb:                 // Bitwise Logical OR Masks
		case STARS_NN_korq:                 // Bitwise Logical OR Masks
		case STARS_NN_kord:                 // Bitwise Logical OR Masks
		case STARS_NN_kortestw:             // OR Masks And Set Flags
		case STARS_NN_kortestb:             // OR Masks And Set Flags
		case STARS_NN_kortestq:             // OR Masks And Set Flags
		case STARS_NN_kortestd:             // OR Masks And Set Flags
		case STARS_NN_kshiftlw:             // Shift Left Mask Registers
		case STARS_NN_kshiftlb:             // Shift Left Mask Registers
		case STARS_NN_kshiftlq:             // Shift Left Mask Registers
		case STARS_NN_kshiftld:             // Shift Left Mask Registers
		case STARS_NN_kshiftrw:             // Shift Right Mask Registers
		case STARS_NN_kshiftrb:             // Shift Right Mask Registers
		case STARS_NN_kshiftrq:             // Shift Right Mask Registers
		case STARS_NN_kshiftrd:             // Shift Right Mask Registers
		case STARS_NN_kxnorw:               // Bitwise Logical XNOR Masks
		case STARS_NN_kxnorb:               // Bitwise Logical XNOR Masks
		case STARS_NN_kxnorq:               // Bitwise Logical XNOR Masks
		case STARS_NN_kxnord:               // Bitwise Logical XNOR Masks
		case STARS_NN_ktestw:               // Packed Bit Test Masks and Set Flags
		case STARS_NN_ktestb:               // Packed Bit Test Masks and Set Flags
		case STARS_NN_ktestq:               // Packed Bit Test Masks and Set Flags
		case STARS_NN_ktestd:               // Packed Bit Test Masks and Set Flags
		case STARS_NN_kxorw:                // Bitwise Logical XOR Masks
		case STARS_NN_kxorb:                // Bitwise Logical XOR Masks
		case STARS_NN_kxorq:                // Bitwise Logical XOR Masks
		case STARS_NN_kxord:                // Bitwise Logical XOR Masks
			return false;
			break;

		// SHA Extensions

		case STARS_NN_sha1rnds4:            // Perform Four Rounds of SHA1 Operation
		case STARS_NN_sha1nexte:            // Calculate SHA1 State Variable E after Four Rounds
		case STARS_NN_sha1msg1:             // Perform an Intermediate Calculation for the Next Four SHA1 Message Dwords
		case STARS_NN_sha1msg2:             // Perform a Final Calculation for the Next Four SHA1 Message Dwords
		case STARS_NN_sha256rnds2:          // Perform Two Rounds of SHA256 Operation
		case STARS_NN_sha256msg1:           // Perform an Intermediate Calculation for the Next Four SHA256 Message Dwords
		case STARS_NN_sha256msg2:           // Perform a Final Calculation for the Next Four SHA256 Message Dwords
			return false;
			break;

		// Intel Software Guard Extensions

		case STARS_NN_encls:                // Execute an Enclave System Function of Specified Leaf Number
		case STARS_NN_enclu:                // Execute an Enclave User Function of Specified Leaf Number
			return false;
			break;

		// AMD XOP

		case STARS_NN_vfrczpd:              // Extract Fraction Packed Double-Precision Floating-Point
		case STARS_NN_vfrczps:              // Extract Fraction Packed Single-Precision Floating-Point
		case STARS_NN_vfrczsd:              // Extract Fraction Scalar Double-Precision Floating-Point
		case STARS_NN_vfrczss:              // Extract Fraction Scalar Single-Precision Floating Point
		case STARS_NN_vpcmov:               // Vector Conditional Moves
		case STARS_NN_vpcomb:               // Compare Vector Signed Bytes
		case STARS_NN_vpcomd:               // Compare Vector Signed Doublewords
		case STARS_NN_vpcomq:               // Compare Vector Signed Quadwords
		case STARS_NN_vpcomub:              // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomud:              // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomuq:              // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomuw:              // Compare Vector Unsigned Words
		case STARS_NN_vpcomw:               // Compare Vector Signed Words
		case STARS_NN_vpermil2pd:           // Permute Two-Source Double-Precision Floating-Point Values
		case STARS_NN_vpermil2ps:           // Permute Two-Source Single-Precision Floating-Point Values
		case STARS_NN_vphaddbd:             // Packed Horizontal Add Signed Byte to Signed Doubleword
		case STARS_NN_vphaddbq:             // Packed Horizontal Add Signed Byte to Signed Quadword
		case STARS_NN_vphaddbw:             // Packed Horizontal Add Signed Byte to Signed Word
		case STARS_NN_vphadddq:             // Packed Horizontal Add Signed Doubleword to Signed Quadword
		case STARS_NN_vphaddubd:            // Packed Horizontal Add Unsigned Byte to Doubleword
		case STARS_NN_vphaddubq:            // Packed Horizontal Add Unsigned Byte to Quadword
		case STARS_NN_vphaddubw:            // Packed Horizontal Add Unsigned Byte to Word
		case STARS_NN_vphaddudq:            // Packed Horizontal Add Unsigned Doubleword to Quadword
		case STARS_NN_vphadduwd:            // Packed Horizontal Add Unsigned Word to Doubleword
		case STARS_NN_vphadduwq:            // Packed Horizontal Add Unsigned Word to Quadword
		case STARS_NN_vphaddwd:             // Packed Horizontal Add Signed Word to Signed Doubleword
		case STARS_NN_vphaddwq:             // Packed Horizontal Add Signed Word to Signed Quadword
		case STARS_NN_vphsubbw:             // Packed Horizontal Subtract Signed Byte to Signed Word
		case STARS_NN_vphsubdq:             // Packed Horizontal Subtract Signed Doubleword to Signed Quadword
		case STARS_NN_vphsubwd:             // Packed Horizontal Subtract Signed Word to Signed Doubleword
		case STARS_NN_vpmacsdd:             // Packed Multiply Accumulate Signed Doubleword to Signed Doubleword
		case STARS_NN_vpmacsdqh:            // Packed Multiply Accumulate Signed High Doubleword to Signed Quadword
		case STARS_NN_vpmacsdql:            // Packed Multiply Accumulate Signed Low Doubleword to Signed Quadword
		case STARS_NN_vpmacssdd:            // Packed Multiply Accumulate Signed Doubleword to Signed Doubleword with Saturation
		case STARS_NN_vpmacssdqh:           // Packed Multiply Accumulate Signed High Doubleword to Signed Quadword with Saturation
		case STARS_NN_vpmacssdql:           // Packed Multiply Accumulate Signed Low Doubleword to Signed Quadword with Saturation
		case STARS_NN_vpmacsswd:            // Packed Multiply Accumulate Signed Word to Signed Doubleword with Saturation
		case STARS_NN_vpmacssww:            // Packed Multiply Accumulate Signed Word to Signed Word with Saturation
		case STARS_NN_vpmacswd:             // Packed Multiply Accumulate Signed Word to Signed Doubleword
		case STARS_NN_vpmacsww:             // Packed Multiply Accumulate Signed Word to Signed Word
		case STARS_NN_vpmadcsswd:           // Packed Multiply: Add and Accumulate Signed Word to Signed Doubleword with Saturation
		case STARS_NN_vpmadcswd:            // Packed Multiply Add and Accumulate Signed Word to Signed Doubleword
		case STARS_NN_vpperm:               // Packed Permute Bytes
		case STARS_NN_vprotb:               // Packed Rotate Bytes
		case STARS_NN_vprotd:               // Packed Rotate Doublewords
		case STARS_NN_vprotq:               // Packed Rotate Quadwords
		case STARS_NN_vprotw:               // Packed Rotate Words
		case STARS_NN_vpshab:               // Packed Shift Arithmetic Bytes
		case STARS_NN_vpshad:               // Packed Shift Arithmetic Doublewords
		case STARS_NN_vpshaq:               // Packed Shift Arithmetic Quadwords
		case STARS_NN_vpshaw:               // Packed Shift Arithmetic Words
		case STARS_NN_vpshlb:               // Packed Shift Logical Bytes
		case STARS_NN_vpshld:               // Packed Shift Logical Doublewords
		case STARS_NN_vpshlq:               // Packed Shift Logical Quadwords
		case STARS_NN_vpshlw:               // Packed Shift Logical Words
			return false;
			break;

		// AMP XOP comparison pseudo-ops

		case STARS_NN_vpcomltb:             // Compare Vector Signed Bytes
		case STARS_NN_vpcomleb:             // Compare Vector Signed Bytes
		case STARS_NN_vpcomgtb:             // Compare Vector Signed Bytes
		case STARS_NN_vpcomgeb:             // Compare Vector Signed Bytes
		case STARS_NN_vpcomeqb:             // Compare Vector Signed Bytes
		case STARS_NN_vpcomneqb:            // Compare Vector Signed Bytes
		case STARS_NN_vpcomfalseb:          // Compare Vector Signed Bytes
		case STARS_NN_vpcomtrueb:           // Compare Vector Signed Bytes

		case STARS_NN_vpcomltw:             // Compare Vector Signed Words
		case STARS_NN_vpcomlew:             // Compare Vector Signed Words
		case STARS_NN_vpcomgtw:             // Compare Vector Signed Words
		case STARS_NN_vpcomgew:             // Compare Vector Signed Words
		case STARS_NN_vpcomeqw:             // Compare Vector Signed Words
		case STARS_NN_vpcomneqw:            // Compare Vector Signed Words
		case STARS_NN_vpcomfalsew:          // Compare Vector Signed Words
		case STARS_NN_vpcomtruew:           // Compare Vector Signed Words

		case STARS_NN_vpcomltd:             // Compare Vector Signed Doublewords
		case STARS_NN_vpcomled:             // Compare Vector Signed Doublewords
		case STARS_NN_vpcomgtd:             // Compare Vector Signed Doublewords
		case STARS_NN_vpcomged:             // Compare Vector Signed Doublewords
		case STARS_NN_vpcomeqd:             // Compare Vector Signed Doublewords
		case STARS_NN_vpcomneqd:            // Compare Vector Signed Doublewords
		case STARS_NN_vpcomfalsed:          // Compare Vector Signed Doublewords
		case STARS_NN_vpcomtrued:           // Compare Vector Signed Doublewords

		case STARS_NN_vpcomltq:             // Compare Vector Signed Quadwords
		case STARS_NN_vpcomleq:             // Compare Vector Signed Quadwords
		case STARS_NN_vpcomgtq:             // Compare Vector Signed Quadwords
		case STARS_NN_vpcomgeq:             // Compare Vector Signed Quadwords
		case STARS_NN_vpcomeqq:             // Compare Vector Signed Quadwords
		case STARS_NN_vpcomneqq:            // Compare Vector Signed Quadwords
		case STARS_NN_vpcomfalseq:          // Compare Vector Signed Quadwords
		case STARS_NN_vpcomtrueq:           // Compare Vector Signed Quadwords

		case STARS_NN_vpcomltub:            // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomleub:            // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomgtub:            // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomgeub:            // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomequb:            // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomnequb:           // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomfalseub:         // Compare Vector Unsigned Bytes
		case STARS_NN_vpcomtrueub:          // Compare Vector Unsigned Bytes

		case STARS_NN_vpcomltuw:            // Compare Vector Unsigned Words
		case STARS_NN_vpcomleuw:            // Compare Vector Unsigned Words
		case STARS_NN_vpcomgtuw:            // Compare Vector Unsigned Words
		case STARS_NN_vpcomgeuw:            // Compare Vector Unsigned Words
		case STARS_NN_vpcomequw:            // Compare Vector Unsigned Words
		case STARS_NN_vpcomnequw:           // Compare Vector Unsigned Words
		case STARS_NN_vpcomfalseuw:         // Compare Vector Unsigned Words
		case STARS_NN_vpcomtrueuw:          // Compare Vector Unsigned Words

		case STARS_NN_vpcomltud:            // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomleud:            // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomgtud:            // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomgeud:            // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomequd:            // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomnequd:           // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomfalseud:         // Compare Vector Unsigned Doublewords
		case STARS_NN_vpcomtrueud:          // Compare Vector Unsigned Doublewords

		case STARS_NN_vpcomltuq:            // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomleuq:            // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomgtuq:            // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomgeuq:            // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomequq:            // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomnequq:           // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomfalseuq:         // Compare Vector Unsigned Quadwords
		case STARS_NN_vpcomtrueuq:          // Compare Vector Unsigned Quadwords
			return false;
			break;

		// AMD Excavator

		case STARS_NN_monitorx:             // Setup Monitor Address
		case STARS_NN_mwaitx:               // Monitor Wait with Timeout
			return false;
			break;

		// AMD Zen

		case STARS_NN_clzero:               // Zero out 64 byte cache
			return false;
			break;

		// Intel Processor Trace

		case STARS_NN_ptwrite:              // Write Data to a Processor Trace Packet
			return false;
			break;

		// new Intel AVX-512 instructions (December 2016)

		case STARS_NN_v4fmaddps:            // Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations)
		case STARS_NN_v4fnmaddps:           // Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations)
		case STARS_NN_v4fmaddss:            // Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations)
		case STARS_NN_v4fnmaddss:           // Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations)
		case STARS_NN_vp4dpwssd:            // Dot Product of Signed Words with Dword Accumulation (4-iterations)
		case STARS_NN_vp4dpwssds:           // Dot Product of Signed Words with Dword Accumulation and Saturation (4-iterations)
		case STARS_NN_vpopcntd:             // Return the Count of Number of Bits Set to 1 in DWORD
		case STARS_NN_vpopcntq:             // Return the Count of Number of Bits Set to 1 in QWORD
			return false;
			break;

		// Read Processor ID

		case STARS_NN_rdpid:                // Read Processor ID
			return false;
			break;

		// Invoke VM function

		case STARS_NN_vmfunc:               // Invoke VM function
			return false;
			break;

		// Control-flow Enforcement

		case STARS_NN_incsspd:              // Increment Shadow Stack Pointer (by 4)
		case STARS_NN_incsspq:              // Increment Shadow Stack Pointer (by 8)
		case STARS_NN_rdsspd:               // Read (low 32 bits of) Shadow Stack Pointer
		case STARS_NN_rdsspq:               // Read Shadow Stack Pointer
		case STARS_NN_saveprevssp:          // Save Previous Shadow Stack Pointer
		case STARS_NN_rstorssp:             // Restore saved Shadow Stack Pointer
		case STARS_NN_wrssd:                // Write (4 bytes) to shadow stack
		case STARS_NN_wrssq:                // Write (8 bytes) to shadow stack
		case STARS_NN_wrussd:               // Write (4 bytes) to User Shadow Stack
		case STARS_NN_wrussq:               // Write (8 bytes) to User Shadow Stack
		case STARS_NN_setssbsy:             // Mark Shadow Stack Busy
		case STARS_NN_clrssbsy:             // Clear Shadow Stack Busy Flag
		case STARS_NN_endbr64:              // Terminate an Indirect Branch in 64-bit Mode
		case STARS_NN_endbr32:              // Terminate an Indirect Branch in 32-bit and Compatibility Mode
			return false;
			break;

		default:
			SMP_msg("ERROR: Unknown instruction opcode at %llx : %s\n", (unsigned long long) this->GetAddr(),
				DisAsmText.GetDisAsm(this->GetAddr()));
			return false;
			break;
	} // end switch on opcode
	return true;
} // end SMPInstr::BuildRTL()

// Iterate through all reg transfers and call SyncRTLDefUse for each.
void SMPInstr::SyncAllRTs(bool UseFP, STARS_sval_t FPDelta) {
	for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) {
		this->SyncRTLDefUse(this->RTL.GetRT(index), UseFP, FPDelta);
	}
	return;
} // end of SMPInstr:SyncAllRTs()

// Ensure that each operand of the RTL is found in the appropriate DEF or USE list.
void SMPInstr::SyncRTLDefUse(SMPRegTransfer *CurrRT, bool UseFP, STARS_sval_t FPDelta) {
	// The ExtraKills are almost never represented in the DEF 
	//  lists. When they are, they are added in MDFixupDefUseLists(), so we ignore them here.

	// The only DEFs should come from left operands of SMP_ASSIGN operators, i.e. the effects
	//  of register transfers.
	STARSOpndTypePtr LeftOp, RightOp;
	set<DefOrUse, LessDefUse>::iterator CurrDef, CurrUse;
	bool DebugFlag = false;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
	DebugFlag |= (0 == strcmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName()));
#endif

#if SMP_VERBOSE_DEBUG_BUILD_RTL
	if (DebugFlag) {
		SMP_msg("SyncRTLDefUse entered. Dump of USE list:\n");
		this->Uses.Dump();
	}
#endif

	LeftOp = CurrRT->GetLeftOperand();
	if (SMP_ASSIGN == CurrRT->GetOperator()) {
		assert(! LeftOp->IsVoidOp());
		assert(! LeftOp->IsImmedOp());
		LeftOp->CleanOpndEncoding();
		CurrDef = this->Defs.FindRef(LeftOp);
		if (CurrDef == this->GetLastDef() && !LeftOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL
			SMP_msg("WARNING: DEF not found for SMP_ASSIGN in %s ; added op:", DisAsmText.GetDisAsm(this->GetAddr()));
			PrintOperand(LeftOp);
			SMP_msg("\n");
#endif
			this->Defs.SetRef(LeftOp, CurrRT->GetOperatorType());
		}
	}
	else { // not SMP_ASSIGN; left operand should be a USE
		if (! ((nullptr == LeftOp) || LeftOp->IsVoidOp())) {
			CurrUse = this->Uses.FindRef(LeftOp);
			if (CurrUse == this->GetLastUse()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: USE not found for ");
				PrintOperand(LeftOp);
				SMP_msg(" in %s ; added\n", DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				this->Uses.SetRef(LeftOp);
			}
		}
	}
	if (!CurrRT->HasRightSubTree()) {
		RightOp = CurrRT->GetRightOperand();  // right operand should be a USE
		if (!((nullptr == RightOp) || RightOp->IsVoidOp())) {
			RightOp->CleanOpndEncoding();
			CurrUse = this->Uses.FindRef(RightOp);
			if (CurrUse == this->GetLastUse()) {
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
				SMP_msg("WARNING: USE not found for ");
				PrintOperand(RightOp);
				SMP_msg(" in %s ; added\n", DisAsmText.GetDisAsm(this->GetAddr()));
#endif
				this->Uses.SetRef(RightOp);
			}
		}
	}
	else { // recurse into right subtree
		this->SyncRTLDefUse(CurrRT->GetRightTree(), UseFP, FPDelta);
	}

	// Guard operands can only be USEs.
	SMPGuard *GuardExpr = CurrRT->GetGuard();
	if (NULL != GuardExpr) {
		LeftOp = GuardExpr->GetLeftOperand();
		if ((!((nullptr == LeftOp) || LeftOp->IsVoidOp())) && (!LeftOp->IsImmedOp())) {
			LeftOp->CleanOpndEncoding();
			CurrUse = this->Uses.FindRef(LeftOp);
			if (CurrUse == this->GetLastUse()) {
				this->Uses.SetRef(LeftOp);
			}
		}
		RightOp = GuardExpr->GetRightOperand();
		if ((!((nullptr == RightOp) || RightOp->IsVoidOp())) && (!RightOp->IsImmedOp())) {
			RightOp->CleanOpndEncoding();
			CurrUse = this->Uses.FindRef(RightOp);
			if (CurrUse == this->GetLastUse()) {
				this->Uses.SetRef(RightOp);
			}
		}
	}
	return;
} // end of SMPInstr::SyncRTLDefUse()

// Get rid of unnecessary SIB byte encodings
void SMPInstr::CleanSIBEncoding(STARSOpndTypePtr &RTLOp) {
	if ((nullptr != RTLOp) && RTLOp->IsMemOp()) {
		int BaseReg;
		int IndexReg;
		uint16_t ScaleFactor;
		STARS_ea_t offset;
		MDExtractAddressFields(RTLOp, BaseReg, IndexReg, ScaleFactor, offset);
		if (RTLOp->HasSIBByte()) {
			if ((IndexReg == STARS_x86_R_none) && (BaseReg != STARS_x86_R_none)) {
				// No need for a SIB byte if just base reg or base reg + offset.
				RTLOp->ClearSIB();
				RTLOp->SetReg((STARS_regnum_t) BaseReg);
			}
		}
		if ((0 == offset) && RTLOp->IsMemDisplacementOp()) {
			RTLOp->SetTypeToMemNoDisplacement();
		}
	}
	return;
} // end of SMPInstr::CleanSIBEncoding()

// Update the memory source operands to have the new type from profiling info.
void SMPInstr::UpdateMemLoadTypes(SMPOperandType newType) {
	bool MemSrc = false;
   STARSOpndTypePtr Opnd;
	set<DefOrUse, LessDefUse>::iterator UseIter;
	for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
		Opnd = UseIter->GetOp();
		MemSrc = Opnd->IsMemOp();
		if (MemSrc) {
			SMPOperandType type = UseIter->GetType();

			assert(newType == (NUMERIC|PROF_BASE));
			if (type == UNINIT) {
				this->SetUseType(Opnd, newType);
				break;
			}
			else if (type >= POINTER) {
				this->SetUseType(Opnd, (SMPOperandType)(UNKNOWN|PROF_BASE));
				break;
			}
		}
	}
	return ;
} // end of SMPInstr::UpdateMemLoadTypes()

// Return true if we have register DefOp += ImmOp.
bool SMPInstr::MDIsAddImmediateToReg(STARSOpndTypePtr &DefOp, STARSOpndTypePtr &ImmOp) {
	bool FoundAddImmed = false;
	bool FoundImmed = false;
	bool FoundRegUse = false;

	if (STARS_NN_add == this->GetIDAOpcode()) {
		set<DefOrUse, LessDefUse>::iterator UseIter = this->GetFirstUse();
		while (UseIter != this->GetLastUse()) {
			STARSOpndTypePtr UseOp = UseIter->GetOp();
			if (UseOp->IsImmedOp()) {
				ImmOp = UseOp;
				FoundImmed = true;
			}
			else if (UseOp->IsRegOp()) {
				set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef();
				STARSOpndTypePtr TempDefOp = DefIter->GetOp();
				if (!TempDefOp->IsRegOp()) {
					return false;
				}
				if (MDLessReg(UseOp->GetReg(), TempDefOp->GetReg()) 
				|| MDLessReg(TempDefOp->GetReg(), UseOp->GetReg())) {
					return false;
				}
				// If we make it here, we have the same register DEFed as we found USEd.
				DefOp = TempDefOp;
				FoundRegUse = true;
			}
			++UseIter;
		}
		FoundAddImmed = (FoundImmed && FoundRegUse);
	}
	return FoundAddImmed;
} // end of SMPInstr::MDIsAddImmediateToReg()