return nullptr;
}
- AssertionDsc* curAssertion = optGetAssertion(index);
+ AssertionDsc* curAssertion = optGetAssertion(index);
+ bool assertionKindIsEqual = (curAssertion->assertionKind == OAK_EQUAL);
// Allow or not to reverse condition for OAK_NOT_EQUAL assertions.
bool allowReverse = true;
printf("\nVN relop based constant assertion prop in " FMT_BB ":\n", compCurBB->bbNum);
printf("Assertion index=#%02u: ", index);
printTreeID(op1);
- printf(" %s ", (curAssertion->assertionKind == OAK_EQUAL) ? "==" : "!=");
+ printf(" %s ", assertionKindIsEqual ? "==" : "!=");
if (genActualType(op1->TypeGet()) == TYP_INT)
{
printf("%d\n", vnStore->ConstantValue<int>(vnCns));
op1->gtVNPair.SetBoth(vnCns); // Preserve the ValueNumPair, as ChangeOperConst/SetOper will clear it.
- // Also set the value number on the relop.
- if (curAssertion->assertionKind == OAK_EQUAL)
+ // set foldResult to either 0 or 1
+ bool foldResult = assertionKindIsEqual;
+ if (tree->gtOper == GT_NE)
+ {
+ foldResult = !foldResult;
+ }
+
+ // Set the value number on the relop to 1 (true) or 0 (false)
+ if (foldResult)
{
tree->gtVNPair.SetBoth(vnStore->VNOneForType(TYP_INT));
}
//
Compiler::fgWalkResult Compiler::optVNConstantPropCurStmt(BasicBlock* block, Statement* stmt, GenTree* tree)
{
+ // Don't perform const prop on expressions marked with GTF_DONT_CSE
+ if (!tree->CanCSE())
+ {
+ return WALK_CONTINUE;
+ }
+
// Don't propagate floating-point constants into a TYP_STRUCT LclVar
// This can occur for HFA return values (see hfa_sf3E_r.exe)
if (tree->TypeGet() == TYP_STRUCT)
// GT_COPY/GT_RELOAD is considered having a reg if it
// has a reg assigned to any of its positions.
//
-// Assumption:
-// In order for this to work properly, gtClearReg must be called
-// prior to setting the register value.
-//
bool GenTree::gtHasReg() const
{
bool hasReg = false;
}
}
+//----------------------------------------------------------------------------
+// UsesDivideByConstOptimized:
+// returns true if rationalize will use the division by constant
+// optimization for this node.
+//
+// Arguments:
+// this - a GenTreeOp node
+// comp - the compiler instance
+//
+// Return Value:
+// Return true iff the node is a GT_DIV,GT_UDIV, GT_MOD or GT_UMOD with
+// an integer constant and we can perform the division operation using
+// a reciprocal multiply or a shift operation.
+//
+bool GenTreeOp::UsesDivideByConstOptimized(Compiler* comp)
+{
+ if (!comp->opts.OptimizationEnabled())
+ {
+ return false;
+ }
+
+ if (!OperIs(GT_DIV, GT_MOD, GT_UDIV, GT_UMOD))
+ {
+ return false;
+ }
+#if defined(TARGET_ARM64)
+ if (OperIs(GT_MOD, GT_UMOD))
+ {
+ // MOD, UMOD not supported for ARM64
+ return false;
+ }
+#endif // TARGET_ARM64
+
+ bool isSignedDivide = OperIs(GT_DIV, GT_MOD);
+ GenTree* dividend = gtGetOp1()->gtEffectiveVal(/*commaOnly*/ true);
+ GenTree* divisor = gtGetOp2()->gtEffectiveVal(/*commaOnly*/ true);
+
+#if !defined(TARGET_64BIT)
+ if (dividend->OperIs(GT_LONG))
+ {
+ return false;
+ }
+#endif
+
+ if (dividend->IsCnsIntOrI())
+ {
+ // We shouldn't see a divmod with constant operands here but if we do then it's likely
+ // because optimizations are disabled or it's a case that's supposed to throw an exception.
+ // Don't optimize this.
+ return false;
+ }
+
+ ssize_t divisorValue;
+ if (divisor->IsCnsIntOrI())
+ {
+ divisorValue = static_cast<ssize_t>(divisor->AsIntCon()->IconValue());
+ }
+ else
+ {
+ ValueNum vn = divisor->gtVNPair.GetLiberal();
+ if (comp->vnStore->IsVNConstant(vn))
+ {
+ divisorValue = comp->vnStore->CoercedConstantValue<ssize_t>(vn);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ const var_types divType = TypeGet();
+
+ if (divisorValue == 0)
+ {
+ // x / 0 and x % 0 can't be optimized because they are required to throw an exception.
+ return false;
+ }
+ else if (isSignedDivide)
+ {
+ if (divisorValue == -1)
+ {
+ // x / -1 can't be optimized because INT_MIN / -1 is required to throw an exception.
+ return false;
+ }
+ else if (isPow2(divisorValue))
+ {
+ return true;
+ }
+ }
+ else // unsigned divide
+ {
+ if (divType == TYP_INT)
+ {
+ // Clear up the upper 32 bits of the value, they may be set to 1 because constants
+ // are treated as signed and stored in ssize_t which is 64 bit in size on 64 bit targets.
+ divisorValue &= UINT32_MAX;
+ }
+
+ size_t unsignedDivisorValue = (size_t)divisorValue;
+ if (isPow2(unsignedDivisorValue))
+ {
+ return true;
+ }
+ }
+
+ const bool isDiv = OperIs(GT_DIV, GT_UDIV);
+
+ if (isDiv)
+ {
+ if (isSignedDivide)
+ {
+ // If the divisor is the minimum representable integer value then the result is either 0 or 1
+ if ((divType == TYP_INT && divisorValue == INT_MIN) || (divType == TYP_LONG && divisorValue == INT64_MIN))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // If the divisor is greater or equal than 2^(N - 1) then the result is either 0 or 1
+ if (((divType == TYP_INT) && (divisorValue > (UINT32_MAX / 2))) ||
+ ((divType == TYP_LONG) && (divisorValue > (UINT64_MAX / 2))))
+ {
+ return true;
+ }
+ }
+ }
+
+// TODO-ARM-CQ: Currently there's no GT_MULHI for ARM32
+#if defined(TARGET_XARCH) || defined(TARGET_ARM64)
+ if (!comp->opts.MinOpts() && ((divisorValue >= 3) || !isSignedDivide))
+ {
+ // All checks pass we can perform the division operation using a reciprocal multiply.
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+//------------------------------------------------------------------------
+// CheckDivideByConstOptimized:
+// Checks if we can use the division by constant optimization
+// on this node
+// and if so sets the flag GTF_DIV_BY_CNS_OPT and
+// set GTF_DONT_CSE on the constant node
+//
+// Arguments:
+// this - a GenTreeOp node
+// comp - the compiler instance
+//
+void GenTreeOp::CheckDivideByConstOptimized(Compiler* comp)
+{
+ if (UsesDivideByConstOptimized(comp))
+ {
+ gtFlags |= GTF_DIV_BY_CNS_OPT;
+
+ // Now set DONT_CSE on the GT_CNS_INT divisor, note that
+ // with ValueNumbering we can have a non GT_CNS_INT divisior
+ GenTree* divisor = gtGetOp2()->gtEffectiveVal(/*commaOnly*/ true);
+ if (divisor->OperIs(GT_CNS_INT))
+ {
+ divisor->gtFlags |= GTF_DONT_CSE;
+ }
+ }
+}
+
//
//------------------------------------------------------------------------
// gtBlockOpInit: Initializes a BlkOp GenTree
}
goto DASH;
+ case GT_DIV:
+ case GT_MOD:
+ case GT_UDIV:
+ case GT_UMOD:
+ if (tree->gtFlags & GTF_DIV_BY_CNS_OPT)
+ {
+ printf("M"); // We will use a Multiply by reciprical
+ --msgLength;
+ break;
+ }
+ goto DASH;
+
case GT_LCL_FLD:
case GT_LCL_VAR:
case GT_LCL_VAR_ADDR:
else if ((tree->AsIntCon()->gtIconVal > -1000) && (tree->AsIntCon()->gtIconVal < 1000))
{
printf(" %ld", dspIconVal);
-#ifdef TARGET_64BIT
}
+#ifdef TARGET_64BIT
else if ((tree->AsIntCon()->gtIconVal & 0xFFFFFFFF00000000LL) != 0)
{
- printf(" 0x%llx", dspIconVal);
-#endif
+ if (dspIconVal >= 0)
+ {
+ printf(" 0x%llx", dspIconVal);
+ }
+ else
+ {
+ printf(" -0x%llx", -dspIconVal);
+ }
}
+#endif
else
{
- printf(" 0x%X", dspIconVal);
+ if (dspIconVal >= 0)
+ {
+ printf(" 0x%X", dspIconVal);
+ }
+ else
+ {
+ printf(" -0x%X", -dspIconVal);
+ }
}
if (tree->IsIconHandle())
assert(_gtRegNum == reg);
}
+ void ClearRegNum()
+ {
+ _gtRegNum = REG_NA;
+ INDEBUG(gtRegTag = GT_REGTAG_NONE;)
+ }
+
// Copy the _gtRegNum/gtRegTag fields
void CopyReg(GenTree* from);
bool gtHasReg() const;
#define GTF_OVERFLOW 0x10000000 // Supported for: GT_ADD, GT_SUB, GT_MUL and GT_CAST.
// Requires an overflow check. Use gtOverflow(Ex)() to check this flag.
+#define GTF_DIV_BY_CNS_OPT 0x80000000 // GT_DIV -- Uses the division by constant optimization to compute this division
+
#define GTF_ARR_BOUND_INBND 0x80000000 // GT_ARR_BOUNDS_CHECK -- have proved this check is always in-bounds
#define GTF_ARRLEN_ARR_IDX 0x80000000 // GT_ARR_LENGTH -- Length which feeds into an array index expression
assert(oper == GT_NOP || oper == GT_RETURN || oper == GT_RETFILT || OperIsBlk(oper));
}
+ // returns true if we will use the division by constant optimization for this node.
+ bool UsesDivideByConstOptimized(Compiler* comp);
+
+ // checks if we will use the division by constant optimization this node
+ // then sets the flag GTF_DIV_BY_CNS_OPT and GTF_DONT_CSE on the constant
+ void CheckDivideByConstOptimized(Compiler* comp);
+
+ // True if this node is marked as using the division by constant optimization
+ bool MarkedDivideByConstOptimized() const
+ {
+ return (gtFlags & GTF_DIV_BY_CNS_OPT) != 0;
+ }
+
#if DEBUGGABLE_GENTREE
GenTreeOp() : GenTreeUnOp(), gtOp2(nullptr)
{