Skip to content

Commit 73215bc

Browse files
authored
Merge pull request #426 from riscv-non-isa/valist-bitfield
va_list & bit-field improvements
2 parents 5ffe5b5 + 9e93d96 commit 73215bc

File tree

1 file changed

+59
-22
lines changed

1 file changed

+59
-22
lines changed

riscv-cc.adoc

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ contents of any fixed registers like `gp` and `tp` never change,
170170
NOTE: Calling convention for big-endian is *NOT* included in this specification
171171
yet, we intend to define that in future version of this specification.
172172

173+
[#integer-cc]
173174
=== Integer Calling Convention
174175

175176
The base integer calling convention provides eight argument registers,
@@ -216,21 +217,6 @@ Empty structs or union arguments or return values are ignored by C compilers
216217
which support them as a non-standard extension. This is not the case for {Cpp},
217218
which requires them to be sized types.
218219

219-
Bitfields are packed in little-endian fashion. A bitfield that would span the
220-
alignment boundary of its integer type is padded to begin at the next
221-
alignment boundary. For example, `struct { int x : 10; int y : 12; }` is
222-
a 32-bit type with `x` in bits 9-0, `y` in bits 21-10, and bits 31-22
223-
undefined. By contrast, `struct { short x : 10; short y : 12; }` is a 32-bit
224-
type with `x` in bits 9-0, `y` in bits 27-16, and bits 31-28 and bits 15-10
225-
undefined.
226-
227-
Bitfields may larger than its integer type, bits excess than its integer
228-
type will treat as padding bits, then padding to begin at the next alignment
229-
boundary. For example `struct { char x : 9; char y; }` is a 24 byte type with
230-
`x` in bits 7-0, `y` in bit 23-16, and bits 15-8 undefined,
231-
`struct { char x : 9; char y : 2 }` is a 16-bit type with `x` in bits 7-0, `y`
232-
in bit 10-9, and bit 8, bits 15-11 is undefined.
233-
234220
Arguments passed by reference may be modified by the callee.
235221

236222
Floating-point reals are passed the same way as aggregates of the same size;
@@ -639,15 +625,66 @@ The type `size_t` is defined as `unsigned int` for RV32 and `unsigned long` for
639625

640626
The type `ptrdiff_t` is defined as `int` for RV32 and `long` for RV64.
641627

628+
=== Bit-fields
629+
630+
Bit-fields are packed in little-endian fashion. A bit-field that would span the
631+
alignment boundary of its integer type is padded to begin at the next
632+
alignment boundary. For example, `struct { int x : 10; int y : 12; }` is
633+
a 32-bit type with `x` in bits 9-0, `y` in bits 21-10, and bits 31-22
634+
undefined. By contrast, `struct { short x : 10; short y : 12; }` is a 32-bit
635+
type with `x` in bits 9-0, `y` in bits 27-16, and bits 31-28 and bits 15-10
636+
undefined.
637+
638+
Bit-fields which are larger than their integer types are only present in {Cpp}
639+
and are defined by the _Itanium {Cpp} ABI_ <<itanium-cxx-abi>>. The bit-field
640+
and containing struct are aligned on a boundary corresponding to the largest
641+
integral type smaller than the bit-field, up to 64-bit alignment on RV32 or
642+
128-bit alignment on RV64. Any bits in excess of the size of the declared type
643+
are treated as padding. For example `struct { char x : 9; char y; }` is a
644+
24-bit type with `x` in bits 7-0, `y` in bit 23-16, and bits 15-8 undefined;
645+
`struct { char x : 9; char y : 2 }` is a 16-bit type with `x` in bits 7-0, `y`
646+
in bit 10-9, and bits 8 and 15-11 undefined.
647+
648+
Unnamed nonzero length bit-fields allocate space in the same fashion as named
649+
bitfields but do not affect the alignment of the containing struct.
650+
651+
Zero length bit-fields are aligned relative to the start of the containing
652+
struct according to their declared type and, since they must be unnamed, do not
653+
affect the struct alignment. C requies bit-fields on opposite sides of a
654+
zero-length bitfield to be treated as separate memory locations for the
655+
purposes of data races.
656+
642657
=== va_list, va_start, and va_arg
643658

644-
The `va_list` type is `void*`. A callee with variadic arguments is responsible
645-
for copying the contents of registers used to pass variadic arguments to the
646-
vararg save area, which must be contiguous with arguments passed on the stack.
647-
The `va_start` macro initializes its `va_list` argument to point to the start
648-
of the vararg save area. The `va_arg` macro will increment its `va_list`
649-
argument according to the size of the given type, taking into account the
650-
rules about 2×XLEN aligned arguments being passed in "aligned" register pairs.
659+
The `va_list` type has the same representation as `void*` and points to a
660+
sequence of zero or more arguments with preceding padding for alignment,
661+
formatted and aligned as variadic arguments passed on the stack according to
662+
the integer calling convention (<<integer-cc>>). All standard calling conventions use the
663+
same representation for variadic arguments to allow `va_list` types to be
664+
shared between them.
665+
666+
The `va_start` macro in a function initializes its `va_list` argument to point
667+
to the first address at which a variadic argument could be passed to the
668+
function. If all integer argument registers are used for named formal
669+
arguments, the first variadic argument will have been passed on the stack by
670+
the caller, and the `va_list` can point to the address immediately after the
671+
last named argument passed on the stack, or the `sp` value on entry if no named
672+
arguments were passed on the stack. If some integer argument registers were not
673+
used for named formal arguments, then the first variadic argument may have been
674+
passed in a register. The function is then expected to construct a _varargs
675+
save area_ immediately below the entry `sp` and fill it with the entry values
676+
of all integer argument registers not used for named arguments, in sequence.
677+
The `va_list` value can then be initialized to the start of the varargs save
678+
area, and it will iterate through any variadic arguments passed via registers
679+
before continuing to variadic arguments passed on the stack, if any.
680+
681+
The `va_arg` macro will align its `va_list` argument, fetch a value, and
682+
increment the `va_list` according to the alignment and size of a variadic
683+
argument of the given type, which may not be the same as the alignment and size
684+
of the given type in memory. If the type is passed by reference, the size and
685+
alignment used will be those of a pointer, and the fetched pointer will be used
686+
as the address of the actual argument. The `va_copy` macro is a single pointer
687+
copy and the `va_end` macro performs no operation.
651688

652689
=== Vector type sizes and alignments
653690

0 commit comments

Comments
 (0)