-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[DAG] SDPatternMatch - add matchers for reassociatable binops #119985
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
Merged
mshockwave
merged 13 commits into
llvm:main
from
Esan5:users/esan/dag/reassociatable-matchers
Mar 21, 2025
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
0bcf808
add reassociatable matchers
Esan5 d02eab4
tests
Esan5 5c05bd0
trigger builds
Esan5 428bed6
drop curly braces
Esan5 62027dc
add tests using sub
Esan5 f414330
prefer SmallBitVector over SmallVector<bool> and SmallVector<int>
Esan5 cb167b8
format and update comment
Esan5 249ce54
For loop styling
Esan5 e7bafdd
for loop
Esan5 9b4af6d
for loop
Esan5 a8d1db3
false is default initialization
Esan5 39b27b9
curly braces
Esan5 6fddcd0
array ref
Esan5 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -651,3 +651,128 @@ TEST_F(SelectionDAGPatternMatchTest, matchAdvancedProperties) { | |
EXPECT_TRUE(sd_match(Add, DAG.get(), | ||
m_LegalOp(m_IntegerVT(m_Add(m_Value(), m_Value()))))); | ||
} | ||
|
||
TEST_F(SelectionDAGPatternMatchTest, matchReassociatableOp) { | ||
using namespace SDPatternMatch; | ||
|
||
SDLoc DL; | ||
auto Int32VT = EVT::getIntegerVT(Context, 32); | ||
|
||
SDValue Op0 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 1, Int32VT); | ||
SDValue Op1 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 2, Int32VT); | ||
SDValue Op2 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 3, Int32VT); | ||
SDValue Op3 = DAG->getCopyFromReg(DAG->getEntryNode(), DL, 8, Int32VT); | ||
|
||
// (Op0 + Op1) + (Op2 + Op3) | ||
SDValue ADD01 = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, Op1); | ||
SDValue ADD23 = DAG->getNode(ISD::ADD, DL, Int32VT, Op2, Op3); | ||
SDValue ADD = DAG->getNode(ISD::ADD, DL, Int32VT, ADD01, ADD23); | ||
|
||
EXPECT_FALSE(sd_match(ADD01, m_ReassociatableAdd(m_Value()))); | ||
EXPECT_TRUE(sd_match(ADD01, m_ReassociatableAdd(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match(ADD23, m_ReassociatableAdd(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match( | ||
ADD, m_ReassociatableAdd(m_Value(), m_Value(), m_Value(), m_Value()))); | ||
|
||
// Op0 + (Op1 + (Op2 + Op3)) | ||
SDValue ADD123 = DAG->getNode(ISD::ADD, DL, Int32VT, Op1, ADD23); | ||
SDValue ADD0123 = DAG->getNode(ISD::ADD, DL, Int32VT, Op0, ADD123); | ||
EXPECT_TRUE( | ||
sd_match(ADD123, m_ReassociatableAdd(m_Value(), m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match(ADD0123, m_ReassociatableAdd(m_Value(), m_Value(), | ||
m_Value(), m_Value()))); | ||
|
||
// (Op0 - Op1) + (Op2 - Op3) | ||
SDValue SUB01 = DAG->getNode(ISD::SUB, DL, Int32VT, Op0, Op1); | ||
SDValue SUB23 = DAG->getNode(ISD::SUB, DL, Int32VT, Op2, Op3); | ||
SDValue ADDS0123 = DAG->getNode(ISD::ADD, DL, Int32VT, SUB01, SUB23); | ||
|
||
EXPECT_FALSE(sd_match(SUB01, m_ReassociatableAdd(m_Value(), m_Value()))); | ||
EXPECT_FALSE(sd_match(ADDS0123, m_ReassociatableAdd(m_Value(), m_Value(), | ||
m_Value(), m_Value()))); | ||
|
||
// SUB + SUB matches (Op0 - Op1) + (Op2 - Op3) | ||
EXPECT_TRUE( | ||
sd_match(ADDS0123, m_ReassociatableAdd(m_Sub(m_Value(), m_Value()), | ||
m_Sub(m_Value(), m_Value())))); | ||
EXPECT_FALSE(sd_match(ADDS0123, m_ReassociatableAdd(m_Value(), m_Value(), | ||
m_Value(), m_Value()))); | ||
|
||
// (Op0 * Op1) * (Op2 * Op3) | ||
SDValue MUL01 = DAG->getNode(ISD::MUL, DL, Int32VT, Op0, Op1); | ||
SDValue MUL23 = DAG->getNode(ISD::MUL, DL, Int32VT, Op2, Op3); | ||
SDValue MUL = DAG->getNode(ISD::MUL, DL, Int32VT, MUL01, MUL23); | ||
|
||
EXPECT_TRUE(sd_match(MUL01, m_ReassociatableMul(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match(MUL23, m_ReassociatableMul(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match( | ||
MUL, m_ReassociatableMul(m_Value(), m_Value(), m_Value(), m_Value()))); | ||
|
||
// Op0 * (Op1 * (Op2 * Op3)) | ||
SDValue MUL123 = DAG->getNode(ISD::MUL, DL, Int32VT, Op1, MUL23); | ||
SDValue MUL0123 = DAG->getNode(ISD::MUL, DL, Int32VT, Op0, MUL123); | ||
EXPECT_TRUE( | ||
sd_match(MUL123, m_ReassociatableMul(m_Value(), m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match(MUL0123, m_ReassociatableMul(m_Value(), m_Value(), | ||
m_Value(), m_Value()))); | ||
|
||
// (Op0 - Op1) * (Op2 - Op3) | ||
SDValue MULS0123 = DAG->getNode(ISD::MUL, DL, Int32VT, SUB01, SUB23); | ||
EXPECT_TRUE( | ||
sd_match(MULS0123, m_ReassociatableMul(m_Sub(m_Value(), m_Value()), | ||
m_Sub(m_Value(), m_Value())))); | ||
EXPECT_FALSE(sd_match(MULS0123, m_ReassociatableMul(m_Value(), m_Value(), | ||
m_Value(), m_Value()))); | ||
|
||
// (Op0 && Op1) && (Op2 && Op3) | ||
SDValue AND01 = DAG->getNode(ISD::AND, DL, Int32VT, Op0, Op1); | ||
SDValue AND23 = DAG->getNode(ISD::AND, DL, Int32VT, Op2, Op3); | ||
SDValue AND = DAG->getNode(ISD::AND, DL, Int32VT, AND01, AND23); | ||
|
||
EXPECT_TRUE(sd_match(AND01, m_ReassociatableAnd(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match(AND23, m_ReassociatableAnd(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match( | ||
AND, m_ReassociatableAnd(m_Value(), m_Value(), m_Value(), m_Value()))); | ||
|
||
// Op0 && (Op1 && (Op2 && Op3)) | ||
SDValue AND123 = DAG->getNode(ISD::AND, DL, Int32VT, Op1, AND23); | ||
SDValue AND0123 = DAG->getNode(ISD::AND, DL, Int32VT, Op0, AND123); | ||
EXPECT_TRUE( | ||
sd_match(AND123, m_ReassociatableAnd(m_Value(), m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match(AND0123, m_ReassociatableAnd(m_Value(), m_Value(), | ||
m_Value(), m_Value()))); | ||
|
||
// (Op0 - Op1) && (Op2 - Op3) | ||
SDValue ANDS0123 = DAG->getNode(ISD::AND, DL, Int32VT, SUB01, SUB23); | ||
EXPECT_TRUE( | ||
sd_match(ANDS0123, m_ReassociatableAnd(m_Sub(m_Value(), m_Value()), | ||
m_Sub(m_Value(), m_Value())))); | ||
EXPECT_FALSE(sd_match(ANDS0123, m_ReassociatableAnd(m_Value(), m_Value(), | ||
m_Value(), m_Value()))); | ||
|
||
// (Op0 || Op1) || (Op2 || Op3) | ||
SDValue OR01 = DAG->getNode(ISD::OR, DL, Int32VT, Op0, Op1); | ||
SDValue OR23 = DAG->getNode(ISD::OR, DL, Int32VT, Op2, Op3); | ||
SDValue OR = DAG->getNode(ISD::OR, DL, Int32VT, OR01, OR23); | ||
|
||
EXPECT_TRUE(sd_match(OR01, m_ReassociatableOr(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match(OR23, m_ReassociatableOr(m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match( | ||
OR, m_ReassociatableOr(m_Value(), m_Value(), m_Value(), m_Value()))); | ||
|
||
// Op0 || (Op1 || (Op2 || Op3)) | ||
SDValue OR123 = DAG->getNode(ISD::OR, DL, Int32VT, Op1, OR23); | ||
SDValue OR0123 = DAG->getNode(ISD::OR, DL, Int32VT, Op0, OR123); | ||
EXPECT_TRUE( | ||
sd_match(OR123, m_ReassociatableOr(m_Value(), m_Value(), m_Value()))); | ||
EXPECT_TRUE(sd_match( | ||
OR0123, m_ReassociatableOr(m_Value(), m_Value(), m_Value(), m_Value()))); | ||
|
||
// (Op0 - Op1) || (Op2 - Op3) | ||
SDValue ORS0123 = DAG->getNode(ISD::OR, DL, Int32VT, SUB01, SUB23); | ||
EXPECT_TRUE( | ||
sd_match(ORS0123, m_ReassociatableOr(m_Sub(m_Value(), m_Value()), | ||
m_Sub(m_Value(), m_Value())))); | ||
EXPECT_FALSE(sd_match( | ||
ORS0123, m_ReassociatableOr(m_Value(), m_Value(), m_Value(), m_Value()))); | ||
} | ||
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. could you add some negative tests showing that it works as expected even when there are non-associative operations in the expression tree? |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@Esan5 I'm hitting an issue with this with m_Value() leaves that can match in multiple positions - it looks like the last leaf is binding to every m_Value() instead of sharing the matches correctly - do we need to run the matches again after reassociatableMatchHelper to ensure that each leaf is allocated and matched to a single pattern? I think technically this could still fail with m_Deferred() matches wdyt?
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.
I may be misunderstanding, but is the intention here for
to match
The code in this helper function should prevent a given sub-pattern from being used to match more then one leaf by tracking which patterns have already been used.
Unfortunately, I don't have enough experience with LLVM to identify the intended behavior, can you clarify what this test case should do?
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.
I was expecting m_Value(A) to match one of %s0 or %s1 and m_Value(B) to match the other - but instead both are matching to the same one.
I was really hoping to do this, but I doubt the current implementation can manage it: