[PATCH][TableGen] Fully resolve class-instance values before defs in multiclasses
Sean Silva
chisophugis at gmail.com
Fri Sep 12 13:34:17 PDT 2014
On Thu, Sep 11, 2014 at 9:57 PM, Adam Nemet <anemet at apple.com> wrote:
>
> On Sep 11, 2014, at 12:56 PM, Tom Stellard <tom at stellard.net> wrote:
>
> On Wed, Sep 10, 2014 at 05:56:57PM -0700, Adam Nemet wrote:
>
> By class-instance values I mean 'Class<Arg>' in 'Class<Arg>.Field' or in
> 'Other<Class<Arg>>' (syntactically a SimpleValue). This is to
> differentiate
> from unnamed/anonymous record definitions (syntactically an ObjectBody)
> which
> are not affected by this change.
>
> Consider the testcase:
>
> class Struct<int i> {
> int I = !shl(i, 1);
> int J = !shl(I, 1);
> }
>
> class Class<Struct s> {
> int Class_J = s.J;
> }
>
> multiclass MultiClass<int i> {
> def Def : Class<Struct<i>>;
> }
>
> defm Defm : MultiClass<2>;
>
> Before this fix, DefmDef.Class_J yields !shl(I, 1) instead of 8.
>
> This is the sequence of events. We start with this:
>
> multiclass MultiClass<int i> {
> def Def : Class<Struct<i>>;
> }
>
> During ParseDef the anonymous object for the class-instance value is
> created:
>
> multiclass Multiclass<int i> {
> def anonymous_0 : Struct<i>;
>
> def Def : Class<NAME#anonymous_0>;
> }
>
> Then class Struct<i> is added to anonymous_0. Also
> Class<NAME#anonymous_0> is
> added to Def:
>
> multiclass Multiclass<int i> {
> def anonymous_0 {
> int I = !shl(i, 1);
> int J = !shl(I, 1);
> }
>
> def Def {
> int Class_J = NAME#anonymous_0.J;
> }
> }
>
> So far so good but then we move on to instantiating this in the defm
> by substituting the template arg 'i'.
>
> This is how the anonymous prototype looks after fully instantiating.
>
> defm Defm = {
> def Defmanonymous_0 {
> int I = 4;
> int J = !shl(I, 1);
> }
>
> Note that we only resolved the reference to the template arg. The
> non-template-arg reference in 'J' has not been resolved yet.
>
> Then we go on to instantiating the Def prototype:
>
> def DefmDef {
> int Class_J = NAME#anonymous_0.J;
> }
>
> Which is resolved to Defmanonymous_0.J and then to !shl(I, 1).
>
> When we fully resolve each record in a defm, Defmanonymous_0.J does get
> set to 8
> but that's too late for its use.
>
> The patch adds a new attribute to the Record class that indicates that this
> def is actually a class-instance value that may be *used* by other defs
> in a multiclass. (This is unlike regular defs which don't reference each
> other and thus can be resolved independently.) These are then fully
> resolved before the
> other defs while the multiclass is instantiated.
>
>
> Hi Adam,
>
> Is there any reason why your patch works on defs inside multiclasses and
> not all
> defs? I'm running into a similar problem with this example:
>
> class A <bits<2> op> {
> field bits<2> OP = op;
> }
>
> class B <bits <2> op> {
> field A OP = A<op>;
> }
>
> def : B <0>;
>
> As you can see, the value of B.OP.OP fails to resolve:
>
> ------------- Classes -----------------
> class A<bits<2> A:op = { ?, ? }> {
> field bits<2> OP = { A:op{1}, A:op{0} };
> string NAME = ?;
> }
> class B<bits<2> B:op = { ?, ? }> {
> field A OP = anonymous_0;
> string NAME = ?;
> }
> ------------- Defs -----------------
> def anonymous_0 { // A
> field bits<2> OP = { B:op{1}, B:op{0} };
> string NAME = ?;
> }
> def anonymous_1 { // B
> field A OP = anonymous_0;
> string NAME = ?;
> }
>
> I'm wondering if modifying your patch to work everywhere and not just
> in multiclasses will fix this. Do you think this might work?
>
>
> Hi Tom,
>
> I think conceptually you’re right, these should be handled similarly but
> unfortunately they are not. In fact I am not even sure I understand how
> your case is supposed to be handled by the current design.
>
> Multiclasses have this concept of defprototypes. E.g. in:
>
> multiclass Multiclass<int i> {
> def anonymous_0 : Struct<i>;
>
> def Def : Class<NAME#anonymous_0>;
> }
>
> Even though we create anonymous_0 on the fly we don’t make it a top-level
> def but rather a defprototype just like Def. Defprototypes (as opposed to
> definitions) still depend on template args of the enclosing multiclass.
> This all happens when we instantiate the multiclass at the defm.
>
> Classes don’t have this intermediate concepts. This is also pretty clear
> from what tablegen prints. As you can see anonymous_0 becomes as top-level
> def and is detached from class B. So there is little surprise we don’t
> substitute B:op upon instantiating B.
>
> My immediate thought is that we may want to extend the defprototype
> concept to regular classes…
>
> For the record, I also had another idea to mostly push the existing
> design. If you used specific fields from the class instance value rather
> than the entire thing, we could make this work by fully resolving the class
> before substituting template args:
>
> class B <bits <2> op> {
> field bits<2> OP = A<op>.OP;
> }
>
> The last line is anonymous_0.OP and it would become { B:op{1}, B:op{0} }
> with the new round of reference-resolution. So after substituting the
> template arg B:op, field OP resolves properly.
>
> This unfortunately still breaks down if you hold on to the entire object
> just like in your original code and let’s say you try to use one of its
> fields outside. E.g. note z.z. in:
>
> class A <int op1> {
> int OP1 = op1;
> }
>
> class B <int op2> {
> A OP2 = A<op2>;
> int OP3 = OP2.OP1;
> }
>
> def b : B <1>;
>
> def z {
> int k = b.OP3;
> int z = b.OP2.OP1;
> }
>
> As expected z.z fails to resolve:
>
> ------------- Classes -----------------
> class A<int A:op1 = ?> {
> int OP1 = A:op1;
> string NAME = ?;
> }
> class B<int B:op2 = ?> {
> A OP2 = anonymous_0;
> int OP3 = OP2.OP1;
> string NAME = ?;
> }
> ------------- Defs -----------------
> def anonymous_0 { // A
> int OP1 = B:op2;
> string NAME = ?;
> }
> def b { // B
> A OP2 = anonymous_0;
> int OP3 = 1;
> string NAME = ?;
> }
> def z {
> int k = 1;
> int z = B:op2;
> string NAME = ?;
> }
>
> I’m copying Jakob to see if he has any ideas how this is supposed to work
> but my current assumption is that these two cases are distinct, so the
> patch still stands. That said, we may want to move classes more in the
> direction of multiclasses…
>
Both cases fall into the general pile of "TableGen's resolution/evaluation
machinery is extremely convoluted". Your original patch makes this worse; I
would categorize it as a band-aid. If you really need it as a band-aid to
fix an important use case, then carry on, but if that's the case then a
little bit of refactoring in another part of TableGen to pay back that
technical debt would be appreciated.
-- Sean Silva
>
> Thanks,
> Adam
>
> Thanks,
> Tom
>
>
>
> I added vg_leak to the new test. I am not sure if this is necessary but I
> don't think I have a way to test it. I can also check in without the XFAIL
> and let the bots test this part.
>
> Also tested that X86.td.expanded and AAarch64.td.expanded were unchange
> before
> and after this change. (This issue triggering this problem is a WIP
> patch.)
>
> Part of <rdar://problem/17688758>
>
> Please let me know if it looks good.
>
> Thanks,
> Adam
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140912/c9ba670c/attachment.html>
More information about the llvm-commits
mailing list