Newer
Older
}
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);
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
// 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_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision
case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision
case SMP_AVERAGE_U: // Average of unsigned operands
case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
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
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
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
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
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
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
// 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()
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
// 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_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision
case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision
case SMP_AVERAGE_U: // Average of unsigned operands
case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
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
return transfer;
} // end of SMPInstr::DoesOperatorTransferSign()
// Initial inferences (if any) about FG info of operand based solely on the RTL operator type above it in RTL.