-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Prerequisite work item for the CSE of GT_CNS_INT for ARM64 work item #39021
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -615,10 +615,6 @@ void GenTree::CopyReg(GenTree* from) | |
| // 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; | ||
|
|
@@ -6674,6 +6670,173 @@ void GenTreeIntCon::FixupInitBlkValue(var_types asgType) | |
| } | ||
| } | ||
|
|
||
| //---------------------------------------------------------------------------- | ||
| // 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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want this to happen in minopts (
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will add a check for minopts to UsesDivideByConstOptimization() |
||
| { | ||
| 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; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you have answered earlier why we check
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because changing the CNS_INT to a CSE LclVar will cause lower to fail to use the multiplication by reciprocal optimization.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I think I understand now. From these two comments:
In general we want to set |
||
| } | ||
| } | ||
| } | ||
|
|
||
| // | ||
| //------------------------------------------------------------------------ | ||
| // gtBlockOpInit: Initializes a BlkOp GenTree | ||
|
|
@@ -9899,6 +10062,18 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z _ | |
| } | ||
| 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: | ||
|
|
@@ -10566,16 +10741,30 @@ void Compiler::gtDispConst(GenTree* tree) | |
| 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); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Starting from VS2013 we have support for "%zd" (and other runtime parts are already using it), so I would suggest to just replace this block with: Note: gcc and clang have always supported that.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like see these numbers in hex, especially with my shared CSE constant changes where we often have to add or subtract a small offset.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have not seen hex numbers being printed with a negative sign, but maybe it is fine. Thanks for the explanation. |
||
| } | ||
| } | ||
| #endif | ||
| else | ||
| { | ||
| printf(" 0x%X", dspIconVal); | ||
| if (dspIconVal >= 0) | ||
| { | ||
| printf(" 0x%X", dspIconVal); | ||
| } | ||
| else | ||
| { | ||
| printf(" -0x%X", -dspIconVal); | ||
| } | ||
| } | ||
|
|
||
| if (tree->IsIconHandle()) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: formatting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks like an unintentional new line.