[GlobalISel] How to pattern match a G_STORE with offset compuation through TableGen

Hi all,

I wish to describe a pattern in tablegen to pattern match G_STORE with base_address plus offset form. I am now implementing it in ${Target}InstructionSelector.cpp.

For example:

  liveins: $arg0, $arg1, $arg2
  %2:argreg(s32) = COPY $arg0
  %3:argreg(s32) = COPY $arg1
  %0:argreg64r(p1) = G_MERGE_VALUES %2:argreg(s32), %3:argreg(s32)
  %1:argreg(s32) = COPY $arg2
  %8:vregr(s32) = G_CONSTANT i32 2
  %5:vregr(s32) = G_SHL %1:argreg, %8:vregr(s32)
  %6:argreg64r(p1) = G_PTR_ADD %0:argreg64r, %5:vregr(s32)
  G_STORE %1:argreg(s32), %6:argreg64r(p1) :: (store (s32) into %ir.arrayidx, !tbaa !3, addrspace 1)

When select ‘G_STORE’, my C++ code takes G_PTR_ADD’s 2nd and 3rd operands, which are ‘base_ptr’ and ‘offset’ respectively, and then create ${Target} Store Instruction with ‘base_ptr’ and ‘offset’ as its operands.
This is the result:

  liveins: $arg0, $arg1, $arg2
  %2:argreg = COPY $arg0
  %3:argreg = COPY $arg1
  %0:argreg64 = PseudoMERGE %2:argreg, %3:argreg
  %1:argreg = COPY $arg2
  %5:vreg = MUL %1:argreg, 4
  STORE %1:argreg, %0:argreg64, %5:vreg

G_SHL with 2 (bits) is lowered to ${Target} MUL instruction, this is ‘offset’.

Can I describe this in tablegen instead of writing C++ code?


1 Like

Found a way to pattern match it.

I was inspired by [GISel/DAG] Getting a TableGen pattern to match both `G_ADD` and `G_PTR_ADD` in GISel, and his patch ⚙ D131254 [AMDGPU][GISel] Enable Selection of ADD3 for G_PTR_ADD

My implementation in tablegen:

  • Store instruction:

    def STORE : Instr<"st", [], (outs),
                      (ins Arg:$val, Arg64:$ptr, VReg:$offset)>;
  • Define ptradd

      // iPTR:$out_ptr = ptradd iPTR:$ptr, int:$offset
      def SDTPtrAddOp : SDTypeProfile<1, 2, [
        SDTCisSameAs<0, 1>, SDTCisInt<2>, SDTCisPtrTy<1>
      def ptradd : SDNode<"ISD::ADD", SDTPtrAddOp, []>;
      def : GINodeEquiv<G_PTR_ADD, ptradd>;
  • Pattern matches: G_STORE %1:argreg(s32), G_PTR_ADD %0:argreg64r, %5:vregr(s32) :: (store (s32) into %ir.arrayidx, !tbaa !3, addrspace 1)

    // matches (op2 ty2:$x, (op1 ty0:$y, ty1:$z))
    class ThreeOpFrag<SDPatternOperator op1, SDPatternOperator op2>
        : PatFrag<(ops node:$x, node:$y, node:$z),
                  (op2 node:$x, (op1 node:$y, node:$z))> {
    def p1 : PtrValueType<i64, 1>;
    //   (ins Arg:$Rn, Arg64:$Rm, VReg:$Offset)>;
    class StorePats<SDPatternOperator op1, SDPatternOperator op2, Instruction inst>
        : Pat<(ThreeOpFrag<op1, op2> i32:$val, p1:$ptr, i32:$offset),
              (inst Arg:$val, Arg64:$ptr, VReg:$offset)>;
    def : StorePats<ptradd, st, STORE>;

I found I have to explicit use p1 for $ptr, iPTRAny didn’t work.
This pattern rule can replace my c++ code.