<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Helvetica Neue" class="">Hi All,</font><br class=""><br class=""><font face="Helvetica Neue" class="">I've more or less finished updating the examples to the DAG style we were talking about. Hopefully I haven't forgotten anything, there was a lot to keep track of :-). Overall, I think there's a couple places where things get a a little awkward (mainly debug info) but things generally look good to me.</font><br class=""><br class=""><font face="Helvetica Neue" class=""><u class="">A Simple Example</u></font><br class=""><br class=""><font face="Menlo" class="">def : GICombineRule<(defs reg:$D, reg:$S),<br class="">                    (match (G_ZEXT s32:$t1, s8:$S),<br class="">                           (G_TRUNC s16:$D, s32:$t1)),<br class="">                    (apply (G_ZEXT s16:$D, s8:$S))>;</font><br class=""><br class=""><font face="Helvetica Neue" class="">This has been converted to the style that fits within tblgen's DAG type but isn't (directly) a DAG. The DAG structure is defined by the matching names instead of tblgen's DAG type. This avoids the restrictions of the DAG type and is something that's needed anyway to allow one node to be referenced in multiple places. I've kept the 'match' node at the top of the match to allow instructions and predicates to be freely combined within this section (see later examples). Without it, the stricter type checking on list<X> would require Instruction, GIMatchPredicate, and any future matching extensions to have a common base class.</font><br class=""><br class=""><font face="Helvetica Neue" class="">The explicit specification of root has also been removed in favour of a default value and a 'let' assignment to deal with any cases where the algorithm-chosen default is unsuitable (see the upside-down match section below). The default would be the set of defs minus the set of uses. This covers the common single-root case, as well as the multi-root case. The 'let' would be required for the upside-down and inside-out matches.</font><br class=""><br class=""><font face="Helvetica Neue" class="">One consequence of this style is that there's no means to have anonymous operands that still define the edges of the DAG being matched as shown by the need to name $t1 above.</font><br class=""><br class=""><font face="Helvetica Neue" class="">I'll come back to possibility of removing the defs section in a follow-up email as I suspect I'm over the size limit again. The bit I need to mention in this email is that the formerly anonymous operands are omitted from the defs section in these examples.</font><br class=""><br class=""><font face="Helvetica Neue" class=""><u class="">Generalizing the Simple Example</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">As before, this is the example above with the concrete types removed.</font><br class=""><font face="Menlo" class="">    def isScalarType : GIMatchPredicate<bool, (ins type:$A), (outs), [{<br class="">      return ${A}.isScalar();<br class="">    }]>;<br class="">    def isLargerType : GIMatchPredicate<bool, (ins type:$A, type:$B), (outs), [{<br class="">      return ${A}.getSizeInBits() > ${B}.getSizeInBits();<br class="">    }]>;<br class="">    def : GICombineRule<(defs reg:$D, reg:$S),<br class="">                        (match (G_ZEXT $t1, $S),<br class="">                               (G_TRUNC $D, $t1),<br class="">                               (isScalarType type:$D),<br class="">                               (isLargerType type:$D, type:$S)),<br class="">                        (apply (G_ZEXT $D, $S))>;<br class=""></font><br class=""><font face="Helvetica Neue" class="">There's little different here aside from what's mentioned in the simple example. I've just changed the argument order of GIMatchPredicate to better match the order in the underlying function prototype.</font><br class=""><br class=""><font face="Helvetica Neue" class=""><u class="">Preserving DILocation and other debug info</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">We have a choice of syntax here and neither seems to be clearly better than the other when considering just locations:</font><br class=""><font face="Menlo" class="">    def : GICombineRule<(defs reg:$D, reg:$S, instr:$MI0, instr:$MI1),<br class="">                        (match (G_ZEXT $t0, $S):$MI0,<br class="">                               (G_TRUNC $D, $t0):$MI1),<br class="">                               (isScalarType type:$D),<br class="">                               (isLargerType type:$D, type:$S)),<br class="">                        (apply (G_ZEXT $D, $S, (debug_locations $MI0, $MI1)))>;<br class=""><br class="">    def : GICombineRule<(defs reg:$D, reg:$S, debug_location:$DL0</font><span style="font-family: Menlo;" class="">, debug_location:$DL0</span><span style="font-family: Menlo;" class="">),</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class="">                        (match (G_ZEXT $t0, $S, debug_location:$DL0),<br class="">                               (G_TRUNC $D, $t0, debug_location:$DL1)),<br class="">                               (isScalarType type:$D),<br class="">                               (isLargerType type:$D, type:$S)),<br class="">                        (apply (G_ZEXT $D, $S, (debug_locations $DL0, $DL1)))>;</font><br class=""><br class=""><font face="Helvetica Neue" class="">However, the former is more compact when DBG_VALUE is involved since naming the instruction gives access to three of the four pieces of data we need to pass on to the apply step:</font><br class=""><font face="Menlo" class="">    def : GICombineRule<(defs reg:$D, reg:$S, </font><span style="font-family: Menlo;" class="">instr:$MI0, instr:$MI1, </span><span style="font-family: Menlo;" class="">instr:$MI2, instr:$MI3, </span><span style="font-family: Menlo;" class="">debug_expr:$DNewExpr),</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class="">                        (match (G_ZEXT $t0, $S):$MI0,<br class="">                               (G_TRUNC $D, $t0):$MI1,<br class="">                               (DBG_VALUE $t0):$MI2,<br class="">                               (DBG_VALUE $D):$MI3,<br class="">                               (isScalarType type:$D),<br class="">                               (isLargerType type:$D, type:$S)),<br class="">                        (apply (createDIExprLLVMFragment debug_expr:$MI2, type:$D):$DNewExpr,<br class="">                               (G_ZEXT $D, $S, (debug_location $MI0, $MI1)),<br class="">                               (DBG_VALUE $D, debug_local:$MI2, debug_expr:$DNewExpr, (debug_location $MI2)),<br class="">                               (DBG_VALUE $D, debug_local:$MI3, debug_expr:$MI3, (debug_location $MI3))))>;</font><br class=""><br class=""><font face="Helvetica Neue" class=""><u class="">Matching immediates and G_CONSTANT/G_FCONSTANT</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">There isn't much that's special about the changes in this section. Rewriting the examples into the DAG style gives:</font><br class=""><font face="Menlo" class="">    def : GICombineRule<(defs reg:$D, reg:$A, imm:$VAL),<br class="">                        (match (G_MUL $D, $A, $VAL),<br class="">                               (isTwo imm:$VAL)),<br class="">                        (apply (MYTGT_DOUBLE $D, $A))>;</font><br class=""><font face="Helvetica Neue" class="">Or equivalently:</font><br class=""><font face="Menlo" class="">    def imm_2 : GIPredicatedDefKind<(isTwo imm)>;<br class="">    def : GICombineRule<(defs reg:$D, reg:$A, imm_2:$VAL),<br class="">                        (match (G_MUL $D, $A, $VAL)),<br class="">                        (apply (MYTGT_DOUBLE $D, $A))>;</font><br class=""><br class=""><font face="Helvetica Neue" class="">And here's the example that replaces 2 * (A + B) with 2A + 2B:</font><br class=""><font face="Menlo" class="">    def : GICombineRule<<br class="">      (defs reg:$D, reg:$A, imm:$B, imm_2:$C),<br class="">      (match (G_ADD $t1, $A, $B),<br class="">             (G_MUL $D, $t1, $C)),<br class="">      (apply (create_imm [{ 2 * ${B}->getZExtValue() }], apint_value:$B):$NB,<br class="">             (G_ADD $t1, $A, $A),<br class="">             (G_ADD $D, $t1, $NB))>;<br class=""></font><br class=""><font face="Helvetica Neue" class=""><u class="">Passing arbitrary data from match to apply</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">The main change in this section that hasn't already been discussed is that the result of extending_load_predicate has been moved to the new 'outs' section of GIMatchPredicate and the code expansion refers to a particular output of the predicate using 'matchinfo.B' similar to a struct member or multi-operand ComplexPatterns.</font><br class=""><br class=""><font face="Menlo" class="">    def extending_load_matchdata : GIDefMatchData<"PreferredTuple">;<br class="">    def extending_load_predicate : GIMatchPredicate<<br class="">         bool, (ins reg:$A), (outs extending_load_matchdata:$B), [{<br class="">      return Helper.matchCombineExtendingLoads(${A}, ${B});<br class="">    }]>;<br class="">    def extending_loads : GICombineRule<<br class="">      (defs operand:$D, reg:$A, extending_load_matchdata:$matchinfo),<br class="">      (match (G_LOAD $D, $A),<br class="">             (extending_load_predicate operand:$A,<br class="">                                       extending_load_matchdata:$matchinfo)),<br class="">      (apply (exec [{ Helper.applyCombineExtendingLoads(${D}, ${matchinfo.B}); }],<br class="">                   reg:$D, extending_load_matchdata:$matchinfo)>;<br class=""><br class=""></font><font face="Helvetica Neue" class="">The main problem with this is that this prevents access to the contents of matchinfo from outside of C++. To overcome this, I'd suggest allowing the '${foo.bar}' syntax in tablegen's dag type. It should be a fairly simple change and there's no tblgen-internal reason to not allow dots in the names. Existing backends would have to check for it though which could be a tblgen performance issue.</font><br class=""><br class=""><font face="Helvetica Neue" class=""><u class="">Macros</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">Aside from changing to the DAG style, the main change here is that the children of 'oneof' all have 'match' at the top-level. This is for the same reason 'match' was kept on the simple example: the relaxed type checking on 'dag' compared to 'list<X>' allows us to freely mix DAG-style matches and predicates.</font><br class=""><font face="Menlo" class="">    def ANYLOAD : GIMacro<(defs def:$R, use:$S, uint64_t:$IDX),<br class="">                          (match (oneof (match (G_LOAD $R, $S)),<br class="">                                        (match (G_SEXTLOAD $R, $S)),<br class="">                                        (match (G_ZEXTLOAD $R, $S))):$IDX>;<br class="">    def extending_loads : GICombineRule<<br class="">      (defs reg:$D, reg:$A, extending_load_matchdata:$matchinfo, ANYLOAD:$ANYLOAD),<br class="">      (match (ANYLOAD $D, $A),<br class="">             (extending_load_predicate operand:$A,<br class="">                                       extending_load_matchdata:$matchinfo)),<br class="">      (apply (exec [{ Helper.applyCombineExtendingLoads(${</font>D<font face="Menlo" class="">}, ${matchinfo.B}); }],<br class="">                   reg:$D, extending_load_matchdata:$matchinfo)>;<br class=""></font><br class=""><font face="Helvetica Neue" class=""><u class="">'Upside-down' matches (i.e. roots at the top) and similar</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">As mentioned back in the simple example, these need to specify the match roots using a 'let' statement to override the default:</font><br class=""><font face="Menlo" class="">def : GICombineRule<<br class="">  (defs reg:$D, reg:$A),<br class="">  (match (G_LOAD $t1, $D),<br class="">         (G_SEXT $A, $t1)),<br class="">  (apply (G_SEXTLOAD $A, $D))> {<br class="">  let MatchStartsFrom = (roots $D);</font></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class="">};<br class=""><br class="">def : GICombineRule<<br class="">  (defs reg:$D, reg:$A, reg:$B, reg:$C),<br class="">  (match (G_TRUNC s32:$t1, s64:$A),<br class="">         (G_TRUNC s32:$t2, s64:$B),<br class="">         (G_ADD $D, $t1, $t2)<br class="">         (G_SEXT s64:$C, $D)),<br class="">  (apply (G_ADD $D, $A, $B),<br class="">         (G_SEXT_INREG $C, $D))> {<br class=""></font><span style="font-family: Menlo;" class=""> </span><span style="font-family: Menlo;" class=""> </span><span style="font-family: Menlo;" class="">let MatchStartsFrom = (roots $D);</span><font face="Menlo" class=""><br class="">};</font><br class=""><br class=""><font face="Helvetica Neue" class=""><u class="">Multiple roots</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">All the changes in this section have already been discussed above:</font><br class=""><font face="Menlo" class="">def : GICombineRule<<br class="">  (defs reg:$D1, reg:$D2, reg:$A, reg:$B),<br class="">  (match (G_ADD $D1, $A, $B),<br class="">         (G_SUB $D2, $A, $B)),<br class="">  (apply (BUTTERFLY $D1, $D2, $A, $B))>;<br class=""></font>$D1 and $D2 are both automatically chosen as roots since they are def'd but not used.<br class=""><br class=""><font face="Helvetica Neue" class=""><u class="">Subregisters</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">This is a new example based on our discussion about MIR having direct support for subregisters. We use subregister indexes to specify that it's a subregister that should be emitted by the apply step.</font><br class=""><font face="Menlo" class="">def : GICombineRule<<br class="">  (defs reg:$D, reg:$A, reg:$B),<br class="">  (match (G_TRUNC s32:$t1, s64:$A),<br class="">         (G_TRUNC s32:$t2, s64:$B),<br class="">         (G_ADD $D, $t1, $t2),<br class="">  (apply (ADD32 $D, (sub_lo $A), (sub_lo $B)))>;<br class=""></font><br class=""><font face="Helvetica Neue" class=""><u class="">Matching MachineMemOperands</u></font><br class=""><br class=""><font face="Helvetica Neue" class="">While re-writing these examples, I also realized I didn't have any examples for testing properties of the MachineMemOperand, so here's one:</font><br class=""><font face="Menlo" class="">    def mmo_is_load_8 : GIMatchPredicate<<br class="">         (ins instr:$A), (outs), [{<br class="">      if (!${A}.hasOneMemOperand())<br class="">        return false;<br class="">      const auto &MMO = *${A}.memoperands_begin();<br class="">      return MMO.isLoad() && MMO.getSize() == 1;<br class="">    }]>;<br class="">    def : GICombineRule<<br class="">      (defs operand:$D, operand:$A),<br class="">      (match (G_LOAD $D, $A):$MI,<br class="">             (mmo_is_load8 instr:$MI)),<br class="">      (apply ...)>;<br class=""></font><font face="Helvetica Neue" class="">I've made use of the naming instructions here since this was better in the debug info section. If we choose the alternative in that section then we can change it to $D or $A instead (either way the generated code would call getParent()).</font><br class=""><br class=""><br class=""></div></body></html>