[PATCH] D122569: [lit] Support %if ... %else syntax for RUN lines
Joel E. Denny via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 19 15:44:29 PDT 2022
jdenny added a comment.
In D122569#3458804 <https://reviews.llvm.org/D122569#3458804>, @asavonic wrote:
> In D122569#3458476 <https://reviews.llvm.org/D122569#3458476>, @arichardson wrote:
>
>> While this is not a huge amount of code to be added to lit, I do wonder if we really need it. Wouldn't something like `%feature{foo}` that expands to 0 or 1 be sufficient? You could then use shell conditionals/`test` to avoid running lines.
>> Looking at the examples from D121727 <https://reviews.llvm.org/D121727>, you could do the following:
>>
>> RUN: if [ %feature{ptxas} -ne 0 ]; then ptxas -c %t-nvptx.ptx -o /dev/null; fi
>> RUN: test %feature{ptxas} -ne 0 && ptxas -c %t-nvptx.ptx -o /dev/null
>
> The variant with `if` is probably not going to work on windows.
Agreed. It won't work in lit's internal shell currently either. `%if` is a portable `if`. Maybe it would be good to point this out in the documentation?
> As for the `test` - I'm not sure how it works in this case.
My hunch is that `test` is also not portable.
================
Comment at: llvm/utils/lit/lit/TestRunner.py:1235
+ if not match:
+ raise ValueError("'%{' is missing for %if substitution")
+ cond = ln[:match.start()]
----------------
It would be nice to extend the test suite to check that these syntax errors are actually detected.
================
Comment at: llvm/utils/lit/lit/TestRunner.py:1306
+
+ while len(ln):
+ # %if starts a new scope ('if' branch). Push '%if cond' to
----------------
asavonic wrote:
> jdenny wrote:
> > Instead of a loop with a custom stack data structure, a recursive descent parser might be easier to understand and extend, especially if we add more constructs similar to `%if` later. That is, the python call stack would be used as the parser stack, and stack entries would be simple local variables, function parameters, and function returns.
> >
> > This is just a suggestion. I'm not insisting. However, I do invite other reviewers to offer their opinion.
> Done. It does look better as a recursive function.
Nice. Thanks.
================
Comment at: llvm/utils/lit/lit/TestRunner.py:1363
# seems reasonable.
ln = _caching_re_compile(a).sub(str(b), escape(ln))
----------------
asavonic wrote:
> jdenny wrote:
> > Why does `%%` need to be escaped again here?
> This is because of recursive substitution:
> ```
> substitutions = [
> ("%rec1, "%%s"),
> ("%s", "/path")
> ]
> ```
> If we expand `%rec1` to `%%s` in the first iteration of the loop, we have to escape `%%` before the next iteration. Otherwise instead of of `%s` we'll get `%/path`. This is tested in `shtest-recursive-substitution/escaping` test.
Make sense. Thanks for explaining.
================
Comment at: llvm/utils/lit/tests/Inputs/shtest-if-else/test.txt:22
+# RUN: echo test-%if feature %{ 3 %} %else %{ fail %}-test
+# RUN: echo test-%if feature %{ 4 4 %} %else %{ fail %}-test
+# CHECK-NEXT: {{^.*'RUN}}: at line [[#@LINE-2]]'; echo test- 3 -test
----------------
Maybe test the preservation of space in `%else` as well.
================
Comment at: llvm/utils/lit/tests/Inputs/shtest-if-else/test.txt:75
+#
+# RUN: %if feature {echo %{%}}
+# CHECK-NEXT: {{^.*'RUN}}: at line [[#@LINE-1]]'; echo {}
----------------
asavonic wrote:
> jdenny wrote:
> > If we're going to have these `%{` and `%}` escapes, they need to be documented somewhere. However, I think they're going to be confusing:
> >
> > - First, `%{foobar}` is already a common syntax for lit substitutions. The if-then-else syntax's `%{` and `}` collide with it. For example, how should I write `%{pathsep}` in a then or else block? I have to write it as `%%{pathsep%}`, right?
> > - More generally, whether `{` and `}` need to be escaped and whether `%{` and `%}` are defined depend on the context. That seems error-prone.
> >
> > What if we go the other way? That is, we could change the `{` and `}` around a then or else block to `%{` and `%}`. That way, the entire if-then-else syntax is clearly at the preprocessor/substitution level: `%if`, `%else`, `%{`, and `%}`. On the other hand, `{` and `}` behave as usual in the shell code, and the only character in shell code that ever needs to be escaped continues to be `%`.
> >
> > But does that syntax have collisions?
> >
> > - I just tried `git grep 'RUN.*%}'` and found no matches in llvm's repo. It seems `%}` is unambiguous. If a use arises, it can be escaped as `%%}`. Again, only `%` ever has to be escaped.
> > - The `%{` is really just for symmetry with `%}`. The `%{` doesn't actually need to be recognized in arbitrary shell code anywhere. That is, the if-then-else parser would only need to recognize it after an `%if cond` or `%else`. There doesn't appear to be a way for it to collide with, for example, `%{pathsep}`.
> >
> > Did I miss anything?
> Done. The patch now uses `%{` and `%}` as begin/end tokens. It also helps to distinguish them from boolean expressions with a regex-match (`{{regex}}`).
Thanks. Please add a test that a substitution like `%{foo}` works in the then and else blocks. You'll probably have to define your own as I'm not sure it's safe to rely on the way the built-in substitutions expand.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D122569/new/
https://reviews.llvm.org/D122569
More information about the llvm-commits
mailing list