Newer
Older
// Try to find in the function level.
UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum);
}
if ((UseDefAddr == (FirstFuncAddr - 1)) || AboveStackFrame
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
|| (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
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
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();
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
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()) {
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
// 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)
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
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()
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
// 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);
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
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;
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()
clc5q
committed
// 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;
op_t UseOp, SearchOp;
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;
}
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 = this->GetMoveSource();
assert(o_void != UseOp.type);
SearchOp = UseOp;
if (o_reg == UseOp.type) {
CanonicalizeOpnd(SearchOp);
}
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
assert(UseIter != this->GetLastUse());
if (UseIter->DoesNotTruncate()) {
benign = true;
IdiomCode = 2;
#if SMP_MEASURE_NUMERIC_ANNOTATIONS
++SuppressTruncationRegPiecesAllUsed;
#endif
}
else {
set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef();
assert(DefIter != this->GetLastDef());
int DefSSANum = DefIter->GetSSANum();
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)) {
}
}
return benign;
} // end of SMPInstr::IsBenignTruncation()
clc5q
committed
// Do we not consider overflow or underflow on this type of instruction to be an error?
bool SMPInstr::IsBenignOverflow(int &IdiomCode) {
clc5q
committed
bool benign = false;
set<DefOrUse, LessDefUse>::iterator DefIter, UseIter;
SMPOperandType DefType, UseType;
clc5q
committed
int DefSSANum;
ea_t DefAddr;
op_t DefOp;
if (this->MDIsDefiniteBenignUnderflowOpcode(IdiomCode)) {
clc5q
committed
// No further analysis at block or function scope is needed.
benign = true;
}
else if (this->MDIsMaybeBenignUnderflowOpcode()) { // might have the subtract instruction in tricky sequence
clc5q
committed
// 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.
clc5q
committed
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();
clc5q
committed
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;
}
clc5q
committed
}
}
}
else if (this->MDIsMaybeBenignOverflowOpcode()) { // might have the add instruction in tricky sequence
clc5q
committed
DefIter = this->GetFirstNonFlagsDef();
assert(DefIter != this->GetLastDef());
if (DefIter->DoesNotOverflow()) {
benign = true; // short circuit; already analyzed
IdiomCode = 6;
clc5q
committed
}
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();
this->Defs.SetNoOverflow(DefOp, true);
benign = true;
IdiomCode = 6;