Newer
Older
clc5q
committed
// can improve this in the future. **!!**
bool IsMemOp = (o_reg != DefOp.type);
bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
;
#else
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
MemPropagate = MemPropagate && SafeFunc;
#endif
if ((o_reg == DefOp.type) || MemPropagate) {
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC,
this->GetAddr(), SSANum, IsMemOp);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC,
SSANum, IsMemOp);
}
this->SetCategoryInferenceComplete();
case 4: // Unary INC, DEC, etc.: dest=source, so type remains the same
assert(this->RTL.GetRT(0)->HasRightSubTree());
UseOp = this->RTL.GetRT(0)->GetLeftOperand(); // USE == DEF
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT != CurrUse->GetType()) {
// Only one USE, and it has a type assigned, so assign that type
// to the DEF.
CurrDef = this->GetFirstDef();
while (CurrDef != this->GetLastDef()) {
// Two DEFs: EFLAGS is NUMERIC, dest==source
DefOp = CurrDef->GetOp();
SSANum = CurrDef->GetSSANum();
if (DefOp.is_reg(X86_FLAGS_REG)) {
; // SetImmedTypes already made it NUMERIC
CurrDef = this->SetDefType(DefOp, CurrUse->GetType());
clc5q
committed
// Be conservative and only propagate register DEFs and SAFE stack locs. We
// can improve this in the future. **!!**
bool IsMemOp = (o_reg != DefOp.type);
MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
;
#else
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
MemPropagate = MemPropagate && SafeFunc;
#endif
if ((o_reg == DefOp.type) || MemPropagate) {
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, CurrUse->GetType(),
this->GetAddr(), SSANum, IsMemOp);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, CurrUse->GetType(),
SSANum, IsMemOp);
}
this->SetCategoryInferenceComplete();
this->SetTypeInferenceComplete();
}
break;
case 6: // Result is always POINTER
DefOp = this->GetFirstDef()->GetOp();
SSANum = this->GetFirstDef()->GetSSANum();
CurrDef = this->SetDefType(DefOp, POINTER);
this->SetCategoryInferenceComplete();
clc5q
committed
// Be conservative and only propagate register DEFs and SAFE stack locs. We
// can improve this in the future. **!!**
IsMemOp = (o_reg != DefOp.type);
MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
;
#else
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
MemPropagate = MemPropagate && SafeFunc;
#endif
if ((o_reg == DefOp.type) || MemPropagate) {
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, POINTER,
this->GetAddr(), SSANum, IsMemOp);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, POINTER,
SSANum, IsMemOp);
}
clc5q
committed
SMP_msg("ERROR: Unknown type category for %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
this->SetCategoryInferenceComplete();
break;
} // end switch on TypeCategory
} // end if (!CategoryInference)
// Walk the RTL and infer types based on operators and operands.
clc5q
committed
SMP_msg("RTcount: %zu\n", this->RTL.GetCount());
for (size_t index = 0; index < this->RTL.GetCount(); ++index) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
continue;
if (!(CurrRT->IsTypeInferenceComplete())) {
changed |= this->InferOperatorType(CurrRT);
}
clc5q
committed
SMP_msg("returned from InferOperatorType\n");
} // end for all RTs in the RTL
return changed;
} // end of SMPInstr::InferTypes()
// Infer the type of an operator within an RT based on the types of its operands and
// based on the operator itself. Recurse down the tree if necessary.
// Return true if the operator type of the RT is updated.
bool SMPInstr::InferOperatorType(SMPRegTransfer *CurrRT) {
bool updated = false;
clc5q
committed
bool LeftNumeric, RightNumeric, OperNumeric;
bool LeftPointer, RightPointer, OperPointer;
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
bool SafeFunc = this->BasicBlock->GetFunc()->IsSafe();
set<DefOrUse, LessDefUse>::iterator CurrDef;
set<DefOrUse, LessDefUse>::iterator CurrUse;
set<DefOrUse, LessDefUse>::iterator LeftUse;
set<DefOrUse, LessDefUse>::iterator RightUse;
SMPOperandType LeftType = UNINIT;
SMPOperandType RightType = UNINIT;
SMPOperandType OperType = UNINIT;
op_t UseOp = InitOp, DefOp = InitOp, LeftOp = InitOp, RightOp = InitOp;
SMPoperator CurrOp = CurrRT->GetOperator();
#if SMP_VERBOSE_DEBUG_INFER_TYPES
clc5q
committed
bool DebugFlag = false;
#if 1
DebugFlag |= (0 == strcmp("InputMove", this->BasicBlock->GetFunc()->GetFuncName()));
#endif
DebugFlag = DebugFlag || ((this->address == 0x806453b) || (this->address == 0x806453e));
#if SMP_VERBOSE_DEBUG_INFER_TYPES
if (DebugFlag) {
clc5q
committed
SMP_msg("Entered InferOperatorType for CurrOp: %d at %x\n", CurrOp, this->GetAddr());
}
if (CurrRT->IsTypeInferenceComplete()) {
return updated;
}
switch (CurrOp) {
case SMP_NULL_OPERATOR:
break;
case SMP_CALL: // CALL instruction
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(CODEPTR, this);
UseOp = CurrRT->GetRightOperand();
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, CODEPTR);
}
else if (CODEPTR != CurrUse->GetType()) {
clc5q
committed
SMP_msg("WARNING: call target is type %d, setting to CODEPTR at %x in %s\n",
CurrUse->GetType(), this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
CurrUse = this->SetUseType(UseOp, CODEPTR);
}
break;
case SMP_INPUT: // input from port
if (UNINIT == CurrRT->GetOperatorType()) {
updated = true;
}
break;
case SMP_OUTPUT: // output to port
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(NUMERIC, this);
updated = true;
}
break;
case SMP_SIGN_EXTEND:
case SMP_ZERO_EXTEND:
// Should we infer that all operands are NUMERIC? !!!???!!!!
break;
case SMP_ADDRESS_OF: // take effective address
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(POINTER, this);
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
// Left operand is having its address taken, but we cannot infer what its
// type is.
updated = true;
}
break;
case SMP_U_LEFT_SHIFT: // unsigned left shift
case SMP_S_LEFT_SHIFT: // signed left shift
case SMP_U_RIGHT_SHIFT: // unsigned right shift
case SMP_S_RIGHT_SHIFT: // signed right shift
case SMP_ROTATE_LEFT:
case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
case SMP_ROTATE_RIGHT:
case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
case SMP_U_MULTIPLY:
case SMP_S_MULTIPLY:
case SMP_U_DIVIDE:
case SMP_S_DIVIDE:
case SMP_U_REMAINDER:
case SMP_BITWISE_NOT: // unary operator
case SMP_BITWISE_XOR:
case SMP_S_COMPARE: // signed compare (subtraction-based)
case SMP_U_COMPARE: // unsigned compare (AND-based)
case SMP_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
case SMP_EQUAL:
case SMP_NOT_EQUAL:
case SMP_LOGICAL_AND:
case SMP_LOGICAL_OR:
case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
case SMP_REVERSE_SHIFT_U: // all the same to our type system; all NUMERIC
case SMP_SHUFFLE: // all the same to our type system; all NUMERIC
case SMP_COMPARE_EQ_AND_SET: // packed compare for equality and set bits; all NUMERIC
case SMP_COMPARE_GT_AND_SET: // packed compare for greater-than and set bits; all NUMERIC
case SMP_INTERLEAVE: // interleave fields from two packed operands; NUMERIC
case SMP_CONCATENATE: // all the same to our type system; all NUMERIC
if (UNINIT == CurrRT->GetOperatorType()) {
CurrRT->SetOperatorType(NUMERIC, this);
updated = true;
}
// Left operand should be NUMERIC if it exists.
UseOp = CurrRT->GetLeftOperand();
if (UseOp.type != o_void) {
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: Adding missing USE of ");
clc5q
committed
SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
this->Uses.SetRef(UseOp, NUMERIC, -1);
updated = true;
}
else if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, NUMERIC);
updated = true;
}
}
// Right operand should be NUMERIC if it exists.
if (CurrRT->HasRightSubTree()) {
// Recurse into subtree
clc5q
committed
#if SMP_AGGRESSIVE_TYPE_INFERENCE
if (UNINIT == CurrRT->GetRightTree()->GetOperatorType()) {
CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
}
#endif
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else {
UseOp = CurrRT->GetRightOperand();
if (UseOp.type != o_void) {
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: Adding missing USE of ");
clc5q
committed
SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
this->Uses.SetRef(UseOp, NUMERIC, -1);
updated = true;
}
else if (UNINIT == CurrUse->GetType()) {
CurrUse = this->SetUseType(UseOp, NUMERIC);
updated = true;
}
}
}
break;
clc5q
committed
case SMP_NEGATE: // unary negation
UseOp = CurrRT->GetLeftOperand();
assert(o_void != UseOp.type);
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: Adding missing USE of ");
clc5q
committed
PrintOperand(UseOp);
clc5q
committed
SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
updated = true;
}
else {
OperType = CurrRT->GetOperatorType();
LeftType = CurrUse->GetType();
// Only tricky cases are the negation of a POINTER or PTROFFSET.
// Negation of PTROFFSET could be inefficient code that computed
// PTR1 - PTR2 and later corrected it to PTR2 - PTR1 by negation.
// The type remains PTROFFSET. Negating a POINTER could be an unusual
// case similar to subtracting a POINTER from a NUMERIC. See comments
// in the SMP_ADD case below, and also the SMP_SUBTRACT case.
if (LeftType == PTROFFSET) {
// Override any prior operator type, in case PTROFFSET was inferred late
// in our analysis and the operator was set to NUMERIC.
CurrRT->SetOperatorType(PTROFFSET, this);
updated = true;
}
else if (IsDataPtr(LeftType)) {
// Override any prior operator type, in case POINTER was inferred late
// in our analysis and the operator was set to NUMERIC.
CurrRT->SetOperatorType(NEGATEDPTR, this);
updated = true;
}
else if (OperType == UNINIT) {
// Default to NUMERIC for most negations.
CurrRT->SetOperatorType(NUMERIC, this);
// But, leave left operand type alone, in case an UNINIT operand
// might be determined later to be PTROFFSET or NEGATEDPTR.
// Leaving it alone causes us not to set TypeInferenceFinished to true
// at the end of this function in the UNINIT case.
updated = true;
}
}
break;
case SMP_INCREMENT:
case SMP_DECREMENT:
clc5q
committed
// The type of the left operand is propagated to the operator, or vice
// versa, whichever receives a type first.
assert(!CurrRT->HasRightSubTree());
UseOp = CurrRT->GetLeftOperand();
assert(o_void != UseOp.type);
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: Adding missing USE of ");
clc5q
committed
SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
this->Uses.SetRef(UseOp);
updated = true;
break;
}
if (UNINIT == CurrRT->GetOperatorType()) {
if (UNINIT != CurrUse->GetType()) {
// Propagate operand type up to the operator.
CurrRT->SetOperatorType(CurrUse->GetType(), this);
updated = true;
}
}
else if (UNINIT == CurrUse->GetType()) {
// Propagate operator type to operand.
CurrUse = this->SetUseType(UseOp, CurrRT->GetOperatorType());
updated = true;
}
break;
case SMP_BITWISE_AND:
case SMP_BITWISE_OR:
// Extract the current types of right and left operands and the operator.
clc5q
committed
OperType = CurrRT->GetOperatorType();
LeftOp = CurrRT->GetLeftOperand();
CurrUse = this->Uses.FindRef(LeftOp);
assert(CurrUse != this->GetLastUse()); // found it
LeftType = CurrUse->GetType();
if (CurrRT->HasRightSubTree()) {
clc5q
committed
updated |= this->InferOperatorType(CurrRT->GetRightTree());
RightType = CurrRT->GetRightTree()->GetOperatorType();
}
else {
RightOp = CurrRT->GetRightOperand();
if (o_void == RightOp.type) {
clc5q
committed
SMP_msg("ERROR: void operand at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
return updated;
if (CurrUse == this->GetLastUse()) {
clc5q
committed
SMP_msg("SERIOUS WARNING: Adding missing USE of ");
clc5q
committed
SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
updated = true;
break;
RightType = CurrUse->GetType();
}
}
// We have to know both operand types to infer the operator, or know the
clc5q
committed
// operator type and one operand type to infer the other operand type.
if ((UNINIT == OperType)
&& ((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);
clc5q
committed
if (UNINIT == OperType) {
// 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
clc5q
committed
SMP_msg("WARNING: hash of two pointers at %x in %s\n",
this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
// 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
clc5q
committed
SMP_msg("WARNING: hash of PTROFFSET and POINTER at %x in %s\n",
this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
// hash operation? leave operator as UNINIT
clc5q
committed
else if ((LeftPointer && IsEqType(RightType, NEGATEDPTR))
|| (RightPointer && IsEqType(LeftType, NEGATEDPTR))) {
// Compiler optimizations can take a ptr expression such as:
// PTR1 - PTR2 + 1
// and hoist the loop-invariant subexpression " - PTR2 + 1"
// out of the loop as "1 - PTR2", which produces a NEGATEDPTR type.
// When PTR1 gets its value determined inside the loop, then the
// addition of PTR1 finally happens, producing a PTROFFSET type,
// which is what the whole expression is.
if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) {
CurrRT->SetOperatorType(PTROFFSET, this);
updated = true;
}
else { // bitwise AND or OR of pointer and pointer difference
clc5q
committed
SMP_msg("WARNING: hash of NEGATEDPTR and POINTER at %x in %s\n",
this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
// hash operation? leave operator as UNINIT
}
break;
}
else { // operator has type other than UNINIT
// We make add-with-carry and subtract-with-borrow exceptions
// to the type propagation. LeftOp could have POINTER type
// inferred later; these instructions can change the type of
// the register from POINTER to NUMERIC, unlike regular
// add and subtract opcodes.
clc5q
committed
OperNumeric = IsEqType(NUMERIC, OperType);
OperPointer = IsDataPtr(OperType);
if (OperNumeric) {
if ((UNINIT == LeftType)
&& (SMP_ADD_CARRY != CurrOp)) {
CurrUse = this->SetUseType(LeftOp, CurrRT->GetOperatorType());
updated = true;
assert(CurrUse != this->GetLastUse());
clc5q
committed
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());
}
break;
}
else { // right operand; propagate operator type if needed
if (UNINIT == RightType) {
CurrUse = this->SetUseType(RightOp, CurrRT->GetOperatorType());
updated = true;
assert(CurrUse != this->GetLastUse());
break;
}
}
case SMP_SUBTRACT_BORROW: // subtract with borrow
// 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()) {
clc5q
committed
updated |= this->InferOperatorType(CurrRT->GetRightTree());
RightType = CurrRT->GetRightTree()->GetOperatorType();
}
else {
RightOp = CurrRT->GetRightOperand();
if (o_void == RightOp.type) {
clc5q
committed
SMP_msg("ERROR: void operand in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
return false;
}
else {
RightUse = this->Uses.FindRef(RightOp);
if (RightUse == this->GetLastUse()) {
clc5q
committed
SMP_msg("WARNING: Adding missing USE of ");
PrintOperand(RightOp);
clc5q
committed
SMP_msg(" in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
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);
clc5q
committed
// Subtracting anything from a NUMERIC leaves it NUMERIC or NEGATEDPTR,
// in the special case in which a POINTER is subtracted from a NUMERIC.
// See NEGATEDPTR comments in the ADD/AND operators case above.
if (RightPointer) {
CurrRT->SetOperatorType(NEGATEDPTR, this);
updated = true;
}
else if (UNINIT == OperType) {
CurrRT->SetOperatorType(NUMERIC, this);
updated = true;
}
clc5q
committed
else if (IsNotEqType(NUMERIC, OperType) && IsNotEqType(NEGATEDPTR, OperType)) {
clc5q
committed
SMP_msg("ERROR: SMP_SUBTRACT from NUMERIC should be NUMERIC or NEGATEDPTR operator.");
SMP_msg(" Operator type is %d in: %s\n", OperType, DisAsmText.GetDisAsm(this->GetAddr()));
#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);
clc5q
committed
SMP_msg("WARNING: PTR - PTROFFSET produces PTR at %x in %s\n",
this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
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
OperNumeric = IsEqType(NUMERIC, OperType);
OperPointer = IsDataPtr(OperType);
if (CurrRT->HasRightSubTree()) {
clc5q
committed
// Might need to iterate through the right tree again, if its operator
// can be typed.
if (UNINIT == RightType) {
clc5q
committed
if (OperPointer) {
// PTR := PTR - ?? ==> ?? is NUMERIC Why? ?? could be PTROFFSET
CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this);
clc5q
committed
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else if (OperType == PTROFFSET) {
clc5q
committed
// PTROFFSET := PTR - ?? ==> ?? is PTR
CurrRT->GetRightTree()->SetOperatorType(LeftType, this);
clc5q
committed
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else if (OperNumeric) {
clc5q
committed
SMP_msg("WARNING: PTR - ?? produces NUMERIC at %x in %s\n",
this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
}
}
break;
}
else { // right operand; propagate operator type if needed
if (UNINIT == RightType) {
clc5q
committed
if (OperPointer) {
// PTR := PTR - ?? ==> ?? is NUMERIC Why? ?? could be PTROFFSET
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;
}
clc5q
committed
else if (OperNumeric) {
clc5q
committed
SMP_msg("WARNING: PTR - ?? produces NUMERIC at %x in %s\n",
this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
clc5q
committed
}
break;
}
}
} // end if OperType is UNINIT ... else ...
} // end if LeftNumeric ... else if LeftPointer ...
else if (UNINIT == LeftType) {
// We make add-with-carry and subtract-with-borrow exceptions
// to the type propagation. LeftOp could have POINTER type
// inferred later; these instructions can change the type of
// the register from POINTER to NUMERIC, unlike regular
// add and subtract opcodes.
if ((UNINIT != OperType)
&& (SMP_SUBTRACT_BORROW != CurrOp)) {
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()) {
clc5q
committed
updated |= this->InferOperatorType(CurrRT->GetRightTree());
RightType = CurrRT->GetRightTree()->GetOperatorType();
}
else {
UseOp = CurrRT->GetRightOperand();
if (o_void == UseOp.type) {
clc5q
committed
SMP_msg("ERROR: void operand for SMP_ASSIGN in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
return false;
}
else {
CurrUse = this->Uses.FindRef(UseOp);
if (CurrUse == this->GetLastUse()) {
clc5q
committed
SMP_msg("WARNING: Adding missing USE of ");
clc5q
committed
SMP_msg(" in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
this->Uses.SetRef(UseOp);
updated = true;
clc5q
committed
#if SMP_VERBOSE_DEBUG_INFER_TYPES
if (DebugFlag) {
clc5q
committed
SMP_msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->address, LeftType,
OperType, RightType);
}
clc5q
committed
#endif
if ((UNINIT == RightType) && (UNINIT == LeftType)) {
break;
}
else if (UNINIT == OperType) {
// UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT.
clc5q
committed
bool UpdatedOperType = false;
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;
clc5q
committed
OperType = RightType;
UpdatedOperType = true;
}
}
clc5q
committed
else { // LeftType must not be UNINIT
CurrRT->SetOperatorType(LeftType, this);
updated = true;
clc5q
committed
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
UpdatedOperType = true;
}
// Speed up type propagation by passing the RightType/OperType to the Def
// on this iteration.
if (UpdatedOperType) {
// Propagate the new DEF type unless it is an indirect memory access.
// Future: Propagate until re-DEF of addressing register terminates
// the propagation. **!!**
CurrDef = this->SetDefType(DefOp, OperType);
LeftType = OperType;
if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
bool IsMemOp = (o_reg != DefOp.type);
bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
;
#else
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
MemPropagate = MemPropagate && SafeFunc;
#endif
if ((o_reg == DefOp.type) || MemPropagate) {
int SSANum = CurrDef->GetSSANum();
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
this->GetAddr(), SSANum, IsMemOp);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
SSANum, IsMemOp);
}
}
}
}
break;
}
else if (UNINIT == LeftType) {
// SMP_ASSIGN operator has type, so propagate it.
CurrDef = this->SetDefType(DefOp, OperType);
clc5q
committed
LeftType = 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())) {
bool IsMemOp = (o_reg != DefOp.type);
bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP);
#if SMP_PROPAGATE_MEM_TYPES
;
#else
clc5q
committed
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
MemPropagate = MemPropagate && SafeFunc;
#endif
if ((o_reg == DefOp.type) || MemPropagate) {
clc5q
committed
int SSANum = CurrDef->GetSSANum();
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
this->GetAddr(), SSANum, IsMemOp);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
SSANum, IsMemOp);
}
}
}
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()) {
clc5q
committed
SMP_msg("WARNING: Avoiding lattice oscillation from type %d to %d at %x for: ",
CurrUse->GetType(), OperType, this->address);
PrintOperand(CurrUse->GetOp());
clc5q
committed
SMP_msg("\n");
}
}
CurrUse = this->SetUseType(UseOp, OperType);
updated = true;
clc5q
committed
SMP_msg("ERROR: Unknown operator %d at %x in %s\n",
CurrOp, this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
break;
} // end switch on operator
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
// Determine if type inference is finished for this register transfer.
if (updated && (!TypeInferenceFinished)) {
bool FinishedRight = false;
bool FinishedLeft = false;
bool FinishedOperator = (CurrRT->GetOperatorType() != UNINIT);
if (FinishedOperator) {
switch (CurrOp) {
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_SIGN_EXTEND:
case SMP_ZERO_EXTEND:
case SMP_ADDRESS_OF: // take effective address
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
case SMP_BITWISE_NOT: // unary operator
case SMP_NEGATE: // unary negation
case SMP_DECREMENT:
case SMP_INCREMENT:
case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
// Unary operators have no right operand.
FinishedRight = true;
break;
default: // All binary operators come here
if (CurrRT->HasRightSubTree()) {
FinishedRight = CurrRT->GetRightTree()->IsTypeInferenceComplete();
}
else {
UseOp = CurrRT->GetRightOperand();
if (UseOp.type != o_void) {
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
FinishedRight = (CurrUse->GetType() != UNINIT);
}
else { // if o_void, no further type inference on it is possible.
FinishedRight = true;
}
}
break;
} // end switch on CurrOp
clc5q
committed
if (FinishedRight) { // no point checking left op if right op is not finished
DefOp = CurrRT->GetLeftOperand();
if (DefOp.type != o_void) {
if (SMP_ASSIGN == CurrOp) {
CurrDef = this->Defs.FindRef(DefOp);
assert(CurrDef != this->GetLastDef());
FinishedLeft = (CurrDef->GetType() != UNINIT);
}
else { // not ASSIGN, so really a UseOp not DefOp
CurrUse = this->Uses.FindRef(DefOp);
assert(CurrUse != this->GetLastUse());
FinishedLeft = (CurrUse->GetType() != UNINIT);
}
}
else { // if o_void, no further type inference on it is possible.
FinishedLeft = true;
}
}
TypeInferenceFinished = (FinishedLeft && FinishedRight);
} // end if (FinishedOperator)
} // end if (updated && (!TypeInferenceFinished))
if (TypeInferenceFinished) {
CurrRT->SetTypeInferenceComplete();
}
return updated;
} // end of SMPInstr::InferOperatorType()
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
// Transfer function: Does operator propagate signedness of its operands to its result?
bool SMPInstr::DoesOperatorTransferSign(SMPoperator CurrOp) {
bool transfer = false;
switch (CurrOp) {
case SMP_NULL_OPERATOR:
case SMP_CALL: // CALL instruction
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
// No concept of signedness for some operators
break;
case SMP_ADDRESS_OF: // take effective address
case SMP_U_LEFT_SHIFT: // unsigned left shift
case SMP_U_RIGHT_SHIFT: // unsigned right shift
case SMP_ROTATE_LEFT:
case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
case SMP_ROTATE_RIGHT:
case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
case SMP_U_MULTIPLY:
case SMP_U_DIVIDE:
case SMP_U_REMAINDER:
case SMP_ZERO_EXTEND:
case SMP_BITWISE_NOT: // unary operator
case SMP_BITWISE_XOR:
case SMP_BITWISE_AND_NOT:
case SMP_U_COMPARE: // unsigned compare (AND-based)
case SMP_S_LEFT_SHIFT: // signed left shift
case SMP_S_RIGHT_SHIFT: // signed right shift
case SMP_S_MULTIPLY:
case SMP_S_DIVIDE:
case SMP_SIGN_EXTEND:
case SMP_NEGATE: // unary negation
case SMP_S_COMPARE: // signed compare (subtraction-based)
case SMP_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
// Inherently unsigned and signed operators force the signedness
// of their results, rather than propagating the signedness of
// their operands.
break;
case SMP_DECREMENT:
case SMP_INCREMENT:
case SMP_ADD:
case SMP_ADD_CARRY: // add with carry
case SMP_SUBTRACT:
case SMP_SUBTRACT_BORROW: // subtract with borrow
case SMP_ASSIGN:
case SMP_BITWISE_AND:
case SMP_BITWISE_OR:
case SMP_EQUAL:
case SMP_NOT_EQUAL:
case SMP_LOGICAL_AND:
case SMP_LOGICAL_OR:
case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
transfer = true;
break;
case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's
case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC
transfer = true;
break;
default:
clc5q
committed
SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
break;
} // end switch on operator