An inline asm call can result in an immediate after inlining. Therefore emit a
diagnostic here if constraint requires an immediate but one isn't supplied.
Details
- Reviewers
joerg mgorny efriedma rsmith - Commits
- rGffea3e373697: Merging r367750: --------------------------------------------------------------…
rL368421: Merging r367750:
rG41a2847a9ae5: Emit diagnostic if an inline asm constraint requires an immediate
rL367750: Emit diagnostic if an inline asm constraint requires an immediate
Diff Detail
- Repository
- rL LLVM
Event Timeline
I can confirm that it fixes our issue but I don't feel confident reviewing the code itself. Copying reviewers from the original diff.
It does not fix the issues on our side, but pushes them to a different place. It is still an improvement, but the problem is not solved yet.
On the frontend side:
- __builtin_constant_p is not expanded correctly in EvalConstant.cpp when used as part of codegen for -O0. This means that trivially unreachable branches are emitted (e.g. with a BR with a literal false as condition),
- The constant evaluator has a general problem with overly pessimistic analysis when it comes to possible side effects. Still have to discuss the correct handling with Richard for this.
On the backend side:
- The is_constant intrinsic is lowered too late. The prepare-isel pass it is currently part of is run after the last SimplifyCFG pass, so the now-dead basic blocks are never pruned and therefore the asm statements survive.
All that said, with the discussed generalization from literal 'n' to 'expects immediate', I think this code solves the part of the problem it is meant to solve.
GCC has this to say about __builtin_constant_p's behavior:
A return of 0 does not indicate that the value is not a constant, but merely that GCC cannot prove it is a constant with the specified value of the -O option.
When I was modifying our implementation recently, I made it so that if there are no optimizations then we evaluate to 0 in the front-end before code-gen. It might be that those blocks are being emitted, but they should have something like br i1 false, label %true_bb, label %false_bb or equivalent.
On the backend side:
- The is_constant intrinsic is lowered too late. The prepare-isel pass it is currently part of is run after the last SimplifyCFG pass, so the now-dead basic blocks are never pruned and therefore the asm statements survive.
Is this at -O0 or all optimization levels?
All that said, with the discussed generalization from literal 'n' to 'expects immediate', I think this code solves the part of the problem it is meant to solve.
W00T!
Yes, that's correct. The problem is that with -O0, we never run SimplifyCFG, so those conditional branches make it straight to the backend. As discussed with Richard on IRC, the core issue is that for -O0, the IR generation for __builtin_constant_p is different from the constant folding as part of AST/EvalConstant.cpp. The latter is used by EmitIfStmt and friends to decide whether the BBs should be created in first place and currently fails evaluation for bcp.
On the backend side:
- The is_constant intrinsic is lowered too late. The prepare-isel pass it is currently part of is run after the last SimplifyCFG pass, so the now-dead basic blocks are never pruned and therefore the asm statements survive.
Is this at -O0 or all optimization levels?
With -O0, the intrinsic is never generated and no SimplifyCFG is run either (see above).
Ah! I understand now. I'll see if there's something I can do to help with this. Could you send me some test cases so that I can test things?
The patch still needs to be generalized to handle all ICE constraints, but it is not blocked by the review for handling the is.constant intrinsic.
I added a new constraint type C_Immdediate which indicates that a constraint requires an immediate value.
Please take a look.
lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | ||
---|---|---|
439 ↗ | (On Diff #210713) | This is an unrelated chunk. Can you drop it please? I like the idea, but it would be nicer if it didn't need to create an intermediate label at all. |
Remove file that sneaked in.
lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | ||
---|---|---|
439 ↗ | (On Diff #210713) | Ah! Yes, this sneaked in there... |
With the exception of the small improvements outlined, this looks good to me.
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | ||
---|---|---|
7966 ↗ | (On Diff #212029) | Unrelated, but shouldn't Flags be filtered first? E.g. Flags &= ~(InlineAsm::Extra_MayLoad | InlineAsm::Extra_MayStore); There seems to be one test case (PowerPC/xray-ret-is-terminate.ll) that depends on this somewhat. Adding C_Immediate here seems to be wrong though, since immediates are never loads or stores. As such, shall we just drop this chunk and bring up the Flags update separate? |
8056 ↗ | (On Diff #212029) | like the "n" constraint |
lib/Target/X86/X86ISelLowering.cpp | ||
44780 ↗ | (On Diff #212029) | 'L' means 0xFF or 0xFFFF, that should be C_Immediate. |
44781 ↗ | (On Diff #212029) | 'M' means 0..3 as shifts for LEA, should be C_Immediate as well. |
Mark some constraints which require immediates as needing immediates.
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | ||
---|---|---|
7966 ↗ | (On Diff #212029) | I wanted to retain the original behavior, but yeah it seems like C_Immediate isn't really worth checking here. As for the Flags, wouldn't clearing the flags remove previous iterations which set them? This is being called in a loop over all asm contraints... |
LGTM otherwise.
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | ||
---|---|---|
8055 ↗ | (On Diff #212068) | Typo still. |
Update testing. This adds support for RISC-V inline asm immediate constraints
so that we emit the same errors that the front-end would.
I've updated this patch to better coincide with D60943. It adds support for RISC-V inline asm immediate constraints (to make the errors match those of the front-end) and a few more tests. Please take another look, since these are non-trivial changes.
Thanks!