-
Notifications
You must be signed in to change notification settings - Fork 4.6k
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
Gtneg mul divoptimizations #45604
Gtneg mul divoptimizations #45604
Changes from 11 commits
e487fe3
7f04f55
bbaf21f
bc91dcc
084a285
b575ab6
9727f8e
7829712
b4bf7e9
bd9a464
9136999
2e72f94
6467520
4a7f9b5
cb71a90
fea92de
8d2dc8e
46b8fff
55d54e6
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 |
---|---|---|
|
@@ -2833,8 +2833,8 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) | |
{ | ||
noway_assert(call->gtCallArgs->GetNode()->TypeGet() == TYP_I_IMPL || | ||
call->gtCallArgs->GetNode()->TypeGet() == TYP_BYREF || | ||
call->gtCallArgs->GetNode()->gtOper == | ||
GT_NOP); // the arg was already morphed to a register (fgMorph called twice) | ||
call->gtCallArgs->GetNode()->gtOper == GT_NOP); // the arg was already morphed to a register | ||
// (fgMorph called twice) | ||
maxRegArgs = 1; | ||
} | ||
else | ||
|
@@ -9090,8 +9090,8 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) | |
// copy-back). | ||
unsigned retValTmpNum = BAD_VAR_NUM; | ||
CORINFO_CLASS_HANDLE structHnd = nullptr; | ||
if (call->HasRetBufArg() && | ||
call->gtCallLateArgs == nullptr) // Don't do this if we're re-morphing (which will make late args non-null). | ||
if (call->HasRetBufArg() && call->gtCallLateArgs == nullptr) // Don't do this if we're re-morphing (which will make | ||
// late args non-null). | ||
{ | ||
// We're enforcing the invariant that return buffers pointers (at least for | ||
// struct return types containing GC pointers) are never pointers into the heap. | ||
|
@@ -11605,16 +11605,16 @@ GenTree* Compiler::getSIMDStructFromField(GenTree* tree, | |
} | ||
|
||
/***************************************************************************** | ||
* If a read operation tries to access simd struct field, then transform the | ||
* operation to the SIMD intrinsic SIMDIntrinsicGetItem, and return the new tree. | ||
* Otherwise, return the old tree. | ||
* Argument: | ||
* tree - GenTree*. If this pointer points to simd struct which is used for simd | ||
* intrinsic, we will morph it as simd intrinsic SIMDIntrinsicGetItem. | ||
* Return: | ||
* A GenTree* which points to the new tree. If the tree is not for simd intrinsic, | ||
* return nullptr. | ||
*/ | ||
* If a read operation tries to access simd struct field, then transform the | ||
* operation to the SIMD intrinsic SIMDIntrinsicGetItem, and return the new tree. | ||
* Otherwise, return the old tree. | ||
* Argument: | ||
* tree - GenTree*. If this pointer points to simd struct which is used for simd | ||
* intrinsic, we will morph it as simd intrinsic SIMDIntrinsicGetItem. | ||
* Return: | ||
* A GenTree* which points to the new tree. If the tree is not for simd intrinsic, | ||
* return nullptr. | ||
*/ | ||
|
||
GenTree* Compiler::fgMorphFieldToSIMDIntrinsicGet(GenTree* tree) | ||
{ | ||
|
@@ -11635,16 +11635,16 @@ GenTree* Compiler::fgMorphFieldToSIMDIntrinsicGet(GenTree* tree) | |
} | ||
|
||
/***************************************************************************** | ||
* Transform an assignment of a SIMD struct field to SIMD intrinsic | ||
* SIMDIntrinsicSet*, and return a new tree. If it is not such an assignment, | ||
* then return the old tree. | ||
* Argument: | ||
* tree - GenTree*. If this pointer points to simd struct which is used for simd | ||
* intrinsic, we will morph it as simd intrinsic set. | ||
* Return: | ||
* A GenTree* which points to the new tree. If the tree is not for simd intrinsic, | ||
* return nullptr. | ||
*/ | ||
* Transform an assignment of a SIMD struct field to SIMD intrinsic | ||
* SIMDIntrinsicSet*, and return a new tree. If it is not such an assignment, | ||
* then return the old tree. | ||
* Argument: | ||
* tree - GenTree*. If this pointer points to simd struct which is used for simd | ||
* intrinsic, we will morph it as simd intrinsic set. | ||
* Return: | ||
* A GenTree* which points to the new tree. If the tree is not for simd intrinsic, | ||
* return nullptr. | ||
*/ | ||
|
||
GenTree* Compiler::fgMorphFieldAssignToSIMDIntrinsicSet(GenTree* tree) | ||
{ | ||
|
@@ -11909,6 +11909,22 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) | |
return fgMorphCast(tree); | ||
|
||
case GT_MUL: | ||
// -a * C => a * -C, where C is constant | ||
// MUL(NEG(a), C) => MUL(a, NEG(C)) | ||
if (fgGlobalMorph && op1->OperIs(GT_NEG) && !op1->gtGetOp1()->IsCnsIntOrI() && op2->IsCnsIntOrI() && | ||
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.
|
||
!op2->IsIconHandle() && op2->AsIntCon()->IconValue() != 1 && op2->AsIntCon()->IconValue() != 0 && | ||
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. Why do you check 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 checked Still learning about the CoreCLR JIT, I greatly appreciate the advice :). 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. On second thought I think
it would allow the optimization to happen in other phases, so I think it would be better. |
||
op2->AsIntCon()->IconValue() != -1 && !tree->gtOverflow()) | ||
{ | ||
// tree: MUL | ||
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. is this the comment for the tree before the transformation?
|
||
// op1: a | ||
// op2: NEG | ||
// op2Child: C | ||
|
||
tree->AsOp()->gtOp1 = op1->gtGetOp1(); | ||
DEBUG_DESTROY_NODE(op1); | ||
op2->AsIntCon()->SetIconValue(-op2->AsIntCon()->IconValue()); // -C | ||
return fgMorphSmpOp(tree, mac); | ||
} | ||
|
||
#ifndef TARGET_64BIT | ||
if (typ == TYP_LONG) | ||
|
@@ -12056,6 +12072,23 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) | |
return fgMorphSmpOp(tree, mac); | ||
} | ||
|
||
// -a / C => a / -C, where C is constant | ||
// DIV(NEG(a), C) => DIV(a, NEG(C)) | ||
if (fgGlobalMorph && op1->OperIs(GT_NEG) && !op1->gtGetOp1()->IsCnsIntOrI() && op2->IsCnsIntOrI() && | ||
!op2->IsIconHandle() && op2->AsIntCon()->IconValue() != 1 && op2->AsIntCon()->IconValue() != 0 && | ||
op2->AsIntCon()->IconValue() != -1) | ||
{ | ||
// tree: DIV | ||
// op1: a | ||
// op2: NEG | ||
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. the same here. |
||
// op2Child: C | ||
|
||
tree->AsOp()->gtOp1 = op1->gtGetOp1(); | ||
DEBUG_DESTROY_NODE(op1); | ||
op2->AsIntCon()->SetIconValue(-op2->AsIntCon()->IconValue()); // -C | ||
return fgMorphSmpOp(tree, mac); | ||
} | ||
|
||
#ifndef TARGET_64BIT | ||
if (typ == TYP_LONG) | ||
{ | ||
|
@@ -13920,6 +13953,27 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) | |
return child; | ||
} | ||
|
||
// Distribute negation over simple multiplication/division expressions | ||
if (op1->OperIs(GT_MUL) || op1->OperIs(GT_DIV)) | ||
{ | ||
if (!op1->AsOp()->gtOp1->IsCnsIntOrI() && op1->AsOp()->gtOp2->IsCnsIntOrI()) | ||
{ | ||
// -(a * C) => a * -C | ||
// -(a / C) => a / -C | ||
oper = op1->gtOper; | ||
tree->SetOper(op1->gtOper); | ||
GenTree* newOp1 = op1->AsOp()->gtOp1; // a | ||
GenTree* newOp2 = op1->AsOp()->gtOp2; // C | ||
newOp2->AsIntCon()->SetIconValue(-newOp2->AsIntCon()->IconValue()); | ||
|
||
// Only need to destroy op1 since op2 will be null already | ||
DEBUG_DESTROY_NODE(op1); | ||
|
||
tree->AsOp()->gtOp1 = op1 = newOp1; | ||
tree->AsOp()->gtOp2 = op2 = newOp2; | ||
} | ||
} | ||
|
||
/* Any constant cases should have been folded earlier */ | ||
noway_assert(!op1->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD) || optValnumCSE_phase); | ||
break; | ||
|
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.
did jit-format cause these changes or were these unintentional edits? Could you please try to delete them and run jit-format again?