Skip to content

Commit 1374d68

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

File tree

53 files changed

+301
-134
lines changed

Some content is hidden

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

53 files changed

+301
-134
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_cranelift/src/abi/mod.rs

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

832832
pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam {
833833
let param = AbiParam::new(ty);
834-
if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size.bits() {
834+
if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() {
835835
match (&*tcx.sess.target.arch, &*tcx.sess.target.vendor) {
836836
("x86_64", _) | ("aarch64", "apple") => match (ty, is_signed) {
837837
(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
@@ -170,7 +170,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
170170
}
171171

172172
fn const_usize(&self, i: u64) -> RValue<'gcc> {
173-
let bit_size = self.data_layout().pointer_size.bits();
173+
let bit_size = self.data_layout().pointer_size().bits();
174174
if bit_size < 64 {
175175
// make sure it doesn't overflow
176176
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
));

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
539539
// For rusty ABIs, small aggregates are actually passed
540540
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
541541
// so we re-use that same threshold here.
542-
layout.size() <= self.data_layout().pointer_size * 2
542+
layout.size() <= self.data_layout().pointer_size() * 2
543543
}
544544
};
545545

0 commit comments

Comments
 (0)