This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] Hard float ABI support

Authored by asb on Apr 9 2019, 5:45 AM.



The RISC-V hard float calling convention requires the frontend to:

  • Detect cases where, once "flattened", a struct can be passed using int+fp or fp+fp registers under the hard float ABI and coerce to the appropriate type(s)
  • Track usage of GPRs and FPRs in order to gate the above, and to determine when signext/zeroext attributes must be added to integer scalars

This patch attempts to do this in compliance with the documented ABI, and uses ABIArgInfo::CoerceAndExpand in order to do this. @rjmccall, as author of that code I've tagged you as reviewer for initial feedback on my usage.

Note that a previous version of the ABI indicated that when passing an int+fp struct using a GPR+FPR, the int would need to be sign or zero-extended appropriately. GCC never did this and the ABI was changed, which makes life easier as ABIArgInfo::CoerceAndExpand can't currently handle sign/zero-extension attributes.

Diff Detail

Event Timeline

asb created this revision.Apr 9 2019, 5:45 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 9 2019, 5:45 AM
rjmccall added inline comments.Apr 9 2019, 8:11 AM
102 ↗(On Diff #194295)

You can remove the TODO here, assuming that this CC support is all that's necessary to support these ABIs.

9223 ↗(On Diff #194295)

Should this include pointers? Pointers are often interchangeably with integers by ABIs.

The same question also applies to C++ references and data-member-pointer types, and maybe others that I'm not thinking of.

9298 ↗(On Diff #194295)

This definitely needs to handle bit-fields in some way.

9352 ↗(On Diff #194295)

This should use alignTo, not max. It's possible that they're equivalent for the narrow cases that can come out of all the checks above, but it's both clearer and safer to use the correct computation.

9374 ↗(On Diff #194295)

This seems like a reasonable use of coerce-and-expand.

asb updated this revision to Diff 198797.May 9 2019, 5:25 AM
asb marked 3 inline comments as done.


  • Expanded and improved tests
  • Set ABI defines
  • Remove errant TODO
  • Use alignTo

Still to do:

  • Review and test bitfield handling (which is likely incomplete)
9223 ↗(On Diff #194295)

The ABI doesn't consider pointers and integers interchangeable in this case. An "integer" is indeed an integer.

rjmccall added inline comments.May 16 2019, 10:32 AM

Is this the only consideration for floating-point types? Clang does have increasing support for half / various float16 types.


The comment here is wrong because fp+fp is allowed, right?

Is this not already caught by the post-processing checks you do in detectFPCCEligibleStruct? Would it make more sense to just do all those checks there?


Field2Ty = Field1Ty, please.


I really expect there to be something in this block about whether the field is a bit-field. What exactly does your ABI specify if there's a bit-field?

mhorne added a subscriber: mhorne.Jun 1 2019, 10:56 AM
asb updated this revision to Diff 208308.Jul 7 2019, 8:48 PM
asb marked 7 inline comments as done.
asb retitled this revision from [RISCV][WIP/RFC] Hard float ABI support to [RISCV] Hard float ABI support.
asb edited the summary of this revision. (Show Details)

Address all review comments from @rjmccall. Bitfield handling matches observed behaviour of GCC and I have an active PR to properly document this in the RISC-V psabi. Tests are updated to check this behaviour.

Many thanks for the review comments - do you think this is ready to land?

asb added inline comments.Jul 7 2019, 9:06 PM

These types aren't supported on RISC-V currently. As the ABI hasn't really been explicitly confirmed, I've defaulted to the integer ABI in that case. Could move to an assert if you prefer, though obviously any future move to enable half floats for RISC-V should include ABI tests too.


Thanks, I meant to say int+int isn't eligible. Reworded to say that.

I don't think it would simplify things to do all checks in detectFPCCEligibleStruct. More repetition would be required in order to do checks on both Float1Ty and Float2Ty.


I've updated to handle bitfields and submitted a pull request to the RISC-V psABI to improve the documentation. Unfortunately the handling of zero-width bitfields is a little weird, but the preference seems to be to just document what GCC does.

rogfer01 added inline comments.Jul 7 2019, 10:41 PM

I found some mismatch in behaviour between gcc and g++ that we may want to address in the psABI first.

For instance, given the following struct (I'm using gcc 8.3.0)

// t.c
struct A
  int :0;
  double d;
  int :0;
  long x;
  int :0;

extern void bar(struct A);
void foo(struct A a)
  a.d =- a.d;
  a.x += 1;
  return bar(a);

we are emitting this

$ clang --target=riscv64 -march=rv64gc -mabi=lp64d -S -o-  t.c -O2  
foo:                                    # @foo
# %bb.0:                                # %entry
        addi    a2, zero, -1
        slli    a2, a2, 63
        xor     a0, a0, a2
        addi    a1, a1, 1
        tail    bar

which matches with what g++ does (i.e in both cases a0 is a.d and a1 is a.x)

$ ./riscv64-unknown-linux-gnu-g++ -S -O2 -o- -x c
	fmv.d.x	fa5,a0
	addi	sp,sp,-16
	fneg.d	fa5,fa5
	addi	a1,a1,1
	addi	sp,sp,16
	fmv.x.d	a0,fa5
	tail	bar

But I found a mismatch while using C++. Clang emits the same for C and C++ (modulo .cfi stuff)

$ clang --target=riscv64 -march=rv64gc -mabi=lp64d -S -o-  -x c++ t.c -O2  
_Z3foo1A:                               # @_Z3foo1A
# %bb.0:                                # %entry
        addi    a2, zero, -1
        slli    a2, a2, 63
        xor     a0, a0, a2
        addi    a1, a1, 1
        .cfi_def_cfa_offset 0
        tail    _Z3bar1A

But g++ seems to ignore the zero-width bitfields: fa0 is a.d and a0 is a.x

$ riscv64-unknown-linux-gnu-g++  -S -O2 -x c++ t.c -o-
        fneg.d  fa0,fa0
        addi    sp,sp,-16
        .cfi_def_cfa_offset 16
        addi    a0,a0,1
        addi    sp,sp,16
        .cfi_def_cfa_offset 0
        tail    _Z3bar1A

This is a bit worrying as it might complicate interoperability between C and C++ (I tried wrapping everything inside an extern "C" just in case but it didn't change g++'s behaviour).

Do you mind to confirm this issue?


Typo in Filed2Ty and Filed2Off

asb marked an inline comment as done.Jul 8 2019, 6:56 AM
asb added inline comments.

Thanks, I'm seeing this in GCC 9.1.0 as well. I left[ a comment]( on the relevant psABI issue. It seems there is a GCC bug here, but hopefully someone can confirm what the "correct" behaviour is.

asb updated this revision to Diff 208392.Jul 8 2019, 6:58 AM
asb marked an inline comment as done.

Updated to address comment typo picked up by @rogfer01 (thanks!).

As noted in another comment, it's not entirely clear what zero-width bitfield behaviour to match (see here) as GCC seems buggy and the ABI is under-specified. Ideally I'd like to land this patch and follow-up to adjust the zero-width bitfield behaviour if necessary once that psABI issue is resolved.

As noted in another comment, it's not entirely clear what zero-width bitfield behaviour to match (see here) as GCC seems buggy and the ABI is under-specified. Ideally I'd like to land this patch and follow-up to adjust the zero-width bitfield behaviour if necessary once that psABI issue is resolved.

Agreed, I presume the original intent in the psABI was to have C and C++ behave the same. We're siding with gcc in this patch but it should not be difficult to change if the psABI resolves this in favour of g++.

I'm fine with proceeding with your best guess about what the ABI should be.


Defaulting to the integer ABI is fine.


Okay. It just seemed to me that responsibility was oddly split between the functions.


Okay. So consecutive bit-fields are considered individually, not packed into a single storage unit and then considered? Unfortunate ABI rule, but if it's what you have to implement, so be it.

asb updated this revision to Diff 208477.Jul 8 2019, 12:33 PM
asb marked 4 inline comments as done.

Tweaked a code comment.

Just to confirm, @rjmccall are you happy for me to commit this?


I added a comment to document this. It's not something I'd expose in a public API, but I think it's defensible to catch this case outside of the helper. I had another look at refactoring but the readability just seemed to be reduced when pulling out all the checks to the caller (rather than catching the single case that detectFPCCEligibleStructHelper can't handle).


I'm afraid that's the rule as written, and what gcc seems to implement.

rjmccall accepted this revision.Jul 8 2019, 12:39 PM

Yes, I think you can commit.

This revision is now accepted and ready to land.Jul 8 2019, 12:39 PM
asb added a comment.Jul 8 2019, 12:41 PM

Thanks for the careful review John, I really appreciate it!

This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptJul 18 2019, 8:33 AM

Your use of CoerceAndExpand seems fine; thanks for pinging me on it

rkruppe removed a subscriber: rkruppe.Apr 10 2021, 2:36 AM