Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/c-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ statements, including both RISC-V specific and common operand constraints.
.Constraints on Operands of Inline Assembly Statements
[%autowidth]
|===
|*Constraint* | |*Note*
|*Constraint* |*Description* |*Note*
|m |An address that is held in a general-purpose register with offset. |
|A |An address that is held in a general-purpose register. |
|r |General purpose register |
Expand All @@ -746,13 +746,18 @@ statements, including both RISC-V specific and common operand constraints.
|K |5-bit unsigned immediate integer operand |
|J |Zero integer immediate operand |
|s |symbol or label reference with a constant offset |
|cr |RVC general purpose register (`x8`-`x15`) |
|cf |RVC floating point register (`f8`-`f15`) |
|Pr |Even-odd general purpose register pair |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do any other targets support pair? I haven't been able to find any in LLVM and I don't know how to implement it in LLVM.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AArch64 supports tuples of 8 64-bit registers, as implemented here llvm/llvm-project@7d94043

I noticed that the NXP LLVM fork with Zilsd support seems to allocate both v2i<xlen> and i<2*xlen> to the paired register class, but maybe we only need to do the former? I'm not sure, as it would be nice to be able to pass uint<2*xlen>_t to a GPR pair constraint.

I understand that pair constraint is the most complex part of this proposal. I have most of a patch for the other constraints, which I will try to finish in the next few days and post to LLVM.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked this up later, and on LLVM, SystemZ also supports GPR pairs using r - https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/SystemZ/SystemZISelLowering.h#L444-L446

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arm supports pairs in inline asm using the "H" output modifier: https://developer.arm.com/documentation/dui0774/l/armclang-Inline-Assembler/Inline-assembly-template-modifiers/Template-modifiers-for-AArch32-state?lang=en. E.g. when reading a 64-bit system register in 32-bit mode:

    uint64_t _val;
    __asm__("mrrc p15, 0, %0, %H0, c14 : "=r" (_val));
    return _val;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went looking at this and honestly, using a specific constraint rather than something implicit in a modifier seems much more obvious. But thanks for pointing out they had it, the LLVM implementation (they do a bunch of fixing things up later in isel rather than in lowering) was so strange that I hadn't come across what was going on. The RISC-V implementation has ended up following what SystemZ did, which has some overlaps with how Arm works but not many.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also one more constraint on GCC side, a multi-letter constraint must have same length, e.g. define both Rp and Rpr are invalid, since it come with length 2 and 3.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm starting to wonder how extensible we really need pairs to be. So far they've only turned up in the ISA for GPRs. I think for vector tuples, i think right now it's possible to just use vr or vd with the right type of argument?

So maybe all we need is GPR pairs, and we don't need to think about extensibility?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed an update with R, just saying that c* is extensible and pairs are not. We can still change the letter though.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think right now it's possible to just use vr or vd with the right type of argument?

Yes, just vr or vd for vector tuple is fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So maybe all we need is GPR pairs, and we don't need to think about extensibility?

I am OK with R for GPR pair only for now :)

|vr |Vector register |
|vd |Vector register, excluding v0 |
|vm |Vector register, only v0 |
|===

NOTE: Immediate value must be a compile-time constant.

NOTE: The `c*` and `P*` constraints are designed to be extensible to more kinds of registers in the future.

=== The Difference Between `m` and `A` Constraints

The difference between `m` and `A` is whether the operand can have an offset;
Expand Down Expand Up @@ -809,6 +814,7 @@ statements, including both RISC-V specific and common operand modifiers.
|*Modifiers* |*Description* |*Note*
|z |Print `zero` (`x0`) register for immediate 0, typically used with constraints `J` |
|i |Print `i` if corresponding operand is immediate. |
|N |Print register encoding as integer (0-31). |
|===

[id=function-multi-version]
Expand Down