The TableGen language seems to be growing Lisp macros from two different directions. Che-Liang Chiou added a preprocessor with for loops, and David Greene added multidefs. It seems that some kind of macro facility is needed, perhaps we should discuss what it is supposed to look like? /jakob
Jakob Stoklund Olesen <jolesen at apple.com> writes:> The TableGen language seems to be growing Lisp macros from two > different directions. > > Che-Liang Chiou added a preprocessor with for loops, and David Greene > added multidefs. > > It seems that some kind of macro facility is needed, perhaps we should > discuss what it is supposed to look like?Don't throw the Greenspunning term around unless you really mean it. The problem I solved via multidefs was this: how does one write a set of Pat<> patterns in a generic way? For example, I want to be able to do this: defm MOVH : vs1x_fps_binary_vv_node_rmonly< 0x16, "movh", undef, 0, // rr [(undef)], // rm [(set DSTREGCLASS:$dst, (DSTTYPE (movlhps SRCREGCLASS:$src1, (DSTTYPE (bitconvert (v2f64 (scalar_to_vector (loadf64 addr:$src2))))))))], // rr Pat [], // rm Pat [[(DSTTYPE (movlhps SRCREGCLASS:$src1, (load addr:$src2))), (MNEMONIC SRCREGCLASS:$src1, addr:$src2)], [(INTDSTTYPE (movlhps SRCREGCLASS:$src1, (load addr:$src2))), (MNEMONIC SRCREGCLASS:$src1, addr:$src2)]]>; I need to have the various types substituted and the mnemonic with appropriate suffixes substituted. I need to have this done for each Pat<> pattern in the list ("rm Pat" above). To do this TableGen needs to know something about the top-level defm (the "defm name," if you will) and something about the types and classes the defm gets instantiated with. Therefore, I need some way to process a list of patterns and do substitutions in the context of a specific defm and all of the classes it inherits from. I'm open to another solution but multidef has served its purpose well and I would need equivalent functionality. TableGen is missing a lot of functionality but I think it should be added incrementally rather than rewritten in some grand scheme. -Dave
greened at obbligato.org (David A. Greene) writes:> The problem I solved via multidefs was this: how does one write a set of > Pat<> patterns in a generic way? > > For example, I want to be able to do this: > > defm MOVH : > vs1x_fps_binary_vv_node_rmonly< > 0x16, "movh", undef, 0, > // rr > [(undef)], > // rm > [(set DSTREGCLASS:$dst, > (DSTTYPE (movlhps SRCREGCLASS:$src1, > (DSTTYPE (bitconvert > (v2f64 (scalar_to_vector > (loadf64 addr:$src2))))))))], > // rr Pat > [], > // rm Pat > [[(DSTTYPE (movlhps SRCREGCLASS:$src1, (load addr:$src2))), > (MNEMONIC SRCREGCLASS:$src1, addr:$src2)], > [(INTDSTTYPE (movlhps SRCREGCLASS:$src1, (load addr:$src2))), > (MNEMONIC SRCREGCLASS:$src1, addr:$src2)]]>; > > I need to have the various types substituted and the mnemonic with > appropriate suffixes substituted. I need to have this done for each > Pat<> pattern in the list ("rm Pat" above). To do this TableGen needs > to know something about the top-level defm (the "defm name," if you > will) and something about the types and classes the defm gets > instantiated with. > > Therefore, I need some way to process a list of patterns and do > substitutions in the context of a specific defm and all of the classes > it inherits from.So here's why I think the for loop proposal can't be a preprocessing phase. Down in the guts of this I fundamentally need to be able to do this: multiclass blah<list<int> Values> { for v = Values { def DEF#v : base_class<v>; } } Will that work? Is the for loop evaluated after parameter binding? I like the for loop idea. But it can't be "just" a preprocessing step. Also, I know I introduced the #..# "pasting" operation but I've found it to be too limiting. In this example: (Equivalent TableGen code with a for-loop) ---------------------------------------- multiclass PTX_FLOAT_4OP<string opcstr, SDNode opnode1, SDNode opnode2> { for nbit = [32, 32, 64, 64], op_suffix = [r, i, r, i], op_type = [RegF32, f32imm, RegF64, f64imm], op_node_type = [RegF32, fpimm, RegF64, fpimm] in { def rr#op_suffix#nbit : InstPTX<(outs RegF#nbit:$d), (ins RegF#nbit:$a, RegF#nbit:$b, #op_type:$c), !strconcat(opcstr, ".f#nbit\t$d, $a, $b, $c"), [(set RegF#nbit:$d, (opnode2 (opnode1 RegF#nbit:$a, RegF#nbit:$b), #op_node_type:$c))]>; } } what if we instead did this: (Equivalent TableGen code with a for-loop) ---------------------------------------- multiclass PTX_FLOAT_4OP<string opcstr, SDNode opnode1, SDNode opnode2> { for nbit = [32, 32, 64, 64], op_suffix = [r, i, r, i], op_type = [RegF32, f32imm, RegF64, f64imm], op_node_type = [RegF32, fpimm, RegF64, fpimm] in { def !strconcat(!strconcat("rr", !cast<string>(op_suffix)), "nbit") [...] } } Yes, it's a bit more verbose but also more flexible in what you can do with iterator values. -Dave
On Oct 6, 2011, at 7:59 AM, David A. Greene wrote:> For example, I want to be able to do this: > > defm MOVH : > vs1x_fps_binary_vv_node_rmonly< > 0x16, "movh", undef, 0, > // rr > [(undef)], > // rm > [(set DSTREGCLASS:$dst, > (DSTTYPE (movlhps SRCREGCLASS:$src1, > (DSTTYPE (bitconvert > (v2f64 (scalar_to_vector > (loadf64 addr:$src2))))))))], > // rr Pat > [], > // rm Pat > [[(DSTTYPE (movlhps SRCREGCLASS:$src1, (load addr:$src2))), > (MNEMONIC SRCREGCLASS:$src1, addr:$src2)], > [(INTDSTTYPE (movlhps SRCREGCLASS:$src1, (load addr:$src2))), > (MNEMONIC SRCREGCLASS:$src1, addr:$src2)]]>;This kind of thing is very hard to read and understand. ISAs don't change a lot, and .td files are read lot more than they are written. I actually think it is preferable to leave some redundancy in the .td files, it makes it much easier to find things. It is already tedious to expand multiclasses in your head when you are looking for the properties of a specific instruction. /jakob