Tablegen NativeCodeCall Called Twice

I have a pattern rewrite rule in a tablegen file that uses a NativeCodeCall. I was only expecting the NativeCodeCall to be triggered once per pattern match, but instead I see it called twice.

The operation legality is dynamic depending on the presence of an attribute that is added by the NativeCodeCall. The value of the attribute is based on state that is retained between matches. Multiple calls for the same match affects that state, hence why calling twice is a problem.

Is there any reason why the NativeCodeCall is triggered twice? Is there anyway to avoid this?

Thanks in advance.

1 Like

Called twice potentially due to oversight but that depends on how you are using it. E.g., for lowering we can often examine multiple different patterns and it could be that a pattern fails to match the requirements post the initial native code call match, and so if you have a near miss match, then it could be called 2x (also the matching ordering is not formalized and may change).

in general I don’t think one can safely have native code call there be stateful/have different results per invocation unless each potential match is always a valid match, and even then that is assuming rewrite behavior specific to certain rewrite drivers and not true in general. DRR is statement of equality under constraints, if the attr constraints change every use then that complicates pattern fusions and other optimizations pending.

What do you wish to achieve with the state? Perhaps there is a different way to achieve it.

I don’t see it documented anywhere, but it does seem that the NativeCodeCalls should be side effect free.

The pass that I am creating should annotate a memory offset onto the operation. A following pass will use this information.

The issue is that when an argument to a rewrite target is passed, it is first tested for existence.
I see RewriterGen.cpp generate:

if (foo) { tblgen_attrs.emplace_back(rewriter.getIdentifier(“bar”), foo); }

Now if foo is a native call, this call will be evaluated twice, once for the condifion and once for the emplace_pack argument.
For two reasons, this is undesirable.
First, the call may have a side-effect, if only it might do memory allocation.
Secondly, performance wise, calling such a function twice can be undesirable.

I implemented a patch that first binds this expression to a local variable, which is then used twice.
If the call has no side-effect, the bahavior is unchanged. If it does have, the behavior is better controllable for the user.

More generally, having worked on compiler generators and rewrite formalism since 1987, I think any high-level-language translator should avoid evaluating a single source expression multiple times in its target code.

Indeed, I think in this case it was an oversight in the generated code when this was added. I’ll try to take a look at it soon, but if please file a bug to remind me/ping in case it slips.

Also, I’d be very interested in your previous work and if you have ideas on how we could improve these here.

Here it is:

https://bugs.llvm.org/show_bug.cgi?id=47898

Hi Jacques,

I did submit a bug:

https://bugs.llvm.org/show_bug.cgi?id=47898

Attached is a patch I made locally to fix the problem.

Lex

(Attachment RewriterGen.patch is missing)

Next attempt to upload patch file.
It might be a duplicate of https://reviews.llvm.org/D82101

Lex

RewriterGen.patch.txt (1.63 KB)