This is an archive of the discontinued LLVM Phabricator instance.

[SelectionDAG] treat X constrained labels as i for asm
ClosedPublic

Authored by nickdesaulniers on Dec 13 2021, 5:31 PM.

Details

Summary

Completely rework how we handle X constrained labels for inline asm.

X should really be treated as i. Then existing tests can be moved to use
i D115410 and clang can just emit i D115311. (D115410 and D115311 are
callbr, but this can be done for label inputs, too).

Coincidentally, this simplification solves an ICE uncovered by D87279
based on assumptions made during D69868.

This is the third approach considered. See also discussions v1 (D114895)
and v2 (D115409).

Reported-by: kernel test robot <lkp@intel.com>
Fixes: https://github.com/ClangBuiltLinux/linux/issues/1512

Diff Detail

Event Timeline

nickdesaulniers requested review of this revision.Dec 13 2021, 5:31 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 13 2021, 5:31 PM
nickdesaulniers planned changes to this revision.Dec 13 2021, 5:31 PM
nickdesaulniers edited the summary of this revision. (Show Details)
  • add more tests, rework parts of TargetLowering::LowerAsmOperandForConstraint
llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
4605–4629

Note to reviewers: I got a little carried away refactoring the existing code here. If it's too distracting from this review, I'm happy to pre-commit this hunk.

llvm/test/CodeGen/AArch64/inlineasm-X-constraint.ll
124

Note to reviewers, the below code modified looks like it was originally a typo, based on this comment.

llvm/test/CodeGen/X86/callbr-asm-bb-exports.ll
20

Note to reviewers: I'm happy to pre-commit removing this regex so that we can better see here what changed. Please let me know if that would be worthwhile.

jyknight added inline comments.Dec 16 2021, 2:56 PM
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
1686

How does BasicBlock get here, vs BlockAddress?

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
5094–5095

I'm still confused as to why this deals in both BlockAddress and BasicBlock types -- why aren't the values all BlockAddresses?

llvm/test/CodeGen/AArch64/inlineasm-X-constraint.ll
130

Can now "CHECK: bl bb"?

llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll
84 ↗(On Diff #394402)

The asm fallthrough grew a label it didn't need before? And...that affected the need to save/restore lr or something?

Hmm...wait...it sure looks like the expected code in this test was demonstrating a bug...! It wasn't saving/restoring lr (mflr/mtlr) around the callbr, but the callbr said it clobbers lr! That doesn't seem right -- despite the test asserting it...

OK...but why did this change fix that?

nickdesaulniers marked an inline comment as done.
  • update aarch64 test to check branch target
nickdesaulniers added inline comments.
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
1686

Note that this method also handles BlockAddresses above in the conditional for isa<Constant> (BlockAddress isa<Constant>; BasicBlock !isa<Constant> on line 1622.

Without this check, llvm/test/CodeGen/X86/asm-block-labels.ll asserts:

Can't get register for value!
UNREACHABLE executed at /android0/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp:1685!
...
2.	Running pass 'X86 DAG->DAG Instruction Selection' on function '@bar'
...
 #7 0x00000000030f2e89 llvm::SelectionDAGBuilder::getValueImpl(llvm::Value const*) (/android0/llvm-project/llvm/build/bin/llc+0x30f2e89)
 #8 0x00000000030f1bbf llvm::SelectionDAGBuilder::getValue(llvm::Value const*) (/android0/llvm-project/llvm/build/bin/llc+0x30f1bbf)
 #9 0x00000000030fcd7b llvm::SelectionDAGBuilder::visitInlineAsm(llvm::CallBase const&, llvm::BasicBlock const*) (/android0/llvm-project/llvm/build/bin/llc+0x30fcd7b)

Note that @bar is only composed of call (no callbr); one statement has a label operand.

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
5094–5095

llvm/test/CodeGen/X86/asm-block-labels.ll with assert without the check for BasicBlock.

Value type is non-standard value, Other.
UNREACHABLE executed at /android0/llvm-project/llvm/include/llvm/Support/MachineValueType.h:865!
...
2.	Running pass 'X86 DAG->DAG Instruction Selection' on function '@bar'
...
 #8 0x00000000030d9abc getCopyToParts(llvm::SelectionDAG&, llvm::SDLoc const&, llvm::SDValue, llvm::SDValue*, unsigned int, llvm::MVT, llvm::Value const*, llvm::Optional<unsigned int>, llvm::ISD::NodeType) SelectionDAGBuilder.cpp:0:0
 #9 0x00000000030d9207 llvm::RegsForValue::getCopyToRegs(llvm::SDValue, llvm::SelectionDAG&, llvm::SDLoc const&, llvm::SDValue&, llvm::SDValue*, llvm::Value const*, llvm::ISD::NodeType) const (/android0/llvm-project/llvm/build/bin/llc+0x30d9207)
#10 0x00000000030feb26 llvm::SelectionDAGBuilder::visitInlineAsm(llvm::CallBase const&, llvm::BasicBlock const*) (/android0/llvm-project/llvm/build/bin/llc+0x30feb26)
#11 0x00000000030dca47 llvm::SelectionDAGBuilder::visit(llvm::Instruction const&) (/android0/llvm-project/llvm/build/bin/llc+0x30dca47)

ie. call (and technically callbr) can accept a label operand; not just a blockaddress. Why are label operands distinct from blockaddresses? /me shrugs.

llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll
84 ↗(On Diff #394402)
void added inline comments.Dec 21 2021, 12:23 PM
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

The old code uses DAG.getTargetBlockAddress(...). This new code uses DAG.getBlockAddress(...). What's the difference?

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
4605–4629

This is fine, but in the future it might be best to commit refactoring in a separate NFC commit.

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

BlockAddressSDNode::classof is interesting; there's one node with two possible opcodes; ISD::BlockAddress and ISD::TargetBlockAddress.

SelectionDAG:: getTargetBlockAddress is also interesting, as it is implemented in terms of a call to SelectionDAG::getBlockAddress with the optional isTarget parameter set to true (defaulting to false otherwise).

So this change as is (Diff 395500) is not setting the isTarget flag, which just changes the opcode of the SDNode. The only places in the codebase where I observe ISD::TargetBlockAddress being handled differently from ISD::BlockAddress are:

  1. TargetLowering::ComputeConstraintToUse which I actually unify in this diff, see below.
  2. SelectionDAGISel::SelectCodeCommon. I'm not quite sure yet what this code is doing, will read through it a couple times now. Perhaps that's what's causing the difference in llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll and llvm/test/CodeGen/X86/callbr-asm-bb-exports.ll? That said PPCTargetLowering::PPCTargetLowering is doing something "Custom" with ISD::BlockAddress but not ISD::TargetBlockAddress. I wonder if it should be? Rephrased: should PPCTargetLowering::LowerOperation have an additional case ISD::TargetBlockAddress that also dispatches to PPCTargetLowering::LowerBlockAddress AND PPCTargetLowering::PPCTargetLowering mark ISD::TargetBlockAddress as having custom handling? Lots (all?) backends seem to follow this pattern though? Messing with that creates a pretty spectacular failure though.
  3. SDNode::getOperationName which converts an SDNode to a std::string based on the opcode. Not interesting/relevant.

Just another thought. If we're ok matching GCC with D115471, I could actually rebase this on that, then restore the ArgNo based checking here back to what it was when asm goto support was first introduced. Then we'd still be using TargetBlockAddresses rather than BlockAddresses.

void added inline comments.Dec 21 2021, 2:22 PM
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

There is a use of it in the .td files:

$ grep tblockaddress
llvm/include/llvm/Target/TargetSelectionDAG.td:def tblockaddress: SDNode<"ISD::TargetBlockAddress",  SDTPtrLeaf, [],
  ...

My concern is that changing this will affect code gen in peculiar ways. Is it possible to retain the previous use of the TargetBlockAddress? Or could we transmography the node from a ISD::BlockAddress to ISD::TargetBlockAddress?

craig.topper added inline comments.Dec 21 2021, 2:22 PM
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

For more information. The "Target" version of nodes are ignored by the isel step of SelectionDAG. They are considered already selected and ignored. This is what the code in SelectNodeCommon is doing.

BlockAddress needs to be replaced before isel finishes, TargetBlockAddress is the only version that can go through InstrEmitter to make MachineIR.

I think usually TargetBlockAddress should be created from BlockAddress as part of lowering. Maybe we were doing something different for asm goto because we weren't really using blockaddress the way it was originally intended? I don't recall if I wrote that part of the code or if I inherited it when I took over the asm goto patch.

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

That said PPCTargetLowering::PPCTargetLowering is doing something "Custom" with ISD::BlockAddress but not ISD::TargetBlockAddress. I wonder if it should be?

Ok, so IIUC, it looks like the backend specific TargetLowering methods "raise" or "promote" ISD::BlockAddresses to ISD::TargetBlockAddresses. I suspect it's more correct for this part of ISEL (SelectionDAGBuilder::visitInlineAsm) to lower to ISD::BlockAddress and then let the target specific backends raise those to ISD::TargetBlockAddresses correctly. But I will admit I'm pretty unfamiliar with all this, so I probably don't know what I'm talking about.

void accepted this revision.Dec 21 2021, 2:35 PM
void added inline comments.
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

I don't recall if I wrote that part of the code or if I inherited it when I took over the asm goto patch.

I think you're on the git blame output for that one. ;-)

Okay, I'll back off on this. It sounds like it was more an attempt to say "No, we're sure we have the correct thing here."

This revision is now accepted and ready to land.Dec 21 2021, 2:35 PM
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

Is it possible to retain the previous use of the TargetBlockAddress?

The issue is in disambiguating between BlockAddress input operands that are just inputs vs indirect destinations of the asm goto. See my previous approaches https://reviews.llvm.org/D114895, https://reviews.llvm.org/D115409 to this. I think https://reviews.llvm.org/D115471 further complicates this since it changes the ordering of the arguments to the asm.

If I rebased this diff on D115471, then I could retain the use of TargetBlockAddress here, simply dropping the NumMatchingOps logic.

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
5094–5095

So it looks like a label is a Type that a Value can have, while blockaddress is a Constant Value, IIUC. Still, this holds:

call (and technically callbr) can accept a label operand; not just a blockaddress.

See also the above relationship between ISD::TargetBlockAddress and ISD::BlockAddress; they're the same SDNode (BlockAddressSDNode). This hunk of this change is unifying the operands rather than relying one of the possible opcodes for this type of SDNode.

nickdesaulniers added inline comments.
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
8570–8571

For more information. The "Target" version of nodes are ignored by the isel step of SelectionDAG. They are considered already selected and ignored. This is what the code in SelectNodeCommon is doing.

BlockAddress needs to be replaced before isel finishes, TargetBlockAddress is the only version that can go through InstrEmitter to make MachineIR.

I think usually TargetBlockAddress should be created from BlockAddress as part of lowering. Maybe we were doing something different for asm goto because we weren't really using blockaddress the way it was originally intended? I don't recall if I wrote that part of the code or if I inherited it when I took over the asm goto patch.

That seems to match up with what @sunfish mentions on discord:

the Target* constants are for things which are legalized, such as immediates which are known to be directly lowerable to machine code. The non-Target form is the pre-legalized version which may need to be legalized, into TargetBlockAddress or something else.

So while yes, we know that the indirect destinations are immediates, this change here of mine is forcing the blockaddresses to now be legalized whereas before my change they were not. Perhaps that's slightly slower, but it resolves the ambiguity between indirect destination blockaddresses, and non-indirect destination blockaddresses.

nickdesaulniers marked an inline comment as not done.Dec 30 2021, 2:34 PM
nickdesaulniers added inline comments.
llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
5094–5095

call (and technically callbr) can accept a label operand; not just a blockaddress.

Scratch and technically callbr; Verifier::visitCallBrInst validates that we do not permit naked label Values in the arg list for callbr IIUC.

To re-summarize the answer to the question

why aren't the values all BlockAddresses?

Because call instructions can have arguments that are labels; not just blockaddresses, as observed in llvm/test/CodeGen/X86/asm-block-labels.ll.

llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll
84 ↗(On Diff #394402)

So I thought this may be because of the changes to SelectionDAGBuilder::visitInlineAsm here (in D115688 Diff 395500).

As a test, I rebased locally D115471 to appear first, rather than last in the patch set, rebasing this on that. That allowed me to remove the NumMatching logic, but keep basically the same version as when callbr support was initially added; if the indirect dests are always the final inputs, the ambiguity alluded to in this patch no longer exists.

I know you weren't enthused by D115471, but I think landing that first actually simplifies this patch (the diff to llvm/test/CodeGen/X86/callbr-asm-bb-exports.ll here goes away, and we return SelectionDAGBuilder::visitInlineAsm back to how it was prior to output support). For that reason, I'd like you to reconsider D115471.

Hmm...wait...it sure looks like the expected code in this test was demonstrating a bug...! It wasn't saving/restoring lr (mflr/mtlr) around the callbr, but the callbr said it clobbers lr! That doesn't seem right -- despite the test asserting it...

I left an additional comment on https://reviews.llvm.org/D101657.

OK...but why did this change fix that?

I'm still not precisely sure why this change tickled that, but perhaps let's fix that first? https://reviews.llvm.org/D116424

LG, with a few minor comments.

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
1686

Taking the label directly as a value seems like something we should not be supporting at all. Yet, since I guess we already did, OK, fine.

llvm/test/CodeGen/AArch64/inlineasm-X-constraint.ll
130

Still outstanding: would be nice to include the target in the check line, verifying that it's an immediate not a register.

llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll
84 ↗(On Diff #394402)

I assume the diff in this file has gone away now?

nickdesaulniers marked 4 inline comments as done.
  • rebase on pre-committed TargetLowering refactor
jyknight accepted this revision.Jan 11 2022, 7:54 AM
This revision was landed with ongoing or failed builds.Jan 11 2022, 10:30 AM
This revision was automatically updated to reflect the committed changes.