Newer
Older
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
clc5q
committed
}
}
else {
FoundMoveZX = false;
}
clc5q
committed
}
return FoundMoveZX;
} // end of SMPInstr::IsOpSourceZeroExtendedMove()
clc5q
committed
// Does UseOp ultimately come from a move-with-zero-extension instruction OR from a condition code OR from a right shift?
bool SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(op_t UseOp, int UseSSANum, bool TruncationCheck) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
clc5q
committed
return false;
}
bool FoundMoveZXCC = false;
clc5q
committed
bool RegDef = (o_reg == UseOp.type);
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
clc5q
committed
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
clc5q
committed
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
clc5q
committed
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
clc5q
committed
|| (UseDefAddr == BADADDR) || IndirectMemAccess) {
// Cannot search for general memory DEFs; must be stack or register.
// FirstFuncAddr - 1 signifies the pseudo-inst to hold DEFs of regs
clc5q
committed
// 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.
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
FoundMoveZXCC = false;
}
else if (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
// 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.
size_t BlockNum = (size_t) 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());
size_t PhiListSize = DefPhiIter->GetPhiListSize();
PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
for (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()) {
op_t MoveUseOp = DefInst->GetMoveSource();
clc5q
committed
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;
clc5q
committed
} // end of SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode()
// Trace through moves to any of the above cases, return source inst
bool SMPInstr::IsOpSourceSpecial(op_t UseOp, int UseSSANum, bool TruncationCheck, ea_t &SourceInstAddr) {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) {
return false;
}
bool FoundMoveNotZXCCSubreg = false;
bool RegDef = (o_reg == UseOp.type);
bool LocalName = this->GetBlock()->IsLocalName(UseOp);
bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP);
bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->WritesAboveLocalFrame(UseOp, this->AreDefsNormalized())));
ea_t UseAddr = this->GetAddr();
ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr();
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
bool UpExposedUse = (UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1));
if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == BADADDR) || UpExposedUse)) {
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
|| (UseDefAddr == BADADDR) || IndirectMemAccess) {
// Cannot search for general memory DEFs; must be stack or register.
// FirstFuncAddr - 1 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 (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
// 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.
size_t BlockNum = (size_t) 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());
size_t PhiListSize = DefPhiIter->GetPhiListSize();
PhiDefBlock->SetProcessed(true); // Prevent infinite recursion
for (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()) {
op_t MoveUseOp = DefInst->GetMoveSource();
clc5q
committed
if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
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()
// 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 {
return (((NN_rcl <= SMPcmd.itype) && (NN_ror >= SMPcmd.itype))
|| ((NN_sal <= SMPcmd.itype) && (NN_shr >= SMPcmd.itype))
|| (NN_shld == SMPcmd.itype) || (NN_shrd == SMPcmd.itype));
} // end of SMPInstr::MDIsShiftOrRotate()
clc5q
committed
// Is opcode a shift to the right?
bool SMPInstr::MDIsShiftRight(void) const {
return ((NN_sar == SMPcmd.itype) || (NN_shr == SMPcmd.itype));
}
// 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(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()));
op_t ShiftCount = CurrRT->GetRightOperand();
if (o_imm == ShiftCount.type) {
uval_t ImmVal = ShiftCount.value;
// 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()
clc5q
committed
#if 0
// Find SearchDelta in StackDeltaSet, inserting it if not found. Return whether it was initially found.
bool SMPInstr::FindStackPtrDelta(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;
uval_t ImmVal;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
DebugFlag = DebugFlag || (this->address == 0x805cd52) || (this->address == 0x805cd56);
DebugFlag |= (0 == strncmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName(), 15));
#endif
CurrUse = this->GetFirstUse();
while (CurrUse != this->GetLastUse()) {
UseOp = CurrUse->GetOp();
clc5q
committed
SMP_msg("SetImmedTypes USE: ");
clc5q
committed
SMP_msg("\n");
if (o_imm == UseOp.type) {
ImmVal = UseOp.value;
if (IsImmedGlobalAddress((ea_t) ImmVal)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting to GLOBALPTR\n");
CurrUse = this->SetUseType(UseOp, GLOBALPTR);
#if 0
else if (IsDataAddress((ea_t) ImmVal)) {
// NOTE: We must call IsDataAddress() before we call IsImmedCodeAddress()
// to catch the data addresses within the code address range.
clc5q
committed
if (DebugFlag) SMP_msg("Setting to POINTER\n");
CurrUse = this->SetUseType(UseOp, POINTER);
}
#endif
else if (this->MDIsInterruptCall() || IsImmedCodeAddress((ea_t) ImmVal)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting to CODEPTR\n");
CurrUse = this->SetUseType(UseOp, CODEPTR);
}
else { // NUMERIC
clc5q
committed
if (DebugFlag) SMP_msg("Setting to NUMERIC\n");
CurrUse = this->SetUseType(UseOp, NUMERIC);
else if (o_reg == UseOp.type) {
if (UseOp.is_reg(X86_FLAGS_REG)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting flags reg to NUMERIC\n");
CurrUse = this->SetUseType(UseOp, NUMERIC);
}
#if 1
else if (MDIsStackOrFramePointerReg(UseOp, UseFP)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting reg to STACKPTR\n");
CurrUse = this->SetUseType(UseOp, STACKPTR);
}
#endif
}
#if 0 // could these registers have pointers in them?
else if ((o_trreg == UseOp.type) ||(o_dbreg == UseOp.type) || (o_crreg == UseOp.type)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting special reg to NUMERIC\n");
CurrUse = this->SetUseType(UseOp, NUMERIC);
}
#endif
else if ((o_fpreg == UseOp.type) || (o_mmxreg == UseOp.type) || (o_xmmreg == UseOp.type)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting floating point reg to NUMERIC\n");
CurrUse = this->SetUseType(UseOp, NUMERIC);
}
else if ((o_mem == UseOp.type) || (o_phrase == UseOp.type) || (o_displ == UseOp.type)) {
// 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 (DebugFlag) {
clc5q
committed
SMP_msg("SetImmedTypes DEF: ");
clc5q
committed
SMP_msg("\n");
clc5q
committed
if (DebugFlag) SMP_msg("FuncName: %s\n", this->BasicBlock->GetFunc()->GetFuncName());
if (DefOp.is_reg(X86_FLAGS_REG)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting flags reg DEF to NUMERIC\n");
CurrDef = this->SetDefType(DefOp, NUMERIC);
// No need to propagate this DEF type, as all flags will become NUMERIC.
else if (MDIsStackOrFramePointerReg(DefOp, UseFP)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting reg DEF to STACKPTR\n");
CurrDef = this->SetDefType(DefOp, STACKPTR);
assert(CurrDef != this->Defs.GetLastRef());
// No need to propagate; all stack and frame pointers will become STACKPTR.
else if ((o_fpreg == DefOp.type) || (o_mmxreg == DefOp.type) || (o_xmmreg == DefOp.type)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting floating point reg DEF to NUMERIC\n");
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 ((o_trreg == DefOp.type) || (o_dbreg == DefOp.type) || (o_crreg == DefOp.type)) {
clc5q
committed
if (DebugFlag) SMP_msg("Setting special reg DEF to NUMERIC\n");
CurrDef = this->SetDefType(DefOp, NUMERIC);
}
#endif
else if ((o_mem == DefOp.type) || (o_phrase == DefOp.type) || (o_displ == DefOp.type)) {
// 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;
op_t UseOp;
if ((3 == this->OptType) && (this->HasSourceMemoryOperand())) {
// Loads and stores are OptCategory 3. We want only loads from the stack.
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
UseOp = UseIter->GetOp();
if (MDIsStackAccessOpnd(UseOp, UseFP)) {
this->SetLoadFromStack();
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
break;
}
}
}
return;
} // end of SMPInstr::MDFindLoadFromStack()
// 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) {
unsigned short opcode = this->SMPcmd.itype;
if (NN_movzx == opcode) {
SignMask = FG_MASK_UNSIGNED;
}
else if (NN_movsx == opcode) {
SignMask = FG_MASK_SIGNED;
}
else {
return false;
}
return true;
}
clc5q
committed
// true if increment or addition of small positive immediate value
#define STARS_SMALL_POS_VALUE_LIMIT 16
bool SMPInstr::MDIsSmallPositiveAddition(void) {
unsigned short opcode = this->SMPcmd.itype;
bool found = (NN_inc == opcode);
clc5q
committed
if (!found && ((NN_add == opcode) || (NN_adc == opcode))) {
clc5q
committed
set<DefOrUse, LessDefUse>::iterator UseIter;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
op_t UseOp = UseIter->GetOp();
if (o_imm == UseOp.type) {
clc5q
committed
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())) {
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
ImmVal = RightOp.value;
if ((ImmVal <= STARS_SMALL_POS_VALUE_LIMIT) && (0 < ImmVal)) {
found = true;
}
}
}
}
}
clc5q
committed
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->SMPcmd.itype;
bool found = ((NN_inc == opcode) || (NN_dec == opcode));
if ((NN_add == opcode) || (NN_adc == opcode) || (NN_sub == opcode) || (NN_sbb == opcode)) {
set<DefOrUse, LessDefUse>::iterator UseIter;
for (UseIter = this->GetFirstUse(); !found && (UseIter != this->GetLastUse()); ++UseIter) {
op_t UseOp = UseIter->GetOp();
if (o_imm == UseOp.type) {
uval_t ImmVal = UseOp.value;
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, uval_t &ConstValue) {
bool Simple = false;
clc5q
committed
ValueFound = false;
if (this->IsRegClearIdiom()) {
Simple = true;
ValueFound = true;
ConstValue = 0;
}
else if (this->MDIsMoveInstr()) {
Simple = true;
if (o_imm == this->MoveSource.type) {
ValueFound = true;
ConstValue = this->MoveSource.value;
}
}
return Simple;
} // end of SMPInstr::MDIsSimpleAssignment()
// Inst clears register or adds or subtracts small immediate value, as is done with counter variables.
bool SMPInstr::IsCounterOperation(void) {
bool CounterOperation = false;
bool ImmedValueFound = false;
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->SMPcmd.itype;
return ((NN_and == opcode) || (NN_or == opcode) || (NN_shl == opcode)
|| ((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, uval_t &ConstValue) {
bool FoundConst = false;
assert(UseIter != this->GetLastUse());
op_t UseOp = UseIter->GetOp();
if (UseOp.type == o_imm) {
ConstValue = UseOp.value;
FoundConst = true;
}
else {
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
if ((o_reg == UseOp.type) || MDIsDirectStackAccessOpnd(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);
ea_t UseAddr = this->GetAddr();
ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName);
if (UseDefAddr < this->GetBlock()->GetFunc()->GetNumBlocks()) {
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
// 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 ((UseDefAddr == (this->GetBlock()->GetFirstAddr() - 1)) || (BADADDR == UseDefAddr)) {
// The DEF is in a Phi function in the current block, or is 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) {
set<DefOrUse, LessDefUse>::iterator UseIter;
set<DefOrUse, LessDefUse>::iterator DefIter;
op_t UseOp, DefOp;
struct FineGrainedInfo FGEntry;
unsigned short SignMask, TempSign, WidthMask;
int DefHashValue, UseHashValue;
ea_t DefAddr; // for flags USE in conditional set
int SSANum; // for flags USE in conditional set
bool LocalFlags; // is flags register a local name?
bool case1, case2, case3, case4, case5, case6, case7, case8;
bool SignedSetOpcode = this->MDIsSignedSetValue();
bool UnsignedSetOpcode = this->MDIsUnsignedSetValue();
case1 = this->IsLoadFromStack();
case2 = this->MDIsSignedLoad(SignMask); // sets value of SignMask if it returns true
clc5q
committed
case3 = (7 == this->OptType); // Multiplies and divides
case4 = ((CALL == this->GetDataFlowType()) || (INDIR_CALL == this->GetDataFlowType()));
clc5q
committed
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->address, 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 (o_reg == DefOp.type) {
CanonicalizeOpnd(DefOp);
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))) {
CanonicalizeOpnd(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))) {
CanonicalizeOpnd(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.type == o_reg) && (!(DefOp.is_reg(X86_FLAGS_REG)))) {
CanonicalizeOpnd(DefOp);
DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
if (this->BasicBlock->IsLocalName(DefOp)) {
this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, SignMask);
}
else {
this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask);
}
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.type == o_reg) && (!(UseOp.is_reg(X86_FLAGS_REG)))) {
CanonicalizeOpnd(UseOp);
UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum());
if (this->BasicBlock->IsLocalName(UseOp)) {
this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, SignMask);
}
else {
this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask);
}
} // 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) {
// Get name of function called.
string FuncName = this->GetTrimmedCalledFunctionName();
// Get FG info, if any, for 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.
DefOp = InitOp;
DefOp.type = o_reg;
DefOp.reg = MD_RETURN_VALUE_REG;
DefIter = this->FindDef(DefOp);
assert(DefIter != this->GetLastDef());
DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum());
if (this->BasicBlock->IsLocalName(DefOp)) {
this->BasicBlock->UpdateDefFGInfo(DefHashValue, FGEntry);
}
else {
this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, FGEntry);
}
}
// 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();
// Find the argument assignments and mark them, to trigger later signedness checks.
this->GetBlock()->MarkUnsignedArgs(this->GetAddr(), ArgPosBits);
}
} // end of case4 (function calls)
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
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.type = o_reg; // set up a dummy op for searching
UseOp.reg = X86_FLAGS_REG;
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(o_reg == DefOp.type);
SSANum = DefIter->GetSSANum();
DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum);
UseIter = this->GetFirstUse();
assert(UseIter != this->GetLastUse());
UseOp = UseIter->GetOp();
assert(o_reg == UseOp.type);
assert(UseOp.reg == DefOp.reg);
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 (o_reg == DefOp.type) {
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 (size_t index = 0; index < this->RTL.GetCount(); ++index) {
CurrRT = this->RTL.GetRT(index);
DefOp = CurrRT->GetLeftOperand();
// 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()
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
// 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;
op_t DefOp, UseOp;
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) {
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) {
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(op_t UseOp) {
unsigned short WidthMask;
set<DefOrUse, LessDefUse>::iterator UseIter;
unsigned int UseHashValue;
if (MDIsGeneralPurposeReg(UseOp)) {
WidthMask = ComputeOperandBitWidthMask(UseOp, 0);
CanonicalizeOpnd(UseOp);
UseIter = this->FindUse(UseOp);
assert(UseIter != this->GetLastUse());
UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum());
if (this->BasicBlock->IsLocalName(UseOp)) {
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) {
op_t UseOp;