Skip to content

Commit e22b61b

Browse files
committed
Auto merge of rust-lang#73270 - dylanmckay:avr-use-correct-addrspace, r=nagisa
[AVR] Correctly set the pointer address space when constructing pointers to functions NOTE: Pull request iterations: * https://github.com/dylanmckay/rust/releases/tag/avr-use-correct-addrspace.0 * https://github.com/dylanmckay/rust/releases/tag/avr-use-correct-addrspace.1 * https://github.com/dylanmckay/rust/releases/tag/avr-use-correct-addrspace.2 This patch extends the existing `type_i8p` method so that it requires an explicit address space to be specified. Before this patch, the `type_i8p` method implcitily assumed the default address space, which is not a safe transformation on all targets, namely AVR. The Rust compiler already has support for tracking the "instruction address space" on a per-target basis. This patch extends the code generation routines so that an address space must always be specified. In my estimation, around 15% of the callers of `type_i8p` produced invalid code on AVR due to the loss of address space prior to LLVM final code generation. This would lead to unavoidable assertion errors relating to invalid bitcasts. With this patch, the address space is always either 1) explicitly preserved from the input type, or 2) explicitly set to the instruction address space because the logic is dealing with functions which must be placed there, or 3) explicitly set to the default address space 0 because the logic can only operate on data space pointers and thus we keep the existing semantics of assuming the default, "data" address space.
2 parents 4825e12 + 5581ce6 commit e22b61b

File tree

11 files changed

+188
-36
lines changed

11 files changed

+188
-36
lines changed

src/librustc_codegen_llvm/abi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
366366
unsafe {
367367
llvm::LLVMPointerType(
368368
self.llvm_type(cx),
369-
cx.data_layout().instruction_address_space as c_uint,
369+
cx.data_layout().instruction_address_space.0 as c_uint,
370370
)
371371
}
372372
}

src/librustc_codegen_llvm/common.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_middle::bug;
1616
use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
1717
use rustc_middle::ty::layout::TyAndLayout;
1818
use rustc_span::symbol::Symbol;
19-
use rustc_target::abi::{self, HasDataLayout, LayoutOf, Pointer, Size};
19+
use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size};
2020

2121
use libc::{c_char, c_uint};
2222
use log::debug;
@@ -244,7 +244,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
244244
}
245245
}
246246
Scalar::Ptr(ptr) => {
247-
let base_addr = match self.tcx.global_alloc(ptr.alloc_id) {
247+
let (base_addr, base_addr_space) = match self.tcx.global_alloc(ptr.alloc_id) {
248248
GlobalAlloc::Memory(alloc) => {
249249
let init = const_alloc_to_llvm(self, alloc);
250250
let value = match alloc.mutability {
@@ -254,18 +254,21 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
254254
if !self.sess().fewer_names() {
255255
llvm::set_value_name(value, format!("{:?}", ptr.alloc_id).as_bytes());
256256
}
257-
value
257+
(value, AddressSpace::DATA)
258258
}
259-
GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance),
259+
GlobalAlloc::Function(fn_instance) => (
260+
self.get_fn_addr(fn_instance),
261+
self.data_layout().instruction_address_space,
262+
),
260263
GlobalAlloc::Static(def_id) => {
261264
assert!(self.tcx.is_static(def_id));
262265
assert!(!self.tcx.is_thread_local_static(def_id));
263-
self.get_static(def_id)
266+
(self.get_static(def_id), AddressSpace::DATA)
264267
}
265268
};
266269
let llval = unsafe {
267270
llvm::LLVMConstInBoundsGEP(
268-
self.const_bitcast(base_addr, self.type_i8p()),
271+
self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
269272
&self.const_usize(ptr.offset.bytes()),
270273
1,
271274
)

src/librustc_codegen_llvm/consts.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ use rustc_hir::def_id::DefId;
1313
use rustc_hir::Node;
1414
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
1515
use rustc_middle::mir::interpret::{
16-
read_target_uint, Allocation, ConstValue, ErrorHandled, Pointer,
16+
read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer,
1717
};
1818
use rustc_middle::mir::mono::MonoItem;
1919
use rustc_middle::ty::{self, Instance, Ty};
2020
use rustc_middle::{bug, span_bug};
2121
use rustc_span::symbol::sym;
2222
use rustc_span::Span;
23-
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
23+
use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
2424

2525
use std::ffi::CStr;
2626

@@ -53,10 +53,16 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
5353
)
5454
.expect("const_alloc_to_llvm: could not read relocation pointer")
5555
as u64;
56+
57+
let address_space = match cx.tcx.global_alloc(alloc_id) {
58+
GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
59+
GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA,
60+
};
61+
5662
llvals.push(cx.scalar_to_backend(
5763
Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
5864
&Scalar { value: Primitive::Pointer, valid_range: 0..=!0 },
59-
cx.type_i8p(),
65+
cx.type_i8p_ext(address_space),
6066
));
6167
next_offset = offset + pointer_size;
6268
}

src/librustc_codegen_llvm/type_.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::bug;
1515
use rustc_middle::ty::layout::TyAndLayout;
1616
use rustc_middle::ty::Ty;
1717
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
18-
use rustc_target::abi::{Align, Integer, Size};
18+
use rustc_target::abi::{AddressSpace, Align, Integer, Size};
1919

2020
use std::fmt;
2121
use std::ptr;
@@ -198,9 +198,13 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
198198
assert_ne!(
199199
self.type_kind(ty),
200200
TypeKind::Function,
201-
"don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead"
201+
"don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead or explicitly specify an address space if it makes sense"
202202
);
203-
ty.ptr_to()
203+
ty.ptr_to(AddressSpace::DATA)
204+
}
205+
206+
fn type_ptr_to_ext(&self, ty: &'ll Type, address_space: AddressSpace) -> &'ll Type {
207+
ty.ptr_to(address_space)
204208
}
205209

206210
fn element_type(&self, ty: &'ll Type) -> &'ll Type {
@@ -241,11 +245,11 @@ impl Type {
241245
}
242246

243247
pub fn i8p_llcx(llcx: &llvm::Context) -> &Type {
244-
Type::i8_llcx(llcx).ptr_to()
248+
Type::i8_llcx(llcx).ptr_to(AddressSpace::DATA)
245249
}
246250

247-
fn ptr_to(&self) -> &Type {
248-
unsafe { llvm::LLVMPointerType(&self, 0) }
251+
fn ptr_to(&self, address_space: AddressSpace) -> &Type {
252+
unsafe { llvm::LLVMPointerType(&self, address_space.0) }
249253
}
250254
}
251255

src/librustc_codegen_llvm/type_of.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_middle::bug;
77
use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout};
88
use rustc_middle::ty::print::obsolete::DefPathBasedNames;
99
use rustc_middle::ty::{self, Ty, TypeFoldable};
10-
use rustc_target::abi::{Abi, Align, FieldsShape};
10+
use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
1111
use rustc_target::abi::{Int, Pointer, F32, F64};
1212
use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAndLayoutMethods, Variants};
1313

@@ -310,12 +310,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
310310
F64 => cx.type_f64(),
311311
Pointer => {
312312
// If we know the alignment, pick something better than i8.
313-
let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
314-
cx.type_pointee_for_align(pointee.align)
315-
} else {
316-
cx.type_i8()
317-
};
318-
cx.type_ptr_to(pointee)
313+
let (pointee, address_space) =
314+
if let Some(pointee) = self.pointee_info_at(cx, offset) {
315+
(cx.type_pointee_for_align(pointee.align), pointee.address_space)
316+
} else {
317+
(cx.type_i8(), AddressSpace::DATA)
318+
};
319+
cx.type_ptr_to_ext(pointee, address_space)
319320
}
320321
}
321322
}

src/librustc_codegen_ssa/meth.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
7575
}
7676

7777
// Not in the cache; build it.
78-
let nullptr = cx.const_null(cx.type_i8p());
78+
let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space));
7979

8080
let methods_root;
8181
let methods = if let Some(trait_ref) = trait_ref {

src/librustc_codegen_ssa/mir/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_middle::mir::interpret::ErrorHandled;
66
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
77
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
88
use rustc_target::abi::call::{FnAbi, PassMode};
9+
use rustc_target::abi::HasDataLayout;
910

1011
use std::iter;
1112

@@ -323,7 +324,9 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
323324
// C++ personality function, but `catch (...)` has no type so
324325
// it's null. The 64 here is actually a bitfield which
325326
// represents that this is a catch-all block.
326-
let null = bx.const_null(bx.type_i8p());
327+
let null = bx.const_null(
328+
bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space),
329+
);
327330
let sixty_four = bx.const_i32(64);
328331
funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
329332
cp_bx.br(llbb);

src/librustc_codegen_ssa/traits/type_.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_middle::ty::layout::TyAndLayout;
77
use rustc_middle::ty::{self, Ty};
88
use rustc_span::DUMMY_SP;
99
use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
10-
use rustc_target::abi::Integer;
10+
use rustc_target::abi::{AddressSpace, Integer};
1111

1212
// This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
1313
// `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves.
@@ -27,6 +27,7 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
2727
fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type;
2828
fn type_kind(&self, ty: Self::Type) -> TypeKind;
2929
fn type_ptr_to(&self, ty: Self::Type) -> Self::Type;
30+
fn type_ptr_to_ext(&self, ty: Self::Type, address_space: AddressSpace) -> Self::Type;
3031
fn element_type(&self, ty: Self::Type) -> Self::Type;
3132

3233
/// Returns the number of elements in `self` if it is a LLVM vector type.
@@ -42,7 +43,11 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
4243

4344
pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
4445
fn type_i8p(&self) -> Self::Type {
45-
self.type_ptr_to(self.type_i8())
46+
self.type_i8p_ext(AddressSpace::DATA)
47+
}
48+
49+
fn type_i8p_ext(&self, address_space: AddressSpace) -> Self::Type {
50+
self.type_ptr_to_ext(self.type_i8(), address_space)
4651
}
4752

4853
fn type_int(&self) -> Self::Type {

src/librustc_middle/ty/layout.rs

+29-4
Original file line numberDiff line numberDiff line change
@@ -2166,16 +2166,31 @@ where
21662166
}
21672167

21682168
fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<PointeeInfo> {
2169-
match this.ty.kind {
2169+
let addr_space_of_ty = |ty: Ty<'tcx>| {
2170+
if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
2171+
};
2172+
2173+
let pointee_info = match this.ty.kind {
21702174
ty::RawPtr(mt) if offset.bytes() == 0 => {
21712175
cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo {
21722176
size: layout.size,
21732177
align: layout.align.abi,
21742178
safe: None,
2179+
address_space: addr_space_of_ty(mt.ty),
2180+
})
2181+
}
2182+
ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
2183+
cx.layout_of(cx.tcx().mk_fn_ptr(fn_sig)).to_result().ok().map(|layout| {
2184+
PointeeInfo {
2185+
size: layout.size,
2186+
align: layout.align.abi,
2187+
safe: None,
2188+
address_space: cx.data_layout().instruction_address_space,
2189+
}
21752190
})
21762191
}
2177-
21782192
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
2193+
let address_space = addr_space_of_ty(ty);
21792194
let tcx = cx.tcx();
21802195
let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env());
21812196
let kind = match mt {
@@ -2210,6 +2225,7 @@ where
22102225
size: layout.size,
22112226
align: layout.align.abi,
22122227
safe: Some(kind),
2228+
address_space,
22132229
})
22142230
}
22152231

@@ -2254,7 +2270,9 @@ where
22542270
result = field.to_result().ok().and_then(|field| {
22552271
if ptr_end <= field_start + field.size {
22562272
// We found the right field, look inside it.
2257-
field.pointee_info_at(cx, offset - field_start)
2273+
let field_info =
2274+
field.pointee_info_at(cx, offset - field_start);
2275+
field_info
22582276
} else {
22592277
None
22602278
}
@@ -2277,7 +2295,14 @@ where
22772295

22782296
result
22792297
}
2280-
}
2298+
};
2299+
2300+
debug!(
2301+
"pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
2302+
offset, this.ty.kind, pointee_info
2303+
);
2304+
2305+
pointee_info
22812306
}
22822307
}
22832308

src/librustc_target/abi/mod.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub struct TargetDataLayout {
3232
/// Alignments for vector types.
3333
pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
3434

35-
pub instruction_address_space: u32,
35+
pub instruction_address_space: AddressSpace,
3636
}
3737

3838
impl Default for TargetDataLayout {
@@ -56,7 +56,7 @@ impl Default for TargetDataLayout {
5656
(Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
5757
(Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
5858
],
59-
instruction_address_space: 0,
59+
instruction_address_space: AddressSpace::DATA,
6060
}
6161
}
6262
}
@@ -65,7 +65,7 @@ impl TargetDataLayout {
6565
pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
6666
// Parse an address space index from a string.
6767
let parse_address_space = |s: &str, cause: &str| {
68-
s.parse::<u32>().map_err(|err| {
68+
s.parse::<u32>().map(AddressSpace).map_err(|err| {
6969
format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err)
7070
})
7171
};
@@ -744,6 +744,17 @@ impl FieldsShape {
744744
}
745745
}
746746

747+
/// An identifier that specifies the address space that some operation
748+
/// should operate on. Special address spaces have an effect on code generation,
749+
/// depending on the target and the address spaces it implements.
750+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
751+
pub struct AddressSpace(pub u32);
752+
753+
impl AddressSpace {
754+
/// The default address space, corresponding to data space.
755+
pub const DATA: Self = AddressSpace(0);
756+
}
757+
747758
/// Describes how values of the type are passed by target ABIs,
748759
/// in terms of categories of C types there are ABI rules for.
749760
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
@@ -1013,7 +1024,7 @@ impl<T, E> MaybeResult<T> for Result<T, E> {
10131024
}
10141025
}
10151026

1016-
#[derive(Copy, Clone, PartialEq, Eq)]
1027+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
10171028
pub enum PointerKind {
10181029
/// Most general case, we know no restrictions to tell LLVM.
10191030
Shared,
@@ -1028,11 +1039,12 @@ pub enum PointerKind {
10281039
UniqueOwned,
10291040
}
10301041

1031-
#[derive(Copy, Clone)]
1042+
#[derive(Copy, Clone, Debug)]
10321043
pub struct PointeeInfo {
10331044
pub size: Size,
10341045
pub align: Align,
10351046
pub safe: Option<PointerKind>,
1047+
pub address_space: AddressSpace,
10361048
}
10371049

10381050
pub trait TyAndLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized {

0 commit comments

Comments
 (0)