How to apply pdll to a payload IR?

Hello everyone,
I’m a MLIR freshman, I’m learning PDLL. Now I want to use the pdl to match pattern and rewrite it. How can I use the RewriteAdd.pdll to apply to original payload IR and get the desired result IR? What’s the workflow of this or it there a related simple example?

# Original  payload IR
module {
  func.func @test_pdl(%input0 : f32, %input1 : f32) {
    %neg_out = arith.negf %input1 : f32
    %sub_out = arith.subf %input0, %neg_out : f32
  }
}
# RewriteAdd.pdll
Pattern RewriteAdd with benefit(1) {
  let neg = op<arith.negf>(input1 : Value);
  let add = op<arith.subf>(input0 : Value, neg.0);

  replace add with op<arith.addf>(input1, input0);
}
# Desired result IR
module {
  func.func @test_pdl(%input0 : f32, %input1 : f32) {
    %add_out = arith.addf %input0, %input1 :f32
  }
}

I believe the expected way to achieve what you want is to generate a C++ definition of your pattern using mlir-pdll -x=cpp then link it to your MLIR compiler. So in other words, set-up an MLIR project and have a build script that generates the C++ for your PDLL pattern, that you can then register from your project using the generated populateGeneratedPDLLPatterns function.

I think another way to use PDL patterns is via the transform dialect, for which I think a runtime interpreter exists.

Using mlir-pdll -x mlir -I <include dir> RewriteAdd.pdll can generate .mlir file. And u can use that file in your # Original payload IR like this :

module {
  func.func @test_pdl(%input0 : f32, %input1 : f32) {
    %neg_out = arith.negf %input1 : f32
    %sub_out = arith.subf %input0, %neg_out : f32
    func.return
  }
}

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    transform.with_pdl_patterns %root : !transform.any_op {
    ^bb0(%arg0: !transform.any_op):
      pdl.pattern @RewriteAdd : benefit(1) {
        %0 = operand
        %1 = types
        %2 = operation "arith.negf"(%0 : !pdl.value)  -> (%1 : !pdl.range<type>)
        %3 = operand
        %4 = result 0 of %2
        %5 = types
        %6 = operation "arith.subf"(%3, %4 : !pdl.value, !pdl.value)  -> (%5 : !pdl.range<type>)
        rewrite %6 {
          %7 = operation "arith.addf"(%0, %3 : !pdl.value, !pdl.value)
          replace %6 with %7
        }
      }

      transform.sequence %arg0 : !transform.any_op failures(propagate) {
      ^bb1(%arg1: !transform.any_op):
        %f = pdl_match @RewriteAdd in %arg1 : (!transform.any_op) -> !transform.any_op
      }
    }
    transform.yield
  }
}

mlir-opt --transform-interpreter --allow-unregistered-dialect <file> will do the rewrite. CSE Pass may be needed.

1 Like

Also take a look at the StableHLO to TOSA conversion patterns inside StableHLO repo. These shows a bit larger and rather self contained example too.

@Moxinilian @chenghuaWang @jpienaar , thank you for your replies.

  • @Moxinilian ,it’s a little hard for me to try your proposal now, I believe I’ll try it later.
  • @chenghuaWang , I have tried your proposal, it works for me. But I have another question, there are loc, loc1, loc2 and so on as following, when .mlir generated by mlir-pdll -x mlir -I <include dir> RewriteAdd.pdll, I don’t want to see these, how can I do?
  • @jpienaar , I’ll take a look at StableHLO repo
module {
  pdl.pattern @RewriteAdd : benefit(1) {
    %0 = operand loc(#loc1)
    %1 = types loc(#loc2)
    %2 = operation "arith.negf"(%0 : !pdl.value)  -> (%1 : !pdl.range<type>) loc(#loc2)
    %3 = operand loc(#loc3)
    %4 = result 0 of %2 loc(#loc4)
    %5 = types loc(#loc5)
    %6 = operation "arith.subf"(%3, %4 : !pdl.value, !pdl.value)  -> (%5 : !pdl.range<type>) loc(#loc5)
    rewrite %6 {
      %7 = operation "arith.addf"(%0, %3 : !pdl.value, !pdl.value)  loc(#loc7)
      replace %6 with %7 loc(#loc6)
    } loc(#loc6)
  } loc(#loc)
} loc(#loc)
#loc = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":1:1)
#loc1 = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":2:28)
#loc2 = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":2:13)
#loc3 = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":3:28)
#loc4 = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":3:44)
#loc5 = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":3:13)
#loc6 = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":5:3)
#loc7 = loc("/home/zongwu/wksp/x/examples/pdl/test_rewrite.pdll":5:20)

To be frank, I don’t know of any tools in mlir that can remove location information. If you really need to eliminate the location information, you can write a Pass and use mlir-opt. Of course, you can also write a regex script to manipulate the source code directly.

Understood, thanks for your reply.