This is an archive of the discontinued LLVM Phabricator instance.

[InlineAsm] Add support for address operands ("p").
ClosedPublic

Authored by jonpa on Mar 22 2022, 3:47 AM.

Details

Summary

This patch adds support for inline assembly address operands using the "p" constraint.

This is in fact broken on X86, see example at https://reviews.llvm.org/D110267 (Nov 23). As suggested there, here is the basic support for "p" and introduction of the C_Memory ConstraintType which fixes this bug on X86 (and also adds support for "p" on SystemZ).

Reasoning:

Memory ("m") and Address ("p") are operands that are selected (and printed) the same way by the backend (i.e. "select address"), but on the other hand they are also different as "p" takes an address present at the source level, while "m" causes the address of a value to be passed (indirect). For example, "p" should not get the mayLoad flag.

The different inline asm operand types are handled in InlineAsm.h but also in TargetLowering: An "m" operand is an InlineAsm::Kind_Mem but also a TargetLowering::C_Memory.

InlineAsm supports different constraint codes for memory operands so that the code gets shifted into its place in Flags. I have reused this for address operands by simply adding a new memory constraint "Constraint_p" for "p". I haven't found a reason yet to add a new InlineAsm::Kind_Address, so addresses are InlineAsm::Kind_Mem with Constraint_p.

In TargetLowering I similarly started out by treating "p" as C_Memory, but we then decided to instead introduce a new C_Address ConstraintType. It seems to make sense to have a different type here as they are in some cases treated differently in SelectionDAGBuilder.

Not sure if it is too confusing to have an address be a Kind_Mem and then a C_Address instead of C_Memory, but it kind of makes sense to me. I could possibly imagine renaming Kind_Mem to Kind_MemOrAddr.

X86:

X86TargetInfo::validateAsmConstraint(): I don't know why not 'm' is accepted here..? I think 'p' should also be recognized here, but the test case passes without it...
X86 test cases in clang/test/CodeGen/asm.c and llvm/test/CodeGen/X86/inline-asm-p-constraint.ll.

CodeGenPrepare:

It seems that addresses could be handled just like memory operands, given that they are handled the same by the back-end. "TODO comments" added for this.

GlobalISel:

@npopov: GlobalISel has not really been handled, but C_Address has been added in switch statements to silence warnings.

Diff Detail

Event Timeline

jonpa created this revision.Mar 22 2022, 3:47 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 22 2022, 3:47 AM
jonpa requested review of this revision.Mar 22 2022, 3:47 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 22 2022, 3:47 AM
xiangzhangllvm added a comment.EditedMar 24 2022, 7:59 PM

I didn't see the 'p' defined in
Machine-Constraints on x86

A question I care about is:
How we (customers) can quickly refer to the meaning of new added constrain 'p'.

X86TargetInfo::validateAsmConstraint(): I don't know why not 'm' is accepted here..?

The answer can be find in function TargetInfo::validateInputConstraint.
Because not all constrains will be checked by validateAsmConstraint.

jonpa updated this revision to Diff 418254.Mar 25 2022, 9:40 AM

Thanks for review!

I didn't see the 'p' defined in
Machine-Constraints on x86

A question I care about is:
How we (customers) can quickly refer to the meaning of new added constrain 'p'.

That is a good point, and I think we need to add a description in the LLVM llanguage manual for 'p' under the section "Supported Constraint Code List". As 'p' is a shared code over targets I think it should be listed in the common section (as it is in gcc documentation link). I updated the patch with this addition - what do you think?

X86TargetInfo::validateAsmConstraint(): I don't know why not 'm' is accepted here..?

The answer can be find in function TargetInfo::validateInputConstraint.
Because not all constrains will be checked by validateAsmConstraint.

Ah, I see: first validateInputConstraint() is called and then only if needed is the target validateAsmConstraint() used. I removed the 'p' handling I had added in SystemZ::validateAsmConstraint() which is actually then not needed/used. I am a little surprised now that this works, as validateInputConstraint() does not call 'Info.setAllowsRegister()' for 'p', which is needed for the SystemZ specific address constraints (see https://reviews.llvm.org/D110267).

Thanks for review!

I didn't see the 'p' defined in
Machine-Constraints on x86

A question I care about is:
How we (customers) can quickly refer to the meaning of new added constrain 'p'.

That is a good point, and I think we need to add a description in the LLVM llanguage manual for 'p' under the section "Supported Constraint Code List". As 'p' is a shared code over targets I think it should be listed in the common section (as it is in gcc documentation link). I updated the patch with this addition - what do you think?

X86TargetInfo::validateAsmConstraint(): I don't know why not 'm' is accepted here..?

The answer can be find in function TargetInfo::validateInputConstraint.
Because not all constrains will be checked by validateAsmConstraint.

Ah, I see: first validateInputConstraint() is called and then only if needed is the target validateAsmConstraint() used. I removed the 'p' handling I had added in SystemZ::validateAsmConstraint() which is actually then not needed/used. I am a little surprised now that this works, as validateInputConstraint() does not call 'Info.setAllowsRegister()' for 'p', which is needed for the SystemZ specific address constraints (see https://reviews.llvm.org/D110267).

I agree with you, some constraint codes are typically supported by all targets.

jonpa added a comment.Apr 4 2022, 2:59 AM

Ping!

It would be nice to get review as we expect this to fix inline assembly address operands on X86, while we also have another patch for SystemZ address operands waiting on this...

Thanks for your job, I am not familiar with the SystemZ part, PLS make sure all tests passed.
(+ Better to sync the clang format)
If no others object it, I'll accepted 1 day later.

jonpa updated this revision to Diff 420424.Apr 5 2022, 2:49 AM

Thanks for your job, I am not familiar with the SystemZ part, PLS make sure all tests passed.
(+ Better to sync the clang format)
If no others object it, I'll accepted 1 day later.

All tests are passing, and I fixed the one format issue that this patch introduced.

It would be great to get review on the common code + X86 changes at this stage. I think I could either commit the SystemZ part as well even if no review is given as it is follows quite trivially, or I could wait with that part and commit it at a later point. The X86 tests should be enough on their own, right?

The X86 tests should be enough on their own, right?

Most the common uses existed in the tests.
If it cause very rarely/corner case fail, (I think almost no customers use it), let we fix it when we meet it.

clang/lib/Basic/Targets/X86.cpp
1494

Did you check the difference with the previous constraint "im" at llvm end.
Looks the C_Address is mostly same with C_Memory, but no relation with C_Immediate.

jonpa marked an inline comment as done.Apr 6 2022, 2:57 AM
jonpa added inline comments.
clang/lib/Basic/Targets/X86.cpp
1494

No I have not: there are no tests failing due to this change, and what's more is that the previous handling of "p" was actually incorrect (as showed earlier with example), with wrong code resulting.

I would also hope that the address handling in the X86 backend can handle an immediate if it is accepted as an address...

In my eye, the reason we need the "p" is Front End miss handle the constrain "*", so the "m" and "*m" have the same action at qWvod14G9
(both isIndirect)

In IR level the constrain "p" is equal with "m" (TargetLowering::C_Memory + !isIndirect)

llvm/lib/CodeGen/CodeGenPrepare.cpp
4838

I think C_Address the should return false. It is direct mem (!OpInfo.isIndirect). So no need change here.

5621

I think we can handle the C_Address.
As the comment ahead optimizeMemoryInst, this is used to
"Sink addressing mode computation immediate before MemoryInst if doing so
can be done without increasing register pressure."
Anyway that is not a big problem.

jonpa added a comment.Apr 8 2022, 3:39 AM

In IR level the constrain "p" is equal with "m" (TargetLowering::C_Memory + !isIndirect)

I am not sure there is such a thing as "m" without the indirect flag ('*')... "m" and "p" are however different as "*m" is used to access memory and "p" typically to load the address into a register (at least that's my understanding so far).

llvm/lib/CodeGen/CodeGenPrepare.cpp
4838

I think actually this should be treated the same as an indirect memory operand since the address can be sunk into user just the same way. So for a C_Address, false should *not* be returned, I think.

5621

Yes, they should be treated the same, I agre...

xiangzhangllvm accepted this revision.Apr 10 2022, 5:42 PM

LGTM, I prefer to accept this patch. Thank you for your effort.

This revision is now accepted and ready to land.Apr 10 2022, 5:42 PM
jonpa added a comment.Apr 11 2022, 1:36 AM

Thank you for your review! I will commit this within a few days unless someone else has any objections...

The SystemZ parts LGTM as well. Thanks!

This revision was landed with ongoing or failed builds.Apr 13 2022, 3:52 AM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptApr 13 2022, 3:52 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
jonpa added a comment.Apr 13 2022, 3:53 AM

-no-opaque-pointers added to SystemZ clang test, per 532dc62.