/*
 * SMPInstr.h - <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 by Zephyr Software LLC
 * e-mail: {clc,jwd}@zephyr-software.com
 * URL   : http://www.zephyr-software.com/
 *
 */

#ifndef SMPINSTR_H
#define SMPINSTR_H 1

// SMPInstr.h
//
// This header defines the interfaces needed for analyzing instructions.

#include <cstddef>
#include <string>
#include <bitset>

#include <pro.h>
#include <ida.hpp>
#include <ua.hpp>

#include "SMPDataFlowAnalysis.h"

using namespace std;

// Value to signal error in computing stack pointer alteration by instruction or RTL.
#define SMP_STACK_DELTA_ERROR_CODE  0xebfaf0fd
// Value to signal that stack pointer is bitwise ANDed to align it; unknown delta that can
//  probably be ignored.
#define SMP_STACK_POINTER_BITWISE_AND_CODE 0xebeae0ed

enum SMPoperator {
	SMP_NULL_OPERATOR = 0,
	SMP_CALL,  // CALL instruction
	SMP_INPUT,  // input from port
	SMP_OUTPUT, // output to port
	SMP_ADDRESS_OF, // take effective address
	SMP_U_LEFT_SHIFT, // unsigned left shift
	SMP_S_LEFT_SHIFT, // signed left shift
	SMP_U_RIGHT_SHIFT, // unsigned right shift
	SMP_S_RIGHT_SHIFT, // signed right shift
	SMP_ROTATE_LEFT,
	SMP_ROTATE_LEFT_CARRY, // rotate left through carry
	SMP_ROTATE_RIGHT,
	SMP_ROTATE_RIGHT_CARRY, // rotate right through carry
	SMP_DECREMENT,
	SMP_INCREMENT,
	SMP_ADD,
	SMP_ADD_CARRY,   // add with carry
	SMP_SUBTRACT,
	SMP_SUBTRACT_BORROW,  // subtract with 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, // unary operator
	SMP_BITWISE_XOR,
	SMP_BITWISE_AND_NOT,
	SMP_NEGATE,    // unary negation
	SMP_S_COMPARE, // signed compare (subtraction-based)
	SMP_U_COMPARE, // unsigned compare (AND-based)
	SMP_GENERAL_COMPARE, // comparisons of packed data, strings, signed, unsigned depending on control words
	SMP_LESS_THAN, // boolean test operators
	SMP_GREATER_THAN,
	SMP_LESS_EQUAL,
	SMP_GREATER_EQUAL,
	SMP_EQUAL,
	SMP_NOT_EQUAL,
	SMP_LOGICAL_AND,
	SMP_LOGICAL_OR,
	SMP_UNARY_NUMERIC_OPERATION,  // miscellaneous; produces NUMERIC result
	SMP_BINARY_NUMERIC_OPERATION,  // miscellaneous; produces NUMERIC result
	SMP_SYSTEM_OPERATION,   // for instructions such as CPUID, RDTSC, etc.; NUMERIC
	SMP_UNARY_FLOATING_ARITHMETIC,  // all the same to our type system; all NUMERIC
	SMP_BINARY_FLOATING_ARITHMETIC,  // all the same to our type system; all NUMERIC
	SMP_REVERSE_SHIFT_U, // Shift right operand by bit count in left operand
	SMP_SHUFFLE, // Shuffle bytes, words, etc. within destination operation per source mask
	SMP_COMPARE_EQ_AND_SET, // Compare for equality and set fields to all 1's or all 0's
	SMP_COMPARE_NE_AND_SET, // Compare for not-equal and set fields to all 1's or all 0's
	SMP_COMPARE_GT_AND_SET, // Compare for greater-than and set fields to all 1's or all 0's
	SMP_COMPARE_GE_AND_SET, // Compare for greater-than-or-equal and set fields to all 1's or all 0's
	SMP_COMPARE_LT_AND_SET, // Compare for less-than and set fields to all 1's or all 0's
	SMP_COMPARE_LE_AND_SET, // Compare for less-than-or-equal and set fields to all 1's or all 0's
	SMP_PACK_S,  // Pack operands into extended-precision register, signed saturation for loss of precision
	SMP_PACK_U,  // Pack operands into extended-precision register, unsigned saturation for loss of precision
	SMP_AVERAGE_U, // Average of unsigned operands
	SMP_MULTIPLY_AND_ADD, // multiply and add (or multiply and accumulate)
	SMP_SUM_OF_DIFFS, // sum over two vectors of absolute values of differences of their elements
	SMP_MAX_S, // dest := signed_max(dest, src)
	SMP_MAX_U, // dest := unsigned_max(dest, src)
	SMP_MIN_S, // dest := signed_min(dest, src)
	SMP_MIN_U, // dest := unsigned_min(dest, src)
	SMP_ABSOLUTE_VALUE, // take absolute value
	SMP_CONVERT_INT_TO_FP, // convert integer to floating point
	SMP_CONVERT_FP_TO_INT, // convert floating point to integer
	SMP_CREATE_MASK, // Create AND-mask from operand and byte/word/dword position # in immediate
	SMP_INTERLEAVE, // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
	SMP_CONCATENATE,     // extended-precision concatenation; NUMERIC
	SMP_EXTRACT_ZERO_EXTEND, // Extract sub-reg and zero-extend to reg length
	SMP_ENCRYPTION_OPERATION, // encryption or decryption bit manipulation operation
	SMP_SIGNAL   // signal or raise exception
}; // end enum SMPoperator
#define LAST_SMP_OPERATOR SMP_SIGNAL

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

// Should we keep track of what the operator type was before profiler
//  information was applied? (Memory usage is affected)
#define SMP_TRACK_NONSPEC_OPER_TYPE 0

struct RTLoperator {
	SMPoperator oper;
	SMPOperandType type;
#if SMP_TRACK_NONSPEC_OPER_TYPE
	SMPOperandType NonSpeculativeType;
#endif
};

// Class for a guard expression in an RTL
class SMPGuard {
public:
	// Constructors
	SMPGuard(void);
	// Get methods
	inline SMPoperator GetOperator(void) { return GuardOp; };
	inline op_t &GetLeftOperand(void) { return LeftOperand; };
	inline op_t &GetRightOperand(void) { return RightOperand; };
	// Set methods
	inline void SetOperator(SMPoperator op) { GuardOp = op; };
	inline void SetLeftOperand(op_t Left) { LeftOperand = Left; };
	inline void SetRightOperand(op_t Right) { RightOperand = Right; };
	// Printing methods
	void Dump(void) const;
private:
	op_t LeftOperand;
	op_t RightOperand;
	SMPoperator GuardOp;
}; // end class SMPGuard

// Masks to set bits to use as booleans1 in SMPRegTransfer.
#define RTL_SET_RIGHT_SUBTREE 0x01
#define RTL_SET_TYPE_INFERENCE_COMPLETE 0x02
#define RTL_SET_UNUSED1 0x04
#define RTL_SET_UNUSED2 0x08
#define RTL_SET_UNUSED3 0x10
#define RTL_SET_UNUSED4 0x20
#define RTL_SET_UNUSED5 0x40
#define RTL_SET_UNUSED6 0x80
#define RTL_RESET_RIGHT_SUBTREE 0xfe
#define RTL_RESET_TYPE_INFERENCE_COMPLETE 0xfd
#define RTL_RESET_UNUSED1 0xfb
#define RTL_RESET_UNUSED2 0xf7
#define RTL_RESET_UNUSED3 0xef
#define RTL_RESET_UNUSED4 0xdf
#define RTL_RESET_UNUSED5 0xbf
#define RTL_RESET_UNUSED6 0x7f

// Classes for register transfers and register transfer lists (RTLs)
class SMPRegTransfer {
public:
	// Constructors and destructors
	SMPRegTransfer(void);
	~SMPRegTransfer();
	// Get methods
	inline SMPoperator GetOperator(void) const { return RTop.oper; };
	inline SMPOperandType GetOperatorType(void) const { return RTop.type; };
	op_t GetLeftOperand(void) const;
	op_t GetRightOperand(void) const;
	inline SMPRegTransfer *GetRightTree(void) const { return RightRT; };
	inline SMPGuard *GetGuard(void) const { return Guard; };
	// Set methods
	inline void SetOperator(SMPoperator op) { RTop.oper = op; };
	void SetOperatorType(SMPOperandType OpType, const SMPInstr* instr);
	inline void SetLeftOperand(op_t Left) { LeftOperand = Left; };
	inline void SetRightOperand(op_t Right) { RightOperand = Right; booleans1 &= RTL_RESET_RIGHT_SUBTREE; };
	inline void SetRightTree(SMPRegTransfer *RightTree) { RightRT = RightTree; booleans1 |= RTL_SET_RIGHT_SUBTREE; };
	inline void SetGuard(SMPGuard *NewGuard) { Guard = NewGuard; };
	inline void SetTypeInferenceComplete(void) { booleans1 |= RTL_SET_TYPE_INFERENCE_COMPLETE; };
	inline void SetParentInst(SMPInstr *Parent) { ParentInst = Parent; };
	// Query methods
	inline bool HasRightSubTree(void) const { return (booleans1 & RTL_SET_RIGHT_SUBTREE); };
	inline bool IsTypeInferenceComplete(void) const { return (booleans1 & RTL_SET_TYPE_INFERENCE_COMPLETE); };
	bool OperandTransfersValueToDef(op_t UseOp) const; // Does UseOp arithmetically affect the value of the NonFlagsDef for this RTL?
	// Printing methods
	void Dump(void) const;
	// Analysis methods
	bool IsAllocaRTL(void); // subtracts unknown value from stack pointer
	sval_t ComputeStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta);  // For instruction with operand-dependent effects on stack pointer.
private:
	SMPGuard *Guard;   // guard expression
	RTLoperator RTop;  // operator for the reg transfer
	op_t LeftOperand;  // operand to the left of the operator in the expression
	unsigned char booleans1; // hold boolean flags as bits
#if 0 // now part of booleans1
	bool RightSubTree; // Is right operand another tree (true) or an operand (false)?
	bool TypeInferenceComplete; // RTL tree at this root has all operands and operators typed
#endif
	op_t RightOperand; // valid only if RightSubTree is false
	SMPRegTransfer *RightRT; // right subtree, valid only if RightSubTree is true
	SMPInstr *ParentInst; // SMPInstr that contains this RegTransfer

	// Methods
	bool OperandTransfersHelper(op_t UseOp) const; // recursive helper for OperandTransfersValueToDef()
}; // end class SMPRegTransfer

#define SMP_RT_LIMIT  9    // how many register transfers could be in an RTL?
	// the x86 PUSHA and POPA opcodes need 9 RTLs each
class SMPRTL { // register transfer list
public:
	// Constructors and destructors.
	SMPRTL();
	~SMPRTL();
	// Get methods
	inline size_t GetCount(void) const { return RTCount; };
	SMPRegTransfer *GetRT(size_t index) const;
	// Set methods
	void push_back(SMPRegTransfer *NewEffect);
	// Printing methods
	void Dump(void) const;
	// Analysis methods.
	sval_t TotalStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta); // sum across all RTs in RTL
	// Public data for ease of use.
	vector<op_t> ExtraKills;    // kills other than left operands
private:
	size_t RTCount;
	SMPRegTransfer *RTvector[SMP_RT_LIMIT];
}; // end class SMPRTL

// Masks to set bits to use as booleans1 in SMPInstr.
#define INSTR_SET_GOODRTL 0x01
#define INSTR_SET_JUMP_TARGET 0x02
#define INSTR_SET_BLOCK_TERM 0x04
#define INSTR_SET_TAIL_CALL 0x08
#define INSTR_SET_COND_TAIL_CALL 0x10
#define INSTR_SET_CALL_USED_AS_JUMP 0x20
#define INSTR_SET_DIRECT_RECURSIVE_CALL 0x40
#define INSTR_SET_INTERRUPT 0x80
#define INSTR_RESET_GOODRTL 0xfe
#define INSTR_RESET_JUMP_TARGET 0xfd
#define INSTR_RESET_BLOCK_TERM 0xfb
#define INSTR_RESET_TAIL_CALL 0xf7
#define INSTR_RESET_COND_TAIL_CALL 0xef
#define INSTR_RESET_CALL_USED_AS_JUMP 0xdf
#define INSTR_RESET_DIRECT_RECURSIVE_CALL 0xbf
#define INSTR_RESET_INTERRUPT 0x7f

// Masks to set bits to use as booleans2 in SMPInstr.
#define INSTR_SET_NOP 0x01
#define INSTR_SET_REG_CLEAR_IDIOM 0x02
#define INSTR_SET_DEFS_FLAGS 0x04
#define INSTR_SET_USES_FLAGS 0x08
#define INSTR_SET_FAR_BRANCH_COMPUTED 0x10
#define INSTR_SET_BRANCHES_TO_FAR_CHUNK 0x20
#define INSTR_SET_INDIRECT_MEM_WRITE 0x40
#define INSTR_SET_INDIRECT_MEM_READ 0x80
#define INSTR_RESET_NOP 0xfe
#define INSTR_RESET_REG_CLEAR_IDIOM 0xfd
#define INSTR_RESET_DEFS_FLAGS 0xfb
#define INSTR_RESET_USES_FLAGS 0xf7
#define INSTR_RESET_FAR_BRANCH_COMPUTED 0xef
#define INSTR_RESET_BRANCHES_TO_FAR_CHUNK 0xdf
#define INSTR_RESET_INDIRECT_MEM_WRITE 0xbf
#define INSTR_RESET_INDIRECT_MEM_READ 0x7f

// Masks to set bits to use as booleans3 in SMPInstr.
#define INSTR_SET_LOAD_FROM_STACK 0x01
#define INSTR_SET_MULTIPLICATION_BITS_DISCARDED 0x02
#define INSTR_SET_TYPE_INFERENCE_COMPLETE 0x04
#define INSTR_SET_CATEGORY_INFERENCE_COMPLETE 0x08
#define INSTR_SET_DEFS_TYPED 0x10
#define INSTR_SET_USES_TYPED 0x20
#define INSTR_SET_MEM_DEF_USE_COMPUTED 0x40
#define INSTR_SET_FIRST_IN_BLOCK 0x80
#define INSTR_RESET_LOAD_FROM_STACK 0xfe
#define INSTR_RESET_MULTIPLICATION_BITS_DISCARDED 0xfd
#define INSTR_RESET_TYPE_INFERENCE_COMPLETE 0xfb
#define INSTR_RESET_CATEGORY_INFERENCE_COMPLETE 0xf7
#define INSTR_RESET_DEFS_TYPED 0xef
#define INSTR_RESET_USES_TYPED 0xdf
#define INSTR_RESET_MEM_DEF_USE_COMPUTED 0xbf
#define INSTR_RESET_FIRST_IN_BLOCK 0x7f

// Masks to set bits to use as booleans4 in SMPInstr.
#define INSTR_SET_DEFS_NORMALIZED 0x01
#define INSTR_SET_INST_REMOVED 0x02
#define INSTR_SET_STACK_ALIGNMENT 0x04
#define INSTR_SET_FP_NORMALIZED_TO_SP 0x08
#define INSTR_SET_ALLOCA 0x10
#define INSTR_SET_SUPPRESS_NUMERIC_ANNOTATION 0x20
#define INSTR_SET_HASH_OPERATION 0x40
#define INSTR_SET_UNUSED128 0x80
#define INSTR_RESET_DEFS_NORMALIZED 0xfe
#define INSTR_RESET_INST_REMOVED 0xfd
#define INSTR_RESET_STACK_ALIGNMENT 0xfb
#define INSTR_RESET_FP_NORMALIZED_TO_SP 0xf7
#define INSTR_RESET_ALLOCA 0xef
#define INSTR_RESET_SUPPRESS_NUMERIC_ANNOTATION 0xdf
#define INSTR_RESET_HASH_OPERATION 0xbf
#define INSTR_RESET_UNUSED128 0x7f

class SMPInstr {
public: 
	// Constructors and destructors
	SMPInstr(ea_t addr);
	~SMPInstr();

	// Operators
	int operator==(const SMPInstr &rhs) const;
	int operator<(const SMPInstr &rhs) const;
	int operator<=(const SMPInstr &rhs) const;
	int operator!=(const SMPInstr &rhs) const;

	// Get methods
	inline ea_t GetAddr(void) const { return address; };
	inline ea_t GetCallTarget(void) const { return CallTarget; };
	inline ea_t GetFarBranchTarget(void) const { return FarBranchTarget; };
	char *GetDisasm(void) const;
	inline SMPBasicBlock *GetBlock(void) const { return BasicBlock; };
	inline set<DefOrUse, LessDefUse>::iterator GetFirstUse(void) { return Uses.GetFirstRef(); };
	inline set<DefOrUse, LessDefUse>::iterator GetFirstDef(void) { return Defs.GetFirstRef(); };
	inline set<DefOrUse, LessDefUse>::iterator GetLastUse(void)  { return Uses.GetLastRef(); };
	inline set<DefOrUse, LessDefUse>::iterator GetLastDef(void)  { return Defs.GetLastRef(); };
	inline set<DefOrUse, LessDefUse>::iterator FindUse(op_t SearchOp) { return Uses.FindRef(SearchOp); };
	inline set<DefOrUse, LessDefUse>::iterator FindDef(op_t SearchOp) { return Defs.FindRef(SearchOp); };
	set<DefOrUse, LessDefUse>::iterator GetFirstNonFlagsDef(void);
	inline op_t GetMemDef(void) const { return DEFMemOp; };
	inline op_t GetMemUse(void) const { return USEMemOp; };
#if 0
	inline set<sval_t>::iterator GetFirstStackDelta(void) { return StackDeltaSet.begin(); };
	inline set<sval_t>::iterator GetLastStackDelta(void) { return StackDeltaSet.end(); };
#endif
	inline size_t NumUses(void) const { return Uses.GetSize(); };
	inline size_t NumDefs(void) const { return Defs.GetSize(); };
	inline insn_t GetCmd(void) const { return SMPcmd; };
	inline int GetOptType(void) const { return OptType; };
	inline SMPitype GetDataFlowType(void) const { return type; };
	op_t MDGetMemUseOp(void) const;
	op_t MDGetMemDefOp(void) const;
	op_t GetLeaMemUseOp(void); // return original Lea instruction [pseudo-]memory operand.
	inline op_t GetMoveSource(void) const { return MoveSource; };
	inline op_t GetUseOnlyAddSubOp(void) const { return AddSubSourceOp; };
	inline sval_t GetStackPtrOffset(void) const { return StackPtrOffset; };
	ea_t GetJumpTarget(void) const; // return BADADDR if not jump, target addr otherwise.

	// Set methods
	inline void SetGoodRTL(void) { booleans1 |= INSTR_SET_GOODRTL; };
	inline void ResetCondTailCall(void) { booleans1 &= INSTR_RESET_COND_TAIL_CALL; };
	inline void SetCondTailCall(void) { booleans1 |= INSTR_SET_COND_TAIL_CALL; };
	inline void SetBlock(SMPBasicBlock *Block) { BasicBlock = Block; };
	inline void SetCmd(insn_t cmd) { SMPcmd = cmd; return; };
	inline void SetTerminatesBlock(void) { booleans1 |= INSTR_SET_BLOCK_TERM; };
	void SetTailCall(void);
	void SetLeaMemUseOp(op_t NewLeaOperand); // record original Lea instruction [pseudo-]memory operand.
	inline void SetFirstInBlock(void) { 
		booleans3 |= INSTR_SET_FIRST_IN_BLOCK;
	};
	inline void SetInstRemove(void) { booleans4 |= INSTR_SET_INST_REMOVED; };
	inline void SetAllocaCall(void) { booleans4 |= INSTR_SET_ALLOCA; };
	inline void SetSuppressNumericAnnotation(void) { booleans4 |= INSTR_SET_SUPPRESS_NUMERIC_ANNOTATION; };
	inline void SetHashOperation(void) { booleans4 |= INSTR_SET_HASH_OPERATION; };
	inline void AddDef(op_t DefOp, SMPOperandType DefType, int DefSSANum) {
		Defs.SetRef(DefOp, DefType, DefSSANum);
	}
	void MDAddRegDef(ushort DefReg, bool Shown, SMPOperandType Type = UNINIT);
		// Add DEF of register if not already a DEF
	void MDAddRegUse(ushort UseReg, bool Shown, SMPOperandType Type = UNINIT);
		// Add USE of register if not already a USE
	set<DefOrUse, LessDefUse>::iterator SetUseSSA(op_t CurrOp, int SSASub);
	set<DefOrUse, LessDefUse>::iterator SetDefSSA(op_t CurrOp, int SSASub);
	set<DefOrUse, LessDefUse>::iterator SetUseType(op_t CurrOp, SMPOperandType CurrType);
	set<DefOrUse, LessDefUse>::iterator SetDefType(op_t CurrOp, SMPOperandType CurrType);
	set<DefOrUse, LessDefUse>::iterator SetDefMetadata(op_t CurrOp, SMPMetadataType Status);
	set<DefOrUse, LessDefUse>::iterator SetDefIndWrite(op_t CurrOp, bool IndWriteFlag);
	set<DefOrUse, LessDefUse>::iterator SetUseNoTruncate(op_t CurrOp, bool NoTruncFlag);
	set<DefOrUse, LessDefUse>::iterator SetDefNoOverflow(op_t DefOp, bool NoOverflowFlag);
	inline void EraseUse(set<DefOrUse, LessDefUse>::iterator UseIter)  { Uses.EraseRef(UseIter); };
	void SetRegDead(size_t RegNum); // Set the DeadRegsBitmap entry for Regnum.
	inline void SetStackPtrOffset(sval_t Delta) { StackPtrOffset = Delta; };

	// Query methods
	bool HasDestMemoryOperand(void); // Does instruction write to memory?
	bool HasSourceMemoryOperand(void); // Does instruction read from memory?
	inline bool HasIndirectMemoryWrite(void) const { return (booleans2 & INSTR_SET_INDIRECT_MEM_WRITE); };
	inline bool HasIndirectMemoryRead(void) const { return (booleans2 & INSTR_SET_INDIRECT_MEM_READ); };
	bool HasNegatedPtrUSE(void); // Does a USE have type NEGATEDPTR?
	bool IsSecondSrcOperandNumeric(flags_t F) const;
	bool IsBasicBlockTerminator(void) const;  // kind of inst that ALWAYS terminates a block
	inline bool IsLastInBlock(void) const { return (booleans1 & INSTR_SET_BLOCK_TERM); }; // does terminate its block
	inline bool IsJumpTarget(void) { return (booleans1 & INSTR_SET_JUMP_TARGET); };
	bool IsBranchToFarChunk(void);  // instr jumps outside current chunk
	inline bool IsTailCall(void) const { return (booleans1 & INSTR_SET_TAIL_CALL); };
	inline bool IsCondTailCall(void) const { return (booleans1 & INSTR_SET_COND_TAIL_CALL); };
	inline bool IsCallUsedAsJump(void) const { return (booleans1 & INSTR_SET_CALL_USED_AS_JUMP); };
	inline bool IsRecursiveCall(void) const { return (booleans1 & INSTR_SET_DIRECT_RECURSIVE_CALL); };
	inline bool MDIsInterruptCall(void) const { return (booleans1 & INSTR_SET_INTERRUPT); };
	inline bool IsNop(void) const { return (booleans2 & INSTR_SET_NOP); }; // instruction is simple or complex no-op
	inline bool IsFloatNop(void) const { return (SMPcmd.itype == NN_fnop); };
	inline bool MDIsDecrement(void) const { return (SMPcmd.itype == NN_dec); };
	bool MDIsPushInstr(void) const;
	bool MDIsPopInstr(void) const;
	bool MDIsReturnInstr(void) const;
	bool MDIsEnterInstr(void) const;
	bool MDIsLeaveInstr(void) const;
	bool MDIsHaltInstr(void) const;
	bool MDIsConditionalMoveInstr(void) const;
	bool MDIsMoveInstr(void) const;
	bool MDIsLoadEffectiveAddressInstr(void) const { return (SMPcmd.itype == NN_lea); };
	bool MDIsStackPointerCopy(bool UseFP);  // copies ESP or EBP to register
	bool MDIsFrameAllocInstr(void);
	bool MDIsFrameDeallocInstr(bool UseFP, asize_t LocSize);
	bool MDUsesCalleeSavedReg(void);
	inline bool MDIsUnsignedArithmetic(void) const { return ((NN_mul == SMPcmd.itype) || (NN_div == SMPcmd.itype)); };
	bool MDIsSignedArithmetic(void) const;
	bool MDIsUnsignedBranch(void) const;
	bool MDIsSignedBranch(void) const;
	bool MDIsUnsignedSetValue(void) const;
	bool MDIsSignedSetValue(void) const;
	bool MDIsAnySetValue(void) const;
	bool MDIsHashingArithmetic(void) const; // Is kind of shift or rotate that is used in hash functions
	bool MDIsCompareToPositiveConstant(op_t &NonConstOperand, uval_t &ConstValue) const;
	bool MDIsSubtractionOfConstant(op_t &NonConstOperand, uval_t &ConstValue) const;
	bool MDIsSubregMaskInst(size_t &BytesMasked); // is AND operation that masks off lower BytesMasked bytes
	inline bool MDIsBitwiseNotOpcode(void) const { return (NN_not == SMPcmd.itype); };
	inline bool MDIsBitwiseAndOpcode(void) const { return (NN_and == SMPcmd.itype); };
	inline bool MDIsBitwiseOrOpcode(void) const { return (NN_or == SMPcmd.itype); };
	inline bool MDIsSignBitFill(void) const { return ((NN_sar == SMPcmd.itype) && ((MD_NORMAL_MACHINE_BITWIDTH - 1) == MDGetShiftCount())); };
	inline bool MDDoublesWidth(void) const { 
		return ((NN_cbw == SMPcmd.itype) || (NN_cwde == SMPcmd.itype) || (NN_cdqe == SMPcmd.itype));
	}
	inline bool MDPropagateUseUpFromBranch(void) const { 
		// Do we propagate branch signedness through the register USEs of this opcode to their DEFs?
		return ((NN_cmp == SMPcmd.itype) || (NN_test == SMPcmd.itype) || (NN_mov == SMPcmd.itype)
#if 0
			|| ((NN_bt <= SMPcmd.itype) && (NN_bts >= SMPcmd.itype))
#endif
			);
	};
	inline bool IsLoadFromStack(void) const { return (booleans3 & INSTR_SET_LOAD_FROM_STACK); };
	inline bool IsFirstInBlock(void) const { return (booleans3 & INSTR_SET_FIRST_IN_BLOCK); };
	inline bool HasFlagsDef(void) const { return (booleans2 & INSTR_SET_DEFS_FLAGS); };
	inline bool HasFlagsUse(void) const { return (booleans2 & INSTR_SET_USES_FLAGS); };
	inline bool IsRegClearIdiom(void) const { return (booleans2 & INSTR_SET_REG_CLEAR_IDIOM); };
	bool AllDEFsTyped(void); // No DEF is UNINIT
	bool AllUSEsTyped(void); // No USE is UNINIT
	bool IsNonAddressReg(op_t UseOp) const; // UseOp is a USE reg, not just an address reg in a memory USE
	bool IsSubRegUsedAsShiftCount(op_t UseOp); // Is a subreg of UseOp used as a shift counter?
	bool IsOpSourceSmallPositiveConstant(op_t UseOp, int UseSSANum); // Does UseOp ultimately come from a small positive constant?
	bool IsOpSourceBitwiseNot(op_t UseOp, int UseSSANum); // Does UseOp ultimately come from a bitwise not instruction?
	bool IsOpSourceConditionCode(op_t UseOp, int UseSSANum); // Does UseOp ultimately come from a set-condition-code instruction?
	bool IsOpSourceZeroExtendedMove(op_t UseOp, int UseSSANum, bool TruncationCheck); // Does UseOp ultimately come from a move-with-zero-extension instruction?
	bool IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(op_t UseOp, int UseSSANum, bool TruncationCheck); // Union of two previous methods plus right shifts
	bool IsOpSourceSpecial(op_t UseOp, int UseSSANum, bool TruncationCheck, ea_t &SourceInstAddr); // Trace through moves to any of the above cases, return source addr
	bool MDIsOverflowingOpcode(void) const; // Is non-multiply arithmetic instruction that can possibly overflow?
	bool MDIsUnderflowingOpcode(void) const; // Is non-multiply arithmetic instruction that can possibly underflow?
	bool MDIsAddition(void) const;
	bool MDIsShiftOrRotate(void) const; // Is opcode a shift or rotate?
	bool MDIsShiftRight(void) const; // Is opcode a shift to the right?
	bool ShiftMakesUpperBitsLower(size_t HalfBitWidth, bool MustBeHalfRegWidth); // Do upper HalfBitWidth bits end up lower HalfBitWidth bits?s
	bool MDComparesImmedASCII(void); // Inst compares a location to an apparent ASCII immediate value.
	inline bool HasGoodRTL(void) const { return (booleans1 & INSTR_SET_GOODRTL); };
	inline bool AreDefsNormalized(void) const { return (booleans4 & INSTR_SET_DEFS_NORMALIZED); };
	inline bool IsInstRemoved(void) const { return (booleans4 & INSTR_SET_INST_REMOVED); }; // e.g. inst is unreachable or other optimization removed it
	inline bool IsStackAlignmentInst(void) const { return (booleans4 & INSTR_SET_STACK_ALIGNMENT); };
	inline bool HasFPNormalizedToSP(void) const { return (booleans4 & INSTR_SET_FP_NORMALIZED_TO_SP); };
	inline bool IsAllocaCall(void) const { return (booleans4 & INSTR_SET_ALLOCA); };
	inline bool IsNumericAnnotationSuppressed(void) const { return (booleans4 & INSTR_SET_SUPPRESS_NUMERIC_ANNOTATION); };
	inline bool IsHashOperation(void) const { return (booleans4 & INSTR_SET_HASH_OPERATION); };
	inline bool MDIsReducedWidthMove(void) const { return (MoveSource.dtyp < 2); };
	// 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 IsNumericTrustedSystemCall(void);

#if 0
	bool FindStackPtrDelta(sval_t SearchDelta) const; // Is SearchDelta in the set of possible stack pointer deltas for this inst?
													  //  If not, add it to the set.
#endif

	// Printing methods
	void PrintOperands(void) const;
	char *DestString(int OptType);
	void PrintDeadRegs(FILE *OutputFile); // print the registers that are dead right before this instruction.
	void Dump(void); // Complete debug print, with DEF/USE list, SSA #s, RTL

	// Analysis methods
	op_t GetSourceOnlyOperand(void); // return non-flags-reg non-dest source operand
	set<DefOrUse, LessDefUse>::iterator GetPointerAddressReg(op_t MemOp);
	void Analyze(void); // Fill in basic data for instruction.
	void AnalyzeMarker(void); // Fill in basic data for top of function pseudo-instruction.
	void AnalyzeCallInst(ea_t FirstFuncAddr, ea_t LastFuncAddr); // Detect pseudo-calls
	void AnalyzeIndirectRefs(bool UseFP); // Detect indirect memory operands
	sval_t AnalyzeStackPointerDelta(sval_t IncomingDelta, sval_t FramePtrDelta);
	sval_t FindStackAdjustment(void); // Find amount of stack adjustment, e.g. if this inst is after a call
	void FixupTailCall(void); // make adjustments after discovering inst is a tail call
	bool MDComputeNormalizedDataFlowOp(bool UseFP, sval_t FPDelta, op_t &DefOp); // Normalize stack operands to use incoming stack delta; leave others as is
		// return true if register or stack memory operand, false otherwise
	bool MDNormalizeStackOps(bool UseFP, sval_t FPDelta, bool Recomputing, sval_t DeltaIncrement = 0);
		// Iterate through Defs and Uses, calling MDComputeNormalizedDataFlowOp(); true if changed DEFs or USEs
	void MDGetUnnormalizedOp(op_t &NormOp); // If NormOp is a normalized stack memory operand, unnormalize it.
	bool HasAllocaRTL(void); // RTL shows alloca pattern, i.e. subtracts non-const value from stack pointer
	bool MDIsStackPtrSaveOrRestore(bool UseFP, sval_t FPDelta, bool &Save, sval_t &StackDelta, op_t &CopyOp, bool &Error); // is stack/frame pointer saved to/restored from CopyOp
	void MDFixupDefUseLists(void); // Machine-dependent ad hoc fixes
	void MDFindLoadFromStack(bool UseFP); // determine if instruction is load from stack loc
	bool MDIsSignedLoad(unsigned short &SignMask); // true if sign or zero-extended; pass out mask bits
	bool MDIsSmallPositiveAddition(void); // true if increment or addition of small positive immediate value
	bool MDIsSmallAdditionOrSubtraction(void); // true if increment, decrement, or addition or subtraction of small immediate value
	bool MDIsSimpleAssignment(bool &ValueFound, uval_t &ConstValue); // Inst is move or register clear.
	bool IsCounterOperation(void); // Inst clears register or adds or subtracts small immediate value, as is done with counter variables.
	bool MDIsNonOverflowingBitManipulation(void) const; // Inst does an AND, OR, XOR operation, does not do add, subtract, etc.
	bool FindConstantValue(set<DefOrUse, LessDefUse>::iterator UseIter, uval_t &ConstValue); // return true if traced USE to a constant value
	bool BuildRTL(void);   // Build RTL trees; return true if successfully built.
	void SyncAllRTs(bool UseFP, sval_t FPDelta); // calls SyncRTLDefUse() for all RTs in RTL
	op_t GetPushedOpnd(void); // Extract source operand from PUSH RTL
	int MDGetImmedUse(void); // Get immed value from USE list of inst
	bool MDIsArgumentPass(void); // Does inst pass an outgoing argument?
	bool OperandTransfersValueToDef(op_t UseOp); // Does UseOp arithmetically affect the value of the NonFlagsDef for this inst?
	string GetTrimmedCalledFunctionName(void); // Get funcname from call inst and remove "." and "_" prefices
	void SetImmedTypes(bool UseFP); // type all immediate operands as NUMERIC, CODEPTR, GLOBALPTR
									//  and set other context-free types (ESP == STACKPTR, etc.)
	void MDSetWidthSignInfo(bool UseFP); // Infer sign, bit width, etc. in simple cases within one instr
	void InferSignednessFromSMPTypes(bool UseFP); // Infer sign from the SMP types for USEs and DEFs.

	bool InferTypes(void); // return true if any DEF-USE or RTL operator types were updated.
	bool InferFGInfo(unsigned short IterCount); // infer width on first pass, signedness on all passes
	void AnnotateStackConstants(bool UseFP, FILE *AnnotFile);
	void EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile); // No RTLs available
	void EmitTypeAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile); // Use RTL types
	void EmitSafeReturn(FILE *AnnotFile); // emit annotation to denote that the return belongs to a safe function.
	void EmitIntegerErrorAnnotations(FILE *InfoAnnotFile, list<size_t> &LoopList); // emit check annotations for signedness, overflow, truncation, etc.
	void MDEmitLeaOpcodeOverflowAnnotations(FILE *InfoAnnotFile, list<size_t> &LoopList); // check for silent overflow in load effective address opcodes
	void UpdateMemLoadTypes(SMPOperandType newType);
	bool SkipSignednessCheckOnStackWrite(int DefSSANum); // Should we omit signedness check on store to stack in current inst?

	// 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 TraceUltimateMoveSource(op_t UseOp, int UseSSANum, op_t &UltSource, bool &FPRelative);

private:
	// Data 
	SMPBasicBlock *BasicBlock;  // basic block containing this instruction
	insn_t SMPcmd; // copy of 'cmd' for this instruction
	ulong features; // Canonical features for SMPcmd
	SMPitype  type; // Data flow analysis category
	int OptType;   // Optimization category (see OptCategory[])
	ea_t address;  // Code address for 1st byte of instruction
	sval_t StackPtrOffset; // <=0, before inst executes, relative to stack ptr value at function entry
	unsigned char booleans1; // bit set for first 8 bools
#if 0 // now in booleans1
	bool GoodRTL; // Has a good RTL been built?
	bool JumpTarget; // Is Instr the target of any jumps or branches?
	bool BlockTerm;  // This instruction terminates a basic block.
	bool TailCall;  // This instruction is a tail call (jump to far chunk with stack restored).
	bool CondTailCall;  // Tail call is conditional branch.
	bool CallUsedAsJump; // Call instruction, but actually a jump within the function.
	bool DirectRecursiveCall; // Call to first address in same function
	bool Interrupt;  // Instruction is a software interrupt call.
#endif
	unsigned char booleans2;
#if 0 // now in booleans2
	bool Nop; // instruction is a no-op, including compiler idioms for no-op.
	bool RegClearIdiom; // ASM idiom for move zero into register?
	bool DefsFlags;  // Instr DEFs the flags
	bool UsesFlags;  // Instr USEs the flags
	bool FarBranchComputed; // Have we computed whether branch is to far chunk?
	bool BranchesToFarChunk; // true if branch to far chunk
	bool IndirectMemWrite; // Writes through indirect memory operand
	bool IndirectMemRead;  // Reads through indirect memory operand
#endif
	unsigned char booleans3;
#if 0 // now in booleans3
	bool LoadFromStack; // memory load from stack location
	bool MultiplicationBitsDiscarded; // upper bits of multiply result discarded by instruction
	bool TypeInferenceComplete;  // All types have been resolved
	// For some type categories, inference just based on the category is done one time
	//  only, so this is a variable that is set to true after the first inference
	//  for those instruction types. For other categories, leave it false so that we
	//  try to infer types on each iteration of InferTypes().
	bool CategoryInferenceComplete;
	bool DEFsTyped; // all DEFs have a type other than UNINIT
	bool USEsTyped; // all USEs have a type other than UNINIT
	bool MemDefUseComputed;  // DEFMemOp and USEMemOp have been set
	bool FirstInBlock; // first inst in basic block
#endif
	unsigned char booleans4;
#if 0 // now in booleans4
	bool NormalizedDefs; // stack offsets in DEFs have been normalized with respect to incoming stack delta.
	bool NormalizedUses; // stack offsets in USEs have been normalized with respect to incoming stack delta.
	bool StackAlignmentInst; // AND of stack pointer with mask to align stack frame
	bool FPNormalizedToSP; // inst has frame-pointer-relative stack memory access that has been normalized to stack-pointer-relative
	bool AllocaCall;    // subtracts unknown value from stack pointer to allocate temp memory on stack
	bool SuppressNumericAnnotation; // any numeric error has been determined to be benign
	bool HashOperation; // arithmetic operation will likely overflow benignly because it is part of hash function, pseudo-RNG, etc.
#endif
	std::bitset<1 + MD_LAST_REG_NO> DeadRegsBitmap; // Registers that are dead at this instruction, as a bitmap.
	ea_t CallTarget; // target address of direct or indirect call instruction; BADADDR if unknown or not a call
	ea_t FarBranchTarget; // target address of branch to far chunk; BADADDR if unknown or not a far branch
	SMPOperandType AddSubSourceType;  // Source op (USE only) type for add/sub
	op_t AddSubSourceOp; // operand corresponding to AddSubSourceType
	SMPOperandType AddSubUseType; // type of USE that is also DEFed by add /sub
	op_t AddSubUseOp; // operand corresponding to AddSubUseType
	op_t DEFMemOp; // memory DEF list opnd, if any
	op_t USEMemOp; // memory USE list opnd, if any
#if 0  // now held in a map in SMPFunction
	op_t LeaUSEMemOp; // Original USEMemOp for LEA inst before converting it to arithmetic.
#endif
	op_t MoveSource;  // source operand for any move instruction, including
						// zero-extended or sign-extended.

	DefOrUseSet Defs; // Definitions list
	DefOrUseSet Uses; // Uses list
	SMPRTL RTL;
#if 0
	set<sval_t> StackDeltaSet;  // For functions with extra stack allocations, e.g. alloca() calls, different
								//  paths can produce multiple stack delta values. Temporary container until
								//  the function and stack frame can be analyzed and summarized.
#endif

	// Methods
	inline void ResetGoodRTL(void) { booleans1 &= INSTR_RESET_GOODRTL; };
	inline void SetJumpTarget(void) { booleans1 |= INSTR_SET_JUMP_TARGET; };
	inline void ResetJumpTarget(void) { booleans1 &= INSTR_RESET_JUMP_TARGET; };
	inline void ResetBlockTerm(void) { booleans1 &= INSTR_RESET_BLOCK_TERM; };
	inline void ResetTailCall(void) { booleans1 &= INSTR_RESET_TAIL_CALL; };
	inline void SetCallUsedAsJump(void) { booleans1 |= INSTR_SET_CALL_USED_AS_JUMP; };
	inline void ResetCallUsedAsJump(void) { booleans1 &= INSTR_RESET_CALL_USED_AS_JUMP; };
	inline void SetDirectRecursiveCall(void) { booleans1 |= INSTR_SET_DIRECT_RECURSIVE_CALL; };
	inline void ResetDirectRecursiveCall(void) { booleans1 &= INSTR_RESET_DIRECT_RECURSIVE_CALL; };
	inline void SetInterrupt(void) { booleans1 |= INSTR_SET_INTERRUPT; };
	inline void ResetInterrupt(void) { booleans1 &= INSTR_RESET_INTERRUPT; };

	inline void SetNop(void) { booleans2 |= INSTR_SET_NOP; };
	inline void ResetNop(void) { booleans2 &= INSTR_RESET_NOP; };
	inline void SetRegClearIdiom(void) { booleans2 |= INSTR_SET_REG_CLEAR_IDIOM; };
	inline void ResetRegClearIdiom(void) { booleans2 &= INSTR_RESET_REG_CLEAR_IDIOM; };
	inline bool SetDefsFlags(void) { booleans2 |=  INSTR_SET_DEFS_FLAGS; };
	inline bool ResetDefsFlags(void) { booleans2 &= INSTR_RESET_DEFS_FLAGS; };
	inline bool IsDefsFlags(void) const { return (booleans2 & INSTR_SET_DEFS_FLAGS); };
	inline bool SetUsesFlags(void) { booleans2 |=  INSTR_SET_USES_FLAGS; };
	inline bool ResetUsesFlags(void) { booleans2 &= INSTR_RESET_USES_FLAGS; };
	inline bool IsUsesFlags(void) const { return (booleans2 & INSTR_SET_USES_FLAGS); };
	inline bool SetFarBranchComputed(void) { booleans2 |=  INSTR_SET_FAR_BRANCH_COMPUTED; };
	inline bool ResetFarBranchComputed(void) { booleans2 &= INSTR_RESET_FAR_BRANCH_COMPUTED; };
	inline bool IsFarBranchComputed(void) const { return (booleans2 & INSTR_SET_FAR_BRANCH_COMPUTED); };
	inline bool SetBranchesToFarChunk(void) { booleans2 |=  INSTR_SET_BRANCHES_TO_FAR_CHUNK; };
	inline bool ResetBranchesToFarChunk(void) { booleans2 &= INSTR_RESET_BRANCHES_TO_FAR_CHUNK; };
	inline bool IsBranchesToFarChunk(void) const { return (booleans2 & INSTR_SET_BRANCHES_TO_FAR_CHUNK); };
	inline bool SetIndirectMemWrite(void) { booleans2 |=  INSTR_SET_INDIRECT_MEM_WRITE; };
	inline bool ResetIndirectMemWrite(void) { booleans2 &= INSTR_RESET_INDIRECT_MEM_WRITE; };
	inline bool SetIndirectMemRead(void) { booleans2 |=  INSTR_SET_INDIRECT_MEM_READ; };
	inline bool ResetIndirectMemRead(void) { booleans2 &= INSTR_RESET_INDIRECT_MEM_READ; };

	inline void SetLoadFromStack(void) { booleans3 |= INSTR_SET_LOAD_FROM_STACK; };
	inline void ResetLoadFromStack(void) { booleans3 &= INSTR_RESET_LOAD_FROM_STACK; };
	inline void SetMultiplicationBitsDiscarded(void) { booleans3 |= INSTR_SET_MULTIPLICATION_BITS_DISCARDED; };
	inline void ResetMultiplicationBitsDiscarded(void) { booleans3 &= INSTR_RESET_MULTIPLICATION_BITS_DISCARDED; };
	inline bool AreMultiplicationBitsDiscarded(void) const { return (booleans3 & INSTR_SET_MULTIPLICATION_BITS_DISCARDED); };
	inline void SetTypeInferenceComplete(void) { booleans3 |= INSTR_SET_TYPE_INFERENCE_COMPLETE; };
	inline void ResetTypeInferenceComplete(void) { booleans3 &= INSTR_RESET_TYPE_INFERENCE_COMPLETE; };
	inline bool IsTypeInferenceComplete(void) const { return (booleans3 & INSTR_SET_TYPE_INFERENCE_COMPLETE); };
	inline void SetCategoryInferenceComplete(void) { booleans3 |= INSTR_SET_CATEGORY_INFERENCE_COMPLETE; };
	inline void ResetCategoryInferenceComplete(void) { booleans3 &= INSTR_RESET_CATEGORY_INFERENCE_COMPLETE; };
	inline bool IsCategoryInferenceComplete(void) const { return (booleans3 & INSTR_SET_CATEGORY_INFERENCE_COMPLETE); };
	inline void SetDEFsTyped(void) { booleans3 |= INSTR_SET_DEFS_TYPED; };
	inline void ResetDEFsTyped(void) { booleans3 &= INSTR_RESET_DEFS_TYPED; };
	inline bool AreDEFsTyped(void) const { return (booleans3 & INSTR_SET_DEFS_TYPED); };
	inline void SetUSEsTyped(void) { booleans3 |= INSTR_SET_USES_TYPED; };
	inline void ResetUSEsTyped(void) { booleans3 &= INSTR_RESET_USES_TYPED; };
	inline bool AreUSEsTyped(void) const { return (booleans3 & INSTR_SET_USES_TYPED); };
	inline bool AreMemOpsFound(void) const { return (booleans3 & INSTR_SET_MEM_DEF_USE_COMPUTED); };
	inline void SetMemOpsFound(void) { booleans3 |= INSTR_SET_MEM_DEF_USE_COMPUTED; };

	inline void SetDefsNormalized(void) { booleans4 |= INSTR_SET_DEFS_NORMALIZED; }
	inline void SetStackAlignmentInst(void) { booleans4 |= INSTR_SET_STACK_ALIGNMENT; }
	inline void SetFPNormalizedToSP(void) { booleans4 |= INSTR_SET_FP_NORMALIZED_TO_SP; };

	uval_t MDGetShiftCount(void) const;
	bool AllDefsNumeric(void);  // true if all DEFs are NUMERIC or CODEPTR
	bool AnyDefsProfiled(void);	// true if any defs are profile derived
	bool AllDefMetadataUnused(void); // true if all DEF metadata not needed
	void MDFixupIDAProOperandList(void); // Fix problems with the operands list in SMPcmd.
	void BuildSMPDefUseLists(void); // Build DEF and USE lists for instruction
	void MDAnnotateSIBStackConstants(FILE *, op_t, ea_t, bool); // Handle x86 opcode SIB byte
	void FindMemOps(void); // Find memory DEFs and USEs, store in DEFMemOp and USEMemOp
	bool MDIgnoreMemOps(void); // Should apparent memory operands be ignored? e.g. lea opcode on x86
	bool MDFindPointerUse(op_t MemOp, bool UseFP); // Set base reg to POINTER
	bool MDFindMallocCall(op_t TargetOp); // Set return reg from malloc() call to HEAPPTR
	bool MDIsNop(void) const; // instruction is simple or complex no-op
	inline bool MDIsMultiply(void) const { return ((NN_mul == SMPcmd.itype) || (NN_imul == SMPcmd.itype)); };
	bool MDAlwaysUnsignedDEF(void) const; // Always produces an UNSIGNED DEF
	bool MDAlwaysSignedDEF(void) const; // Always produces a SIGNED DEF
	bool IsBenignTruncation(int &IdiomCode); // Is the instruction such that truncation is not an error?
	bool IsBenignOverflow(int &IdiomCode);  // Is the instruction such that overflow is not an error?
	bool MDIsMaybeBenignOverflowOpcode(void) const; // Is arithmetic opcode that could need its overflow ignored?
	bool MDIsMaybeBenignUnderflowOpcode(void) const; // Is arithmetic opcode that could need its underflow ignored?
	bool MDIsDefiniteBenignUnderflowOpcode(int &IdiomCode); // Is opcode that definitely should have its underflow ignored?
				//  NOTE: Overlaps with MDIsMaybeBenignUnderflowOpcode(), so call this one first.

	bool SubtractsFromItself(void); // RTL has subtraction operator applied to identical operands, producing zero.
	bool SubtractsImmedASCII(void); // Inst subtracts an apparent ASCII immediate value.
	bool IsMultiplyByLargeConstant(uval_t &ConstValue, unsigned short SignMask); // Multiply by large constant; overflow is probably intentional.
	bool IsSubtractionOfLargeConstant(uval_t &ConstValue, unsigned short SignMask); // Subtraction of large constant; underflow is probably intentional.
	bool IsAdditionOfLargeConstant(uval_t &ConstValue, unsigned short SignMask); // Addition of large constant; overflow is probably intentional.
	bool BuildUnaryRTL(SMPoperator UnaryOp); // helper for BuildRTL()
	bool BuildUnary2OpndRTL(SMPoperator UnaryOp); // helper for BuildRTL()
	bool BuildBinaryRTL(SMPoperator BinaryOp, bool HiddenFPStackOp =  false); // helper for BuildRTL()
	bool BuildGuardedSignalRTL(SMPoperator SignalOp); // helper for BuildRTL()
	bool BuildBinaryPlusImmedRTL(SMPoperator BinaryOp, SMPoperator ImmedOp); // helper for BuildRTL()
	bool BuildBinaryIgnoreImmedRTL(SMPoperator BinaryOp); // helper for BuildRTL(), ignore immed operand
	bool BuildLeaRTL(void); // helper for BuildRTL()
	bool BuildDoubleShiftRTL(SMPoperator BinaryOp); // helper for BuildRTL()
	bool BuildPackShiftRTL(SMPoperator PackOp, SMPoperator ShiftOp); // helper for BuildRTL()
	bool BuildBinaryPlusFlagsRTL(SMPoperator BinaryOp); // helper for BuildRTL()
	bool BuildFlagsDestBinaryRTL(SMPoperator BinaryOp); // helper for BuildRTL()
	bool BuildCallRTL(void); // helper for BuildRTL()
	bool BuildReturnRTL(void); // helper for BuildRTL()
	bool BuildJumpRTL(SMPoperator CondBranchOp); // helper for BuildRTL()
	bool BuildEnterRTL(void); // helper for BuildRTL()
	bool BuildLeaveRTL(void); // helper for BuildRTL()
	bool BuildOptType8RTL(void); // helper for BuildRTL()
	bool BuildMoveRTL(SMPoperator GuardOp); // helper for BuildRTL()
	bool BuildLoopRTL(SMPoperator GuardOp); // helper for BuildRTL()
	bool BuildLoadStringRTL(void); // helper for BuildRTL()
	bool BuildCompareStringRTL(void); // helper for BuildRTL()
	bool BuildExchangeRTL(void); // helper for BuildRTL()
	bool BuildExchangeAddRTL(void); // helper for BuildRTL()
	bool BuildCompareExchangeRTL(void); // helper for BuildRTL()
	bool BuildPushRTL(void); // helper for BuildRTL()
	bool BuildPopRTL(void); // helper for BuildRTL()
	void AddToStackPointer(uval_t delta); // helper for BuildRTL()
	void SubFromStackPointer(uval_t delta); // helper for BuildRTL()
	bool BuildMultiplyDivideRTL(SMPoperator BinaryOp);  // helper for BuildRTL()
	void SyncRTLDefUse(SMPRegTransfer *CurrRT, bool UseFP, sval_t FPDelta); // Ensure that all RTL operands are in the DEF/USE lists
	bool InferOperatorType(SMPRegTransfer *CurrRT); // return true if type updated
	void SetAddSubSourceType(void);
	int GetUseOpHashAndSSA(op_t UseOp, int &SSANum); // helper to find SSANum and create & return hash value
	int GetDefOpHashAndSSA(op_t DefOp, int &SSANum); // helper to find SSANum and create & return hash value
	void MDSetRTLRegWidthInfo(SMPRegTransfer *CurrRT); // Walk RTL and set register operand width info.
	void SetRTLUseOpRegWidthInfo(op_t UseOp); // helper, for USE operands in RTL
	unsigned short SignMaskUnionFromUseRegs(void); // union of sign masks from 2 reg USEs for binary arithmetic
	bool DoesOperatorTransferSign(SMPoperator CurrOp); // Does operator propagate signedness upwards?
	void MDFixupSignedness(void); // Adjust signedness based on SSA def-use info.
	bool InitFGInfoFromOperator(SMPoperator CurrOp, struct FineGrainedInfo &InitFG);
		// infer initial FG info (if possible) solely from the operator type

	bool InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter,  struct FineGrainedInfo &OpFG);
		// infer FG info, + width on FirstIter; pass out FG info, return true if changes to FG info maps

	bool UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG);
		// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
	bool UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG);
		// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
	unsigned short GetDefSignInfoFromUseOp(op_t UseOp);
		// Helper to fetch DEF signedness info for UseOp that has none.

	SMPMetadataType GetDefMetadataType(void); // metadata type of non-flags DEF

	bool MDIsAddImmediateToReg(op_t &DefOp, op_t &ImmOp); // return true if we have register DefOp += ImmOp.

	bool MDRecomputeNormalizedDataFlowOp(sval_t DeltaIncrement, bool UpdateMaps, op_t &DefOp); // Alter stack delta for SP-relative stack operands in alloca-calling functions
		// return true if register or stack memory operand, false otherwise
};  // end class SMPInstr

#endif