Newer
Older
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
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
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
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
// 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()
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
// 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.
bool SMPInstr::InitFGInfoFromOperator(SMPoperator CurrOp, struct FineGrainedInfo &InitFG) {
bool changed = false;
switch (CurrOp) {
case SMP_NULL_OPERATOR:
break;
case SMP_CALL: // CALL instruction
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; // target address is unsigned 32-bit
InitFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_CODEPOINTER);
changed = true;
break;
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_ADDRESS_OF: // take effective address
case SMP_U_COMPARE: // unsigned compare (AND-based)
case SMP_S_COMPARE: // signed compare (subtraction-based)
// NOTE: The AND-based and subtraction-based comparisons are used
// on lots of operands of all types, and the conditional jump that
// follows determines signedness, not the operator.
break;
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:
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
changed = true;
break;
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_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
// Special case: If signed multiply operator, it might sometimes
// be used for unsigned operands when upper bits of the result
// are discarded, because there is no difference in the result bits
// between unsigned and signed multiplcation when only the lower
// N bits are retained and the upper N bits are discarded.
if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) {
break;
}
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
changed = true;
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
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
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
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
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= FG_MASK_FLOAT_MMX;
changed = true;
break;
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
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
changed = true;
break;
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
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
changed = true;
break;
case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
changed = true;
break;
default:
clc5q
committed
SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
break;
} // end switch on operator
return changed;
} // end of SMPInstr::InitFGInfoFromOperator()
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
// Helper to take USE operand, find its SSANum, and return its UseHashValue.
int SMPInstr::GetUseOpHashAndSSA(op_t UseOp, int &SSANum) {
op_t SearchOp = UseOp;
SearchOp.reg = MDCanonicalizeSubReg(UseOp.reg);
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
assert(UseIter != this->GetLastUse());
SSANum = UseIter->GetSSANum();
int UseHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
return UseHashValue;
} // end of SMPInstr::GetUseOpHashAndSSA()
// Helper to take DEF operand, find its SSANum, and return its DefHashValue.
int SMPInstr::GetDefOpHashAndSSA(op_t DefOp, int &SSANum) {
op_t SearchOp = DefOp;
SearchOp.reg = MDCanonicalizeSubReg(DefOp.reg);
set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp);
assert(DefIter != this->GetLastDef());
SSANum = DefIter->GetSSANum();
int DefHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
return DefHashValue;
} // end of SMPInstr::GetDefOpHashAndSSA()
// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
bool SMPInstr::UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
set<DefOrUse, LessDefUse>::iterator DefIter;
int SSANum;
int DefHashValue;
op_t SearchOp;
bool LocalName;
struct FineGrainedInfo OldFG, UnionFG;
// If operator is inherently signed, then we will have
// a sign bit set in NewFG from InitFGInfoFromOperator().
DefHashValue = this->GetDefOpHashAndSSA(DefOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(DefOp);
if (LocalName) {
// Get old FG info from block level.
OldFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
}
else { // global name
// Get old FG info from function level.
OldFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
}
UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
// The signs they are a-changin'.
MapsChanged = true;
if (LocalName)
this->BasicBlock->UpdateDefFGInfo(DefHashValue, UnionFG);
this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, UnionFG);
}
return MapsChanged;
} // end of SMPInstr::UpdateDefOpFGInfo()
// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
bool SMPInstr::UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
int SSANum;
int UseHashValue;
bool LocalName;
struct FineGrainedInfo OldFG, UnionFG;
// If operator is inherently signed, then we will have
// a sign bit set in NewFG from InitFGInfoFromOperator().
UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(UseOp);
if (LocalName) {
// Get old FG info from block level.
OldFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else { // global name
// Get old FG info from function level.
OldFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
// The signs they are a-changin'.
MapsChanged = true;
if (LocalName)
this->BasicBlock->UpdateUseFGInfo(UseHashValue, UnionFG);
this->BasicBlock->GetFunc()->UpdateUseFGInfo(UseHashValue, UnionFG);
}
return MapsChanged;
} // end of SMPInstr::UpdateUseOpFGInfo()
// Helper to fetch DEF signedness info for UseOp that has none.
unsigned short SMPInstr::GetDefSignInfoFromUseOp(op_t UseOp) {
int SSANum, UseHashValue;
bool LocalName;
UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(UseOp);
if (LocalName) {
// Get old sign info from block level.
return this->BasicBlock->GetDefSignMiscInfo(UseHashValue);
}
else { // global name
// Get old sign info from function level.
return this->BasicBlock->GetFunc()->GetDefSignMiscInfo(UseHashValue);
}
} // end of SMPInstr::GetDefSignInfoFromUseOp()
// infer FG info, + width on FirstIter; pass out FG info for op subtree, return true if change made to any FG info map.
bool SMPInstr::InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter, struct FineGrainedInfo &OpFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
bool NewChange = false; // Bit changes from InitFGInfoFromOperator() ?
SMPoperator CurrOp = CurrRT->GetOperator();
struct FineGrainedInfo LeftFG, OldLeftFG;
struct FineGrainedInfo RightFG, OldRightFG;
op_t LeftOp, RightOp;
unsigned short WidthMask, SignMask;
bool CurrOpTransfersSign = this->DoesOperatorTransferSign(CurrOp);
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
bool success;
int DefHashValue, UseHashValue, SSANum;
// Recurse to the right first, so we can do a depth-first accumulation of FG info.
RightFG.SignMiscInfo = 0;
RightFG.SizeInfo = 0;
if (CurrRT->HasRightSubTree()) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
} // end if (FirstIter)
MapsChanged |= this->InferOperatorFGInfo(CurrRT->GetRightTree(), FirstIter, RightFG);
}
else {
RightOp = CurrRT->GetRightOperand();
if (RightOp.type == o_imm) {
// If immediate operand is a data address or code address, we can infer that it is unsigned.
uval_t ImmVal = RightOp.value;
if (IsImmedGlobalAddress((ea_t) ImmVal)) {
// Data address (type GLOBALPTR)
RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
}
else if (this->MDIsInterruptCall() || IsImmedCodeAddress((ea_t) ImmVal)) {
// Code address (type GLOBALPTR)
RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
}
}
else if ((RightOp.type == o_reg) && !RightOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
WidthMask = ComputeOperandBitWidthMask(RightOp, 0);
RightFG.SizeInfo |= WidthMask;
} // end if (FirstIter)
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1
#if SMP_AGGRESSIVE_SIGN_TRANSFER
else {
// On all iterations other than 1st, see if USE has FG info.
UseHashValue = this->GetUseOpHashAndSSA(RightOp, SSANum);
if (this->BasicBlock->IsLocalName(RightOp)) {
// Get FG info from block.
RightFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else {
// Get FG info from function level.
RightFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
}
#endif
// Propagate signedness on all iterations.
// If operator is inherently signed, then we will have
// a sign bit set in RightFG from InitFGInfoFromOperator().
if ((RightFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
// We have a USE with no sign info. See if we
// can get sign info from the DEF of this USE so we can
// transfer it up the RTL tree.
RightFG.SignMiscInfo =
(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(RightOp)));
}
if ((RightFG.SignMiscInfo != 0) || (RightFG.SizeInfo != 0))
MapsChanged |= this->UpdateUseOpFGInfo(RightOp, RightFG);
} // end if (RightOP is o_reg)
else if (MDIsStackAccessOpnd(RightOp, UseFP)) {
// We used to assume that all FG info transfers from stack locations to
// the target registers of stack loads happened in SMPInstr::MDSetWidthSignInfo(),
// in an early pass that needed no iteration. The FG info was loaded from the
// StackFGInfo that was computed in SMPFunction::FindOutgoingArgsSize() based solely
// on whether the load was sign-extended or zero-extended. Of course, many stack
// locations have neither kind of signed/unsigned load. So, if we see a store to
// a stack location with no signedness, we transfer the signedness of the RightFG
// to the stack location FGInfo in the code below that processes the LeftOp.
// As a result, we now have a need to examine regular loads from the stack to
// see if there is signedness info for the stack location.
success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, RightOp, RightFG);
if (success) {
SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
RightFG.SizeInfo = 0; // only want to transfer signedness
}
}
} // end if (right subtree) else right operand
LeftFG.SignMiscInfo = 0;
LeftFG.SizeInfo = 0;
LeftOp = CurrRT->GetLeftOperand();
bool OpIsDEF = (SMP_ASSIGN == CurrOp);
// Skip control-flow assignments to the instruction pointer register.
if ((LeftOp.type == o_reg) && !LeftOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, LeftFG);
// Special case: For sign-extended and zero-extended loads,
// we don't know whether the DEF will always be USEd as
// the smaller or larger size. For example, we could
// zero-extend a 16-bit stack location into a 32-bit register
// just because the compiler always loads unsigned shorts
// that way, but we might never use it as a 32-bit value.
// So there is no truncation if we store only 16 bits later.
// By setting the target of an extended load to zero width,
// we signal that we want the maximum USE width to determine
// whether the store is truncated (see EmitIntegerErrorAnnotations).
WidthMask = ComputeOperandBitWidthMask(LeftOp, 0);
if (OpIsDEF) {
if (this->MDIsSignedLoad(SignMask)) {
WidthMask = 0;
}
// DEF inherits sign from right hand side.
LeftFG.SignMiscInfo |= RightFG.SignMiscInfo;
else if ((LeftFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
// We have a USE, not a DEF, with no sign info. See if we
// can get sign info from the DEF of this USE so we can
// transfer it up the RTL tree.
LeftFG.SignMiscInfo =
(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(LeftOp)));
LeftFG.SizeInfo |= WidthMask;
if ((LeftFG.SignMiscInfo != 0) || (LeftFG.SizeInfo != 0)) {
// Either NewChanged or CurrOpTransfersSign is true or we set WidthMask above.
// See if we would change the FG map entry.
if (OpIsDEF) { // Need DEF map info
MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
}
else { // need USE map info
MapsChanged |= this->UpdateUseOpFGInfo(LeftOp, LeftFG);
}
} // end if non-zero LeftFG info
#if SMP_AGGRESSIVE_SIGN_TRANSFER
else {
// On all iterations other than 1st, see if LeftOp has FG info.
if (!OpIsDEF) { // LeftOp is a USE
UseHashValue = this->GetUseOpHashAndSSA(LeftOp, SSANum);
if (this->BasicBlock->IsLocalName(LeftOp)) {
// Get FG info from block.