diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 3de269da22d65..e092bbbfdd674 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -713,10 +713,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } impl<'tcx, T> InferOk<'tcx, T> { - pub fn unit(self) -> InferOk<'tcx, ()> { - InferOk { value: (), obligations: self.obligations } - } - /// Extracts `value`, registering any obligations into `fulfill_cx`. pub fn into_value_registering_obligations( self, @@ -1025,15 +1021,10 @@ impl<'tcx> InferCtxt<'tcx> { _ => {} } - Ok(self.commit_if_ok(|_snapshot| { - let ty::SubtypePredicate { a_is_expected, a, b } = - self.instantiate_binder_with_placeholders(predicate); - - let ok = - self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?; + let ty::SubtypePredicate { a_is_expected, a, b } = + self.instantiate_binder_with_placeholders(predicate); - Ok(ok.unit()) - })) + Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)) } pub fn region_outlives_predicate( diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 632072003539f..bbc98af45c0d7 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -7,6 +7,7 @@ use crate::rustc_smir::Tables; use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; use rustc_span::Symbol; +use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; use stable_mir::mir::{Mutability, Safety}; @@ -460,6 +461,14 @@ impl<'tcx> RustcInternal<'tcx> for Span { } } +impl<'tcx> RustcInternal<'tcx> for Layout { + type T = rustc_target::abi::Layout<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.layouts[*self] + } +} + impl<'tcx, T> RustcInternal<'tcx> for &T where T: RustcInternal<'tcx>, diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index c3db9b358e8b5..4bac98909add0 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::Span; use scoped_tls::scoped_thread_local; +use stable_mir::abi::Layout; use stable_mir::ty::IndexedVal; use stable_mir::Error; use std::cell::Cell; @@ -136,6 +137,10 @@ impl<'tcx> Tables<'tcx> { pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef { stable_mir::mir::mono::StaticDef(self.create_def_id(did)) } + + pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout { + self.layouts.create_or_fetch(layout) + } } pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { @@ -180,6 +185,7 @@ where types: IndexMap::default(), instances: IndexMap::default(), constants: IndexMap::default(), + layouts: IndexMap::default(), })); stable_mir::compiler_interface::run(&tables, || init(&tables, f)) } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 2361a04a6d7c2..621766c695e43 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -3,12 +3,19 @@ //! This trait is currently the main interface between the Rust compiler, //! and the `stable_mir` crate. +#![allow(rustc::usage_of_qualified_ty)] + +use rustc_abi::HasDataLayout; use rustc_middle::ty; +use rustc_middle::ty::layout::{ + FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers, +}; use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; use rustc_middle::ty::{ - GenericPredicates, Instance, ParamEnv, ScalarInt, TypeVisitableExt, ValTree, + GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, }; use rustc_span::def_id::LOCAL_CRATE; +use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; @@ -280,7 +287,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables) } - #[allow(rustc::usage_of_qualified_ty)] fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let inner = ty.internal(&mut *tables); @@ -335,6 +341,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables) } + fn instance_abi(&self, def: InstanceDef) -> Result { + let mut tables = self.0.borrow_mut(); + let instance = tables.instances[def]; + Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables)) + } + fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { let mut tables = self.0.borrow_mut(); let def_id = tables.instances[def].def_id(); @@ -473,6 +485,65 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) } } + + fn ty_layout(&self, ty: Ty) -> Result { + let mut tables = self.0.borrow_mut(); + let ty = ty.internal(&mut *tables); + let layout = tables.layout_of(ty)?.layout; + Ok(layout.stable(&mut *tables)) + } + + fn layout_shape(&self, id: Layout) -> LayoutShape { + let mut tables = self.0.borrow_mut(); + id.internal(&mut *tables).0.stable(&mut *tables) + } } pub struct TablesWrapper<'tcx>(pub RefCell>); + +/// Implement error handling for extracting function ABI information. +impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> { + type FnAbiOfResult = Result<&'tcx rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>>, Error>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: ty::layout::FnAbiError<'tcx>, + _span: rustc_span::Span, + fn_abi_request: ty::layout::FnAbiRequest<'tcx>, + ) -> Error { + Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}")) + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> { + type LayoutOfResult = Result, Error>; + + #[inline] + fn handle_layout_err( + &self, + err: ty::layout::LayoutError<'tcx>, + _span: rustc_span::Span, + ty: ty::Ty<'tcx>, + ) -> Error { + Error::new(format!("Failed to get layout for `{ty}`: {err}")) + } +} + +impl<'tcx> HasParamEnv<'tcx> for Tables<'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + ty::ParamEnv::reveal_all() + } +} + +impl<'tcx> HasTyCtxt<'tcx> for Tables<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'tcx> HasDataLayout for Tables<'tcx> { + fn data_layout(&self) -> &rustc_abi::TargetDataLayout { + self.tcx.data_layout() + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs new file mode 100644 index 0000000000000..632e97b32f520 --- /dev/null +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -0,0 +1,242 @@ +//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones. + +#![allow(rustc::usage_of_qualified_ty)] + +use crate::rustc_smir::{Stable, Tables}; +use rustc_middle::ty; +use rustc_target::abi::call::Conv; +use stable_mir::abi::{ + ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding, + TyAndLayout, ValueAbi, VariantsShape, +}; +use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx}; +use stable_mir::{opaque, Opaque}; + +impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { + type T = VariantIdx; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + VariantIdx::to_val(self.as_usize()) + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Endian { + type T = stable_mir::target::Endian; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + rustc_abi::Endian::Little => stable_mir::target::Endian::Little, + rustc_abi::Endian::Big => stable_mir::target::Endian::Big, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> { + type T = TyAndLayout; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + TyAndLayout { ty: self.ty.stable(tables), layout: self.layout.stable(tables) } + } +} + +impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> { + type T = Layout; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.layout_id(*self) + } +} + +impl<'tcx> Stable<'tcx> + for rustc_abi::LayoutS +{ + type T = LayoutShape; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + LayoutShape { + fields: self.fields.stable(tables), + variants: self.variants.stable(tables), + abi: self.abi.stable(tables), + abi_align: self.align.abi.stable(tables), + size: self.size.stable(tables), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { + type T = FnAbi; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + assert!(self.args.len() >= self.fixed_count as usize); + assert!(!self.c_variadic || matches!(self.conv, Conv::C)); + FnAbi { + args: self.args.as_ref().stable(tables), + ret: self.ret.stable(tables), + fixed_count: self.fixed_count, + conv: self.conv.stable(tables), + c_variadic: self.c_variadic, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> { + type T = ArgAbi; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + ArgAbi { + ty: self.layout.ty.stable(tables), + layout: self.layout.layout.stable(tables), + mode: self.mode.stable(tables), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { + type T = CallConvention; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + Conv::C => CallConvention::C, + Conv::Rust => CallConvention::Rust, + Conv::Cold => CallConvention::Cold, + Conv::PreserveMost => CallConvention::PreserveMost, + Conv::PreserveAll => CallConvention::PreserveAll, + Conv::ArmAapcs => CallConvention::ArmAapcs, + Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, + Conv::Msp430Intr => CallConvention::Msp430Intr, + Conv::PtxKernel => CallConvention::PtxKernel, + Conv::X86Fastcall => CallConvention::X86Fastcall, + Conv::X86Intr => CallConvention::X86Intr, + Conv::X86Stdcall => CallConvention::X86Stdcall, + Conv::X86ThisCall => CallConvention::X86ThisCall, + Conv::X86VectorCall => CallConvention::X86VectorCall, + Conv::X86_64SysV => CallConvention::X86_64SysV, + Conv::X86_64Win64 => CallConvention::X86_64Win64, + Conv::AmdGpuKernel => CallConvention::AmdGpuKernel, + Conv::AvrInterrupt => CallConvention::AvrInterrupt, + Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt, + Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode { + type T = PassMode; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore, + rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)), + rustc_target::abi::call::PassMode::Pair(first, second) => { + PassMode::Pair(opaque(first), opaque(second)) + } + rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => { + PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) } + } + rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => { + PassMode::Indirect { + attrs: opaque(attrs), + meta_attrs: opaque(meta_attrs), + on_stack: *on_stack, + } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape { + type T = FieldsShape; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive, + rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count), + rustc_abi::FieldsShape::Array { stride, count } => { + FieldsShape::Array { stride: stride.stable(tables), count: *count } + } + rustc_abi::FieldsShape::Arbitrary { offsets, .. } => { + FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables) } + } + } + } +} + +impl<'tcx> Stable<'tcx> + for rustc_abi::Variants +{ + type T = VariantsShape; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + rustc_abi::Variants::Single { index } => { + VariantsShape::Single { index: index.stable(tables) } + } + rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => { + VariantsShape::Multiple { + tag: tag.stable(tables), + tag_encoding: tag_encoding.stable(tables), + tag_field: *tag_field, + variants: variants.iter().as_slice().stable(tables), + } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding { + type T = TagEncoding; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + rustc_abi::TagEncoding::Direct => TagEncoding::Direct, + rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => { + TagEncoding::Niche { + untagged_variant: untagged_variant.stable(tables), + niche_variants: niche_variants.stable(tables), + niche_start: *niche_start, + } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Abi { + type T = ValueAbi; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match *self { + rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited, + rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)), + rustc_abi::Abi::ScalarPair(first, second) => { + ValueAbi::ScalarPair(first.stable(tables), second.stable(tables)) + } + rustc_abi::Abi::Vector { element, count } => { + ValueAbi::Vector { element: element.stable(tables), count } + } + rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized }, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Size { + type T = Size; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + self.bytes_usize() + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Align { + type T = Align; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + self.bytes() + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Scalar { + type T = Opaque; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + opaque(self) + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index 7021bdda73501..8b7b26f969c96 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -1,10 +1,10 @@ //! Conversion of internal Rust compiler items to stable ones. use rustc_target::abi::FieldIdx; -use stable_mir::ty::{IndexedVal, VariantIdx}; use crate::rustc_smir::{Stable, Tables}; +mod abi; mod error; mod mir; mod ty; @@ -26,13 +26,6 @@ impl<'tcx> Stable<'tcx> for FieldIdx { } } -impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { - type T = VariantIdx; - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - VariantIdx::to_val(self.as_usize()) - } -} - impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource { type T = stable_mir::mir::CoroutineSource; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { @@ -79,14 +72,3 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span { tables.create_span(*self) } } - -impl<'tcx> Stable<'tcx> for rustc_abi::Endian { - type T = stable_mir::target::Endian; - - fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { - match self { - rustc_abi::Endian::Little => stable_mir::target::Endian::Little, - rustc_abi::Endian::Big => stable_mir::target::Endian::Big, - } - } -} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index ae6cf3fe3e86d..cf6ac5285c245 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -12,9 +12,11 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::AllocId; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use stable_mir::abi::Layout; use stable_mir::mir::mono::InstanceDef; use stable_mir::ty::{ConstId, Span}; use stable_mir::ItemKind; +use std::ops::RangeInclusive; use tracing::debug; use crate::rustc_internal::IndexMap; @@ -32,6 +34,7 @@ pub struct Tables<'tcx> { pub(crate) types: IndexMap, stable_mir::ty::Ty>, pub(crate) instances: IndexMap, InstanceDef>, pub(crate) constants: IndexMap, ConstId>, + pub(crate) layouts: IndexMap, Layout>, } impl<'tcx> Tables<'tcx> { @@ -162,3 +165,13 @@ where (self.0.stable(tables), self.1.stable(tables)) } } + +impl<'tcx, T> Stable<'tcx> for RangeInclusive +where + T: Stable<'tcx>, +{ + type T = RangeInclusive; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + RangeInclusive::new(self.start().stable(tables), self.end().stable(tables)) + } +} diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs new file mode 100644 index 0000000000000..53dac6abefb30 --- /dev/null +++ b/compiler/stable_mir/src/abi.rs @@ -0,0 +1,283 @@ +use crate::compiler_interface::with; +use crate::mir::FieldIdx; +use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx}; +use crate::Opaque; +use std::num::NonZeroUsize; +use std::ops::RangeInclusive; + +/// A function ABI definition. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct FnAbi { + /// The types of each argument. + pub args: Vec, + + /// The expected return type. + pub ret: ArgAbi, + + /// The count of non-variadic arguments. + /// + /// Should only be different from `args.len()` when a function is a C variadic function. + pub fixed_count: u32, + + /// The ABI convention. + pub conv: CallConvention, + + /// Whether this is a variadic C function, + pub c_variadic: bool, +} + +/// Information about the ABI of a function's argument, or return value. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ArgAbi { + pub ty: Ty, + pub layout: Layout, + pub mode: PassMode, +} + +/// How a function argument should be passed in to the target function. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum PassMode { + /// Ignore the argument. + /// + /// The argument is either uninhabited or a ZST. + Ignore, + /// Pass the argument directly. + /// + /// The argument has a layout abi of `Scalar` or `Vector`. + Direct(Opaque), + /// Pass a pair's elements directly in two arguments. + /// + /// The argument has a layout abi of `ScalarPair`. + Pair(Opaque, Opaque), + /// Pass the argument after casting it. + Cast { pad_i32: bool, cast: Opaque }, + /// Pass the argument indirectly via a hidden pointer. + Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool }, +} + +/// The layout of a type, alongside the type itself. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct TyAndLayout { + pub ty: Ty, + pub layout: Layout, +} + +/// The layout of a type in memory. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct LayoutShape { + /// The fields location withing the layout + pub fields: FieldsShape, + + /// Encodes information about multi-variant layouts. + /// Even with `Multiple` variants, a layout still has its own fields! Those are then + /// shared between all variants. + /// + /// To access all fields of this layout, both `fields` and the fields of the active variant + /// must be taken into account. + pub variants: VariantsShape, + + /// The `abi` defines how this data is passed between functions. + pub abi: ValueAbi, + + /// The ABI mandated alignment in bytes. + pub abi_align: Align, + + /// The size of this layout in bytes. + pub size: Size, +} + +impl LayoutShape { + /// Returns `true` if the layout corresponds to an unsized type. + #[inline] + pub fn is_unsized(&self) -> bool { + self.abi.is_unsized() + } + + #[inline] + pub fn is_sized(&self) -> bool { + !self.abi.is_unsized() + } + + /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). + pub fn is_1zst(&self) -> bool { + self.is_sized() && self.size == 0 && self.abi_align == 1 + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Layout(usize); + +impl Layout { + pub fn shape(self) -> LayoutShape { + with(|cx| cx.layout_shape(self)) + } +} + +impl IndexedVal for Layout { + fn to_val(index: usize) -> Self { + Layout(index) + } + fn to_index(&self) -> usize { + self.0 + } +} + +/// Describes how the fields of a type are shaped in memory. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum FieldsShape { + /// Scalar primitives and `!`, which never have fields. + Primitive, + + /// All fields start at no offset. The `usize` is the field count. + Union(NonZeroUsize), + + /// Array/vector-like placement, with all fields of identical types. + Array { stride: Size, count: u64 }, + + /// Struct-like placement, with precomputed offsets. + /// + /// Fields are guaranteed to not overlap, but note that gaps + /// before, between and after all the fields are NOT always + /// padding, and as such their contents may not be discarded. + /// For example, enum variants leave a gap at the start, + /// where the discriminant field in the enum layout goes. + Arbitrary { + /// Offsets for the first byte of each field, + /// ordered to match the source definition order. + /// I.e.: It follows the same order as [crate::ty::VariantDef::fields()]. + /// This vector does not go in increasing order. + offsets: Vec, + }, +} + +impl FieldsShape { + pub fn fields_by_offset_order(&self) -> Vec { + match self { + FieldsShape::Primitive => vec![], + FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(), + FieldsShape::Arbitrary { offsets, .. } => { + let mut indices = (0..offsets.len()).collect::>(); + indices.sort_by_key(|idx| offsets[*idx]); + indices + } + } + } + + pub fn count(&self) -> usize { + match self { + FieldsShape::Primitive => 0, + FieldsShape::Union(count) => count.get(), + FieldsShape::Array { count, .. } => *count as usize, + FieldsShape::Arbitrary { offsets, .. } => offsets.len(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum VariantsShape { + /// Single enum variants, structs/tuples, unions, and all non-ADTs. + Single { index: VariantIdx }, + + /// Enum-likes with more than one inhabited variant: each variant comes with + /// a *discriminant* (usually the same as the variant index but the user can + /// assign explicit discriminant values). That discriminant is encoded + /// as a *tag* on the machine. The layout of each variant is + /// a struct, and they all have space reserved for the tag. + /// For enums, the tag is the sole field of the layout. + Multiple { + tag: Scalar, + tag_encoding: TagEncoding, + tag_field: usize, + variants: Vec, + }, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum TagEncoding { + /// The tag directly stores the discriminant, but possibly with a smaller layout + /// (so converting the tag to the discriminant can require sign extension). + Direct, + + /// Niche (values invalid for a type) encoding the discriminant: + /// Discriminant and variant index coincide. + /// The variant `untagged_variant` contains a niche at an arbitrary + /// offset (field `tag_field` of the enum), which for a variant with + /// discriminant `d` is set to + /// `(d - niche_variants.start).wrapping_add(niche_start)`. + /// + /// For example, `Option<(usize, &T)>` is represented such that + /// `None` has a null pointer for the second tuple field, and + /// `Some` is the identity function (with a non-null reference). + Niche { + untagged_variant: VariantIdx, + niche_variants: RangeInclusive, + niche_start: u128, + }, +} + +/// Describes how values of the type are passed by target ABIs, +/// in terms of categories of C types there are ABI rules for. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum ValueAbi { + Uninhabited, + Scalar(Scalar), + ScalarPair(Scalar, Scalar), + Vector { + element: Scalar, + count: u64, + }, + Aggregate { + /// If true, the size is exact, otherwise it's only a lower bound. + sized: bool, + }, +} + +impl ValueAbi { + /// Returns `true` if the layout corresponds to an unsized type. + pub fn is_unsized(&self) -> bool { + match *self { + ValueAbi::Uninhabited + | ValueAbi::Scalar(_) + | ValueAbi::ScalarPair(..) + | ValueAbi::Vector { .. } => false, + ValueAbi::Aggregate { sized } => !sized, + } + } +} + +/// We currently do not support `Scalar`, and use opaque instead. +type Scalar = Opaque; + +/// General language calling conventions. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CallConvention { + C, + Rust, + + Cold, + PreserveMost, + PreserveAll, + + // Target-specific calling conventions. + ArmAapcs, + CCmseNonSecureCall, + + Msp430Intr, + + PtxKernel, + + X86Fastcall, + X86Intr, + X86Stdcall, + X86ThisCall, + X86VectorCall, + + X86_64SysV, + X86_64Win64, + + AmdGpuKernel, + AvrInterrupt, + AvrNonBlockingInterrupt, + + RiscvInterrupt, +} diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 57c60b70d8aa3..98b1d484c034e 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -5,6 +5,7 @@ use std::cell::Cell; +use crate::abi::{FnAbi, Layout, LayoutShape}; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::Body; @@ -173,6 +174,15 @@ pub trait Context { /// Return information about the target machine. fn target_info(&self) -> MachineInfo; + + /// Get an instance ABI. + fn instance_abi(&self, def: InstanceDef) -> Result; + + /// Get the layout of a type. + fn ty_layout(&self, ty: Ty) -> Result; + + /// Get the layout shape. + fn layout_shape(&self, id: Layout) -> LayoutShape; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 8c66bfb2e9890..4941e54fe4b7e 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -33,6 +33,7 @@ use crate::mir::Body; use crate::mir::Mutability; use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty}; +pub mod abi; #[macro_use] pub mod crate_def; pub mod compiler_interface; diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index c126de23c4b6f..70d44ef8c2256 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,3 +1,4 @@ +use crate::abi::FnAbi; use crate::crate_def::CrateDef; use crate::mir::Body; use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; @@ -56,6 +57,11 @@ impl Instance { with(|context| context.instance_ty(self.def)) } + /// Retrieve information about this instance binary interface. + pub fn fn_abi(&self) -> Result { + with(|cx| cx.instance_abi(self.def)) + } + /// Retrieve the instance's mangled name used for calling the given instance. /// /// This will also look up the correct name of instances from upstream crates. diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 4807a9028eb83..1d4d7b6d3520f 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -3,6 +3,7 @@ use super::{ mir::{Body, Mutability}, with, DefId, Error, Symbol, }; +use crate::abi::Layout; use crate::crate_def::CrateDef; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::target::MachineInfo; @@ -85,6 +86,11 @@ impl Ty { pub fn unsigned_ty(inner: UintTy) -> Ty { Ty::from_rigid_kind(RigidTy::Uint(inner)) } + + /// Get a type layout. + pub fn layout(self) -> Result { + with(|cx| cx.ty_layout(self)) + } } impl Ty { diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 5be8aebc70fd5..679a6f1a3c3ae 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -74,7 +74,11 @@ impl UnixListener { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; const backlog: libc::c_int = - if cfg!(any(target_os = "linux", target_os = "freebsd")) { -1 } else { 128 }; + if cfg!(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd")) { + -1 + } else { + libc::SOMAXCONN + }; cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index f46daca1f3075..fadd64a0353cb 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -22,8 +22,10 @@ - [\*-apple-watchos\*](platform-support/apple-watchos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) + - [arm-none-eabi](platform-support/arm-none-eabi.md) - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) + - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 1893a32270836..59ef744102415 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -137,17 +137,17 @@ target | std | notes [`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv6 Android `arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL `arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat -`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian -`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat +[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian +[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian, hardfloat `armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7-A Android `armv7-unknown-linux-gnueabi` | ✓ | ARMv7-A Linux (kernel 4.15, glibc 2.27) `armv7-unknown-linux-musleabi` | ✓ | ARMv7-A Linux with MUSL `armv7-unknown-linux-musleabihf` | ✓ | ARMv7-A Linux with MUSL, hardfloat -`armv7a-none-eabi` | * | Bare ARMv7-A -`armv7r-none-eabi` | * | Bare ARMv7-R -`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat +[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-A +[`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R +[`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, hardfloat `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL [^x86_32-floats-x87] @@ -166,15 +166,15 @@ target | std | notes `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) `sparcv9-sun-solaris` | ✓ | SPARC Solaris 11, illumos -`thumbv6m-none-eabi` | * | Bare ARMv6-M -`thumbv7em-none-eabi` | * | Bare ARMv7E-M -`thumbv7em-none-eabihf` | * | Bare ARMV7E-M, hardfloat -`thumbv7m-none-eabi` | * | Bare ARMv7-M +[`thumbv6m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv6-M +[`thumbv7em-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7E-M +[`thumbv7em-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMV7E-M, hardfloat +[`thumbv7m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-M [`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7-A Android with NEON `thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23) -`thumbv8m.base-none-eabi` | * | Bare ARMv8-M Baseline -`thumbv8m.main-none-eabi` | * | Bare ARMv8-M Mainline -`thumbv8m.main-none-eabihf` | * | Bare ARMv8-M Mainline, hardfloat +[`thumbv8m.base-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Baseline +[`thumbv8m.main-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline +[`thumbv8m.main-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI @@ -239,11 +239,11 @@ target | std | host | notes `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) -[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers +[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). -`armv4t-none-eabi` | * | | Bare ARMv4T +[`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Bare ARMv4T `armv4t-unknown-linux-gnueabi` | ? | | ARMv4T Linux -[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE +[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE `armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float @@ -257,8 +257,8 @@ target | std | host | notes `armv7-wrs-vxworks-eabihf` | ? | | ARMv7-A for VxWorks [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat -`armv7a-none-eabihf` | * | | Bare ARMv7-A, hardfloat -[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS +[`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * | | Bare ARMv7-A, hardfloat +[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS `armv7s-apple-ios` | ✓ | | ARMv7-A Apple-A6 Apple iOS `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` `bpfeb-unknown-none` | * | | BPF (big endian) @@ -333,15 +333,15 @@ target | std | host | notes [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 -`thumbv4t-none-eabi` | * | | Thumb-mode Bare ARMv4T -[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE +[`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Thumb-mode Bare ARMv4T +[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 -[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS -[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator +[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS +[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md new file mode 100644 index 0000000000000..4f76d0d7bbce7 --- /dev/null +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -0,0 +1,96 @@ +# `{arm,thumb}*-none-eabi(hf)?` + +**Tier: 2** +- [arm(eb)?v7r-none-eabi(hf)?](armv7r-none-eabi.md) +- armv7a-none-eabi +- thumbv6m-none-eabi +- thumbv7m-none-eabi +- thumbv7em-none-eabi(hf)? +- thumbv8m.base-none-eabi +- thumbv8m.main-none-eabi(hf)? + +**Tier: 3** +- [{arm,thumb}v4t-none-eabi](armv4t-none-eabi.md) +- [{arm,thumb}v5te-none-eabi](armv5te-none-eabi.md) +- armv7a-none-eabihf + +Bare-metal target for 32-bit ARM CPUs. + +If a target has a `*hf` variant, that variant uses the hardware floating-point +ABI and enables some minimum set of floating-point features based on the FPU(s) +available in that processor family. + +## Requirements + +These targets are cross-compiled and use static linking. + +By default, the `lld` linker included with Rust will be used; however, you may +want to use the GNU linker instead. This can be obtained for Windows/Mac/Linux +from the [Arm Developer Website][arm-gnu-toolchain], or possibly from your OS's +package manager. To use it, add the following to your `.cargo/config.toml`: + +```toml +[target.] +linker = "arm-none-eabi-ld" +``` + +The GNU linker can also be used by specifying `arm-none-eabi-gcc` as the +linker. This is needed when using GCC's link time optimization. + +[arm-gnu-toolchain]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain + +These targets don't provide a linker script, so you'll need to bring your own +according to the specific device you are using. Pass +`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use +`your_script.ld` during linking. + +Targets named `thumb*` instead of `arm*` +generate Thumb-mode code by default. M-profile processors (`thumbv*m*-*` +targets) only support Thumb-mode code. +For the `arm*` targets, Thumb-mode code generation can be enabled by using +`-C target-feature=+thumb-mode`. Using the unstable +`#![feature(arm_target_feature)]`, the attribute +`#[target_feature(enable = "thumb-mode")]` can be applied to individual +`unsafe` functions to cause those functions to be compiled to Thumb-mode code. + +## Building Rust Programs + +For the Tier 3 targets in this family, rust does not ship pre-compiled +artifacts. + +Just use the `build-std` nightly cargo feature to build the `core` library. You +can pass this as a command line argument to cargo, or your `.cargo/config.toml` +file might include the following lines: + +```toml +[unstable] +build-std = ["core"] +``` + +Most of `core` should work as expected, with the following notes: +* If the target is not `*hf`, then floating-point operations are emulated in + software. +* Integer division is also emulated in software on some targets, depending on + the CPU. +* Architectures prior to ARMv7 don't have atomic instructions. + +`alloc` is also supported, as long as you provide your own global allocator. + +Rust programs are output as ELF files. + +## Testing + +This is a cross-compiled target that you will need to emulate during testing. + +The exact emulator that you'll need depends on the specific device you want to +run your code on. + +## Cross-compilation toolchains and C code + +The target supports C code compiled with the `arm-none-eabi` target triple and +a suitable `-march` or `-mcpu` flag. + +`gcc` or `clang` can be used, but note that `gcc` uses `-fshort-enums` by +default for `arm-none*` targets, while `clang` does not. `rustc` matches the +`gcc` behavior, i.e., the size of a `#[repr(C)] enum` in Rust can be as little +as 1 byte, rather than 4, as they are on `arm-linux` targets. diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md index a230eba6bf95c..29c47db8351c7 100644 --- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -6,51 +6,16 @@ Bare-metal target for any cpu in the ARMv4T architecture family, supporting ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code generation. -In particular this supports the Gameboy Advance (GBA), but there's nothing GBA -specific with this target, so any ARMv4T device should work fine. +In particular this supports the Game Boy Advance (GBA), but there's nothing +GBA-specific with this target, so any ARMv4T device should work fine. + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. ## Target Maintainers * [@Lokathor](https://github.com/lokathor) -## Requirements - -The target is cross-compiled, and uses static linking. - -This target doesn't provide a linker script, you'll need to bring your own -according to the specific device you want to target. Pass -`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use -`your_script.ld` during linking. - -## Building Rust Programs - -Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. - -Just use the `build-std` nightly cargo feature to build the `core` library. You -can pass this as a command line argument to cargo, or your `.cargo/config.toml` -file might include the following lines: - -```toml -[unstable] -build-std = ["core"] -``` - -Most of `core` should work as expected, with the following notes: -* the target is "soft float", so `f32` and `f64` operations are emulated in - software. -* integer division is also emulated in software. -* the target is old enough that it doesn't have atomic instructions. - -Rust programs are output as ELF files. - -For running on hardware, you'll generally need to extract the "raw" program code -out of the ELF and into a file of its own. The `objcopy` program provided as -part of the GNU Binutils can do this: - -```shell -arm-none-eabi-objcopy --output-target binary [in_file] [out_file] -``` - ## Testing This is a cross-compiled target that you will need to emulate during testing. diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md index f469dab1c42fa..37284ba720997 100644 --- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md @@ -8,54 +8,13 @@ generation. The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `t32`. +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + ## Target Maintainers * [@QuinnPainter](https://github.com/QuinnPainter) -## Requirements - -The target is cross-compiled, and uses static linking. - -By default, the `lld` linker included with Rust will be used. - -However, you may want to use the `arm-none-eabi-ld` linker instead. This can be obtained for Windows/Mac/Linux from the [ARM -Developer Website][arm-dev], or possibly from your OS's package manager. To use it, add the following to your `.cargo/config.toml`: - -```toml -[target.armv5te-none-eabi] -linker = "arm-none-eabi-ld" -``` - -[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain - -This target doesn't provide a linker script, you'll need to bring your own -according to the specific device you want to target. Pass -`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use -`your_script.ld` during linking. - -## Building Rust Programs - -Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. - -Just use the `build-std` nightly cargo feature to build the `core` library. You -can pass this as a command line argument to cargo, or your `.cargo/config.toml` -file might include the following lines: - -```toml -[unstable] -build-std = ["core"] -``` - -Most of `core` should work as expected, with the following notes: -* the target is "soft float", so `f32` and `f64` operations are emulated in - software. -* integer division is also emulated in software. -* the target is old enough that it doesn't have atomic instructions. - -`alloc` is also supported, as long as you provide your own global allocator. - -Rust programs are output as ELF files. - ## Testing This is a cross-compiled target that you will need to emulate during testing. @@ -63,4 +22,5 @@ This is a cross-compiled target that you will need to emulate during testing. Because this is a device-agnostic target, and the exact emulator that you'll need depends on the specific device you want to run your code on. -For example, when programming for the DS, you can use one of the several available DS emulators, such as [melonDS](https://melonds.kuribo64.net/). +For example, when programming for the DS, you can use one of the several +available DS emulators, such as [melonDS](https://melonds.kuribo64.net/). diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md new file mode 100644 index 0000000000000..670cead9e006b --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -0,0 +1,47 @@ +# `arm(eb)?v7r-none-eabi(hf)?` + +**Tier: 2** + +Bare-metal target for CPUs in the ARMv7-R architecture family, supporting +dual ARM/Thumb mode, with ARM mode as the default. + +Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r]. + +The `eb` versions of this target generate code for big-endian processors. + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +[cortex-r]: https://en.wikipedia.org/wiki/ARM_Cortex-R + +## Target maintainers + +- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net` + +## Requirements + +When using the big-endian version of this target, note that some variants of +the Cortex-R have both big-endian instructions and data. This configuration is +known as BE-32, while data-only big-endianness is known as BE-8. To build +programs for BE-32 processors, the GNU linker must be used with the `-mbe32` +option. See [ARM Cortex-R Series Programmer's Guide: Endianness][endianness] +for more details about different endian modes. + +When using the hardfloat targets, the minimum floating-point features assumed +are those of the `vfpv3-d16`, which includes single- and double-precision, with +16 double-precision registers. This floating-point unit appears in Cortex-R4F +and Cortex-R5F processors. See [VFP in the Cortex-R processors][vfp] +for more details on the possible FPU variants. + +If your processor supports a different set of floating-point features than the +default expectations of `vfpv3-d16`, then these should also be enabled or +disabled as needed with `-C target-feature=(+/-)`. + +[endianness]: https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness + +[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors + +## Cross-compilation toolchains and C code + +This target supports C code compiled with the `arm-none-eabi` target triple and +`-march=armv7-r` or a suitable `-mcpu` flag. diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs new file mode 100644 index 0000000000000..30b42bc3bfafc --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -0,0 +1,143 @@ +// run-pass +//! Test information regarding type layout. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] +#![feature(ascii_char, ascii_char_variants)] + +extern crate rustc_hir; +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape}; +use stable_mir::mir::mono::Instance; +use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind}; +use std::assert_matches::assert_matches; +use std::convert::TryFrom; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + // Find items in the local crate. + let items = stable_mir::all_local_items(); + + // Test fn_abi + let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap(); + let instance = Instance::try_from(target_fn).unwrap(); + let fn_abi = instance.fn_abi().unwrap(); + assert_eq!(fn_abi.conv, CallConvention::Rust); + assert_eq!(fn_abi.args.len(), 2); + + check_ignore(&fn_abi.args[0]); + check_primitive(&fn_abi.args[1]); + check_result(fn_abi.ret); + + // Test variadic function. + let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap(); + check_variadic(variadic_fn); + + ControlFlow::Continue(()) +} + +/// Check the variadic function ABI: +/// ```no_run +/// pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize { +/// 0 +/// } +/// ``` +fn check_variadic(variadic_fn: CrateItem) { + let instance = Instance::try_from(variadic_fn).unwrap(); + let abi = instance.fn_abi().unwrap(); + assert!(abi.c_variadic); + assert_eq!(abi.args.len(), 1); +} + +/// Check the argument to be ignored: `ignore: [u8; 0]`. +fn check_ignore(abi: &ArgAbi) { + assert!(abi.ty.kind().is_array()); + assert_eq!(abi.mode, PassMode::Ignore); + let layout = abi.layout.shape(); + assert!(layout.is_sized()); + assert!(layout.is_1zst()); +} + +/// Check the primitive argument: `primitive: char`. +fn check_primitive(abi: &ArgAbi) { + assert!(abi.ty.kind().is_char()); + assert_matches!(abi.mode, PassMode::Direct(_)); + let layout = abi.layout.shape(); + assert!(layout.is_sized()); + assert!(!layout.is_1zst()); + assert_matches!(layout.fields, FieldsShape::Primitive); +} + +/// Check the return value: `Result`. +fn check_result(abi: ArgAbi) { + assert!(abi.ty.kind().is_enum()); + assert_matches!(abi.mode, PassMode::Indirect { .. }); + let layout = abi.layout.shape(); + assert!(layout.is_sized()); + assert_matches!(layout.fields, FieldsShape::Arbitrary { .. }); + assert_matches!(layout.variants, VariantsShape::Multiple { .. }) +} + +fn get_item<'a>( + items: &'a CrateItems, + item: (ItemKind, &str), +) -> Option<&'a stable_mir::CrateItem> { + items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "alloc_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_stable_mir(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + #![feature(c_variadic)] + #![allow(unused_variables)] + + pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result {{ + // We only care about the signature. + todo!() + }} + + + pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{ + 0 + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 8554630e9c999..7ce3597206b62 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -209,7 +209,6 @@ fn check_len(item: CrateItem) { assert_eq!(alloc.read_uint(), Ok(2)); } -// Use internal API to find a function in a crate. fn get_item<'a>( items: &'a CrateItems, item: (ItemKind, &str), diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index ad66751133214..e9a2599d8732c 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -69,9 +69,9 @@ fn extract_elem_ty(ty: Ty) -> Ty { /// Check signature and type of `Vec::::new` and its generic version. fn test_vec_new(instance: mir::mono::Instance) { - let sig = instance.ty().kind().fn_sig().unwrap().skip_binder(); - assert_matches!(sig.inputs(), &[]); - let elem_ty = extract_elem_ty(sig.output()); + let sig = instance.fn_abi().unwrap(); + assert_eq!(&sig.args, &[]); + let elem_ty = extract_elem_ty(sig.ret.ty); assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8))); // Get the signature for Vec::::new.