Skip to content

Commit da214b8

Browse files
committed
[AVR] Correctly set the pointer address space when constructing pointers to functions
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.
1 parent 72417d8 commit da214b8

File tree

17 files changed

+119
-49
lines changed

17 files changed

+119
-49
lines changed

src/librustc_codegen_llvm/abi.rs

Lines changed: 1 addition & 1 deletion
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/builder.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -725,8 +725,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
725725
}
726726
let size = self.intcast(size, self.type_isize(), false);
727727
let is_volatile = flags.contains(MemFlags::VOLATILE);
728-
let dst = self.pointercast(dst, self.type_i8p());
729-
let src = self.pointercast(src, self.type_i8p());
728+
let dst = self.pointercast(dst, self.type_i8p(self.cx.address_space_of_value(dst)));
729+
let src = self.pointercast(src, self.type_i8p(self.cx.address_space_of_value(src)));
730730
unsafe {
731731
llvm::LLVMRustBuildMemCpy(
732732
self.llbuilder,
@@ -758,8 +758,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
758758
}
759759
let size = self.intcast(size, self.type_isize(), false);
760760
let is_volatile = flags.contains(MemFlags::VOLATILE);
761-
let dst = self.pointercast(dst, self.type_i8p());
762-
let src = self.pointercast(src, self.type_i8p());
761+
let dst = self.pointercast(dst, self.type_i8p(self.cx.address_space_of_value(dst)));
762+
let src = self.pointercast(src, self.type_i8p(self.cx.address_space_of_value(src)));
763763
unsafe {
764764
llvm::LLVMRustBuildMemMove(
765765
self.llbuilder,
@@ -782,7 +782,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
782782
flags: MemFlags,
783783
) {
784784
let is_volatile = flags.contains(MemFlags::VOLATILE);
785-
let ptr = self.pointercast(ptr, self.type_i8p());
785+
let ptr = self.pointercast(ptr, self.type_i8p(self.cx.address_space_of_value(ptr)));
786786
unsafe {
787787
llvm::LLVMRustBuildMemSet(
788788
self.llbuilder,
@@ -1275,7 +1275,7 @@ impl Builder<'a, 'll, 'tcx> {
12751275

12761276
let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic);
12771277

1278-
let ptr = self.pointercast(ptr, self.cx.type_i8p());
1278+
let ptr = self.pointercast(ptr, self.cx.type_i8p(self.cx.address_space_of_value(ptr)));
12791279
self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
12801280
}
12811281

src/librustc_codegen_llvm/common.rs

Lines changed: 3 additions & 3 deletions
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;
@@ -265,7 +265,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
265265
};
266266
let llval = unsafe {
267267
llvm::LLVMConstInBoundsGEP(
268-
self.const_bitcast(base_addr, self.type_i8p()),
268+
self.const_bitcast(base_addr, self.type_i8p(AddressSpace::default())),
269269
&self.const_usize(ptr.offset.bytes()),
270270
1,
271271
)
@@ -296,7 +296,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
296296

297297
let llval = unsafe {
298298
llvm::LLVMConstInBoundsGEP(
299-
self.const_bitcast(base_addr, self.type_i8p()),
299+
self.const_bitcast(base_addr, self.type_i8p(AddressSpace::default())),
300300
&self.const_usize(offset.bytes()),
301301
1,
302302
)

src/librustc_codegen_llvm/consts.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Instance, Ty};
2020
use rustc_middle::{bug, span_bug};
2121
use rustc_span::symbol::{sym, Symbol};
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

@@ -56,7 +56,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
5656
llvals.push(cx.scalar_to_backend(
5757
Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
5858
&Scalar { value: Primitive::Pointer, valid_range: 0..=!0 },
59-
cx.type_i8p(),
59+
cx.type_i8p(AddressSpace::default()),
6060
));
6161
next_offset = offset + pointer_size;
6262
}
@@ -496,7 +496,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
496496

497497
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
498498
// This static will be stored in the llvm.used variable which is an array of i8*
499-
let cast = llvm::LLVMConstPointerCast(g, self.type_i8p());
499+
let cast = llvm::LLVMConstPointerCast(g, self.type_i8p(AddressSpace::default()));
500500
self.used_statics.borrow_mut().push(cast);
501501
}
502502
}

src/librustc_codegen_llvm/context.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use rustc_session::config::{CFGuard, CrateType, DebugInfo};
2020
use rustc_session::Session;
2121
use rustc_span::source_map::{Span, DUMMY_SP};
2222
use rustc_span::symbol::Symbol;
23-
use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx};
23+
use rustc_target::abi::{
24+
AddressSpace, HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx,
25+
};
2426
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
2527

2628
use std::cell::{Cell, RefCell};
@@ -452,7 +454,7 @@ impl CodegenCx<'b, 'tcx> {
452454
($($field_ty:expr),*) => (self.type_struct( &[$($field_ty),*], false))
453455
}
454456

455-
let i8p = self.type_i8p();
457+
let i8p = self.type_i8p(AddressSpace::default());
456458
let void = self.type_void();
457459
let i1 = self.type_i1();
458460
let t_i8 = self.type_i8();

src/librustc_codegen_llvm/intrinsic.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_middle::ty::{self, Ty};
2424
use rustc_middle::{bug, span_bug};
2525
use rustc_span::Span;
2626
use rustc_span::Symbol;
27-
use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive};
27+
use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Primitive};
2828
use rustc_target::spec::PanicStrategy;
2929

3030
use std::cmp::Ordering;
@@ -927,7 +927,7 @@ fn codegen_msvc_try(
927927
//
928928
// More information can be found in libstd's seh.rs implementation.
929929
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
930-
let slot = bx.alloca(bx.type_i8p(), ptr_align);
930+
let slot = bx.alloca(bx.type_i8p(AddressSpace::default()), ptr_align);
931931
bx.invoke(try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
932932

933933
normal.ret(bx.const_i32(0));
@@ -949,10 +949,13 @@ fn codegen_msvc_try(
949949
//
950950
// When modifying, make sure that the type_name string exactly matches
951951
// the one used in src/libpanic_unwind/seh.rs.
952-
let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_i8p());
952+
let type_info_vtable =
953+
bx.declare_global("??_7type_info@@6B@", bx.type_i8p(AddressSpace::default()));
953954
let type_name = bx.const_bytes(b"rust_panic\0");
954-
let type_info =
955-
bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_i8p()), type_name], false);
955+
let type_info = bx.const_struct(
956+
&[type_info_vtable, bx.const_null(bx.type_i8p(AddressSpace::default())), type_name],
957+
false,
958+
);
956959
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
957960
unsafe {
958961
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
@@ -1032,14 +1035,14 @@ fn codegen_gnu_try(
10321035
// being thrown. The second value is a "selector" indicating which of
10331036
// the landing pad clauses the exception's type had been matched to.
10341037
// rust_try ignores the selector.
1035-
let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
1038+
let lpad_ty = bx.type_struct(&[bx.type_i8p(AddressSpace::default()), bx.type_i32()], false);
10361039
let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 1);
10371040
let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() {
10381041
Some(tydesc) => {
10391042
let tydesc = bx.get_static(tydesc);
1040-
bx.bitcast(tydesc, bx.type_i8p())
1043+
bx.bitcast(tydesc, bx.type_i8p(AddressSpace::default()))
10411044
}
1042-
None => bx.const_null(bx.type_i8p()),
1045+
None => bx.const_null(bx.type_i8p(AddressSpace::default())),
10431046
};
10441047
catch.add_clause(vals, tydesc);
10451048
let ptr = catch.extract_value(vals, 0);

src/librustc_codegen_llvm/llvm/ffi.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,6 +1919,8 @@ extern "C" {
19191919
pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
19201920
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
19211921

1922+
pub fn LLVMRustGetPointerTypeAddressSpace(ty: &Type) -> u32;
1923+
19221924
#[allow(improper_ctypes)]
19231925
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
19241926
#[allow(improper_ctypes)]

src/librustc_codegen_llvm/type_.rs

Lines changed: 19 additions & 6 deletions
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,17 @@ 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::default())
204+
}
205+
206+
fn type_ptr_to_ext(&self, ty: &'ll Type, address_space: AddressSpace) -> &'ll Type {
207+
ty.ptr_to(address_space)
208+
}
209+
210+
fn address_space_of_type(&self, ty: &'ll Type) -> AddressSpace {
211+
ty.address_space()
204212
}
205213

206214
fn element_type(&self, ty: &'ll Type) -> &'ll Type {
@@ -241,11 +249,16 @@ impl Type {
241249
}
242250

243251
pub fn i8p_llcx(llcx: &llvm::Context) -> &Type {
244-
Type::i8_llcx(llcx).ptr_to()
252+
Type::i8_llcx(llcx).ptr_to(AddressSpace::default())
253+
}
254+
255+
pub fn address_space(&self) -> AddressSpace {
256+
let space_number = unsafe { llvm::LLVMRustGetPointerTypeAddressSpace(self) };
257+
AddressSpace(space_number)
245258
}
246259

247-
fn ptr_to(&self) -> &Type {
248-
unsafe { llvm::LLVMPointerType(&self, 0) }
260+
fn ptr_to(&self, address_space: AddressSpace) -> &Type {
261+
unsafe { llvm::LLVMPointerType(&self, address_space.0) }
249262
}
250263
}
251264

src/librustc_codegen_llvm/va_arg.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_codegen_ssa::traits::{
88
};
99
use rustc_middle::ty::layout::HasTyCtxt;
1010
use rustc_middle::ty::Ty;
11-
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size};
11+
use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Size};
1212

1313
#[allow(dead_code)]
1414
fn round_pointer_up_to_alignment(
@@ -32,7 +32,7 @@ fn emit_direct_ptr_va_arg(
3232
slot_size: Align,
3333
allow_higher_align: bool,
3434
) -> (&'ll Value, Align) {
35-
let va_list_ptr_ty = bx.cx().type_ptr_to(bx.cx.type_i8p());
35+
let va_list_ptr_ty = bx.cx().type_ptr_to(bx.cx.type_i8p(AddressSpace::default()));
3636
let va_list_addr = if list.layout.llvm_type(bx.cx) != va_list_ptr_ty {
3737
bx.bitcast(list.immediate(), va_list_ptr_ty)
3838
} else {
@@ -42,7 +42,15 @@ fn emit_direct_ptr_va_arg(
4242
let ptr = bx.load(va_list_addr, bx.tcx().data_layout.pointer_align.abi);
4343

4444
let (addr, addr_align) = if allow_higher_align && align > slot_size {
45-
(round_pointer_up_to_alignment(bx, ptr, align, bx.cx().type_i8p()), align)
45+
(
46+
round_pointer_up_to_alignment(
47+
bx,
48+
ptr,
49+
align,
50+
bx.cx().type_i8p(AddressSpace::default()),
51+
),
52+
align,
53+
)
4654
} else {
4755
(ptr, slot_size)
4856
};

src/librustc_codegen_ssa/base.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use rustc_session::utils::NativeLibKind;
4848
use rustc_session::Session;
4949
use rustc_span::Span;
5050
use rustc_symbol_mangling::test as symbol_names_test;
51-
use rustc_target::abi::{Abi, Align, LayoutOf, Scalar, VariantIdx};
51+
use rustc_target::abi::{Abi, AddressSpace, Align, HasDataLayout, LayoutOf, Scalar, VariantIdx};
5252

5353
use std::cmp;
5454
use std::ops::{Deref, DerefMut};
@@ -423,7 +423,13 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
423423
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
424424
// depending on whether the target needs `argc` and `argv` to be passed in.
425425
let llfty = if cx.sess().target.target.options.main_needs_argc_argv {
426-
cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
426+
cx.type_func(
427+
&[
428+
cx.type_int(),
429+
cx.type_ptr_to(cx.type_i8p(cx.data_layout().instruction_address_space)),
430+
],
431+
cx.type_int(),
432+
)
427433
} else {
428434
cx.type_func(&[], cx.type_int())
429435
};
@@ -471,7 +477,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
471477
);
472478
(
473479
start_fn,
474-
vec![bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p())), arg_argc, arg_argv],
480+
vec![
481+
bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p(AddressSpace::default()))),
482+
arg_argc,
483+
arg_argv,
484+
],
475485
)
476486
} else {
477487
debug!("using user-defined start fn");
@@ -501,7 +511,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
501511
} else {
502512
// The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
503513
let arg_argc = bx.const_int(cx.type_int(), 0);
504-
let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p()));
514+
let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p(AddressSpace::default())));
505515
(arg_argc, arg_argv)
506516
}
507517
}

0 commit comments

Comments
 (0)