Skip to content

Commit 948d4d6

Browse files
committed
compiler: Parse p- specs in datalayout string, allow definition of default data address space
1 parent c9cb979 commit 948d4d6

File tree

50 files changed

+337
-145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+337
-145
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 198 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ impl ReprOptions {
221221
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
222222
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
223223

224+
/// Informations relative to a specific address space.
225+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
226+
pub struct AddressSpaceInfo {
227+
/// The size of the bitwise representation of the pointer.
228+
pointer_size: Size,
229+
/// The alignment requirements for pointers in this address space.
230+
pointer_align: AbiAlign,
231+
/// The size of the index that used for address calculations on pointers in this address space.
232+
pointer_index: Size,
233+
}
234+
224235
/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
225236
/// for a target, which contains everything needed to compute layouts.
226237
#[derive(Debug, PartialEq, Eq)]
@@ -236,13 +247,22 @@ pub struct TargetDataLayout {
236247
pub f32_align: AbiAlign,
237248
pub f64_align: AbiAlign,
238249
pub f128_align: AbiAlign,
239-
pub pointer_size: Size,
240-
pub pointer_align: AbiAlign,
241250
pub aggregate_align: AbiAlign,
242251

243252
/// Alignments for vector types.
244253
pub vector_align: Vec<(Size, AbiAlign)>,
245254

255+
pub default_address_space: AddressSpace,
256+
pub default_address_space_info: AddressSpaceInfo,
257+
258+
/// The address space informations relative to all the known address spaces.
259+
///
260+
/// # Note
261+
///
262+
/// This vector does not contain the [`AddressSpaceInfo`] relative to the default address space,
263+
/// which instead lives in [`Self::default_address_space_info`].
264+
address_space_info: Vec<(AddressSpace, AddressSpaceInfo)>,
265+
246266
pub instruction_address_space: AddressSpace,
247267

248268
/// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,13 +287,18 @@ impl Default for TargetDataLayout {
267287
f32_align: AbiAlign::new(align(32)),
268288
f64_align: AbiAlign::new(align(64)),
269289
f128_align: AbiAlign::new(align(128)),
270-
pointer_size: Size::from_bits(64),
271-
pointer_align: AbiAlign::new(align(64)),
272290
aggregate_align: AbiAlign { abi: align(8) },
273291
vector_align: vec![
274292
(Size::from_bits(64), AbiAlign::new(align(64))),
275293
(Size::from_bits(128), AbiAlign::new(align(128))),
276294
],
295+
default_address_space: AddressSpace::ZERO,
296+
default_address_space_info: AddressSpaceInfo {
297+
pointer_size: Size::from_bits(64),
298+
pointer_align: AbiAlign::new(align(64)),
299+
pointer_index: Size::from_bits(64),
300+
},
301+
address_space_info: vec![],
277302
instruction_address_space: AddressSpace::ZERO,
278303
c_enum_min_size: Integer::I32,
279304
}
@@ -298,6 +323,7 @@ impl TargetDataLayout {
298323
/// determined from llvm string.
299324
pub fn parse_from_llvm_datalayout_string<'a>(
300325
input: &'a str,
326+
default_address_space: AddressSpace,
301327
) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
302328
// Parse an address space index from a string.
303329
let parse_address_space = |s: &'a str, cause: &'a str| {
@@ -334,6 +360,8 @@ impl TargetDataLayout {
334360
};
335361

336362
let mut dl = TargetDataLayout::default();
363+
dl.default_address_space = default_address_space;
364+
337365
let mut i128_align_src = 64;
338366
for spec in input.split('-') {
339367
let spec_parts = spec.split(':').collect::<Vec<_>>();
@@ -349,13 +377,63 @@ impl TargetDataLayout {
349377
["f32", a @ ..] => dl.f32_align = parse_align(a, "f32")?,
350378
["f64", a @ ..] => dl.f64_align = parse_align(a, "f64")?,
351379
["f128", a @ ..] => dl.f128_align = parse_align(a, "f128")?,
352-
// FIXME(erikdesjardins): we should be parsing nonzero address spaces
353-
// this will require replacing TargetDataLayout::{pointer_size,pointer_align}
354-
// with e.g. `fn pointer_size_in(AddressSpace)`
355-
[p @ "p", s, a @ ..] | [p @ "p0", s, a @ ..] => {
356-
dl.pointer_size = parse_size(s, p)?;
357-
dl.pointer_align = parse_align(a, p)?;
380+
[p, s, a @ ..] if p.starts_with("p") => {
381+
// Some targets, such as CHERI, use the 'f' suffix in the p- spec to signal that
382+
// they use 'fat' pointers. The resulting prefix may look like `pf<addr_space>`.
383+
let p = p.trim_start_matches(char::is_alphabetic);
384+
385+
let addr_space = if !p.is_empty() {
386+
parse_address_space(p, "p")?
387+
} else {
388+
AddressSpace::ZERO
389+
};
390+
391+
let pointer_size = parse_size(s, p)?;
392+
let info = AddressSpaceInfo {
393+
pointer_index: pointer_size,
394+
pointer_size,
395+
pointer_align: parse_align(a, p)?,
396+
};
397+
if addr_space == default_address_space {
398+
dl.default_address_space_info = info;
399+
} else {
400+
match dl.address_space_info.iter_mut().find(|(a, _)| *a == addr_space) {
401+
Some(e) => e.1 = info,
402+
None => {
403+
dl.address_space_info.push((addr_space, info));
404+
}
405+
}
406+
}
407+
}
408+
[p, s, _pr, i, a @ ..] if p.starts_with("p") => {
409+
// Some targets, such as CHERI, use the 'f' suffix in the p- spec to signal that
410+
// they use 'fat' pointers. The resulting prefix may look like `pf<addr_space>`.
411+
let p = p.trim_start_matches(char::is_alphabetic);
412+
413+
let addr_space = if !p.is_empty() {
414+
parse_address_space(p, "p")?
415+
} else {
416+
AddressSpace::ZERO
417+
};
418+
419+
let info = AddressSpaceInfo {
420+
pointer_align: parse_align(a, p)?,
421+
pointer_size: parse_size(s, p)?,
422+
pointer_index: parse_size(i, p)?,
423+
};
424+
425+
if addr_space == default_address_space {
426+
dl.default_address_space_info = info;
427+
} else {
428+
match dl.address_space_info.iter_mut().find(|(a, _)| *a == addr_space) {
429+
Some(e) => e.1 = info,
430+
None => {
431+
dl.address_space_info.push((addr_space, info));
432+
}
433+
}
434+
}
358435
}
436+
359437
[s, a @ ..] if s.starts_with('i') => {
360438
let Ok(bits) = s[1..].parse::<u64>() else {
361439
parse_size(&s[1..], "i")?; // For the user error.
@@ -390,10 +468,25 @@ impl TargetDataLayout {
390468
_ => {} // Ignore everything else.
391469
}
392470
}
471+
472+
// Inherit, if not given, address space informations for specific LLVM elements from the
473+
// default data address space.
474+
if (dl.instruction_address_space != dl.default_address_space)
475+
&& dl
476+
.address_space_info
477+
.iter()
478+
.find(|(a, _)| *a == dl.instruction_address_space)
479+
.is_none()
480+
{
481+
dl.address_space_info
482+
.push((dl.instruction_address_space, dl.default_address_space_info.clone()));
483+
}
484+
393485
Ok(dl)
394486
}
395487

396-
/// Returns **exclusive** upper bound on object size in bytes.
488+
/// Returns **exclusive** upper bound on object size in bytes, in the default data address
489+
/// space.
397490
///
398491
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
399492
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +497,26 @@ impl TargetDataLayout {
404497
/// so we adopt such a more-constrained size bound due to its technical limitations.
405498
#[inline]
406499
pub fn obj_size_bound(&self) -> u64 {
407-
match self.pointer_size.bits() {
500+
match self.pointer_size().bits() {
501+
16 => 1 << 15,
502+
32 => 1 << 31,
503+
64 => 1 << 61,
504+
bits => panic!("obj_size_bound: unknown pointer bit size {bits}"),
505+
}
506+
}
507+
508+
/// Returns **exclusive** upper bound on object size in bytes.
509+
///
510+
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
511+
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
512+
/// index every address within an object along with one byte past the end, along with allowing
513+
/// `isize` to store the difference between any two pointers into an object.
514+
///
515+
/// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes,
516+
/// so we adopt such a more-constrained size bound due to its technical limitations.
517+
#[inline]
518+
pub fn obj_size_bound_in(&self, address_space: AddressSpace) -> u64 {
519+
match self.pointer_size_in(address_space).bits() {
408520
16 => 1 << 15,
409521
32 => 1 << 31,
410522
64 => 1 << 61,
@@ -415,7 +527,18 @@ impl TargetDataLayout {
415527
#[inline]
416528
pub fn ptr_sized_integer(&self) -> Integer {
417529
use Integer::*;
418-
match self.pointer_size.bits() {
530+
match self.pointer_index().bits() {
531+
16 => I16,
532+
32 => I32,
533+
64 => I64,
534+
bits => panic!("ptr_sized_integer: unknown pointer bit size {bits}"),
535+
}
536+
}
537+
538+
#[inline]
539+
pub fn ptr_sized_integer_in(&self, address_space: AddressSpace) -> Integer {
540+
use Integer::*;
541+
match self.pointer_index_in(address_space).bits() {
419542
16 => I16,
420543
32 => I32,
421544
64 => I64,
@@ -439,6 +562,66 @@ impl TargetDataLayout {
439562
Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(),
440563
))
441564
}
565+
566+
/// Get the pointer size in the default data address space.
567+
#[inline]
568+
pub fn pointer_size(&self) -> Size {
569+
self.default_address_space_info.pointer_size
570+
}
571+
572+
/// Get the pointer size in a specific address space.
573+
#[inline]
574+
pub fn pointer_size_in(&self, c: AddressSpace) -> Size {
575+
if c == self.default_address_space {
576+
return self.default_address_space_info.pointer_size;
577+
}
578+
579+
if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
580+
e.1.pointer_size
581+
} else {
582+
panic!("Use of unknown address space {c:?}");
583+
}
584+
}
585+
586+
/// Get the pointer index in the default data address space.
587+
#[inline]
588+
pub fn pointer_index(&self) -> Size {
589+
self.default_address_space_info.pointer_index
590+
}
591+
592+
/// Get the pointer index in a specific address space.
593+
#[inline]
594+
pub fn pointer_index_in(&self, c: AddressSpace) -> Size {
595+
if c == self.default_address_space {
596+
return self.default_address_space_info.pointer_index;
597+
}
598+
599+
if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
600+
e.1.pointer_index
601+
} else {
602+
panic!("Use of unknown address space {c:?}");
603+
}
604+
}
605+
606+
/// Get the pointer alignment in the default data address space.
607+
#[inline]
608+
pub fn pointer_align(&self) -> AbiAlign {
609+
self.default_address_space_info.pointer_align
610+
}
611+
612+
/// Get the pointer alignment in a specific address space.
613+
#[inline]
614+
pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign {
615+
if c == self.default_address_space {
616+
return self.default_address_space_info.pointer_align;
617+
}
618+
619+
if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) {
620+
e.1.pointer_align
621+
} else {
622+
panic!("Use of unknown address space {c:?}");
623+
}
624+
}
442625
}
443626

444627
pub trait HasDataLayout {
@@ -1101,10 +1284,7 @@ impl Primitive {
11011284
match self {
11021285
Int(i, _) => i.size(),
11031286
Float(f) => f.size(),
1104-
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1105-
// different address spaces can have different sizes
1106-
// (but TargetDataLayout doesn't currently parse that part of the DL string)
1107-
Pointer(_) => dl.pointer_size,
1287+
Pointer(a) => dl.pointer_size_in(a),
11081288
}
11091289
}
11101290

@@ -1115,10 +1295,7 @@ impl Primitive {
11151295
match self {
11161296
Int(i, _) => i.align(dl),
11171297
Float(f) => f.align(dl),
1118-
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1119-
// different address spaces can have different alignments
1120-
// (but TargetDataLayout doesn't currently parse that part of the DL string)
1121-
Pointer(_) => dl.pointer_align,
1298+
Pointer(a) => dl.pointer_align_in(a),
11221299
}
11231300
}
11241301
}

compiler/rustc_ast_lowering/src/format.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
5555
/// Get the maximum value of int_ty. It is platform-dependent due to the byte size of isize
5656
fn int_ty_max(&self, int_ty: IntTy) -> u128 {
5757
match int_ty {
58-
IntTy::Isize => self.tcx.data_layout.pointer_size.signed_int_max() as u128,
58+
IntTy::Isize => self.tcx.data_layout.pointer_size().signed_int_max() as u128,
5959
IntTy::I8 => i8::MAX as u128,
6060
IntTy::I16 => i16::MAX as u128,
6161
IntTy::I32 => i32::MAX as u128,
@@ -67,7 +67,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
6767
/// Get the maximum value of uint_ty. It is platform-dependent due to the byte size of usize
6868
fn uint_ty_max(&self, uint_ty: UintTy) -> u128 {
6969
match uint_ty {
70-
UintTy::Usize => self.tcx.data_layout.pointer_size.unsigned_int_max(),
70+
UintTy::Usize => self.tcx.data_layout.pointer_size().unsigned_int_max(),
7171
UintTy::U8 => u8::MAX as u128,
7272
UintTy::U16 => u16::MAX as u128,
7373
UintTy::U32 => u32::MAX as u128,

compiler/rustc_codegen_cranelift/src/abi/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ pub(crate) fn codegen_drop<'tcx>(
786786

787787
pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam {
788788
let param = AbiParam::new(ty);
789-
if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size.bits() {
789+
if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() {
790790
match (&*tcx.sess.target.arch, &*tcx.sess.target.vendor) {
791791
("x86_64", _) | ("aarch64", "apple") => match (ty, is_signed) {
792792
(types::I8 | types::I16, true) => param.sext(),

compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
127127
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
128128
if on_stack {
129129
// Abi requires aligning struct size to pointer size
130-
let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
130+
let size = self.layout.size.align_to(tcx.data_layout.pointer_align().abi);
131131
let size = u32::try_from(size.bytes()).unwrap();
132132
smallvec![apply_attrs_to_abi_param(
133133
AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),),

compiler/rustc_codegen_cranelift/src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::debuginfo::FunctionDebugContext;
1515
use crate::prelude::*;
1616

1717
pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
18-
match tcx.data_layout.pointer_size.bits() {
18+
match tcx.data_layout.pointer_size().bits() {
1919
16 => types::I16,
2020
32 => types::I32,
2121
64 => types::I64,

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
443443
let addend = {
444444
let endianness = tcx.data_layout.endian;
445445
let offset = offset.bytes() as usize;
446-
let ptr_size = tcx.data_layout.pointer_size;
446+
let ptr_size = tcx.data_layout.pointer_size();
447447
let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter(
448448
offset..offset + ptr_size.bytes() as usize,
449449
);

compiler/rustc_codegen_gcc/src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
162162
}
163163

164164
fn const_usize(&self, i: u64) -> RValue<'gcc> {
165-
let bit_size = self.data_layout().pointer_size.bits();
165+
let bit_size = self.data_layout().pointer_size().bits();
166166
if bit_size < 64 {
167167
// make sure it doesn't overflow
168168
assert!(i < (1 << bit_size));

compiler/rustc_codegen_gcc/src/consts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ pub(crate) fn const_alloc_to_gcc_uncached<'gcc>(
294294
let alloc = alloc.inner();
295295
let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1);
296296
let dl = cx.data_layout();
297-
let pointer_size = dl.pointer_size.bytes() as usize;
297+
let pointer_size = dl.pointer_size().bytes() as usize;
298298

299299
let mut next_offset = 0;
300300
for &(offset, prov) in alloc.provenance().ptrs().iter() {
@@ -331,7 +331,7 @@ pub(crate) fn const_alloc_to_gcc_uncached<'gcc>(
331331
),
332332
abi::Scalar::Initialized {
333333
value: Primitive::Pointer(address_space),
334-
valid_range: WrappingRange::full(dl.pointer_size),
334+
valid_range: WrappingRange::full(dl.pointer_size()),
335335
},
336336
cx.type_i8p_ext(address_space),
337337
));

0 commit comments

Comments
 (0)