[PATCH] D124750: [MLIR] Add a utility to sort the operands of commutative ops
Srishti Srivastava via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Mon May 9 18:19:06 PDT 2022
srishti-pm added a comment.
In D124750#3502295 <https://reviews.llvm.org/D124750#3502295>, @mehdi_amini wrote:
> You're telling me "what" while I'm actually more interested in the "why" here?
I'm not sure what your question is, with a "why". Let me think about this a bit. I'll get back to you.
> Same as before: this does not tell me why, can you provide an example where this matters?
Sure. This is a bit lengthy. I'm really sorry for that !
So, lets start with some basic understanding here. Let's say I am writing a `matchAndRewrite()` function, where I take the following INPUT and convert it to the following OUTPUT:
INPUT:
a = div b, c
d = sub e, f
g = add d, a
h = const 0
i = mul h, g
OUTPUT:
i = some_op b, c, e, f
Now, when I'm writing a C++ code to match and rewrite:
If I only sort the `i = mul h, g` op, I get my canonicalized input as follows:
CANONICALIZED INPUT #1:
a = div b, c
d = sub e, f
g = add d, a
h = const 0
i = mul g, h
So, I'm basically sorting `i = mul h, g` to `i = mul g, h` using the utility and then writing the if-else statements to match the CANONICALIZED INPUT #1.
So, a psuedo code will be:
if mul.operand[0].defOp != add OR mul.operand[1].defOp != const 0
return failure
if add.operand[0].defOp != sub
if add.operand[0].defOp != div OR add.operand[1].defOp != sub
return failure
else
get the values of b, c, e, and f
else if add.operand[1].defOp == div
get the values of b, c, e, and f
else
return failure
rewrite<some_op>(mul, b, c, e, f)
But, if I had sorted the producers as well, my canonicalized input would be:
CANONICALIZED INPUT #2:
a = div b, c
d = sub e, f
g = add a, d
h = const 0
i = mul g, h
and thus my code will reduce to:
if mul.operand[0].defOp != add OR mul.operand[1].defOp != const 0
return failure
if add.operand[0].defOp != div OR add.operand[1].defOp != sub
return failure
get the values of b, c, e, and f
rewrite<some_op>(mul, b, c, e, f)
So, in essence, we can see that the effort of an end user writing a C++ pattern has reduced if I sort the producers as well. But, one may argue that I could have sorted the `add` op after seeing it and then my if-else statements would reduce. So, the above illustration doesn't explain why we sort the producers.
The real reason for sorting the producers is that, if such a thing is not done, the sorting and this entire utility will be virtually useless. A deterministic sorting of an op requires its producers to be sorted. Our sorting algorithm is based on the breadth-first traversal of backard slices. One the same level of DAG, the traversal looks at operands from the first to the last. That is how the breadth-first traversal is defined here. Now, if this traversal is non-deterministic, then, the whole use of sorting something will collapse. **Maybe, this can be BEST explained with the below example.**
If I have this IR:
d = div b, c
s = sub e, f
x = xor k, l
g = add s, d
h = add d, x
i = add g, h
Then, `i = add g, h` will be sorted to `i = add g, h` (no change).
**But**, when I have the below IR (which is functionally the same as the above IR):
d = div b, c
s = sub e, f
x = xor k, l
g = add d, s
h = add d, x
i = add g, h
Then, `i = add g, h` will be sorted to `i = add h, g`.
So, we have two functionally same IRs being sorted differently. This is clearly not useful. The sorting depends on what the input IR is. So, even after sorting, we still have functionally same IRs that look different. So, the pattern matcher (a human) still has to write an excessive number of if-else statements to match the input. This is exactly what this sorting was supposed to avoid. This is as good as not having done any sorting at all!
Is the motivation clear now?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D124750/new/
https://reviews.llvm.org/D124750
More information about the cfe-commits
mailing list