#[non_exhaustive]pub struct TargetInfo {Show 20 fields
pub tuple: TargetTuple,
pub scalars: DataLayout,
pub pointer_width: u32,
pub little_endian: bool,
pub char_is_signed: bool,
pub long_width: u32,
pub long_double_width: u32,
pub long_double_format: Format,
pub float64x_format: Option<Format>,
pub wchar_width: u32,
pub wchar_is_signed: bool,
pub bit_int_granule: u32,
pub lock_free_width: u32,
pub object_format: ObjectFormat,
pub bit_field_style: BitFieldStyle,
pub unnamed_bit_field_aligns: bool,
pub empty_record_size: u64,
pub va_list: Option<VaList>,
pub regs: &'static RegFile,
pub call_regs: Option<&'static CallRegs>,
}Expand description
The facts about a target that the compiler reads instead of hard-coding.
This is the whole of what a pass is allowed to know about where its output will run.
It grows, and every field added here is one fewer #[cfg] somewhere it should not be.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.tuple: TargetTupleThe machine this describes, as the ten field tuple rather than as a three field triple.
It is the tuple because a record layout is a question every row of the target table has an
answer to, and a triple can spell fifteen of the forty two. Nothing else in this type had
to change to widen it: every field below is already derived from rucc-abi’s description
of this tuple, and the ones that were not were the bugs.
scalars: DataLayoutThe sizes, the alignments and the signedness this target’s headers were written against.
The widths below are views of this and the alignments are not, which is the reason it is
kept whole. A long long is eight bytes on every row of the table and is aligned to four
on System V i386 and to eight everywhere else, and no width can say that.
pointer_width: u32Width of a pointer in bits.
little_endian: boolWhether bytes are ordered little end first.
char_is_signed: boolWhether a bare char is signed.
Signed on x86-64 and unsigned on AArch64 Linux, which is the classic source of code that works on one and not the other, so it is data rather than an assumption.
long_width: u32Width of long in bits. This is the field that separates the LP64 world from
Windows LLP64.
long_double_width: u32Width of long double in bits: 80 bits of x87 stored in 128 on every x86-64 target but
MSVC, 128 of true quad precision on AArch64 Linux and RISC-V, and 64 on Apple’s AArch64 and
under MSVC.
Apple’s x86-64 is not one of the 64-bit ones, which is the trap. The change to a double
came with AArch64 and the Intel answer stayed as it was, so x86_64-apple-darwin and
x86_64-unknown-linux-gnu agree here and aarch64-apple-darwin is the odd one.
long_double_format: FormatThe format long double actually is, which the width does not say.
It is 128 bits wide on SysV x86-64 and on AArch64 Linux and the two are not the same type: one is the x87 eighty bit format padded out to sixteen bytes and the other is true quad precision with a hundred and thirteen bits of significand. Anything that converts a constant or folds one has to know which, and the width alone cannot say.
float64x_format: Option<Format>The format _Float64x is, which is the widest format the target has short of a software
one.
It follows the architecture and not the operating system, which is what makes it worth a
field of its own next to long double. Apple and Windows define long double as a
double and neither of them takes _Float64x down with it: the type has to be wider
than a _Float64, so it is the x87 eighty bit format on x86-64 and quad precision on
AArch64 and RISC-V wherever it is written.
None on a machine whose widest format is a double, which is 32-bit ARM and wasm32.
The type does not exist there and neither reference defines the macros that describe it,
so the honest answer is that there is no format rather than a double in its place.
wchar_width: u32Width of wchar_t in bits, which decides what a wide literal is encoded in.
It is 16 on Windows, so a wide string there is UTF-16 and a character outside the basic plane takes two elements, and 32 everywhere else, where a wide string is UTF-32 and no character takes more than one.
wchar_is_signed: boolWhether wchar_t is signed.
x86-64 Linux makes it a signed int and AArch64 Linux makes it an unsigned int,
following the psABI’s rule for plain char, so L'\xffffffff' is minus one on one of
them and four billion on the other.
bit_int_granule: u32The granule a _BitInt wider than 64 bits is laid out in, in bits.
Above 64 bits the psABIs stop treating a _BitInt like a standard integer type and
start treating it like an array of these, so its size is rounded up to a multiple of
this and its alignment is this. It is 64 on x86-64 and RISC-V and 128 on AArch64, which
is why _BitInt(65) is sixteen bytes aligned to eight on one and sixteen bytes aligned
to sixteen on the other. Measured with clang 18 on x86-64 Linux and clang on AArch64
Darwin rather than read off the documents.
lock_free_width: u32The widest access, in bits, this machine performs atomically without taking a lock.
It is what __atomic_always_lock_free and __atomic_is_lock_free answer from, and it is
a claim about what this compiler emits rather than about what the processor is capable of.
Sixty four on every target here. x86-64 does sixteen bytes atomically with cmpxchg16b,
which is not in the baseline the psABI names and which nothing in this compiler writes, and
AArch64 does the same with its pair instructions, which nothing writes either. A target
that answered yes for sixteen bytes and then called a library that has to take a lock for
them would have two answers to one question, and the wrong one is the one in the header.
object_format: ObjectFormatThe object format to emit.
bit_field_style: BitFieldStyleHow bit-fields are allocated into storage, which is the one record layout question where two targets in this table run different algorithms rather than the same one over different numbers.
unnamed_bit_field_aligns: boolWhether an unnamed bit-field raises the record’s alignment the way a named one does.
Almost everywhere it does not, which is why struct { char c; int :20; } is four bytes
aligned to one on x86-64 and four aligned to four with the field named. AAPCS64 says
otherwise and says it for the zero width member too, so struct { unsigned :0; } is
aligned to four on AArch64 Linux and to one on Apple’s AArch64, on Windows on AArch64, on
x86-64 and on RISC-V. Measured with the pinned reference across every row that has one,
because it is neither an architecture rule nor an operating system rule: it is the ABI, and
Apple and Microsoft each dropped it.
Windows says yes as well, and there it is not AAPCS64 but Microsoft’s own rule, which is
why the two facts are separate fields rather than one. In a union the Microsoft rule goes
further and no bit-field contributes alignment at all, named or not, so this field is only
half the answer there and BitFieldStyle carries the other half.
empty_record_size: u64How large a record with no storage in it is, in bytes, before its alignment is applied.
Zero everywhere but MSVC, where it is four. A struct with no members is not C at all, it
is a GNU extension, and C++ gives it a size of one, so there is no standard to read the
answer out of and the number has to come from whatever else compiles for the target. On
mingw that is GCC and the answer is zero. On MSVC it is clang, because MSVC itself rejects
the declaration outright, and clang’s Microsoft record layout gives it four bytes and gives
an array of three of them twelve. So this is a fact about the environment and not about the
operating system, which is the one place in this type where those two come apart in that
direction.
It covers a record with no members and a record whose only members occupy nothing, which is the zero width bit-field, the zero length array and the flexible array member. All four were measured and all four agree.
va_list: Option<VaList>What __builtin_va_list is, which is the type every va_list in every header is a
typedef of.
None on a target whose answer is a type this crate does not build yet. 32-bit ARM’s is
a structure of one pointer and s390x’s is a structure of four members, and neither is any
of the four below. A target with no backend cannot compile a call to va_arg in any case,
so saying so beats naming a neighbour’s type and having a header believe it.
regs: &'static RegFileThe registers the machine has, which is RegFile::EMPTY for an architecture nothing
has described yet.
call_regs: Option<&'static CallRegs>Which registers the calling convention gives which job, or None while the
architecture has no register file to name them out of.
Implementations§
Source§impl TargetInfo
impl TargetInfo
Sourcepub fn call(&self) -> Option<Call>
pub fn call(&self) -> Option<Call>
The start of one call, with every argument register still to spend, and None on a
target whose ABI is not described.
The None is AArch64 on Windows and nothing else today. That ABI is AAPCS64 with a
different variadic rule and x18 reserved, per spec/cross-compile/06-abis.md section 6.1,
and it is not written down yet. This used to answer AAPCS64 for it, which is the almost
right answer, and an almost right ABI is the failure mode spec/cross-compile/02-the-goal.md
exists to rule out: everything builds, everything links, and a structure crosses a
library boundary with its members in the wrong registers. A caller that cannot compile
the call says so instead.
Source§impl TargetInfo
impl TargetInfo
Sourcepub fn new(triple: Triple) -> Self
pub fn new(triple: Triple) -> Self
The description of triple.
The three field triple spells fifteen of the forty two rows of the target table, which is
every row with a backend and every row a driver will be handed today, so this is what the
compiler proper calls. TargetInfo::for_tuple is the one that answers for the whole
table.
Sourcepub fn for_tuple(target: TargetTuple) -> Self
pub fn for_tuple(target: TargetTuple) -> Self
The description of target.
Every row of the target table has one of these, whether or not there is a backend that can
emit code for it, because laying a record out and reading a header are questions that do
not need a backend. The fields that genuinely need one say so: TargetInfo::regs is
empty and TargetInfo::call_regs is None for an architecture whose register file is
not written down.
Sourcepub const fn max_object_size(&self) -> u64
pub const fn max_object_size(&self) -> u64
The largest an object may be on this target, in bytes.
PTRDIFF_MAX, which is what C 6.5.6 needs it to be: subtracting two pointers into one
object has to have an answer, and the answer has a ptrdiff_t to fit in. So an object
of exactly this many bytes is allowed and one byte more is not, which is the line GCC
draws too. It is the only size limit in the compiler and every layout question that has
one asks here rather than at whatever its own arithmetic happens to overflow at.
Trait Implementations§
Source§impl Clone for TargetInfo
impl Clone for TargetInfo
Source§fn clone(&self) -> TargetInfo
fn clone(&self) -> TargetInfo
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more