Anirudh Prasad via llvm-dev
2021-Jun-28 16:14 UTC
[llvm-dev] RFC: New mechanism for hard register operands to inline asm
Hi All,
Thank you very much for your feedback and opinions on this proposal. Based on
the comments, this is what I'm going to do next.
1. Cross post this RFC to the Clang Developer's mailing list to get some
more feedback.
2. Come up with draft implementations of how the implementation of the
constraint would look like and hash out any open questions.
As others have mentioned in this thread, it would be okay to implement this if
both GCC and Clang implement it (to maintain consistency). GCC hasn't
implemented it yet (the RFC has been posted already to signal the intent of
implementing it). So parallelly, I believe it would be good to get a few
discussions going on possible implementation details and/or approaches to
implement it on the Clang side.
Best Regards,
Anirudh Prasad
-----Anirudh Prasad/Canada/IBM wrote: -----
To: llvm-dev at lists.llvm.org
From: Anirudh Prasad/Canada/IBM
Date: 06/22/2021 11:54AM
Subject: RFC: New mechanism for hard register operands to inline asm
Hi All,
We wanted to bring up the possibility of introducing a new inline asm constraint
for all targets. This new constraint is meant to be used as a replacement for
the register asm construct. Part of the motivation behind this proposal is to
come up with something that is a bit nicer and more obvious to use. The new
inline asm constraint would be as follows:
{“<register-name>”} (operand name) ...
The constraint will try to tie the particular inline asm operand to a specific
register.
This is also proposed as an RFC in the GCC mailing lists
(https://gcc.gnu.org/pipermail/gcc/2021-June/236269.html). We would ideally like
to maintain consistency with GCC.
We have an example in the IBM Z kernel source code, where we believe an
introduction of such an inline asm constraint would be beneficial.
Example: turning this source:
```
int diag8_response(int cmdlen, char *response, int *rlen)
{
register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
register unsigned long reg3 asm ("3") = (addr_t) response;
register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
register unsigned long reg5 asm ("5") = *rlen; /* <-- */
asm volatile(
" diag %2,%0,0x8\n"
" brc 8,1f\n"
" agr %1,%4\n"
"1:\n"
: "+d" (reg4), "+d" (reg5)
: "d" (reg2), "d" (reg3), "d"
(*rlen): "cc");
*rlen = reg5;
return reg4;
}
```
into this:
```
int diag8_response(int cmdlen, char *response, int *rlen)
{
unsigned long len = cmdlen | 0x40000000L;
asm volatile(
" diag %2,%0,0x8\n"
" brc 8,1f\n"
" agr %1,%4\n"
"1:\n"
: "+{r4}" (len), "+{r5}" (*rlen)
: "{r2}" ((addr_t)cpcmd_buf), "{r3}"
((addr_t)response), "d" (*rlen): "cc");
return len;
}
```
Why we believe the introduction of this new “hard register” inline asm
constraint to be useful?
1. It is more flexible than the register asm construct since a user does not
need to be concerned with which registers are previously mapped to which
variable(s).
2. The documentation of the register asm construct (https:/
/gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html) specifies that
function calls might clobber registers assigned with "register asm".
Using this new inline asm constraint ensures that the operand is assigned to a
particular register only in the context of the inline asm call.
3. One register asm variable cannot be used for 2 different inline assembly
statements if the value is expected in different hard registers.
We are very interested in hearing opinions on the above proposal!
Thanks and Best Regards,
Anirudh Prasad