Newer
Older
updated = true;
break;
RightType = CurrUse->GetType();
}
}
// We have to know both operand types to infer the operator, or know the
// operator type to infer the operand types.
if ((UNINIT == CurrRT->GetOperatorType())
&& ((UNINIT == LeftType) || (UNINIT == RightType)))
break;
// If both operands are NUMERIC, operator and result are NUMERIC.
// If one operand is NUMERIC and the other is a pointer type,
// then the ADD operator and the result will inherit this second type,
// while AND and OR operators will remain UNINIT (we don't know what
// type "ptr AND 0xfffffff8" has until we see how it is used).
clc5q
committed
LeftNumeric = IsEqType(NUMERIC, LeftType);
RightNumeric = IsEqType(NUMERIC, RightType);
LeftPointer = IsDataPtr(LeftType);
RightPointer = IsDataPtr(RightType);
if (UNINIT == CurrRT->GetOperatorType()) {
// Infer operator type from left and right operands.
CurrRT->SetOperatorType(NUMERIC, this);
}
else if (LeftNumeric || RightNumeric) {
// ADD of NUMERIC to non-NUMERIC preserves non-NUMERIC type.
// AND and OR operations should leave the operator UNINIT for now.
if (LeftNumeric && (UNINIT != RightType)
&& ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) {
CurrRT->SetOperatorType(RightType, this);
else if (RightNumeric && (UNINIT != LeftType)
&& ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) {
CurrRT->SetOperatorType(LeftType, this);
else if (LeftPointer && RightPointer) {
// Arithmetic on two pointers
if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) {
CurrRT->SetOperatorType(UNKNOWN, this);
updated = true;
}
else { // bitwise AND or OR of two pointers
msg("WARNING: hash of two pointers at %x in %s\n",
this->GetAddr(), this->GetDisasm());
// hash operation? leave operator as UNINIT
clc5q
committed
else if ((LeftPointer && IsEqType(RightType, PTROFFSET))
|| (RightPointer && IsEqType(LeftType, PTROFFSET))) {
// Arithmetic on PTR and PTROFFSET
if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) {
// We assume (A-B) is being added to B or vice versa **!!**
CurrRT->SetOperatorType(POINTER, this);
updated = true;
}
else { // bitwise AND or OR of pointer and pointer difference
msg("WARNING: hash of PTROFFSET and POINTER at %x in %s\n",
this->GetAddr(), this->GetDisasm());
// hash operation? leave operator as UNINIT
}
} // end if UNINIT operator type
else { // operator has type other than UNINIT
if (UNINIT == LeftType) {
CurrUse = this->SetUseType(LeftOp, CurrRT->GetOperatorType());
updated = true;
assert(CurrUse != this->GetLastUse());
}
if (CurrRT->HasRightSubTree()) {
// Must need to iterate through the right tree again, as the operator
// has been typed.
if (UNINIT == RightType) {
CurrRT->GetRightTree()->SetOperatorType(CurrRT->GetOperatorType(), this);
updated = true;
}
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else { // right operand; propagate operator type if needed
if (UNINIT == RightType) {
CurrUse = this->SetUseType(RightOp, CurrRT->GetOperatorType());
updated = true;
assert(CurrUse != this->GetLastUse());
case SMP_SUBTRACT_BORROW: // subtract with borrow
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
// Extract the current types of right and left operands and the operator.
OperType = CurrRT->GetOperatorType();
LeftOp = CurrRT->GetLeftOperand();
LeftUse = this->Uses.FindRef(LeftOp);
assert(LeftUse != this->GetLastUse()); // found it
LeftType = LeftUse->GetType();
if (CurrRT->HasRightSubTree()) {
RightType = CurrRT->GetRightTree()->GetOperatorType();
}
else {
RightOp = CurrRT->GetRightOperand();
if (o_void == RightOp.type) {
msg("ERROR: void operand in %s\n", this->GetDisasm());
return false;
}
else {
RightUse = this->Uses.FindRef(RightOp);
if (RightUse == this->GetLastUse()) {
msg("WARNING: Adding missing USE of ");
PrintOperand(RightOp);
msg(" in %s\n", this->GetDisasm());
this->Uses.SetRef(RightOp);
updated = true;
break;
}
else {
RightType = RightUse->GetType();
}
}
}
// If left operand is NUMERIC, operator is NUMERIC.
clc5q
committed
LeftNumeric = IsEqType(NUMERIC, LeftType);
RightNumeric = IsEqType(NUMERIC, RightType);
LeftPointer = IsDataPtr(LeftType);
RightPointer = IsDataPtr(RightType);
if (LeftNumeric) {
// Subtracting anything from a NUMERIC leaves it NUMERIC.
if (UNINIT == OperType) {
CurrRT->SetOperatorType(NUMERIC, this);
updated = true;
}
else if (NUMERIC != OperType) {
msg("ERROR: SMP_SUBTRACT from NUMERIC should be NUMERIC operator.");
msg(" Operator type is %d in: %s\n", OperType, this->GetDisasm());
}
#if 0
if (!RightNumeric) {
// Right operand is being used as a NUMERIC, so propagate NUMERIC to it.
if (CurrRT->HasRightSubTree()) {
CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
}
else {
RightUse = this->SetUseType(RightOp, NUMERIC);
}
updated = true;
}
#endif
} // end if LeftNumeric
else if (LeftPointer) {
if (UNINIT == OperType) {
// If we subtract another pointer type, we produce PTROFFSET.
if (RightPointer) {
CurrRT->SetOperatorType(PTROFFSET, this);
updated = true;
}
else if (RightType == PTROFFSET) {
// We assume B - (B - A) == A **!!**
CurrRT->SetOperatorType(POINTER, this);
msg("WARNING: PTR - PTROFFSET produces PTR in %s\n", this->GetDisasm());
updated = true;
}
else if (RightNumeric) {
// pointer minus NUMERIC keeps same pointer type
CurrRT->SetOperatorType(LeftType, this);
updated = true;
}
}
else { // we have an operator type for the SMP_SUBTRACT
clc5q
committed
bool OperatorPointer = IsDataPtr(OperType);
if (CurrRT->HasRightSubTree()) {
// Must need to iterate through the right tree again, as the operator
// has been typed.
if (UNINIT == RightType) {
if (OperatorPointer) {
// PTR := PTR - ?? ==> ?? is NUMERIC
CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
updated = true;
}
else if (OperType == PTROFFSET) {
clc5q
committed
// PTROFFSET := PTR - ?? ==> ?? is PTR
CurrRT->GetRightTree()->SetOperatorType(LeftType, this);
updated = true;
}
}
updated |= this->InferOperatorType(CurrRT->GetRightTree());
break;
}
else { // right operand; propagate operator type if needed
if (UNINIT == RightType) {
if (OperatorPointer) {
// PTR := PTR - ?? ==> ?? is NUMERIC
RightUse = this->SetUseType(RightOp, NUMERIC);
updated = true;
assert(RightUse != this->GetLastUse());
}
else if (OperType == PTROFFSET) {
// PTROFFSET := PTR - ?? ==> ?? is PTR
RightUse = this->SetUseType(RightOp, LeftType);
updated = true;
}
break;
}
}
} // end if OperType is UNINIT ... else ...
} // end if LeftNumeric ... else if LeftPointer ...
else if (UNINIT == LeftType) {
if (UNINIT != OperType) {
LeftUse = this->SetUseType(LeftOp, OperType);
assert(LeftUse != this->GetLastUse());
updated = true;
}
}
break;
// Extract the current types of right and left operands and SMP_ASSIGN operator.
OperType = CurrRT->GetOperatorType();
DefOp = CurrRT->GetLeftOperand();
CurrDef = this->Defs.FindRef(DefOp);
assert(CurrDef != this->GetLastDef()); // found it
LeftType = CurrDef->GetType();
if (CurrRT->HasRightSubTree()) {
RightType = CurrRT->GetRightTree()->GetOperatorType();
}
else {
UseOp = CurrRT->GetRightOperand();
if (o_void == UseOp.type) {
msg("ERROR: void operand for SMP_ASSIGN in %s\n", this->GetDisasm());
return false;
}
else {
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
msg("WARNING: Adding missing USE of ");
PrintOperand(UseOp);
msg(" in %s\n", this->GetDisasm());
this->Uses.SetRef(UseOp);
updated = true;
}
// We keep it simple by only trying to propagate one step at a time, from
// the right operand or tree up to the SMP_ASSIGN operator, then from
// the operator to the left (DEF) operand, or from left up to operator
// and down the right, depending on where the existing types are.
if (DebugFlag) {
msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->address, LeftType,
OperType, RightType);
}
if ((UNINIT == RightType) && (UNINIT == LeftType)) {
// We will only try to solve the right hand side on this iteration.
if (CurrRT->HasRightSubTree()) {
updated |= this->InferOperatorType(CurrRT->GetRightTree());
else if (UNINIT == OperType) {
// UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT.
if (UNINIT != RightType) {
// We have to special case conditional moves. Only if both operands
// (the source and the prior value of the potential destination,
// which was added to the USE set by BuildMoveRTL()) agree in type
// can we propagate their common type to the operator and ultimately
// to the DEF.
if ((!this->MDIsConditionalMoveInstr()) || this->Uses.TypesAgreeNoFlags()) {
CurrRT->SetOperatorType(RightType, this);
updated = true;
}
}
else {
CurrRT->SetOperatorType(LeftType, this);
updated = true;
}
break;
}
else if (UNINIT == LeftType) {
// SMP_ASSIGN operator has type, so propagate it.
LeftType = OperType;
CurrDef = this->SetDefType(DefOp, OperType);
// Propagate the new DEF type unless it is an indirect memory access.
// Future: Propagate until re-DEF of addressing register terminates
// the propagation. **!!**
if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
clc5q
committed
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
if ((o_reg == DefOp.type)
|| (SafeFunc && MDIsStackAccessOpnd(DefOp, UseFP))) {
clc5q
committed
int SSANum = CurrDef->GetSSANum();
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
clc5q
committed
this->GetAddr(), SSANum);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
SSANum);
}
}
}
break;
}
else if (UNINIT == RightType) {
// SMP_ASSIGN operator has type, so propagate it.
if (CurrRT->HasRightSubTree()) {
CurrRT->GetRightTree()->SetOperatorType(OperType, this);
updated = true;
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else {
// For conditional moves, propagate to the pseudo-USE of the
// destination register as well as the source operand.
if (this->MDIsConditionalMoveInstr()) {
CurrUse = this->FindUse(DefOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT == CurrUse->GetType())
CurrUse = this->SetUseType(DefOp, OperType);
else if (OperType != CurrUse->GetType()) {
msg("WARNING: Avoiding lattice oscillation from type %d to %d at %x for: ",
CurrUse->GetType(), OperType, this->address);
PrintOperand(CurrUse->GetOp());
msg("\n");
}
}
CurrUse = this->SetUseType(UseOp, OperType);
updated = true;
break;
default:
msg("Unknown operator in %s\n", this->GetDisasm());
break;
} // end switch on operator
return updated;
} // end of SMPInstr::InferOperatorType()
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
// Get the meet of the metadata types of all non-flags DEFs.
SMPMetadataType SMPInstr::GetDefMetadataType(void) {
SMPMetadataType MeetType = DEF_METADATA_UNANALYZED;
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
SMPMetadataType CurrType;
op_t DefOp = CurrDef->GetOp();
if (DefOp.is_reg(X86_FLAGS_REG))
continue; // flags are always unused metadata; irrelevant
CurrType = CurrDef->GetMetadataStatus();
if (MeetType == CurrType)
continue; // no meet operation to perform
// Any time we find USED metadata, that overrides all other types.
if (CurrType == DEF_METADATA_USED)
return CurrType;
if (MeetType == DEF_METADATA_UNANALYZED)
MeetType = CurrType;
else if (MeetType < DEF_METADATA_REDUNDANT) {
// Conflict between types of different DEFs. It could be that
// a multiply or divide instruction DEFs EAX and EDX, and one
// of them is used in a store and the other is unused. In that
// case, the final MeetType is USED and we can return. Or, if
// one type is UNUSED and the other is REDUNDANT, we can set
// the final type to the REDUNDANT type and return. The USED case
// is handled above, so we must have the UNUSED vs. REDUNDANT case.
assert(CurrType >= DEF_METADATA_REDUNDANT);
MeetType = CurrType;
}
else { // MeetType REDUNDANT, not equal to CurrType.
if (CurrType >= DEF_METADATA_REDUNDANT) {
// One type is profile derived, both are REDUNDANT.
MeetType = DEF_METADATA_PROF_REDUNDANT;
}
else {
assert(DEF_METADATA_UNUSED == CurrType);
// leave MeetType as REDUNDANT
}
}
} // end for all DEFs
return MeetType;
} // end of SMPInstr::GetDefMetadataType()
// Handle x86 opcode SIB byte annotations.
void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, op_t Opnd, ea_t offset, bool UseFP) {
int BaseReg;
int IndexReg;
ea_t displacement;
ushort ScaleFactor;
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement);
if (BaseReg == R_sp) { // ESP cannot be IndexReg
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm);
}
else if (UseFP && ((IndexReg == R_bp) || (BaseReg == R_bp))) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm);
}
return;
} // end of MDAnnotateSIBStackConstants
// Emit annotations for constants used as ptr offsets from EBP or
// ESP into the stack frame. Only pay attention to EBP-relative
// offsets if EBP is being used as a frame pointer (UseFP == true).
void SMPInstr::AnnotateStackConstants(bool UseFP, FILE *AnnotFile) {
op_t Opnd;
ea_t offset;
int BaseReg;
int IndexReg;
ushort ScaleFactor;
#if 0
if (this->address == 0x80925f4) {
msg("PROBLEM INSTRUCTION: \n");
this->PrintOperands();
}
#endif
for (int i = 0; i < UA_MAXOP; ++i) {
Opnd = SMPcmd.Operands[i];
if ((Opnd.type == o_displ) || (Opnd.type == o_phrase))
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
if (Opnd.type == o_displ) {
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // no SIB
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
} // end if (Opnd.hasSIB) ... else ...
} // end if (Opnd.type == o_displ)
else if (Opnd.type == o_phrase) {
offset = 0; // mmStrata thinks [esp] is [esp+0]
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // Something like [ecx]; is it [esp] or [ebp] ?
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
} // end if (Opnd.hasSIB) ... else ...
} // end else if (Opnd.type == o_phrase)
} // end for all operands
// If we move a stack pointer or frame pointer into another register, we
// need to annotate the implicit zero offset, e.g. mov edi,esp == mov edi,esp+0
// and edi is becoming a stack pointer that mmStrata needs to track.
if (this->MDIsStackPointerCopy(UseFP)) {
// Two possibilities: a move of the stack pointer, or an "lea"
// opcode, e.g. lea eax,[eap+8] ==> eax:=esp+8. In the move
// instruction (e.g. mov eax,esp), we have the implicit zero
// offset from the stack pointer register, but in the lea case,
// we might have zero or some other offset (lea eax,[esp] has
// the implicit zero).
int ESPoffset = 0;
if (NN_lea == this->SMPcmd.itype) {
ESPoffset = this->MDGetImmedUse();
}
if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, ESPoffset, disasm);
qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, ESPoffset, disasm);
}
}
return;
} // end of SMPInstr::AnnotateStackConstants()
// Emit all annotations for the instruction in the absence of RTL type inference.
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags); // assumes 2nd source is Imm or not-numeric?!
bool OrphanCode = (NULL == this->BasicBlock);
ProfilerInformation *ProfInfo = NULL;
#if SMP_CHILDACCESS_ALL_CODE
if (!OrphanCode)
ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
#endif
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
++OptCount[OptType]; // keep count for debugging info
#if SMP_DEBUG_MEM
if (MemDest || MemSrc) {
msg("OptType: %d %s", OptType, disasm);
this->PrintOperands();
}
#endif
// Emit appropriate optimization annotations.
bool SDTInstrumentation = false;
switch (OptType) {
case 0: // SDT will have to handle these
{
#if SMP_DEBUG_TYPE0
msg("OptType 0: %x %s\n", addr, disasm);
#endif
// mmStrata wants to suppress warnings on the PUSH
// instructions that precede the LocalVarsAllocInstr
// (i.e. the PUSHes of callee-saved regs).
if ((!AllocSeen || !NeedsFrame) && this->MDIsPushInstr()) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
addr, -3, disasm);
}
else {
SDTInstrumentation = true;
}
break;
}
case 1: // nothing for SDT to do
{ qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
break;
}
case 4: // INC, DEC, etc.: no SDT work unless MemDest
{ if (MemDest || MemSrc) {
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
break;
}
case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
{ if (MemDest || MemSrc) {
SDTInstrumentation = true;
break; // treat as category 0
}
clc5q
committed
if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
clc5q
committed
else {
SDTInstrumentation = true;
}
break;
}
case 6: // Only OS code should include these; problem for SDT
{ if (MemDest) {
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
addr, -OptType, disasm);
++AnnotationCount[OptType];
break;
}
case 8: // Implicitly writes to EDX:EAX, always numeric.
{ qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
addr, -2, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
SDTInstrumentation = true;
break;
}
case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0)
{ if (MemDest) {
clc5q
committed
#if SMP_DEBUG2
// MemDest seems to happen too much.
msg("Floating point MemDest: %s \n", disasm);
#endif
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
break;
}
default: // 2,3,7: Optimization possibilities depend on operands
{
#if SMP_DEBUG2
if (OptType == 3) { // MOV instr class
if (MemDest) {
msg("MemDest on MOV: %s\n", disasm);
}
else if (!SecondSrcOperandNum) {
msg("MOV: not 2nd op numeric: %s\n", disasm);
this->PrintOperands();
}
}
#endif
SDTInstrumentation = true;
if (MemDest) {
#if SMP_DEBUG_XOR
if (OptType == 2)
msg("MemDest on OptType 2: %s\n", disasm);
#endif
break; // treat as category 0
}
if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
addr, -2, this->DestString(OptType),
OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
break;
}
} // end switch (OptType)
// always emit stack constant annotations, in case strata is
// instrumenting all instructions, or trying to verify speculative annotations.
this->AnnotateStackConstants(UseFP, AnnotFile);
// If mmStrata is going to have to deal with the
// instruction, then we can annotate EBP and ESP
// relative constant offsets. If we have emitted
// an annotation of type -1, there is no point
// in telling mmStrata about these constants.
// Likewise, we can tell mmStrata if a MemDest is an
// non-directly-accessed child object.
if (SDTInstrumentation) {
if (strlen(this->DeadRegsString) > 0) {
// Optimize by informing mmStrata of dead registers. It can avoid saving
// and restoring dead state. This is particularly important for EFLAGS,
// as restoring the flags is a pipeline serializing instruction.
qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
addr, this->SMPcmd.size, this->DeadRegsString, disasm);
}
#if SMP_CHILDACCESS_ALL_CODE
int ChildOffset, ChildSize;
if (MemDest && !OrphanCode
&& ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr,
ChildOffset, ChildSize)) {
qfprintf(AnnotFile, "%10x %6d INSTR CHILDACCESS %d %d ZZ %s \n",
addr, this->SMPcmd.size, ChildOffset, ChildSize, disasm);
}
#endif
}
return;
} // end of SMPInstr::EmitAnnotations()
/**
* Emits Safe Returns
* Mark the type of the annotation as "-4". Currently the SDT is ignoring this
* annotation.
*/
void SMPInstr::EmitSafeReturn(FILE *AnnotFile)
{
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL SafeReturn %s\n",
this->address, -4, disasm);
// Emit all annotations for the instruction using RTL type inference.
void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
int TypeGroup = SMPTypeCategory[this->SMPcmd.itype];
bool NumericDEFs = this->AllDefsNumeric(); // all DEFs are NUMERIC or CODEPTR
bool ProfiledDEFs = this->AnyDefsProfiled(); // all DEFs are NUMERIC or CODEPTR
bool UnusedMetadata = this->AllDefMetadataUnused();
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags); // assumes 2nd source is imm or not-numeric??
SMPMetadataType DefMetadataType = this->GetDefMetadataType();
ProfilerInformation *ProfInfo;
ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
++OptCount[this->OptType]; // keep count for debugging info
// Emit appropriate optimization annotations.
bool SDTInstrumentation = false;
// If the DEF metadata is all unused, mmStrata can skip the instruction.
// We omit this for groups 1 and 14, so that the metadata analysis
// does not get statistical credit for instructions that were already
// getting -1 annotations without analysis.
if ((1 != TypeGroup) && (14 != TypeGroup) && (!this->MDIsInterruptCall())) {
if (UnusedMetadata) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataUnused %s \n",
++AnnotationCount[this->OptType];
return;
}
else if (DEF_METADATA_REDUNDANT == DefMetadataType) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataRedundant %s \n",
addr, -1, disasm);
++AnnotationCount[this->OptType];
return;
}
else if (DEF_METADATA_PROF_REDUNDANT == DefMetadataType) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataRedundant %s \n",
addr, -257, disasm);
++AnnotationCount[this->OptType];
clc5q
committed
// Profiler annotations could be backed off due to false
// positives, in which case we will need stack constant
// annotations.
this->AnnotateStackConstants(UseFP, AnnotFile);
switch (TypeGroup) {
case 0: // SDT will have to handle these
case 11: // PUSH/POP **!!** What if we push/pop NUMERIC type? Optimize?
// --jdh
// pop numeric's can be optimized with a numericdef annotation.
// numeric push's can't immediately be optimized, but if the stack location
// can be proven as dead metadata, then perhaps optimize.
// --jdh
// mmStrata wants to suppress warnings on the PUSH
// instructions that precede the LocalVarsAllocInstr
// (i.e. the PUSHes of callee-saved regs).
if ((!AllocSeen || !NeedsFrame) && this->MDIsPushInstr()) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
addr, -3, disasm);
}
else {
SDTInstrumentation = true;
}
break;
case 1: // nothing for SDT to do
case 14:
if (MemDest) {
msg("ERROR: MemDest in Type Category 1 or 14: %x %s\n", addr, disasm);
SDTInstrumentation = true;
break;
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[this->OptType], disasm);
++AnnotationCount[this->OptType];
break;
case 4: // INC, DEC, etc.: no SDT work unless MemDest
if (MemDest || MemSrc) { // pretty conservative here?
// could be more aggressive if we know there's no overflow. -- jdh
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n",
addr, -1, disasm);
case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
if (MemDest) {
SDTInstrumentation = true;
break; // treat as category 0
}
#endif
this->SetAddSubSourceType();
if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) {
// treat as category 1
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[this->OptType], disasm);
++AnnotationCount[this->OptType];
else if (IsEqType(NUMERIC, this->AddSubSourceType)
&& !this->MDIsFrameAllocInstr()
&& (this->SMPcmd.itype != NN_adc)
&& (this->SMPcmd.itype != NN_sbb)) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL 2ndSrcNumeric %s \n",
addr, -1, disasm);
}
else if (NumericDEFs) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->OptType), disasm);
#if SMP_OPTIMIZE_ADD_TO_NUMERIC
else if ((NN_add == this->SMPcmd.itype) && (!MemSrc)
&& IsNumeric(this->AddSubUseType)) {
// reg1 := reg1 + reg2, where reg1 comes in as NUMERIC,
// means that reg1 will get DEFed to the type of reg2,
// whatever it is. If reg2 were known to be NUMERIC,
// we would have hit one of the annotation cases above.
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s := %s ZZ AddToNumeric %s \n",
addr, -5, RegNames[this->AddSubUseOp.reg],
RegNames[this->AddSubSourceOp.reg], disasm);
++AnnotationCount[this->OptType];
}
#endif
else {
SDTInstrumentation = true;
}
break;
case 6: // Only OS code should include these; problem for SDT
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
addr, -OptType, disasm);
break;
case 8: // Implicitly writes to EDX:EAX, always numeric.
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
addr, -2, OptExplanation[this->OptType], disasm);
++AnnotationCount[this->OptType];
SDTInstrumentation = true;
break;
case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0)
if (MemDest) {
SDTInstrumentation = true;
#if 0
if (NumericDEFs) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->OptType), disasm);
}
#endif
}
else {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[this->OptType], disasm);
++AnnotationCount[this->OptType];
}
break;
clc5q
committed
case 10: // AND, OR, etc.: If all DEFs have been inferred to be
// NUMERIC, then output optimizing annotation.
SDTInstrumentation = true;
if (MemDest) { // **!!** optimize with numeric annotation in future
break; // treat as category 0
}
else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->OptType), disasm);
}
break;
case 12: // Exchange, exchange and add, conditional exchange: All NUMERIC
// sources ==> NUMERIC DEFs, so nothing for mmStrata to do.
if (MemDest) { // **!!** optimize with numeric annotation in future
SDTInstrumentation = true;
break; // treat as category 0
}
else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr,
ProfiledDEFs ? -256-1 : -1, OptExplanation[TypeGroup], disasm);
}
else
SDTInstrumentation = true;
break;
case 15: // Floating point, NUMERIC, possible memory destination.
// If not memory destination, fpreg dest, so nothing for mmStrata to do.
if (MemDest) { // **!!** optimize with numeric annotation in future
SDTInstrumentation = true;
break; // treat as category 0
}
else { // NUMERIC floating register result; these regs are always NUMERIC
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr,
-1, OptExplanation[TypeGroup], disasm);
}
break;
default: // 2,3,7: Optimization possibilities depend on operands
SDTInstrumentation = true;
if (MemDest) {
break; // treat as category 0
}
if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
addr, -2, this->DestString(this->OptType),
OptExplanation[this->OptType], disasm);
++AnnotationCount[this->OptType];
}
else if (NumericDEFs) { // NUMERIC move instruction
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->OptType), disasm);
}
break;
} // end switch (OptType)
// always annotate stack constants for the profiler, etc.
this->AnnotateStackConstants(UseFP, AnnotFile);
// If mmStrata is going to have to deal with the
// instruction, then we can annotate EBP and ESP
// relative constant offsets. If we have emitted
// an annotation of type -1, there is no point
// in telling mmStrata about these constants.
// Likewise, we can tell mmStrata if a MemDest is an
// non-directly-accessed child object.
int ChildOffset, ChildSize;
if (SDTInstrumentation) {
if (strlen(this->DeadRegsString) > 0) {
// Optimize by informing mmStrata of dead registers. It can avoid saving
// and restoring dead state. This is particularly important for EFLAGS,
// as restoring the flags is a pipeline serializing instruction.
qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
addr, this->SMPcmd.size, this->DeadRegsString, disasm);
}
if (MemDest && ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr,
ChildOffset, ChildSize)) {
qfprintf(AnnotFile, "%10x %6d INSTR CHILDACCESS %d %d ZZ %s \n",
addr, this->SMPcmd.size, ChildOffset, ChildSize, disasm);
}
#if SMP_IDENTIFY_POINTER_ADDRESS_REG
if (MemDest) {
assert(o_void != this->DestMemOp.type);
set<DefOrUse, LessDefUse>::iterator PtrUse;
PtrUse = this->GetPointerAddressReg(this->DestMemOp);
if (PtrUse != this->GetLastUse()) { // found POINTER addr reg USE
if (PtrUse->GetOp().type == o_reg) {
ushort PtrReg = PtrUse->GetOp().reg;
qfprintf(AnnotFile, "%10x %6d INSTR POINTER reg %s ZZ %s \n",
addr, this->SMPcmd.size, RegNames[PtrReg], disasm);
}
}
}
#endif
}
return;
} // end of SMPInstr::EmitTypeAnnotations()
// Go through the PUSH RTL and get the operand pushed.
op_t SMPInstr::GetPushedOpnd(void) {
op_t VoidOp = InitOp;
if (NN_push == this->SMPcmd.itype) {
for (size_t OpNum = 0; OpNum < UA_MAXOP; ++OpNum) {
op_t TempOp = this->SMPcmd.Operands[OpNum];
if (this->features & UseMacros[OpNum]) { // USE
return TempOp;
}
}
msg("ERROR: Could not find PUSH operand at %x %s\n", this->address,
this->GetDisasm());
return VoidOp;
}
else {
return VoidOp;