Skip to content

Commit ef6e4ef

Browse files
committed
compiler: Parse p- specs in datalayout string, allow definition of default data address space
1 parent 6d122ab commit ef6e4ef

File tree

37 files changed

+280
-115
lines changed

37 files changed

+280
-115
lines changed

compiler/rustc_abi/src/layout/ty.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ impl<'a> Layout<'a> {
118118

119119
/// Whether the layout is from a type that implements [`std::marker::PointerLike`].
120120
///
121-
/// Currently, that means that the type is pointer-sized, pointer-aligned,
122-
/// and has a initialized (non-union), scalar ABI.
121+
/// Currently, that means that the type is pointer-sized, pointer-aligned, and has a initialized
122+
/// (non-union), scalar ABI; all of this with respect with the default address space.
123123
pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
124-
self.size() == data_layout.pointer_size
125-
&& self.align().abi == data_layout.pointer_align.abi
124+
self.size() == data_layout.pointer_size()
125+
&& self.align().abi == data_layout.pointer_align().abi
126126
&& matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. }))
127127
}
128128
}

compiler/rustc_abi/src/lib.rs

Lines changed: 159 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
4747
use std::str::FromStr;
4848

4949
use bitflags::bitflags;
50+
use rustc_data_structures::fx::FxHashMap;
5051
#[cfg(feature = "nightly")]
5152
use rustc_data_structures::stable_hasher::StableOrd;
5253
use rustc_hashes::Hash64;
@@ -221,6 +222,17 @@ impl ReprOptions {
221222
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
222223
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
223224

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

243253
/// Alignments for vector types.
244254
pub vector_align: Vec<(Size, AbiAlign)>,
245255

256+
pub default_address_space: AddressSpace,
257+
pub address_space_info: FxHashMap<AddressSpace, AddressSpaceInfo>,
258+
246259
pub instruction_address_space: AddressSpace,
247260

248261
/// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
@@ -267,13 +280,20 @@ impl Default for TargetDataLayout {
267280
f32_align: AbiAlign::new(align(32)),
268281
f64_align: AbiAlign::new(align(64)),
269282
f128_align: AbiAlign::new(align(128)),
270-
pointer_size: Size::from_bits(64),
271-
pointer_align: AbiAlign::new(align(64)),
272283
aggregate_align: AbiAlign { abi: align(8) },
273284
vector_align: vec![
274285
(Size::from_bits(64), AbiAlign::new(align(64))),
275286
(Size::from_bits(128), AbiAlign::new(align(128))),
276287
],
288+
default_address_space: AddressSpace::ZERO,
289+
address_space_info: FxHashMap::from_iter([(
290+
AddressSpace::ZERO,
291+
AddressSpaceInfo {
292+
pointer_size: Size::from_bits(64),
293+
pointer_align: AbiAlign::new(align(64)),
294+
pointer_index: Size::from_bits(64),
295+
},
296+
)]),
277297
instruction_address_space: AddressSpace::ZERO,
278298
c_enum_min_size: Integer::I32,
279299
}
@@ -288,6 +308,7 @@ pub enum TargetDataLayoutErrors<'a> {
288308
InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
289309
InconsistentTargetPointerWidth { pointer_size: u64, target: u32 },
290310
InvalidBitsSize { err: String },
311+
MissingAddressSpaceInfo { addr_space: AddressSpace },
291312
}
292313

293314
impl TargetDataLayout {
@@ -298,6 +319,7 @@ impl TargetDataLayout {
298319
/// determined from llvm string.
299320
pub fn parse_from_llvm_datalayout_string<'a>(
300321
input: &'a str,
322+
default_address_space: AddressSpace,
301323
) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
302324
// Parse an address space index from a string.
303325
let parse_address_space = |s: &'a str, cause: &'a str| {
@@ -334,6 +356,8 @@ impl TargetDataLayout {
334356
};
335357

336358
let mut dl = TargetDataLayout::default();
359+
dl.default_address_space = default_address_space;
360+
337361
let mut i128_align_src = 64;
338362
for spec in input.split('-') {
339363
let spec_parts = spec.split(':').collect::<Vec<_>>();
@@ -349,13 +373,48 @@ impl TargetDataLayout {
349373
["f32", a @ ..] => dl.f32_align = parse_align(a, "f32")?,
350374
["f64", a @ ..] => dl.f64_align = parse_align(a, "f64")?,
351375
["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)?;
376+
[p, s, a @ ..] if p.starts_with("p") => {
377+
let p = p.strip_prefix(char::is_alphabetic).unwrap_or_default();
378+
379+
let addr_space = if !p.is_empty() {
380+
parse_address_space(p, "p")?
381+
} else {
382+
AddressSpace::ZERO
383+
};
384+
385+
let pointer_size = parse_size(s, p)?;
386+
let info = AddressSpaceInfo {
387+
pointer_index: pointer_size,
388+
pointer_size,
389+
pointer_align: parse_align(a, p)?,
390+
};
391+
392+
dl.address_space_info
393+
.entry(addr_space)
394+
.and_modify(|v| *v = info)
395+
.or_insert(info);
396+
}
397+
[p, s, _pr, i, a @ ..] if p.starts_with("p") => {
398+
let p = p.strip_prefix(char::is_alphabetic).unwrap_or_default();
399+
400+
let addr_space = if !p.is_empty() {
401+
parse_address_space(p, "p")?
402+
} else {
403+
AddressSpace::ZERO
404+
};
405+
406+
let info = AddressSpaceInfo {
407+
pointer_align: parse_align(a, p)?,
408+
pointer_size: parse_size(s, p)?,
409+
pointer_index: parse_size(i, p)?,
410+
};
411+
412+
dl.address_space_info
413+
.entry(addr_space)
414+
.and_modify(|v| *v = info)
415+
.or_insert(info);
358416
}
417+
359418
[s, a @ ..] if s.starts_with('i') => {
360419
let Ok(bits) = s[1..].parse::<u64>() else {
361420
parse_size(&s[1..], "i")?; // For the user error.
@@ -390,10 +449,28 @@ impl TargetDataLayout {
390449
_ => {} // Ignore everything else.
391450
}
392451
}
452+
453+
if !dl.address_space_info.contains_key(&default_address_space) {
454+
return Err(TargetDataLayoutErrors::MissingAddressSpaceInfo {
455+
addr_space: default_address_space,
456+
});
457+
}
458+
459+
// Inherit, if not given, address space informations for specific LLVM elements from the
460+
// default data address space.
461+
462+
if !dl.address_space_info.contains_key(&dl.instruction_address_space) {
463+
dl.address_space_info.insert(
464+
dl.instruction_address_space,
465+
dl.address_space_info.get(&default_address_space).unwrap().clone(),
466+
);
467+
}
468+
393469
Ok(dl)
394470
}
395471

396-
/// Returns **exclusive** upper bound on object size in bytes.
472+
/// Returns **exclusive** upper bound on object size in bytes, in the default data address
473+
/// space.
397474
///
398475
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
399476
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
@@ -404,7 +481,21 @@ impl TargetDataLayout {
404481
/// so we adopt such a more-constrained size bound due to its technical limitations.
405482
#[inline]
406483
pub fn obj_size_bound(&self) -> u64 {
407-
match self.pointer_size.bits() {
484+
self.obj_size_bound_in(self.default_address_space)
485+
}
486+
487+
/// Returns **exclusive** upper bound on object size in bytes.
488+
///
489+
/// The theoretical maximum object size is defined as the maximum positive `isize` value.
490+
/// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
491+
/// index every address within an object along with one byte past the end, along with allowing
492+
/// `isize` to store the difference between any two pointers into an object.
493+
///
494+
/// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes,
495+
/// so we adopt such a more-constrained size bound due to its technical limitations.
496+
#[inline]
497+
pub fn obj_size_bound_in(&self, address_space: AddressSpace) -> u64 {
498+
match self.pointer_size_in(address_space).bits() {
408499
16 => 1 << 15,
409500
32 => 1 << 31,
410501
64 => 1 << 61,
@@ -414,8 +505,13 @@ impl TargetDataLayout {
414505

415506
#[inline]
416507
pub fn ptr_sized_integer(&self) -> Integer {
508+
self.ptr_sized_integer_in(self.default_address_space)
509+
}
510+
511+
#[inline]
512+
pub fn ptr_sized_integer_in(&self, address_space: AddressSpace) -> Integer {
417513
use Integer::*;
418-
match self.pointer_size.bits() {
514+
match self.pointer_index_in(address_space).bits() {
419515
16 => I16,
420516
32 => I32,
421517
64 => I64,
@@ -439,6 +535,54 @@ impl TargetDataLayout {
439535
Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(),
440536
))
441537
}
538+
539+
/// Get the pointer size in the default data address space.
540+
#[inline]
541+
pub fn pointer_size(&self) -> Size {
542+
self.pointer_size_in(self.default_address_space)
543+
}
544+
545+
/// Get the pointer size in a specific address space.
546+
#[inline]
547+
pub fn pointer_size_in(&self, c: AddressSpace) -> Size {
548+
if let Some(c) = self.address_space_info.get(&c) {
549+
c.pointer_size
550+
} else {
551+
panic!("Use of unknown address space {c:?}");
552+
}
553+
}
554+
555+
/// Get the pointer index in the default data address space.
556+
#[inline]
557+
pub fn pointer_index(&self) -> Size {
558+
self.pointer_index_in(self.default_address_space)
559+
}
560+
561+
/// Get the pointer index in a specific address space.
562+
#[inline]
563+
pub fn pointer_index_in(&self, c: AddressSpace) -> Size {
564+
if let Some(c) = self.address_space_info.get(&c) {
565+
c.pointer_index
566+
} else {
567+
panic!("Use of unknown address space {c:?}");
568+
}
569+
}
570+
571+
/// Get the pointer alignment in the default data address space.
572+
#[inline]
573+
pub fn pointer_align(&self) -> AbiAlign {
574+
self.pointer_align_in(self.default_address_space)
575+
}
576+
577+
/// Get the pointer alignment in a specific address space.
578+
#[inline]
579+
pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign {
580+
if let Some(c) = self.address_space_info.get(&c) {
581+
c.pointer_align
582+
} else {
583+
panic!("Use of unknown address space {c:?}");
584+
}
585+
}
442586
}
443587

444588
pub trait HasDataLayout {
@@ -1104,7 +1248,7 @@ impl Primitive {
11041248
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
11051249
// different address spaces can have different sizes
11061250
// (but TargetDataLayout doesn't currently parse that part of the DL string)
1107-
Pointer(_) => dl.pointer_size,
1251+
Pointer(a) => dl.pointer_size_in(a),
11081252
}
11091253
}
11101254

@@ -1118,7 +1262,7 @@ impl Primitive {
11181262
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
11191263
// different address spaces can have different alignments
11201264
// (but TargetDataLayout doesn't currently parse that part of the DL string)
1121-
Pointer(_) => dl.pointer_align,
1265+
Pointer(a) => dl.pointer_align_in(a),
11221266
}
11231267
}
11241268
}

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_llvm/src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
175175
}
176176

177177
fn const_usize(&self, i: u64) -> &'ll Value {
178-
let bit_size = self.data_layout().pointer_size.bits();
178+
let bit_size = self.data_layout().pointer_size().bits();
179179
if bit_size < 64 {
180180
// make sure it doesn't overflow
181181
assert!(i < (1 << bit_size));

compiler/rustc_codegen_llvm/src/consts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
4343
}
4444
let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1);
4545
let dl = cx.data_layout();
46-
let pointer_size = dl.pointer_size.bytes() as usize;
46+
let pointer_size = dl.pointer_size().bytes() as usize;
4747

4848
// Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`, so `range`
4949
// must be within the bounds of `alloc` and not contain or overlap a pointer provenance.
@@ -111,7 +111,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
111111
InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx),
112112
Scalar::Initialized {
113113
value: Primitive::Pointer(address_space),
114-
valid_range: WrappingRange::full(dl.pointer_size),
114+
valid_range: WrappingRange::full(dl.pointer_size()),
115115
},
116116
cx.type_ptr_ext(address_space),
117117
));

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
605605
GenericCx(
606606
FullCx {
607607
tcx,
608-
scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size),
608+
scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()),
609609
use_dll_storage_attrs,
610610
tls_model,
611611
codegen_unit,

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
165165
None => {
166166
// This is a thin pointer. Create a regular pointer type and give it the correct name.
167167
assert_eq!(
168-
(data_layout.pointer_size, data_layout.pointer_align.abi),
168+
(data_layout.pointer_size(), data_layout.pointer_align().abi),
169169
cx.size_and_align_of(ptr_type),
170170
"ptr_type={ptr_type}, pointee_type={pointee_type}",
171171
);
@@ -174,8 +174,8 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
174174
llvm::LLVMRustDIBuilderCreatePointerType(
175175
DIB(cx),
176176
pointee_type_di_node,
177-
data_layout.pointer_size.bits(),
178-
data_layout.pointer_align.abi.bits() as u32,
177+
data_layout.pointer_size().bits(),
178+
data_layout.pointer_align().abi.bits() as u32,
179179
0, // Ignore DWARF address space.
180180
ptr_type_debuginfo_name.as_c_char_ptr(),
181181
ptr_type_debuginfo_name.len(),
@@ -319,7 +319,9 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
319319
let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
320320
let (size, align) = match fn_ty.kind() {
321321
ty::FnDef(..) => (Size::ZERO, Align::ONE),
322-
ty::FnPtr(..) => (cx.tcx.data_layout.pointer_size, cx.tcx.data_layout.pointer_align.abi),
322+
ty::FnPtr(..) => {
323+
(cx.tcx.data_layout.pointer_size(), cx.tcx.data_layout.pointer_align().abi)
324+
}
323325
_ => unreachable!(),
324326
};
325327
let di_node = unsafe {
@@ -504,7 +506,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D
504506
create_basic_type(
505507
cx,
506508
"<recur_type>",
507-
cx.tcx.data_layout.pointer_size,
509+
cx.tcx.data_layout.pointer_size(),
508510
dwarf_const::DW_ATE_unsigned,
509511
)
510512
})

0 commit comments

Comments
 (0)