Newer
Older
}
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());
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
case SMP_SUBTRACT:
// 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)
|| (FUNC_SAFE == this->BasicBlock->GetFunc()->GetReturnAddressStatus())) {
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()
// 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)) {
if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK 0 displ %s\n",
SMPcmd.ea, SMPcmd.size, disasm);
}
else {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK 0 displ %s\n",
SMPcmd.ea, SMPcmd.size, disasm);
}
}
return;
} // end of SMPInstr::AnnotateStackConstants()
// Emit all annotations for the instruction in the absence of RTL type inference.
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, 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);
++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 && 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",
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
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)
// 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.
if (SDTInstrumentation) {
this->AnnotateStackConstants(UseFP, AnnotFile);
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);
}
}
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, 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 UnusedMetadata = this->AllDefMetadataUnused();
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);
ea_t funcStartAddr=this->GetBlock()->GetFunc()->GetStartAddr();
++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 (UnusedMetadata && (1 != TypeGroup) && (14 != TypeGroup)) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataUnused %s \n",
addr, -1, disasm);
++AnnotationCount[this->OptType];
return;
}
case 0: // SDT will have to handle these
case 11: // PUSH/POP **!!** What if we push/pop NUMERIC type? Optimize?
// mmStrata wants to suppress warnings on the PUSH
// instructions that precede the LocalVarsAllocInstr
// (i.e. the PUSHes of callee-saved regs).
if (!AllocSeen && 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?
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, -2, this->DestString(this->OptType), disasm);
++AnnotationCount[this->OptType];
}
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, -2, this->DestString(this->OptType), disasm);
++AnnotationCount[this->OptType];
}
#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, -2, this->DestString(this->OptType), disasm);
++AnnotationCount[this->OptType];
}
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,
-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, -2, this->DestString(this->OptType), disasm);
++AnnotationCount[this->OptType];
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
}
break;
} // end switch (OptType)
// 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.
if (SDTInstrumentation) {
this->AnnotateStackConstants(UseFP, AnnotFile);
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);
}
}
return;
} // end of SMPInstr::EmitTypeAnnotations()
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
// Go through the PUSH RTL and get the operand pushed.
op_t SMPInstr::GetPushedOpnd(void) {
op_t VoidOp;
VoidOp.type = o_void;
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;
}
} // end of SMPInstr::GetPushedOpnd()
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
// Build the RTL for an instruction with a unary opcode
bool SMPInstr::BuildUnaryRTL(SMPoperator UnaryOp) {
size_t OpNum;
bool DestFound = false;
SMPRegTransfer *TempRT = NULL;
op_t VoidOp;
VoidOp.type = o_void;
op_t FPRegOp;
FPRegOp.type = o_fpreg; // floating point register stack
FPRegOp.reg = 0;
op_t FlagsOp;
FlagsOp.type = o_reg;
FlagsOp.reg = X86_FLAGS_REG;
// Handle special cases first
if (SMP_UNARY_FLOATING_ARITHMETIC == UnaryOp) {
// Use of the floating register stack top is implicit
DestFound = true;
TempRT = new SMPRegTransfer;
TempRT->SetLeftOperand(FPRegOp);
TempRT->SetOperator(SMP_ASSIGN);
SMPRegTransfer *RightRT = new SMPRegTransfer;
RightRT->SetLeftOperand(FPRegOp);
RightRT->SetOperator(UnaryOp);
RightRT->SetRightOperand(VoidOp);
TempRT->SetRightTree(RightRT);
this->RTL.push_back(TempRT);
}
else if ((NN_clc == this->SMPcmd.itype) || (NN_cld == this->SMPcmd.itype)
|| (NN_cmc == this->SMPcmd.itype) || (NN_stc == this->SMPcmd.itype)
|| (NN_std == this->SMPcmd.itype)) {
// Flags register is implicit destination.
DestFound = true;
TempRT = new SMPRegTransfer;
TempRT->SetLeftOperand(FlagsOp);
TempRT->SetOperator(SMP_ASSIGN);
SMPRegTransfer *RightRT = new SMPRegTransfer;
if (NN_cmc == this->SMPcmd.itype) { // complement carry flag USEs old carry flag
RightRT->SetLeftOperand(FlagsOp);
RightRT->SetOperator(SMP_BITWISE_NOT);
}
else {
RightRT->SetLeftOperand(VoidOp);
RightRT->SetOperator(UnaryOp);
}
RightRT->SetRightOperand(VoidOp);
TempRT->SetRightTree(RightRT);
this->RTL.push_back(TempRT);
}
for (OpNum = 0; !DestFound && (OpNum < UA_MAXOP); ++OpNum) {
op_t TempOp = this->SMPcmd.Operands[OpNum];
if (this->features & DefMacros[OpNum]) { // DEF
if (MDKnownOperandType(TempOp)) {
DestFound = true;
TempRT = new SMPRegTransfer;
TempRT->SetLeftOperand(TempOp);
TempRT->SetOperator(SMP_ASSIGN);
SMPRegTransfer *RightRT = new SMPRegTransfer;
RightRT->SetLeftOperand(TempOp);
RightRT->SetOperator(UnaryOp);
RightRT->SetRightOperand(VoidOp);
TempRT->SetRightTree(RightRT);
this->RTL.push_back(TempRT);
}
}
} // end for (OpNum = 0; ...)
#if SMP_DEBUG_BUILD_RTL
if (!DestFound) {
msg("ERROR: Could not find unary operand at %x for %s\n", this->GetAddr(), this->GetDisasm());
}
#endif
return DestFound;
} // end of SMPInstr::BuildUnaryRTL()
// Build the RTL for an instruction with a binary arithmetic opcode
bool SMPInstr::BuildBinaryRTL(SMPoperator BinaryOp) {
size_t OpNum;
bool DestFound = false;
bool SourceFound = false;
bool MemSrc = this->HasSourceMemoryOperand();
bool MemDest = this->HasDestMemoryOperand();
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
SMPRegTransfer *TempRT = NULL;
SMPRegTransfer *RightRT = new SMPRegTransfer;
op_t VoidOp;
VoidOp.type = o_void;
op_t FPRegOp;
FPRegOp.type = o_fpreg; // floating point register stack
FPRegOp.reg = 0;
// Handle special cases first
if (SMP_BINARY_FLOATING_ARITHMETIC == BinaryOp) {
// Use of the floating register stack top is implicit
DestFound = true;
TempRT = new SMPRegTransfer;
TempRT->SetLeftOperand(FPRegOp);
TempRT->SetOperator(SMP_ASSIGN);
RightRT->SetLeftOperand(FPRegOp);
RightRT->SetOperator(BinaryOp);
RightRT->SetRightOperand(VoidOp);
TempRT->SetRightTree(RightRT);
}
for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) {
op_t TempOp = this->SMPcmd.Operands[OpNum];
if (this->features & DefMacros[OpNum]) { // DEF
if (!DestFound && MDKnownOperandType(TempOp)) {
// See comments just below for floating point sources. FP stores
// are analogous to FP loads.
if (!MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) {
DestFound = true;
TempRT = new SMPRegTransfer;
TempRT->SetLeftOperand(TempOp);
TempRT->SetOperator(SMP_ASSIGN);
if (this->RegClearIdiom) {
op_t ImmOp;
ImmOp.type = o_imm;
ImmOp.value = 0;
TempRT->SetRightOperand(ImmOp);
SourceFound = true; // cause loop exit
}
else {
RightRT->SetLeftOperand(TempOp);
RightRT->SetOperator(BinaryOp);
TempRT->SetRightTree(RightRT);
}
}
else {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
msg("WARNING: Skipping DEF operand: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
}
else if (DestFound && (SMP_BINARY_FLOATING_ARITHMETIC != BinaryOp)) {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
msg("ERROR: Found two DEF operands: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
}
else { // USE
if (!SourceFound && MDKnownOperandType(TempOp)) {
// If this is a floating point instruction with the fpregs listed as
// a USE and a memory operand also listed as a USE, then we want to
// ignore the irrelevant USE of the fpreg stack.
// Note that MemDest AND MemSrc means something like add mem,reg is being
// processed, where the memory operand is both DEF and USE.
if (!MemSrc || MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) {
SourceFound = true;
RightRT->SetRightOperand(TempOp);
}
if (!(this->features & UseMacros[OpNum])) {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
msg("WARNING: Operand neither DEF nor USE: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
} // end if DEF ... else ...
} // end for (OpNum = 0; ...)
if (!DestFound || !SourceFound) {
assert(NULL != RightRT);
if (DestFound && (NULL != TempRT))
else
delete RightRT;
if (!DestFound) {
msg("ERROR: Could not find binary DEF operand at %x for %s\n", this->GetAddr(),
this->GetDisasm());
}
else {
msg("ERROR: Could not find binary operand at %x for %s\n", this->GetAddr(),
this->GetDisasm());
this->PrintOperands();
}
#endif
}
else {
this->RTL.push_back(TempRT);
}
return (DestFound && SourceFound);
} // end of SMPInstr::BuildBinaryRTL()
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
// Build the RTL for a load-effective-address instruction.
bool SMPInstr::BuildLeaRTL(void) {
size_t OpNum;
bool DestFound = false;
bool SourceFound = false;
bool MemSrc = this->HasSourceMemoryOperand();
op_t DefOp;
SMPRegTransfer *AssignRT = NULL;
int BaseReg;
int IndexReg;
ushort ScaleFactor;
ea_t offset;
bool ScaledIndexReg;
for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) {
op_t TempOp = this->SMPcmd.Operands[OpNum];
if (this->features & DefMacros[OpNum]) { // DEF
DefOp = TempOp;
DestFound = true;
assert(o_reg == DefOp.type);
}
else { // USE
if (!SourceFound && MDKnownOperandType(TempOp)) {
if ((TempOp.type >= o_mem) && (TempOp.type <= o_displ)) {
SourceFound = true;
MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);