Newer
Older
clc5q
committed
}
}
}
return FoundUse;
} // end of SMPInstr::IsNonAddressReg()
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
// Is a sub-register of UseOp used as a shift counter in the RTL?
// For example, UseOp could be ECX on an x86 machine, and CL
// could be used as a shift or rotate counter.
bool SMPInstr::IsSubRegUsedAsShiftCount(op_t UseOp) {
bool ShiftCounter = false;
if ((o_reg == UseOp.type) && this->MDIsShiftOrRotate()) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
assert(CurrRT->HasRightSubTree());
CurrRT = CurrRT->GetRightTree();
op_t ShiftCountOp = CurrRT->GetRightOperand();
if (o_reg == ShiftCountOp.type) {
ushort UseReg = UseOp.reg;
ushort ShiftCountReg = ShiftCountOp.reg;
ushort WideUseReg = MDCanonicalizeSubReg(UseReg);
ushort WideShiftCountReg = MDCanonicalizeSubReg(ShiftCountReg);
if ((UseReg != ShiftCountReg) && (WideUseReg == WideShiftCountReg)) {
// Registers were not equal, but their canonical enclosing
// registers are equal. Because shift counters that are not
// immediate are the 8-bit subregister in x86 (MD here !!!!!!)
// it must be that the ShiftCountReg is a subreg of UseReg.
// This is the condition we are looking for.
ShiftCounter = true;
}
}
}
return ShiftCounter;
} // end of SMPInstr::IsSubRegUsedAsShiftCount()
// 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
// Does the shift or rotate RTL move the upper HalfBitWidth bits
// into the lower half of the register?
bool SMPInstr::ShiftMakesUpperBitsLower(size_t HalfBitWidth) {
bool FullCircle = false;
if (MD_NORMAL_MACHINE_BITWIDTH == (HalfBitWidth * 2)) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if ((NULL != CurrRT) && (CurrRT->HasRightSubTree())) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOper = CurrRT->GetOperator();
if ((SMP_U_RIGHT_SHIFT == CurrOper) || (SMP_S_RIGHT_SHIFT == CurrOper)
|| (SMP_ROTATE_LEFT == CurrOper) || (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 (ImmVal == HalfBitWidth) {
FullCircle = true;
}
}
}
}
}
return FullCircle;
} // SMPInstr::ShiftMakesUpperBitsLower()
// 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.
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 (UseOp.is_reg(R_sp) || (UseFP && UseOp.is_reg(R_bp))) {
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.
}
#if 1
else if (DefOp.is_reg(R_sp) || (DefOp.is_reg(R_bp) && 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();
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
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;
}
// 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;
bool ValueWillChange;
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;
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.
// 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
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
DefOp = DefIter->GetOp();
if (o_reg == DefOp.type) {
DefOp.reg = MDCanonicalizeSubReg(DefOp.reg);
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))) {
DefOp.reg = MDCanonicalizeSubReg(DefOp.reg);
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))) {
UseOp.reg = MDCanonicalizeSubReg(UseOp.reg);
UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum());
if (this->BasicBlock->IsLocalName(UseOp)) {
this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, SignMask);
}
else {
this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask);
}
++UseIter;
} // end 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)))) {
DefOp.reg = MDCanonicalizeSubReg(DefOp.reg);
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)))) {
UseOp.reg = MDCanonicalizeSubReg(UseOp.reg);
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();
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
// 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);
}
}
} // end of case4 (function calls)
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
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);
}
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
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);
DefOp.reg = MDCanonicalizeSubReg(DefOp.reg);
SSANum = DefIter->GetSSANum();
DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum);
UseIter = this->GetFirstUse();
assert(UseIter != this->GetLastUse());
UseOp = UseIter->GetOp();
assert(o_reg == UseOp.type);
UseOp.reg = MDCanonicalizeSubReg(UseOp.reg);
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);
}
}
// 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);
DefOp.reg = MDCanonicalizeSubReg(DefOp.reg);
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()
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
// 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()
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
// 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);
UseOp.reg = MDCanonicalizeSubReg(UseOp.reg);
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(void) {
bool benign = false;
unsigned short SignMask;
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
op_t UseOp, SearchOp;
if (3 == this->GetOptType()) { // Move instruction
bool ExtendedLoad = this->MDIsSignedLoad(SignMask);
if (ExtendedLoad) {
if (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;
}
}
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) {
SearchOp.reg = MDCanonicalizeSubReg(UseOp.reg);
}
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
assert(UseIter != this->GetLastUse());
if (UseIter->DoesNotTruncate()) {
benign = true;
}
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());
}
}
}
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(void) {
bool benign = false;
set<DefOrUse, LessDefUse>::iterator DefIter;
SMPOperandType DefType;
int DefSSANum;
ea_t DefAddr;
op_t DefOp;
clc5q
committed
if (this->MDIsDefiniteBenignUnderflowOpcode()) {
// No further analysis at block or function scope is needed.
benign = true;
}
else if (this->MDIsMaybeBenignUnderflowOpcode()) { // might have the subtract instruction
// 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
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
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
DefSSANum = DefIter->GetSSANum();
DefAddr = this->GetAddr();
DefOp = DefIter->GetOp();
benign = this->GetBlock()->GetFunc()->IsBenignUnderflowDEF(DefOp, DefSSANum, DefAddr);
}
}
}
else if (this->MDIsMaybeBenignOverflowOpcode()) { // might have the add instruction
DefIter = this->GetFirstNonFlagsDef();
assert(DefIter != this->GetLastDef());
if (DefIter->DoesNotOverflow()) {
benign = true; // short circuit; already analyzed
}
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;
}
else {
// A bit of a quandary. Ideally, we would have successful SMP type inference
// and always have PTROFFSET := POINTER + NEGATEDPTR. However, sometimes we
// might have ?? := ?? + NEGATEDPTR. The instruction could be of the type
// NEGATEDPTR := NUMERIC + NEGATEDPTR, so we cannot just assume here that
// we have detected the benign case. We will be safe and do nothing.
;
}
}
}
}
return benign;
} // end of SMPInstr::IsBenignOverflow()
// Do we detect a situation in which it is safe to check for signedness errors on
// the stack write (return false), or not (return true to be safe).
bool SMPInstr::SkipSignednessCheckOnStackWrite(int DefSSANum) {
bool SkipCheck = true;
op_t StackDefOp = this->DEFMemOp;
size_t DefBitWidth = 8 * GetOpDataSize(StackDefOp);
if (DefBitWidth < MD_NORMAL_MACHINE_BITWIDTH) {
// If we are not dealing with a shortened bit width, then
// the next load from the stack will not be sign-extended
// or zero-extended.
if (this->GetBlock()->IsStackOpNextUsedWithSignedness(StackDefOp, this->GetAddr(), DefSSANum)) {
SkipCheck = false;
}
}
return SkipCheck;
} // end of SMPInstr::SkipSignednessCheckOnStackWrite()
clc5q
committed
// Does inst pass an outgoing argument?
bool SMPInstr::MDIsArgumentPass(void) {
bool OutArgPass = false;
// Current model is writing outargs to stack. For other compiler targets in the
// future, we would also include pushes onto the stack.
if (this->HasDestMemoryOperand() && (this->GetOptType() == 3)) { // move to memory
if (this->GetBlock()->GetFunc()->OutArgsRegionComputed()) {
op_t DefOp = this->DEFMemOp;
OutArgPass = this->GetBlock()->GetFunc()->IsInOutgoingArgsRegion(DefOp);
}
}
return OutArgPass;
}
// Trace UseOp through register moves back to its stack location or immediate value source.
// Return true if we are passing an immediate or stack location back in UltSource.
bool SMPInstr::TraceUltimateMoveSource(op_t UseOp, int UseSSANum, op_t &UltSource) {
// If we hit an immediate value or a stack location, we are done.
bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
op_t NewUseOp; // next UseOp up the move chain
clc5q
committed
op_t DefOp, ImmOp;
int NewUseSSANum;
set<DefOrUse,LessDefUse>::iterator UseIter;
clc5q
committed
bool LocalName;
ea_t DefAddr;
SMPInstr *DefInst;
UltSource = InitOp;
bool StackOp = MDIsStackAccessOpnd(UseOp, UseFP);
bool RegisterOp = (UseOp.type == o_reg);
if (this->GetOptType() == 3) { // move instruction
if (UseOp.type == o_imm) {
UltSource = UseOp;
return true;
}
else if ((!RegisterOp) && (!StackOp)) {
// We only trace the move chain through registers or stack locations to an ultimate
// load-effective-address of a stack location, or a move of an immediate value.
return false;
}
}
else if (!this->MDIsLoadEffectiveAddressInstr()) {
clc5q
committed
return false;
else { // Load effective address instruction.
// If it is a stack location being loaded, trace succeeded, else it failed.
if (StackOp) {
UltSource = UseOp;
return true;
}
else {
return false;
}
}
// If we reach this point, we have a move instruction but did not return true or false above.
// Recursion case. Going back up the move chain has just produced a register or
// a stack location, and we still need to find the stack address or immediate value
// that was stored in the register or stack location. The stack location could hold
// a pointer to a stack object, produced by an earlier LEA instruction, or it
// could hold an immediate value (e.g. constant size argument passed to memset() or
// similar function).
clc5q
committed
LocalName = this->GetBlock()->IsLocalName(UseOp);
DefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, this->GetAddr(), UseSSANum, LocalName);
if ((BADADDR == DefAddr) || (DefAddr < (this->GetBlock()->GetFunc()->GetStartAddr() - 1))) {
// Def was not found, or was found in Phi function (DefAddr was block number, not instruction addr).
return false;
}
clc5q
committed
if (DefAddr < (this->GetBlock()->GetFirstAddr())) {
// If DefAddr is 1 byte less than the first addr in the block, then
// it is a pseudo-def in the global DU chains, signifying that the
// value was LiveIn and the true DEF is in another block. We could
// handle this in the future, but right now we will only deal with
// the simpler case in which the move source can be traced
// within the basic block.
return false;
}
// Everything is OK so far; time to recurse up the move chain.
DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr);
if (DefInst->GetOptType() == 3) {
NewUseOp = DefInst->GetMoveSource();
}
else if (DefInst->MDIsLoadEffectiveAddressInstr()) {
NewUseOp = DefInst->GetLeaMemUseOp();
if (MDIsStackAccessOpnd(NewUseOp, UseFP)) {
UltSource = NewUseOp;
return true;
}
else {
return false;
}
}
clc5q
committed
// We don't have a move instruction or a load effective address instruction, which
// can be used to move a stack address into a register. We don't try to trace through
// arithmetic except for two easy cases.
// Case 1: A register is cleared. Same as assigning immediate value zero to the reg.
else if (DefInst->IsRegClearIdiom()) {
clc5q
committed
UltSource.type = o_imm;
UltSource.value = 0; // why would we memset a zero byte region?
return true;
}
clc5q
committed
// Easy arithmetic Case 2: we have reg += ImmediateValue, and reg was DEFed by reg := LEA(StackLoc).
else if (DefInst->MDIsAddImmediateToReg(DefOp, ImmOp)) {
SMPInstr *NewDefInst;
UseIter = DefInst->FindUse(DefOp);
assert(UseIter != DefInst->GetLastUse());
NewUseSSANum = UseIter->GetSSANum();
LocalName = DefInst->GetBlock()->IsLocalName(DefOp);
DefAddr = DefInst->GetBlock()->GetDefAddrFromUseAddr(DefOp, DefInst->GetAddr(), NewUseSSANum, LocalName);
if ((BADADDR == DefAddr) || (DefAddr < (DefInst->GetBlock()->GetFunc()->GetStartAddr() - 1))) {
// Def was not found, or was found in Phi function (DefAddr was block number, not instruction addr).
return false;
}
NewDefInst = DefInst->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr);
clc5q
committed
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
if (NewDefInst->MDIsLoadEffectiveAddressInstr()) {
NewUseOp = NewDefInst->GetLeaMemUseOp();
if (MDIsStackAccessOpnd(NewUseOp, UseFP)) {
// We have the code sequence we were searching for when we first saw the
// addition of an immediate value to a register, e.g.:
// lea ebx,[ebp-2000]
// add ebx,1000
//
// We are essentially making this sequence into a single instruction:
// lea ebx,[ebp-1000]
// by adding the immediate value to the address offset. With a stack that grows
// downward, it does not matter if we add 1000 to [esp+500] to produce [esp+1500],
// or we add 1000 to [ebp-2000] to make [ebp-1000]. Either way, we are simulating the
// addition of 1000 as we move up in the stack frame.
NewUseOp.addr += ImmOp.value; // perform the address arithmetic addition
UltSource = NewUseOp;
return true;
}
else {
return false;
}
}
else {
return false;
}
}
else {
// Not the kind of instruction we need; cut short the recursion.
return false;
}
// NewUseOp is the move source operand that we seek.
UseIter = DefInst->FindUse(NewUseOp);
assert(UseIter != DefInst->GetLastUse());
NewUseSSANum = UseIter->GetSSANum(); // unused for immediates, used for regs and stack
// Recurse
return DefInst->TraceUltimateMoveSource(NewUseOp, NewUseSSANum, UltSource);
} // end of SMPInstr::TraceUltimateMoveSource()
// Infer DEF, USE, and RTL SMPoperator types within the instruction based on the type
// of operator, the type category of the instruction, and the previously known types
// of the operands.
bool SMPInstr::InferTypes(void) {
bool changed = false; // return value
int TypeCategory = SMPTypeCategory[this->SMPcmd.itype];
set<DefOrUse, LessDefUse>::iterator CurrDef;
set<DefOrUse, LessDefUse>::iterator CurrUse;
op_t DefOp = InitOp, UseOp = InitOp;
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
bool SafeFunc = this->BasicBlock->GetFunc()->IsSafe();
bool IsMemOp;
#if SMP_VERBOSE_DEBUG_INFER_TYPES
DebugFlag |= (0 == strcmp("InputMove", this->BasicBlock->GetFunc()->GetFuncName()));
clc5q
committed
SMP_msg("opcode: %d TypeCategory: %d\n", this->SMPcmd.itype, TypeCategory);
// If we are already finished with all types, return false.
if (this->IsTypeInferenceComplete())
clc5q
committed
if (this->AllDEFsTyped() && this->AllUSEsTyped()) {
this->SetTypeInferenceComplete();
clc5q
committed
return false;
}
if (this->HasDestMemoryOperand()) {
changed |= this->MDFindPointerUse(this->MDGetMemDefOp(), UseFP);
}
if (this->HasSourceMemoryOperand()) {
changed |= this->MDFindPointerUse(this->MDGetMemUseOp(), UseFP);
}
// The control flow instructions can be handled simply based on their type
// and do not need an RTL walk.
SMPitype DFAType = this->GetDataFlowType();
bool CallInst = ((DFAType == CALL) || (DFAType == INDIR_CALL));
ushort IndirCallReg = R_none;
if (DebugFlag) {
clc5q
committed
SMP_msg("DFAType: %d CategoryInferenceComplete: %d\n",
DFAType, this->IsCategoryInferenceComplete());
op_t TargetOp = this->SMPcmd.Operands[0];
if (TargetOp.type == o_reg)
IndirCallReg = TargetOp.reg;
}
if ((DFAType >= JUMP) && (DFAType <= INDIR_CALL)) {
// All USEs are either the flags (NUMERIC) or the target address (CODEPTR).
// The exceptions are the USE list for interrupt calls, which includes
// the caller-saved regs, and indirect calls through a memory
// operand, such as call [ebx+esi+20h], where the memory operand
// is a CODEPTR but the addressing registers are a BaseReg and
// IndexReg as in any other memory addressing, and the caller-saved
// regs on any call.
CurrUse = this->GetFirstUse();
while (CurrUse != this->GetLastUse()) {
UseOp = CurrUse->GetOp();
if (UseOp.is_reg(X86_FLAGS_REG))
CurrUse = this->SetUseType(UseOp, NUMERIC);
else if ((CurrUse->GetType() != CODEPTR)
&& (!(this->MDIsInterruptCall() && (o_reg == UseOp.type)))
&& (!(CallInst && MDIsCallerSavedReg(UseOp)))
&& (!(this->HasSourceMemoryOperand()
&& (INDIR_CALL == this->GetDataFlowType())
&& (o_reg == UseOp.type)))) {
CurrUse = this->SetUseType(UseOp, CODEPTR);
if (DFAType == CALL) {
// If the call is to malloc(), then the DEF of the return
// register is of type HEAPPTR.
changed |= this->MDFindMallocCall(UseOp);
}
}
else if ((CurrUse->GetType() != CODEPTR) && CallInst
&& UseOp.is_reg(IndirCallReg)) {
CurrUse = this->SetUseType(UseOp, CODEPTR);
}
this->SetTypeInferenceComplete();
return true;
}
// First, see if we can infer something about DEFs and USEs just from the
// type category of the instruction.
if (!this->IsCategoryInferenceComplete()) {
bool MemPropagate = false;
switch (TypeCategory) {
case 0: // no inference possible just from type category
case 1: // no inference possible just from type category
case 3: // MOV instructions; inference will come from source to dest in RTL walk.
case 5: // binary arithmetic; inference will come in RTL walk.
case 10: // binary arithmetic; inference will come in RTL walk.
case 11: // push and pop instructions; inference will come in RTL walk.
case 12: // exchange instructions; inference will come in RTL walk.
this->SetCategoryInferenceComplete();