mv compiler to compiler/
This commit is contained in:
parent
db534b3ac2
commit
9e5f7d5631
1686 changed files with 941 additions and 1051 deletions
106
compiler/rustc_target/src/abi/call/aarch64.rs
Normal file
106
compiler/rustc_target/src/abi/call/aarch64.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
|
||||
let size = arg.layout.size;
|
||||
|
||||
// Ensure we have at most four uniquely addressable members.
|
||||
if size > unit.size.checked_mul(4, cx).unwrap() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let valid_unit = match unit.kind {
|
||||
RegKind::Integer => false,
|
||||
RegKind::Float => true,
|
||||
RegKind::Vector => size.bits() == 64 || size.bits() == 128,
|
||||
};
|
||||
|
||||
valid_unit.then_some(Uniform { unit, total: size })
|
||||
})
|
||||
}
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(32);
|
||||
return;
|
||||
}
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
let size = ret.layout.size;
|
||||
let bits = size.bits();
|
||||
if bits <= 128 {
|
||||
let unit = if bits <= 8 {
|
||||
Reg::i8()
|
||||
} else if bits <= 16 {
|
||||
Reg::i16()
|
||||
} else if bits <= 32 {
|
||||
Reg::i32()
|
||||
} else {
|
||||
Reg::i64()
|
||||
};
|
||||
|
||||
ret.cast_to(Uniform { unit, total: size });
|
||||
return;
|
||||
}
|
||||
ret.make_indirect();
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_aggregate() {
|
||||
arg.extend_integer_width_to(32);
|
||||
return;
|
||||
}
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
let size = arg.layout.size;
|
||||
let bits = size.bits();
|
||||
if bits <= 128 {
|
||||
let unit = if bits <= 8 {
|
||||
Reg::i8()
|
||||
} else if bits <= 16 {
|
||||
Reg::i16()
|
||||
} else if bits <= 32 {
|
||||
Reg::i32()
|
||||
} else {
|
||||
Reg::i64()
|
||||
};
|
||||
|
||||
arg.cast_to(Uniform { unit, total: size });
|
||||
return;
|
||||
}
|
||||
arg.make_indirect();
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
35
compiler/rustc_target/src/abi/call/amdgpu.rs
Normal file
35
compiler/rustc_target/src/abi/call/amdgpu.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
fn classify_ret<'a, Ty, C>(_cx: &C, ret: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
104
compiler/rustc_target/src/abi/call/arm.rs
Normal file
104
compiler/rustc_target/src/abi/call/arm.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
use crate::abi::call::{ArgAbi, Conv, FnAbi, Reg, RegKind, Uniform};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
|
||||
let size = arg.layout.size;
|
||||
|
||||
// Ensure we have at most four uniquely addressable members.
|
||||
if size > unit.size.checked_mul(4, cx).unwrap() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let valid_unit = match unit.kind {
|
||||
RegKind::Integer => false,
|
||||
RegKind::Float => true,
|
||||
RegKind::Vector => size.bits() == 64 || size.bits() == 128,
|
||||
};
|
||||
|
||||
valid_unit.then_some(Uniform { unit, total: size })
|
||||
})
|
||||
}
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, vfp: bool)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(32);
|
||||
return;
|
||||
}
|
||||
|
||||
if vfp {
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let size = ret.layout.size;
|
||||
let bits = size.bits();
|
||||
if bits <= 32 {
|
||||
let unit = if bits <= 8 {
|
||||
Reg::i8()
|
||||
} else if bits <= 16 {
|
||||
Reg::i16()
|
||||
} else {
|
||||
Reg::i32()
|
||||
};
|
||||
ret.cast_to(Uniform { unit, total: size });
|
||||
return;
|
||||
}
|
||||
ret.make_indirect();
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, vfp: bool)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_aggregate() {
|
||||
arg.extend_integer_width_to(32);
|
||||
return;
|
||||
}
|
||||
|
||||
if vfp {
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let align = arg.layout.align.abi.bytes();
|
||||
let total = arg.layout.size;
|
||||
arg.cast_to(Uniform { unit: if align <= 4 { Reg::i32() } else { Reg::i64() }, total });
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
// If this is a target with a hard-float ABI, and the function is not explicitly
|
||||
// `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates.
|
||||
let vfp = cx.target_spec().llvm_target.ends_with("hf")
|
||||
&& fn_abi.conv != Conv::ArmAapcs
|
||||
&& !fn_abi.c_variadic;
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret, vfp);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg, vfp);
|
||||
}
|
||||
}
|
59
compiler/rustc_target/src/abi/call/avr.rs
Normal file
59
compiler/rustc_target/src/abi/call/avr.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
//! LLVM-frontend specific AVR calling convention implementation.
|
||||
//!
|
||||
//! # Current calling convention ABI
|
||||
//!
|
||||
//! Inherited from Clang's `clang::DefaultABIInfo` implementation - self described
|
||||
//! as
|
||||
//!
|
||||
//! > the default implementation for ABI specific details. This implementation
|
||||
//! > provides information which results in
|
||||
//! > self-consistent and sensible LLVM IR generation, but does not
|
||||
//! > conform to any particular ABI.
|
||||
//! >
|
||||
//! > - Doxygen Doxumentation of `clang::DefaultABIInfo`
|
||||
//!
|
||||
//! This calling convention may not match AVR-GCC in all cases.
|
||||
//!
|
||||
//! In the future, an AVR-GCC compatible argument classification ABI should be
|
||||
//! adopted in both Rust and Clang.
|
||||
//!
|
||||
//! *NOTE*: Currently, this module implements the same calling convention
|
||||
//! that clang with AVR currently does - the default, simple, unspecialized
|
||||
//! ABI implementation available to all targets. This ABI is not
|
||||
//! binary-compatible with AVR-GCC. Once LLVM [PR46140](https://bugs.llvm.org/show_bug.cgi?id=46140)
|
||||
//! is completed, this module should be updated to match so that both Clang
|
||||
//! and Rust emit code to the same AVR-GCC compatible ABI.
|
||||
//!
|
||||
//! In particular, both Clang and Rust may not have the same semantics
|
||||
//! when promoting arguments to indirect references as AVR-GCC. It is important
|
||||
//! to note that the core AVR ABI implementation within LLVM itself is ABI
|
||||
//! compatible with AVR-GCC - Rust and AVR-GCC only differ in the small amount
|
||||
//! of compiler frontend specific calling convention logic implemented here.
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret_ty<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
if ret.layout.is_aggregate() {
|
||||
ret.make_indirect();
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.make_indirect();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<Ty>(fty: &mut FnAbi<'_, Ty>) {
|
||||
if !fty.ret.is_ignore() {
|
||||
classify_ret_ty(&mut fty.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fty.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
|
||||
classify_arg_ty(arg);
|
||||
}
|
||||
}
|
30
compiler/rustc_target/src/abi/call/hexagon.rs
Normal file
30
compiler/rustc_target/src/abi/call/hexagon.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 {
|
||||
ret.make_indirect();
|
||||
} else {
|
||||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
}
|
||||
}
|
54
compiler/rustc_target/src/abi/call/mips.rs
Normal file
54
compiler/rustc_target/src/abi/call/mips.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, Size, TyAndLayoutMethods};
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(32);
|
||||
} else {
|
||||
ret.make_indirect();
|
||||
*offset += cx.data_layout().pointer_size;
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty> + HasDataLayout,
|
||||
{
|
||||
let dl = cx.data_layout();
|
||||
let size = arg.layout.size;
|
||||
let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi;
|
||||
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.cast_to(Uniform { unit: Reg::i32(), total: size });
|
||||
if !offset.is_aligned(align) {
|
||||
arg.pad_with(Reg::i32());
|
||||
}
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
*offset = offset.align_to(align) + size.align_to(align);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty> + HasDataLayout,
|
||||
{
|
||||
let mut offset = Size::ZERO;
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret, &mut offset);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg, &mut offset);
|
||||
}
|
||||
}
|
160
compiler/rustc_target/src/abi/call/mips64.rs
Normal file
160
compiler/rustc_target/src/abi/call/mips64.rs
Normal file
|
@ -0,0 +1,160 @@
|
|||
use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
|
||||
use crate::abi::{self, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
|
||||
// Always sign extend u32 values on 64-bit mips
|
||||
if let abi::Abi::Scalar(ref scalar) = arg.layout.abi {
|
||||
if let abi::Int(i, signed) = scalar.value {
|
||||
if !signed && i.size().bits() == 32 {
|
||||
if let PassMode::Direct(ref mut attrs) = arg.mode {
|
||||
attrs.set(ArgAttribute::SExt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arg.extend_integer_width_to(bits);
|
||||
}
|
||||
|
||||
fn float_reg<'a, Ty, C>(cx: &C, ret: &ArgAbi<'a, Ty>, i: usize) -> Option<Reg>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
match ret.layout.field(cx, i).abi {
|
||||
abi::Abi::Scalar(ref scalar) => match scalar.value {
|
||||
abi::F32 => Some(Reg::f32()),
|
||||
abi::F64 => Some(Reg::f64()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() {
|
||||
extend_integer_width_mips(ret, 64);
|
||||
return;
|
||||
}
|
||||
|
||||
let size = ret.layout.size;
|
||||
let bits = size.bits();
|
||||
if bits <= 128 {
|
||||
// Unlike other architectures which return aggregates in registers, MIPS n64 limits the
|
||||
// use of float registers to structures (not unions) containing exactly one or two
|
||||
// float fields.
|
||||
|
||||
if let abi::FieldsShape::Arbitrary { .. } = ret.layout.fields {
|
||||
if ret.layout.fields.count() == 1 {
|
||||
if let Some(reg) = float_reg(cx, ret, 0) {
|
||||
ret.cast_to(reg);
|
||||
return;
|
||||
}
|
||||
} else if ret.layout.fields.count() == 2 {
|
||||
if let Some(reg0) = float_reg(cx, ret, 0) {
|
||||
if let Some(reg1) = float_reg(cx, ret, 1) {
|
||||
ret.cast_to(CastTarget::pair(reg0, reg1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cast to a uniform int structure
|
||||
ret.cast_to(Uniform { unit: Reg::i64(), total: size });
|
||||
} else {
|
||||
ret.make_indirect();
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_aggregate() {
|
||||
extend_integer_width_mips(arg, 64);
|
||||
return;
|
||||
}
|
||||
|
||||
let dl = cx.data_layout();
|
||||
let size = arg.layout.size;
|
||||
let mut prefix = [None; 8];
|
||||
let mut prefix_index = 0;
|
||||
|
||||
match arg.layout.fields {
|
||||
abi::FieldsShape::Primitive => unreachable!(),
|
||||
abi::FieldsShape::Array { .. } => {
|
||||
// Arrays are passed indirectly
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
abi::FieldsShape::Union(_) => {
|
||||
// Unions and are always treated as a series of 64-bit integer chunks
|
||||
}
|
||||
abi::FieldsShape::Arbitrary { .. } => {
|
||||
// Structures are split up into a series of 64-bit integer chunks, but any aligned
|
||||
// doubles not part of another aggregate are passed as floats.
|
||||
let mut last_offset = Size::ZERO;
|
||||
|
||||
for i in 0..arg.layout.fields.count() {
|
||||
let field = arg.layout.field(cx, i);
|
||||
let offset = arg.layout.fields.offset(i);
|
||||
|
||||
// We only care about aligned doubles
|
||||
if let abi::Abi::Scalar(ref scalar) = field.abi {
|
||||
if let abi::F64 = scalar.value {
|
||||
if offset.is_aligned(dl.f64_align.abi) {
|
||||
// Insert enough integers to cover [last_offset, offset)
|
||||
assert!(last_offset.is_aligned(dl.f64_align.abi));
|
||||
for _ in 0..((offset - last_offset).bits() / 64)
|
||||
.min((prefix.len() - prefix_index) as u64)
|
||||
{
|
||||
prefix[prefix_index] = Some(RegKind::Integer);
|
||||
prefix_index += 1;
|
||||
}
|
||||
|
||||
if prefix_index == prefix.len() {
|
||||
break;
|
||||
}
|
||||
|
||||
prefix[prefix_index] = Some(RegKind::Float);
|
||||
prefix_index += 1;
|
||||
last_offset = offset + Reg::f64().size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Extract first 8 chunks as the prefix
|
||||
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
|
||||
arg.cast_to(CastTarget {
|
||||
prefix,
|
||||
prefix_chunk: Size::from_bytes(8),
|
||||
rest: Uniform { unit: Reg::i64(), total: rest_size },
|
||||
});
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
612
compiler/rustc_target/src/abi/call/mod.rs
Normal file
612
compiler/rustc_target/src/abi/call/mod.rs
Normal file
|
@ -0,0 +1,612 @@
|
|||
use crate::abi::{self, Abi, Align, FieldsShape, Size};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
use crate::spec::{self, HasTargetSpec};
|
||||
|
||||
mod aarch64;
|
||||
mod amdgpu;
|
||||
mod arm;
|
||||
mod avr;
|
||||
mod hexagon;
|
||||
mod mips;
|
||||
mod mips64;
|
||||
mod msp430;
|
||||
mod nvptx;
|
||||
mod nvptx64;
|
||||
mod powerpc;
|
||||
mod powerpc64;
|
||||
mod riscv;
|
||||
mod s390x;
|
||||
mod sparc;
|
||||
mod sparc64;
|
||||
mod wasm32;
|
||||
mod wasm32_bindgen_compat;
|
||||
mod x86;
|
||||
mod x86_64;
|
||||
mod x86_win64;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum PassMode {
|
||||
/// Ignore the argument.
|
||||
Ignore,
|
||||
/// Pass the argument directly.
|
||||
Direct(ArgAttributes),
|
||||
/// Pass a pair's elements directly in two arguments.
|
||||
Pair(ArgAttributes, ArgAttributes),
|
||||
/// Pass the argument after casting it, to either
|
||||
/// a single uniform or a pair of registers.
|
||||
Cast(CastTarget),
|
||||
/// Pass the argument indirectly via a hidden pointer.
|
||||
/// The second value, if any, is for the extra data (vtable or length)
|
||||
/// which indicates that it refers to an unsized rvalue.
|
||||
Indirect(ArgAttributes, Option<ArgAttributes>),
|
||||
}
|
||||
|
||||
// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
|
||||
// of this module
|
||||
pub use attr_impl::ArgAttribute;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[allow(unused)]
|
||||
mod attr_impl {
|
||||
// The subset of llvm::Attribute needed for arguments, packed into a bitfield.
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct ArgAttribute: u16 {
|
||||
const ByVal = 1 << 0;
|
||||
const NoAlias = 1 << 1;
|
||||
const NoCapture = 1 << 2;
|
||||
const NonNull = 1 << 3;
|
||||
const ReadOnly = 1 << 4;
|
||||
const SExt = 1 << 5;
|
||||
const StructRet = 1 << 6;
|
||||
const ZExt = 1 << 7;
|
||||
const InReg = 1 << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A compact representation of LLVM attributes (at least those relevant for this module)
|
||||
/// that can be manipulated without interacting with LLVM's Attribute machinery.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct ArgAttributes {
|
||||
pub regular: ArgAttribute,
|
||||
/// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
|
||||
/// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
|
||||
pub pointee_size: Size,
|
||||
pub pointee_align: Option<Align>,
|
||||
}
|
||||
|
||||
impl ArgAttributes {
|
||||
pub fn new() -> Self {
|
||||
ArgAttributes {
|
||||
regular: ArgAttribute::default(),
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
|
||||
self.regular |= attr;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn contains(&self, attr: ArgAttribute) -> bool {
|
||||
self.regular.contains(attr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum RegKind {
|
||||
Integer,
|
||||
Float,
|
||||
Vector,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Reg {
|
||||
pub kind: RegKind,
|
||||
pub size: Size,
|
||||
}
|
||||
|
||||
macro_rules! reg_ctor {
|
||||
($name:ident, $kind:ident, $bits:expr) => {
|
||||
pub fn $name() -> Reg {
|
||||
Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
reg_ctor!(i8, Integer, 8);
|
||||
reg_ctor!(i16, Integer, 16);
|
||||
reg_ctor!(i32, Integer, 32);
|
||||
reg_ctor!(i64, Integer, 64);
|
||||
reg_ctor!(i128, Integer, 128);
|
||||
|
||||
reg_ctor!(f32, Float, 32);
|
||||
reg_ctor!(f64, Float, 64);
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
|
||||
let dl = cx.data_layout();
|
||||
match self.kind {
|
||||
RegKind::Integer => match self.size.bits() {
|
||||
1 => dl.i1_align.abi,
|
||||
2..=8 => dl.i8_align.abi,
|
||||
9..=16 => dl.i16_align.abi,
|
||||
17..=32 => dl.i32_align.abi,
|
||||
33..=64 => dl.i64_align.abi,
|
||||
65..=128 => dl.i128_align.abi,
|
||||
_ => panic!("unsupported integer: {:?}", self),
|
||||
},
|
||||
RegKind::Float => match self.size.bits() {
|
||||
32 => dl.f32_align.abi,
|
||||
64 => dl.f64_align.abi,
|
||||
_ => panic!("unsupported float: {:?}", self),
|
||||
},
|
||||
RegKind::Vector => dl.vector_align(self.size).abi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An argument passed entirely registers with the
|
||||
/// same kind (e.g., HFA / HVA on PPC64 and AArch64).
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Uniform {
|
||||
pub unit: Reg,
|
||||
|
||||
/// The total size of the argument, which can be:
|
||||
/// * equal to `unit.size` (one scalar/vector),
|
||||
/// * a multiple of `unit.size` (an array of scalar/vectors),
|
||||
/// * if `unit.kind` is `Integer`, the last element
|
||||
/// can be shorter, i.e., `{ i64, i64, i32 }` for
|
||||
/// 64-bit integers with a total size of 20 bytes.
|
||||
pub total: Size,
|
||||
}
|
||||
|
||||
impl From<Reg> for Uniform {
|
||||
fn from(unit: Reg) -> Uniform {
|
||||
Uniform { unit, total: unit.size }
|
||||
}
|
||||
}
|
||||
|
||||
impl Uniform {
|
||||
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
|
||||
self.unit.align(cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct CastTarget {
|
||||
pub prefix: [Option<RegKind>; 8],
|
||||
pub prefix_chunk: Size,
|
||||
pub rest: Uniform,
|
||||
}
|
||||
|
||||
impl From<Reg> for CastTarget {
|
||||
fn from(unit: Reg) -> CastTarget {
|
||||
CastTarget::from(Uniform::from(unit))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uniform> for CastTarget {
|
||||
fn from(uniform: Uniform) -> CastTarget {
|
||||
CastTarget { prefix: [None; 8], prefix_chunk: Size::ZERO, rest: uniform }
|
||||
}
|
||||
}
|
||||
|
||||
impl CastTarget {
|
||||
pub fn pair(a: Reg, b: Reg) -> CastTarget {
|
||||
CastTarget {
|
||||
prefix: [Some(a.kind), None, None, None, None, None, None, None],
|
||||
prefix_chunk: a.size,
|
||||
rest: Uniform::from(b),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
|
||||
(self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
|
||||
.align_to(self.rest.align(cx))
|
||||
+ self.rest.total
|
||||
}
|
||||
|
||||
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
|
||||
self.prefix
|
||||
.iter()
|
||||
.filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
|
||||
.fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
|
||||
acc.max(align)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Return value from the `homogeneous_aggregate` test function.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum HomogeneousAggregate {
|
||||
/// Yes, all the "leaf fields" of this struct are passed in the
|
||||
/// same way (specified in the `Reg` value).
|
||||
Homogeneous(Reg),
|
||||
|
||||
/// There are no leaf fields at all.
|
||||
NoData,
|
||||
}
|
||||
|
||||
/// Error from the `homogeneous_aggregate` test function, indicating
|
||||
/// there are distinct leaf fields passed in different ways,
|
||||
/// or this is uninhabited.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Heterogeneous;
|
||||
|
||||
impl HomogeneousAggregate {
|
||||
/// If this is a homogeneous aggregate, returns the homogeneous
|
||||
/// unit, else `None`.
|
||||
pub fn unit(self) -> Option<Reg> {
|
||||
match self {
|
||||
HomogeneousAggregate::Homogeneous(reg) => Some(reg),
|
||||
HomogeneousAggregate::NoData => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
|
||||
/// the same `struct`. Only succeeds if only one of them has any data,
|
||||
/// or both units are identical.
|
||||
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
|
||||
match (self, other) {
|
||||
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
|
||||
|
||||
(HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
|
||||
if a != b {
|
||||
return Err(Heterogeneous);
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||
fn is_aggregate(&self) -> bool {
|
||||
match self.abi {
|
||||
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Homogeneous` if this layout is an aggregate containing fields of
|
||||
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
|
||||
/// special-cased in ABIs.
|
||||
///
|
||||
/// Note: We generally ignore fields of zero-sized type when computing
|
||||
/// this value (see #56877).
|
||||
///
|
||||
/// This is public so that it can be used in unit tests, but
|
||||
/// should generally only be relevant to the ABI details of
|
||||
/// specific targets.
|
||||
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = Self>,
|
||||
{
|
||||
match self.abi {
|
||||
Abi::Uninhabited => Err(Heterogeneous),
|
||||
|
||||
// The primitive for this algorithm.
|
||||
Abi::Scalar(ref scalar) => {
|
||||
let kind = match scalar.value {
|
||||
abi::Int(..) | abi::Pointer => RegKind::Integer,
|
||||
abi::F32 | abi::F64 => RegKind::Float,
|
||||
};
|
||||
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
|
||||
}
|
||||
|
||||
Abi::Vector { .. } => {
|
||||
assert!(!self.is_zst());
|
||||
Ok(HomogeneousAggregate::Homogeneous(Reg {
|
||||
kind: RegKind::Vector,
|
||||
size: self.size,
|
||||
}))
|
||||
}
|
||||
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
|
||||
// Helper for computing `homogeneous_aggregate`, allowing a custom
|
||||
// starting offset (used below for handling variants).
|
||||
let from_fields_at =
|
||||
|layout: Self,
|
||||
start: Size|
|
||||
-> Result<(HomogeneousAggregate, Size), Heterogeneous> {
|
||||
let is_union = match layout.fields {
|
||||
FieldsShape::Primitive => {
|
||||
unreachable!("aggregates can't have `FieldsShape::Primitive`")
|
||||
}
|
||||
FieldsShape::Array { count, .. } => {
|
||||
assert_eq!(start, Size::ZERO);
|
||||
|
||||
let result = if count > 0 {
|
||||
layout.field(cx, 0).homogeneous_aggregate(cx)?
|
||||
} else {
|
||||
HomogeneousAggregate::NoData
|
||||
};
|
||||
return Ok((result, layout.size));
|
||||
}
|
||||
FieldsShape::Union(_) => true,
|
||||
FieldsShape::Arbitrary { .. } => false,
|
||||
};
|
||||
|
||||
let mut result = HomogeneousAggregate::NoData;
|
||||
let mut total = start;
|
||||
|
||||
for i in 0..layout.fields.count() {
|
||||
if !is_union && total != layout.fields.offset(i) {
|
||||
return Err(Heterogeneous);
|
||||
}
|
||||
|
||||
let field = layout.field(cx, i);
|
||||
|
||||
result = result.merge(field.homogeneous_aggregate(cx)?)?;
|
||||
|
||||
// Keep track of the offset (without padding).
|
||||
let size = field.size;
|
||||
if is_union {
|
||||
total = total.max(size);
|
||||
} else {
|
||||
total += size;
|
||||
}
|
||||
}
|
||||
|
||||
Ok((result, total))
|
||||
};
|
||||
|
||||
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
|
||||
|
||||
match &self.variants {
|
||||
abi::Variants::Single { .. } => {}
|
||||
abi::Variants::Multiple { variants, .. } => {
|
||||
// Treat enum variants like union members.
|
||||
// HACK(eddyb) pretend the `enum` field (discriminant)
|
||||
// is at the start of every variant (otherwise the gap
|
||||
// at the start of all variants would disqualify them).
|
||||
//
|
||||
// NB: for all tagged `enum`s (which include all non-C-like
|
||||
// `enum`s with defined FFI representation), this will
|
||||
// match the homogeneous computation on the equivalent
|
||||
// `struct { tag; union { variant1; ... } }` and/or
|
||||
// `union { struct { tag; variant1; } ... }`
|
||||
// (the offsets of variant fields should be identical
|
||||
// between the two for either to be a homogeneous aggregate).
|
||||
let variant_start = total;
|
||||
for variant_idx in variants.indices() {
|
||||
let (variant_result, variant_total) =
|
||||
from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
|
||||
|
||||
result = result.merge(variant_result)?;
|
||||
total = total.max(variant_total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There needs to be no padding.
|
||||
if total != self.size {
|
||||
Err(Heterogeneous)
|
||||
} else {
|
||||
match result {
|
||||
HomogeneousAggregate::Homogeneous(_) => {
|
||||
assert_ne!(total, Size::ZERO);
|
||||
}
|
||||
HomogeneousAggregate::NoData => {
|
||||
assert_eq!(total, Size::ZERO);
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about how to pass an argument to,
|
||||
/// or return a value from, a function, under some ABI.
|
||||
#[derive(Debug)]
|
||||
pub struct ArgAbi<'a, Ty> {
|
||||
pub layout: TyAndLayout<'a, Ty>,
|
||||
|
||||
/// Dummy argument, which is emitted before the real argument.
|
||||
pub pad: Option<Reg>,
|
||||
|
||||
pub mode: PassMode,
|
||||
}
|
||||
|
||||
impl<'a, Ty> ArgAbi<'a, Ty> {
|
||||
pub fn new(layout: TyAndLayout<'a, Ty>) -> Self {
|
||||
ArgAbi { layout, pad: None, mode: PassMode::Direct(ArgAttributes::new()) }
|
||||
}
|
||||
|
||||
pub fn make_indirect(&mut self) {
|
||||
assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
|
||||
|
||||
// Start with fresh attributes for the pointer.
|
||||
let mut attrs = ArgAttributes::new();
|
||||
|
||||
// For non-immediate arguments the callee gets its own copy of
|
||||
// the value on the stack, so there are no aliases. It's also
|
||||
// program-invisible so can't possibly capture
|
||||
attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull);
|
||||
attrs.pointee_size = self.layout.size;
|
||||
// FIXME(eddyb) We should be doing this, but at least on
|
||||
// i686-pc-windows-msvc, it results in wrong stack offsets.
|
||||
// attrs.pointee_align = Some(self.layout.align.abi);
|
||||
|
||||
let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
|
||||
|
||||
self.mode = PassMode::Indirect(attrs, extra_attrs);
|
||||
}
|
||||
|
||||
pub fn make_indirect_byval(&mut self) {
|
||||
self.make_indirect();
|
||||
match self.mode {
|
||||
PassMode::Indirect(ref mut attrs, _) => {
|
||||
attrs.set(ArgAttribute::ByVal);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend_integer_width_to(&mut self, bits: u64) {
|
||||
// Only integers have signedness
|
||||
if let Abi::Scalar(ref scalar) = self.layout.abi {
|
||||
if let abi::Int(i, signed) = scalar.value {
|
||||
if i.size().bits() < bits {
|
||||
if let PassMode::Direct(ref mut attrs) = self.mode {
|
||||
attrs.set(if signed { ArgAttribute::SExt } else { ArgAttribute::ZExt });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
|
||||
assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
|
||||
self.mode = PassMode::Cast(target.into());
|
||||
}
|
||||
|
||||
pub fn pad_with(&mut self, reg: Reg) {
|
||||
self.pad = Some(reg);
|
||||
}
|
||||
|
||||
pub fn is_indirect(&self) -> bool {
|
||||
match self.mode {
|
||||
PassMode::Indirect(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_sized_indirect(&self) -> bool {
|
||||
match self.mode {
|
||||
PassMode::Indirect(_, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unsized_indirect(&self) -> bool {
|
||||
match self.mode {
|
||||
PassMode::Indirect(_, Some(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ignore(&self) -> bool {
|
||||
match self.mode {
|
||||
PassMode::Ignore => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Conv {
|
||||
// General language calling conventions, for which every target
|
||||
// should have its own backend (e.g. LLVM) support.
|
||||
C,
|
||||
Rust,
|
||||
|
||||
// Target-specific calling conventions.
|
||||
ArmAapcs,
|
||||
|
||||
Msp430Intr,
|
||||
|
||||
PtxKernel,
|
||||
|
||||
X86Fastcall,
|
||||
X86Intr,
|
||||
X86Stdcall,
|
||||
X86ThisCall,
|
||||
X86VectorCall,
|
||||
|
||||
X86_64SysV,
|
||||
X86_64Win64,
|
||||
|
||||
AmdGpuKernel,
|
||||
AvrInterrupt,
|
||||
AvrNonBlockingInterrupt,
|
||||
}
|
||||
|
||||
/// Metadata describing how the arguments to a native function
|
||||
/// should be passed in order to respect the native ABI.
|
||||
///
|
||||
/// I will do my best to describe this structure, but these
|
||||
/// comments are reverse-engineered and may be inaccurate. -NDM
|
||||
#[derive(Debug)]
|
||||
pub struct FnAbi<'a, Ty> {
|
||||
/// The LLVM types of each argument.
|
||||
pub args: Vec<ArgAbi<'a, Ty>>,
|
||||
|
||||
/// LLVM return type.
|
||||
pub ret: ArgAbi<'a, Ty>,
|
||||
|
||||
pub c_variadic: bool,
|
||||
|
||||
/// The count of non-variadic arguments.
|
||||
///
|
||||
/// Should only be different from args.len() when c_variadic is true.
|
||||
/// This can be used to know whether an argument is variadic or not.
|
||||
pub fixed_count: usize,
|
||||
|
||||
pub conv: Conv,
|
||||
|
||||
pub can_unwind: bool,
|
||||
}
|
||||
|
||||
impl<'a, Ty> FnAbi<'a, Ty> {
|
||||
pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
match &cx.target_spec().arch[..] {
|
||||
"x86" => {
|
||||
let flavor = if abi == spec::abi::Abi::Fastcall {
|
||||
x86::Flavor::Fastcall
|
||||
} else {
|
||||
x86::Flavor::General
|
||||
};
|
||||
x86::compute_abi_info(cx, self, flavor);
|
||||
}
|
||||
"x86_64" => {
|
||||
if abi == spec::abi::Abi::SysV64 {
|
||||
x86_64::compute_abi_info(cx, self);
|
||||
} else if abi == spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows {
|
||||
x86_win64::compute_abi_info(self);
|
||||
} else {
|
||||
x86_64::compute_abi_info(cx, self);
|
||||
}
|
||||
}
|
||||
"aarch64" => aarch64::compute_abi_info(cx, self),
|
||||
"amdgpu" => amdgpu::compute_abi_info(cx, self),
|
||||
"arm" => arm::compute_abi_info(cx, self),
|
||||
"avr" => avr::compute_abi_info(self),
|
||||
"mips" => mips::compute_abi_info(cx, self),
|
||||
"mips64" => mips64::compute_abi_info(cx, self),
|
||||
"powerpc" => powerpc::compute_abi_info(self),
|
||||
"powerpc64" => powerpc64::compute_abi_info(cx, self),
|
||||
"s390x" => s390x::compute_abi_info(cx, self),
|
||||
"msp430" => msp430::compute_abi_info(self),
|
||||
"sparc" => sparc::compute_abi_info(cx, self),
|
||||
"sparc64" => sparc64::compute_abi_info(cx, self),
|
||||
"nvptx" => nvptx::compute_abi_info(self),
|
||||
"nvptx64" => nvptx64::compute_abi_info(self),
|
||||
"hexagon" => hexagon::compute_abi_info(self),
|
||||
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
|
||||
"wasm32" if cx.target_spec().target_os != "emscripten" => {
|
||||
wasm32_bindgen_compat::compute_abi_info(self)
|
||||
}
|
||||
"wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
|
||||
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
|
||||
}
|
||||
|
||||
if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
|
||||
attrs.set(ArgAttribute::StructRet);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
39
compiler/rustc_target/src/abi/call/msp430.rs
Normal file
39
compiler/rustc_target/src/abi/call/msp430.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Reference: MSP430 Embedded Application Binary Interface
|
||||
// http://www.ti.com/lit/an/slaa534/slaa534.pdf
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
|
||||
// 3.5 Structures or Unions Passed and Returned by Reference
|
||||
//
|
||||
// "Structures (including classes) and unions larger than 32 bits are passed and
|
||||
// returned by reference. To pass a structure or union by reference, the caller
|
||||
// places its address in the appropriate location: either in a register or on
|
||||
// the stack, according to its position in the argument list. (..)"
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 {
|
||||
ret.make_indirect();
|
||||
} else {
|
||||
ret.extend_integer_width_to(16);
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
arg.extend_integer_width_to(16);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
}
|
||||
}
|
33
compiler/rustc_target/src/abi/call/nvptx.rs
Normal file
33
compiler/rustc_target/src/abi/call/nvptx.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Reference: PTX Writer's Guide to Interoperability
|
||||
// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 {
|
||||
ret.make_indirect();
|
||||
} else {
|
||||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
}
|
||||
}
|
33
compiler/rustc_target/src/abi/call/nvptx64.rs
Normal file
33
compiler/rustc_target/src/abi/call/nvptx64.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Reference: PTX Writer's Guide to Interoperability
|
||||
// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 {
|
||||
ret.make_indirect();
|
||||
} else {
|
||||
ret.extend_integer_width_to(64);
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
arg.extend_integer_width_to(64);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
}
|
||||
}
|
30
compiler/rustc_target/src/abi/call/powerpc.rs
Normal file
30
compiler/rustc_target/src/abi/call/powerpc.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
if ret.layout.is_aggregate() {
|
||||
ret.make_indirect();
|
||||
} else {
|
||||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.make_indirect();
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
}
|
||||
}
|
141
compiler/rustc_target/src/abi/call/powerpc64.rs
Normal file
141
compiler/rustc_target/src/abi/call/powerpc64.rs
Normal file
|
@ -0,0 +1,141 @@
|
|||
// FIXME:
|
||||
// Alignment of 128 bit types is not currently handled, this will
|
||||
// need to be fixed when PowerPC vector support is added.
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
|
||||
use crate::abi::{Endian, HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum ABI {
|
||||
ELFv1, // original ABI used for powerpc64 (big-endian)
|
||||
ELFv2, // newer ABI used for powerpc64le and musl (both endians)
|
||||
}
|
||||
use ABI::*;
|
||||
|
||||
fn is_homogeneous_aggregate<'a, Ty, C>(
|
||||
cx: &C,
|
||||
arg: &mut ArgAbi<'a, Ty>,
|
||||
abi: ABI,
|
||||
) -> Option<Uniform>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
|
||||
// ELFv1 only passes one-member aggregates transparently.
|
||||
// ELFv2 passes up to eight uniquely addressable members.
|
||||
if (abi == ELFv1 && arg.layout.size > unit.size)
|
||||
|| arg.layout.size > unit.size.checked_mul(8, cx).unwrap()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let valid_unit = match unit.kind {
|
||||
RegKind::Integer => false,
|
||||
RegKind::Float => true,
|
||||
RegKind::Vector => arg.layout.size.bits() == 128,
|
||||
};
|
||||
|
||||
valid_unit.then_some(Uniform { unit, total: arg.layout.size })
|
||||
})
|
||||
}
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi: ABI)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(64);
|
||||
return;
|
||||
}
|
||||
|
||||
// The ELFv1 ABI doesn't return aggregates in registers
|
||||
if abi == ELFv1 {
|
||||
ret.make_indirect();
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, ret, abi) {
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
|
||||
let size = ret.layout.size;
|
||||
let bits = size.bits();
|
||||
if bits <= 128 {
|
||||
let unit = if cx.data_layout().endian == Endian::Big {
|
||||
Reg { kind: RegKind::Integer, size }
|
||||
} else if bits <= 8 {
|
||||
Reg::i8()
|
||||
} else if bits <= 16 {
|
||||
Reg::i16()
|
||||
} else if bits <= 32 {
|
||||
Reg::i32()
|
||||
} else {
|
||||
Reg::i64()
|
||||
};
|
||||
|
||||
ret.cast_to(Uniform { unit, total: size });
|
||||
return;
|
||||
}
|
||||
|
||||
ret.make_indirect();
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_aggregate() {
|
||||
arg.extend_integer_width_to(64);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, arg, abi) {
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
|
||||
let size = arg.layout.size;
|
||||
let (unit, total) = if size.bits() <= 64 {
|
||||
// Aggregates smaller than a doubleword should appear in
|
||||
// the least-significant bits of the parameter doubleword.
|
||||
(Reg { kind: RegKind::Integer, size }, size)
|
||||
} else {
|
||||
// Aggregates larger than a doubleword should be padded
|
||||
// at the tail to fill out a whole number of doublewords.
|
||||
let reg_i64 = Reg::i64();
|
||||
(reg_i64, size.align_to(reg_i64.align(cx)))
|
||||
};
|
||||
|
||||
arg.cast_to(Uniform { unit, total });
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
let abi = if cx.target_spec().target_env == "musl" {
|
||||
ELFv2
|
||||
} else {
|
||||
match cx.data_layout().endian {
|
||||
Endian::Big => ELFv1,
|
||||
Endian::Little => ELFv2,
|
||||
}
|
||||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret, abi);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg, abi);
|
||||
}
|
||||
}
|
356
compiler/rustc_target/src/abi/call/riscv.rs
Normal file
356
compiler/rustc_target/src/abi/call/riscv.rs
Normal file
|
@ -0,0 +1,356 @@
|
|||
// Reference: RISC-V ELF psABI specification
|
||||
// https://github.com/riscv/riscv-elf-psabi-doc
|
||||
//
|
||||
// Reference: Clang RISC-V ELF psABI lowering code
|
||||
// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
|
||||
|
||||
use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
|
||||
use crate::abi::{
|
||||
self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods,
|
||||
};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum RegPassKind {
|
||||
Float(Reg),
|
||||
Integer(Reg),
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum FloatConv {
|
||||
FloatPair(Reg, Reg),
|
||||
Float(Reg),
|
||||
MixedPair(Reg, Reg),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct CannotUseFpConv;
|
||||
|
||||
fn is_riscv_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool {
|
||||
match arg.layout.abi {
|
||||
Abi::Vector { .. } => true,
|
||||
_ => arg.layout.is_aggregate(),
|
||||
}
|
||||
}
|
||||
|
||||
fn should_use_fp_conv_helper<'a, Ty, C>(
|
||||
cx: &C,
|
||||
arg_layout: &TyAndLayout<'a, Ty>,
|
||||
xlen: u64,
|
||||
flen: u64,
|
||||
field1_kind: &mut RegPassKind,
|
||||
field2_kind: &mut RegPassKind,
|
||||
) -> Result<(), CannotUseFpConv>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
|
||||
{
|
||||
match arg_layout.abi {
|
||||
Abi::Scalar(ref scalar) => match scalar.value {
|
||||
abi::Int(..) | abi::Pointer => {
|
||||
if arg_layout.size.bits() > xlen {
|
||||
return Err(CannotUseFpConv);
|
||||
}
|
||||
match (*field1_kind, *field2_kind) {
|
||||
(RegPassKind::Unknown, _) => {
|
||||
*field1_kind = RegPassKind::Integer(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size: arg_layout.size,
|
||||
});
|
||||
}
|
||||
(RegPassKind::Float(_), RegPassKind::Unknown) => {
|
||||
*field2_kind = RegPassKind::Integer(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size: arg_layout.size,
|
||||
});
|
||||
}
|
||||
_ => return Err(CannotUseFpConv),
|
||||
}
|
||||
}
|
||||
abi::F32 | abi::F64 => {
|
||||
if arg_layout.size.bits() > flen {
|
||||
return Err(CannotUseFpConv);
|
||||
}
|
||||
match (*field1_kind, *field2_kind) {
|
||||
(RegPassKind::Unknown, _) => {
|
||||
*field1_kind =
|
||||
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
|
||||
}
|
||||
(_, RegPassKind::Unknown) => {
|
||||
*field2_kind =
|
||||
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
|
||||
}
|
||||
_ => return Err(CannotUseFpConv),
|
||||
}
|
||||
}
|
||||
},
|
||||
Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv),
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields {
|
||||
FieldsShape::Primitive => {
|
||||
unreachable!("aggregates can't have `FieldsShape::Primitive`")
|
||||
}
|
||||
FieldsShape::Union(_) => {
|
||||
if !arg_layout.is_zst() {
|
||||
return Err(CannotUseFpConv);
|
||||
}
|
||||
}
|
||||
FieldsShape::Array { count, .. } => {
|
||||
for _ in 0..count {
|
||||
let elem_layout = arg_layout.field(cx, 0);
|
||||
should_use_fp_conv_helper(
|
||||
cx,
|
||||
&elem_layout,
|
||||
xlen,
|
||||
flen,
|
||||
field1_kind,
|
||||
field2_kind,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
FieldsShape::Arbitrary { .. } => {
|
||||
match arg_layout.variants {
|
||||
abi::Variants::Multiple { .. } => return Err(CannotUseFpConv),
|
||||
abi::Variants::Single { .. } => (),
|
||||
}
|
||||
for i in arg_layout.fields.index_by_increasing_offset() {
|
||||
let field = arg_layout.field(cx, i);
|
||||
should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn should_use_fp_conv<'a, Ty, C>(
|
||||
cx: &C,
|
||||
arg: &TyAndLayout<'a, Ty>,
|
||||
xlen: u64,
|
||||
flen: u64,
|
||||
) -> Option<FloatConv>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
|
||||
{
|
||||
let mut field1_kind = RegPassKind::Unknown;
|
||||
let mut field2_kind = RegPassKind::Unknown;
|
||||
if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() {
|
||||
return None;
|
||||
}
|
||||
match (field1_kind, field2_kind) {
|
||||
(RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)),
|
||||
(RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)),
|
||||
(RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)),
|
||||
(RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, xlen: u64, flen: u64) -> bool
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
|
||||
{
|
||||
if let Some(conv) = should_use_fp_conv(cx, &arg.layout, xlen, flen) {
|
||||
match conv {
|
||||
FloatConv::Float(f) => {
|
||||
arg.cast_to(f);
|
||||
}
|
||||
FloatConv::FloatPair(l, r) => {
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
}
|
||||
FloatConv::MixedPair(l, r) => {
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
let total = arg.layout.size;
|
||||
|
||||
// "Scalars wider than 2✕XLEN are passed by reference and are replaced in
|
||||
// the argument list with the address."
|
||||
// "Aggregates larger than 2✕XLEN bits are passed by reference and are
|
||||
// replaced in the argument list with the address, as are C++ aggregates
|
||||
// with nontrivial copy constructors, destructors, or vtables."
|
||||
if total.bits() > 2 * xlen {
|
||||
// We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN.
|
||||
if is_riscv_aggregate(arg) {
|
||||
arg.make_indirect();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let xlen_reg = match xlen {
|
||||
32 => Reg::i32(),
|
||||
64 => Reg::i64(),
|
||||
_ => unreachable!("Unsupported XLEN: {}", xlen),
|
||||
};
|
||||
if is_riscv_aggregate(arg) {
|
||||
if total.bits() <= xlen {
|
||||
arg.cast_to(xlen_reg);
|
||||
} else {
|
||||
arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// "When passed in registers, scalars narrower than XLEN bits are widened
|
||||
// according to the sign of their type up to 32 bits, then sign-extended to
|
||||
// XLEN bits."
|
||||
extend_integer_width(arg, xlen);
|
||||
false
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(
|
||||
cx: &C,
|
||||
arg: &mut ArgAbi<'a, Ty>,
|
||||
xlen: u64,
|
||||
flen: u64,
|
||||
is_vararg: bool,
|
||||
avail_gprs: &mut u64,
|
||||
avail_fprs: &mut u64,
|
||||
) where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
|
||||
{
|
||||
if !is_vararg {
|
||||
match should_use_fp_conv(cx, &arg.layout, xlen, flen) {
|
||||
Some(FloatConv::Float(f)) if *avail_fprs >= 1 => {
|
||||
*avail_fprs -= 1;
|
||||
arg.cast_to(f);
|
||||
return;
|
||||
}
|
||||
Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => {
|
||||
*avail_fprs -= 2;
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
return;
|
||||
}
|
||||
Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => {
|
||||
*avail_gprs -= 1;
|
||||
*avail_fprs -= 1;
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let total = arg.layout.size;
|
||||
let align = arg.layout.align.abi.bits();
|
||||
|
||||
// "Scalars wider than 2✕XLEN are passed by reference and are replaced in
|
||||
// the argument list with the address."
|
||||
// "Aggregates larger than 2✕XLEN bits are passed by reference and are
|
||||
// replaced in the argument list with the address, as are C++ aggregates
|
||||
// with nontrivial copy constructors, destructors, or vtables."
|
||||
if total.bits() > 2 * xlen {
|
||||
// We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN.
|
||||
if is_riscv_aggregate(arg) {
|
||||
arg.make_indirect();
|
||||
}
|
||||
if *avail_gprs >= 1 {
|
||||
*avail_gprs -= 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let double_xlen_reg = match xlen {
|
||||
32 => Reg::i64(),
|
||||
64 => Reg::i128(),
|
||||
_ => unreachable!("Unsupported XLEN: {}", xlen),
|
||||
};
|
||||
|
||||
let xlen_reg = match xlen {
|
||||
32 => Reg::i32(),
|
||||
64 => Reg::i64(),
|
||||
_ => unreachable!("Unsupported XLEN: {}", xlen),
|
||||
};
|
||||
|
||||
if total.bits() > xlen {
|
||||
let align_regs = align > xlen;
|
||||
if is_riscv_aggregate(arg) {
|
||||
arg.cast_to(Uniform {
|
||||
unit: if align_regs { double_xlen_reg } else { xlen_reg },
|
||||
total: Size::from_bits(xlen * 2),
|
||||
});
|
||||
}
|
||||
if align_regs && is_vararg {
|
||||
*avail_gprs -= *avail_gprs % 2;
|
||||
}
|
||||
if *avail_gprs >= 2 {
|
||||
*avail_gprs -= 2;
|
||||
} else {
|
||||
*avail_gprs = 0;
|
||||
}
|
||||
return;
|
||||
} else if is_riscv_aggregate(arg) {
|
||||
arg.cast_to(xlen_reg);
|
||||
if *avail_gprs >= 1 {
|
||||
*avail_gprs -= 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// "When passed in registers, scalars narrower than XLEN bits are widened
|
||||
// according to the sign of their type up to 32 bits, then sign-extended to
|
||||
// XLEN bits."
|
||||
if *avail_gprs >= 1 {
|
||||
extend_integer_width(arg, xlen);
|
||||
*avail_gprs -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) {
|
||||
if let Abi::Scalar(ref scalar) = arg.layout.abi {
|
||||
if let abi::Int(i, _) = scalar.value {
|
||||
// 32-bit integers are always sign-extended
|
||||
if i.size().bits() == 32 && xlen > 32 {
|
||||
if let PassMode::Direct(ref mut attrs) = arg.mode {
|
||||
attrs.set(ArgAttribute::SExt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arg.extend_integer_width_to(xlen);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
let flen = match &cx.target_spec().options.llvm_abiname[..] {
|
||||
"ilp32f" | "lp64f" => 32,
|
||||
"ilp32d" | "lp64d" => 64,
|
||||
_ => 0,
|
||||
};
|
||||
let xlen = cx.data_layout().pointer_size.bits();
|
||||
|
||||
let mut avail_gprs = 8;
|
||||
let mut avail_fprs = 8;
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
if classify_ret(cx, &mut fn_abi.ret, xlen, flen) {
|
||||
avail_gprs -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i, arg) in fn_abi.args.iter_mut().enumerate() {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(
|
||||
cx,
|
||||
arg,
|
||||
xlen,
|
||||
flen,
|
||||
i >= fn_abi.fixed_count,
|
||||
&mut avail_gprs,
|
||||
&mut avail_fprs,
|
||||
);
|
||||
}
|
||||
}
|
79
compiler/rustc_target/src/abi/call/s390x.rs
Normal file
79
compiler/rustc_target/src/abi/call/s390x.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
// FIXME: The assumes we're using the non-vector ABI, i.e., compiling
|
||||
// for a pre-z13 machine or using -mno-vx.
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi, Reg};
|
||||
use crate::abi::{self, HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
fn classify_ret<'a, Ty, C>(ret: &mut ArgAbi<'_, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
|
||||
ret.extend_integer_width_to(64);
|
||||
} else {
|
||||
ret.make_indirect();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
match layout.abi {
|
||||
abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
|
||||
abi::Abi::Aggregate { .. } => {
|
||||
if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
|
||||
is_single_fp_element(cx, layout.field(cx, 0))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 {
|
||||
arg.extend_integer_width_to(64);
|
||||
return;
|
||||
}
|
||||
|
||||
if is_single_fp_element(cx, arg.layout) {
|
||||
match arg.layout.size.bytes() {
|
||||
4 => arg.cast_to(Reg::f32()),
|
||||
8 => arg.cast_to(Reg::f64()),
|
||||
_ => arg.make_indirect(),
|
||||
}
|
||||
} else {
|
||||
match arg.layout.size.bytes() {
|
||||
1 => arg.cast_to(Reg::i8()),
|
||||
2 => arg.cast_to(Reg::i16()),
|
||||
4 => arg.cast_to(Reg::i32()),
|
||||
8 => arg.cast_to(Reg::i64()),
|
||||
_ => arg.make_indirect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
54
compiler/rustc_target/src/abi/call/sparc.rs
Normal file
54
compiler/rustc_target/src/abi/call/sparc.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, Size, TyAndLayoutMethods};
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(32);
|
||||
} else {
|
||||
ret.make_indirect();
|
||||
*offset += cx.data_layout().pointer_size;
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty> + HasDataLayout,
|
||||
{
|
||||
let dl = cx.data_layout();
|
||||
let size = arg.layout.size;
|
||||
let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align).abi;
|
||||
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.cast_to(Uniform { unit: Reg::i32(), total: size });
|
||||
if !offset.is_aligned(align) {
|
||||
arg.pad_with(Reg::i32());
|
||||
}
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
*offset = offset.align_to(align) + size.align_to(align);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty> + HasDataLayout,
|
||||
{
|
||||
let mut offset = Size::ZERO;
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret, &mut offset);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg, &mut offset);
|
||||
}
|
||||
}
|
92
compiler/rustc_target/src/abi/call/sparc64.rs
Normal file
92
compiler/rustc_target/src/abi/call/sparc64.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
// FIXME: This needs an audit for correctness and completeness.
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
|
||||
// Ensure we have at most eight uniquely addressable members.
|
||||
if arg.layout.size > unit.size.checked_mul(8, cx).unwrap() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let valid_unit = match unit.kind {
|
||||
RegKind::Integer => false,
|
||||
RegKind::Float => true,
|
||||
RegKind::Vector => arg.layout.size.bits() == 128,
|
||||
};
|
||||
|
||||
valid_unit.then_some(Uniform { unit, total: arg.layout.size })
|
||||
})
|
||||
}
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !ret.layout.is_aggregate() {
|
||||
ret.extend_integer_width_to(64);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
|
||||
ret.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
let size = ret.layout.size;
|
||||
let bits = size.bits();
|
||||
if bits <= 256 {
|
||||
let unit = Reg::i64();
|
||||
ret.cast_to(Uniform { unit, total: size });
|
||||
return;
|
||||
}
|
||||
|
||||
// don't return aggregates in registers
|
||||
ret.make_indirect();
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !arg.layout.is_aggregate() {
|
||||
arg.extend_integer_width_to(64);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
|
||||
arg.cast_to(uniform);
|
||||
return;
|
||||
}
|
||||
|
||||
let total = arg.layout.size;
|
||||
if total.bits() > 128 {
|
||||
arg.make_indirect();
|
||||
return;
|
||||
}
|
||||
|
||||
arg.cast_to(Uniform { unit: Reg::i64(), total });
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
62
compiler/rustc_target/src/abi/call/wasm32.rs
Normal file
62
compiler/rustc_target/src/abi/call/wasm32.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi, Uniform};
|
||||
use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if val.layout.is_aggregate() {
|
||||
if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) {
|
||||
let size = val.layout.size;
|
||||
if unit.size == size {
|
||||
val.cast_to(Uniform { unit, total: size });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
ret.extend_integer_width_to(32);
|
||||
if ret.layout.is_aggregate() {
|
||||
if !unwrap_trivial_aggregate(cx, ret) {
|
||||
ret.make_indirect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
arg.extend_integer_width_to(32);
|
||||
if arg.layout.is_aggregate() {
|
||||
if !unwrap_trivial_aggregate(cx, arg) {
|
||||
arg.make_indirect_byval();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(cx, &mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
29
compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs
Normal file
29
compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
// This is not and has never been a correct C ABI for WebAssembly, but
|
||||
// for a long time this was the C ABI that Rust used. wasm-bindgen
|
||||
// depends on ABI details for this ABI and is incompatible with the
|
||||
// correct C ABI, so this ABI is being kept around until wasm-bindgen
|
||||
// can be fixed to work with the correct ABI. See #63649 for further
|
||||
// discussion.
|
||||
|
||||
use crate::abi::call::{ArgAbi, FnAbi};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg(arg);
|
||||
}
|
||||
}
|
130
compiler/rustc_target/src/abi/call/x86.rs
Normal file
130
compiler/rustc_target/src/abi/call/x86.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
|
||||
use crate::abi::{self, HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum Flavor {
|
||||
General,
|
||||
Fastcall,
|
||||
}
|
||||
|
||||
fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
match layout.abi {
|
||||
abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
|
||||
abi::Abi::Aggregate { .. } => {
|
||||
if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
|
||||
is_single_fp_element(cx, layout.field(cx, 0))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
if fn_abi.ret.layout.is_aggregate() {
|
||||
// Returning a structure. Most often, this will use
|
||||
// a hidden first argument. On some platforms, though,
|
||||
// small structs are returned as integers.
|
||||
//
|
||||
// Some links:
|
||||
// http://www.angelcode.com/dev/callconv/callconv.html
|
||||
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
|
||||
let t = cx.target_spec();
|
||||
if t.options.abi_return_struct_as_int {
|
||||
// According to Clang, everyone but MSVC returns single-element
|
||||
// float aggregates directly in a floating-point register.
|
||||
if !t.options.is_like_msvc && is_single_fp_element(cx, fn_abi.ret.layout) {
|
||||
match fn_abi.ret.layout.size.bytes() {
|
||||
4 => fn_abi.ret.cast_to(Reg::f32()),
|
||||
8 => fn_abi.ret.cast_to(Reg::f64()),
|
||||
_ => fn_abi.ret.make_indirect(),
|
||||
}
|
||||
} else {
|
||||
match fn_abi.ret.layout.size.bytes() {
|
||||
1 => fn_abi.ret.cast_to(Reg::i8()),
|
||||
2 => fn_abi.ret.cast_to(Reg::i16()),
|
||||
4 => fn_abi.ret.cast_to(Reg::i32()),
|
||||
8 => fn_abi.ret.cast_to(Reg::i64()),
|
||||
_ => fn_abi.ret.make_indirect(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fn_abi.ret.make_indirect();
|
||||
}
|
||||
} else {
|
||||
fn_abi.ret.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
if arg.layout.is_aggregate() {
|
||||
arg.make_indirect_byval();
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
||||
if flavor == Flavor::Fastcall {
|
||||
// Mark arguments as InReg like clang does it,
|
||||
// so our fastcall is compatible with C/C++ fastcall.
|
||||
|
||||
// Clang reference: lib/CodeGen/TargetInfo.cpp
|
||||
// See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
|
||||
|
||||
// IsSoftFloatABI is only set to true on ARM platforms,
|
||||
// which in turn can't be x86?
|
||||
|
||||
let mut free_regs = 2;
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
let attrs = match arg.mode {
|
||||
PassMode::Ignore | PassMode::Indirect(_, None) => continue,
|
||||
PassMode::Direct(ref mut attrs) => attrs,
|
||||
PassMode::Pair(..) | PassMode::Indirect(_, Some(_)) | PassMode::Cast(_) => {
|
||||
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
|
||||
}
|
||||
};
|
||||
|
||||
// At this point we know this must be a primitive of sorts.
|
||||
let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
|
||||
assert_eq!(unit.size, arg.layout.size);
|
||||
if unit.kind == RegKind::Float {
|
||||
continue;
|
||||
}
|
||||
|
||||
let size_in_regs = (arg.layout.size.bits() + 31) / 32;
|
||||
|
||||
if size_in_regs == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if size_in_regs > free_regs {
|
||||
break;
|
||||
}
|
||||
|
||||
free_regs -= size_in_regs;
|
||||
|
||||
if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
|
||||
attrs.set(ArgAttribute::InReg);
|
||||
}
|
||||
|
||||
if free_regs == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
248
compiler/rustc_target/src/abi/call/x86_64.rs
Normal file
248
compiler/rustc_target/src/abi/call/x86_64.rs
Normal file
|
@ -0,0 +1,248 @@
|
|||
// The classification code for the x86_64 ABI is taken from the clay language
|
||||
// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
|
||||
|
||||
use crate::abi::call::{ArgAbi, CastTarget, FnAbi, Reg, RegKind};
|
||||
use crate::abi::{self, Abi, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods};
|
||||
|
||||
/// Classification of "eightbyte" components.
|
||||
// N.B., the order of the variants is from general to specific,
|
||||
// such that `unify(a, b)` is the "smaller" of `a` and `b`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
enum Class {
|
||||
Int,
|
||||
Sse,
|
||||
SseUp,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Memory;
|
||||
|
||||
// Currently supported vector size (AVX-512).
|
||||
const LARGEST_VECTOR_SIZE: usize = 512;
|
||||
const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64;
|
||||
|
||||
fn classify_arg<'a, Ty, C>(
|
||||
cx: &C,
|
||||
arg: &ArgAbi<'a, Ty>,
|
||||
) -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
fn classify<'a, Ty, C>(
|
||||
cx: &C,
|
||||
layout: TyAndLayout<'a, Ty>,
|
||||
cls: &mut [Option<Class>],
|
||||
off: Size,
|
||||
) -> Result<(), Memory>
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
if !off.is_aligned(layout.align.abi) {
|
||||
if !layout.is_zst() {
|
||||
return Err(Memory);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut c = match layout.abi {
|
||||
Abi::Uninhabited => return Ok(()),
|
||||
|
||||
Abi::Scalar(ref scalar) => match scalar.value {
|
||||
abi::Int(..) | abi::Pointer => Class::Int,
|
||||
abi::F32 | abi::F64 => Class::Sse,
|
||||
},
|
||||
|
||||
Abi::Vector { .. } => Class::Sse,
|
||||
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
|
||||
for i in 0..layout.fields.count() {
|
||||
let field_off = off + layout.fields.offset(i);
|
||||
classify(cx, layout.field(cx, i), cls, field_off)?;
|
||||
}
|
||||
|
||||
match &layout.variants {
|
||||
abi::Variants::Single { .. } => {}
|
||||
abi::Variants::Multiple { variants, .. } => {
|
||||
// Treat enum variants like union members.
|
||||
for variant_idx in variants.indices() {
|
||||
classify(cx, layout.for_variant(cx, variant_idx), cls, off)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
|
||||
let first = (off.bytes() / 8) as usize;
|
||||
let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize;
|
||||
for cls in &mut cls[first..=last] {
|
||||
*cls = Some(cls.map_or(c, |old| old.min(c)));
|
||||
|
||||
// Everything after the first Sse "eightbyte"
|
||||
// component is the upper half of a register.
|
||||
if c == Class::Sse {
|
||||
c = Class::SseUp;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let n = ((arg.layout.size.bytes() + 7) / 8) as usize;
|
||||
if n > MAX_EIGHTBYTES {
|
||||
return Err(Memory);
|
||||
}
|
||||
|
||||
let mut cls = [None; MAX_EIGHTBYTES];
|
||||
classify(cx, arg.layout, &mut cls, Size::ZERO)?;
|
||||
if n > 2 {
|
||||
if cls[0] != Some(Class::Sse) {
|
||||
return Err(Memory);
|
||||
}
|
||||
if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) {
|
||||
return Err(Memory);
|
||||
}
|
||||
} else {
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
if cls[i] == Some(Class::SseUp) {
|
||||
cls[i] = Some(Class::Sse);
|
||||
} else if cls[i] == Some(Class::Sse) {
|
||||
i += 1;
|
||||
while i != n && cls[i] == Some(Class::SseUp) {
|
||||
i += 1;
|
||||
}
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(cls)
|
||||
}
|
||||
|
||||
fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg> {
|
||||
if *i >= cls.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match cls[*i] {
|
||||
None => None,
|
||||
Some(Class::Int) => {
|
||||
*i += 1;
|
||||
Some(if size.bytes() < 8 { Reg { kind: RegKind::Integer, size } } else { Reg::i64() })
|
||||
}
|
||||
Some(Class::Sse) => {
|
||||
let vec_len =
|
||||
1 + cls[*i + 1..].iter().take_while(|&&c| c == Some(Class::SseUp)).count();
|
||||
*i += vec_len;
|
||||
Some(if vec_len == 1 {
|
||||
match size.bytes() {
|
||||
4 => Reg::f32(),
|
||||
_ => Reg::f64(),
|
||||
}
|
||||
} else {
|
||||
Reg { kind: RegKind::Vector, size: Size::from_bytes(8) * (vec_len as u64) }
|
||||
})
|
||||
}
|
||||
Some(c) => unreachable!("reg_component: unhandled class {:?}", c),
|
||||
}
|
||||
}
|
||||
|
||||
fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
|
||||
let mut i = 0;
|
||||
let lo = reg_component(cls, &mut i, size).unwrap();
|
||||
let offset = Size::from_bytes(8) * (i as u64);
|
||||
let mut target = CastTarget::from(lo);
|
||||
if size > offset {
|
||||
if let Some(hi) = reg_component(cls, &mut i, size - offset) {
|
||||
target = CastTarget::pair(lo, hi);
|
||||
}
|
||||
}
|
||||
assert_eq!(reg_component(cls, &mut i, Size::ZERO), None);
|
||||
target
|
||||
}
|
||||
|
||||
const MAX_INT_REGS: usize = 6; // RDI, RSI, RDX, RCX, R8, R9
|
||||
const MAX_SSE_REGS: usize = 8; // XMM0-7
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAndLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
|
||||
{
|
||||
let mut int_regs = MAX_INT_REGS;
|
||||
let mut sse_regs = MAX_SSE_REGS;
|
||||
|
||||
let mut x86_64_arg_or_ret = |arg: &mut ArgAbi<'a, Ty>, is_arg: bool| {
|
||||
let mut cls_or_mem = classify_arg(cx, arg);
|
||||
|
||||
if is_arg {
|
||||
if let Ok(cls) = cls_or_mem {
|
||||
let mut needed_int = 0;
|
||||
let mut needed_sse = 0;
|
||||
for &c in &cls {
|
||||
match c {
|
||||
Some(Class::Int) => needed_int += 1,
|
||||
Some(Class::Sse) => needed_sse += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
match (int_regs.checked_sub(needed_int), sse_regs.checked_sub(needed_sse)) {
|
||||
(Some(left_int), Some(left_sse)) => {
|
||||
int_regs = left_int;
|
||||
sse_regs = left_sse;
|
||||
}
|
||||
_ => {
|
||||
// Not enough registers for this argument, so it will be
|
||||
// passed on the stack, but we only mark aggregates
|
||||
// explicitly as indirect `byval` arguments, as LLVM will
|
||||
// automatically put immediates on the stack itself.
|
||||
if arg.layout.is_aggregate() {
|
||||
cls_or_mem = Err(Memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match cls_or_mem {
|
||||
Err(Memory) => {
|
||||
if is_arg {
|
||||
arg.make_indirect_byval();
|
||||
} else {
|
||||
// `sret` parameter thus one less integer register available
|
||||
arg.make_indirect();
|
||||
// NOTE(eddyb) return is handled first, so no registers
|
||||
// should've been used yet.
|
||||
assert_eq!(int_regs, MAX_INT_REGS);
|
||||
int_regs -= 1;
|
||||
}
|
||||
}
|
||||
Ok(ref cls) => {
|
||||
// split into sized chunks passed individually
|
||||
if arg.layout.is_aggregate() {
|
||||
let size = arg.layout.size;
|
||||
arg.cast_to(cast_target(cls, size))
|
||||
} else {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
x86_64_arg_or_ret(&mut fn_abi.ret, false);
|
||||
}
|
||||
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
x86_64_arg_or_ret(arg, true);
|
||||
}
|
||||
}
|
40
compiler/rustc_target/src/abi/call/x86_win64.rs
Normal file
40
compiler/rustc_target/src/abi/call/x86_win64.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use crate::abi::call::{ArgAbi, FnAbi, Reg};
|
||||
use crate::abi::Abi;
|
||||
|
||||
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
|
||||
|
||||
pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
let fixup = |a: &mut ArgAbi<'_, Ty>| {
|
||||
match a.layout.abi {
|
||||
Abi::Uninhabited => {}
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => match a.layout.size.bits() {
|
||||
8 => a.cast_to(Reg::i8()),
|
||||
16 => a.cast_to(Reg::i16()),
|
||||
32 => a.cast_to(Reg::i32()),
|
||||
64 => a.cast_to(Reg::i64()),
|
||||
_ => a.make_indirect(),
|
||||
},
|
||||
Abi::Vector { .. } => {
|
||||
// FIXME(eddyb) there should be a size cap here
|
||||
// (probably what clang calls "illegal vectors").
|
||||
}
|
||||
Abi::Scalar(_) => {
|
||||
if a.layout.size.bytes() > 8 {
|
||||
a.make_indirect();
|
||||
} else {
|
||||
a.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
fixup(&mut fn_abi.ret);
|
||||
}
|
||||
for arg in &mut fn_abi.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
fixup(arg);
|
||||
}
|
||||
}
|
1150
compiler/rustc_target/src/abi/mod.rs
Normal file
1150
compiler/rustc_target/src/abi/mod.rs
Normal file
File diff suppressed because it is too large
Load diff
156
compiler/rustc_target/src/asm/aarch64.rs
Normal file
156
compiler/rustc_target/src/asm/aarch64.rs
Normal file
|
@ -0,0 +1,156 @@
|
|||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
AArch64 AArch64InlineAsmRegClass {
|
||||
reg,
|
||||
vreg,
|
||||
vreg_low16,
|
||||
}
|
||||
}
|
||||
|
||||
impl AArch64InlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::reg => &['w', 'x'],
|
||||
Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v'],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::reg => match ty.size().bits() {
|
||||
64 => None,
|
||||
_ => Some(('w', "w0")),
|
||||
},
|
||||
Self::vreg | Self::vreg_low16 => match ty.size().bits() {
|
||||
8 => Some(('b', "b0")),
|
||||
16 => Some(('h', "h0")),
|
||||
32 => Some(('s', "s0")),
|
||||
64 => Some(('d', "d0")),
|
||||
128 => Some(('q', "q0")),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::reg => Some(('x', "x0")),
|
||||
Self::vreg | Self::vreg_low16 => Some(('v', "v0")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
|
||||
Self::vreg | Self::vreg_low16 => types! {
|
||||
"fp": I8, I16, I32, I64, F32, F64,
|
||||
VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass {
|
||||
x0: reg = ["x0", "w0"],
|
||||
x1: reg = ["x1", "w1"],
|
||||
x2: reg = ["x2", "w2"],
|
||||
x3: reg = ["x3", "w3"],
|
||||
x4: reg = ["x4", "w4"],
|
||||
x5: reg = ["x5", "w5"],
|
||||
x6: reg = ["x6", "w6"],
|
||||
x7: reg = ["x7", "w7"],
|
||||
x8: reg = ["x8", "w8"],
|
||||
x9: reg = ["x9", "w9"],
|
||||
x10: reg = ["x10", "w10"],
|
||||
x11: reg = ["x11", "w11"],
|
||||
x12: reg = ["x12", "w12"],
|
||||
x13: reg = ["x13", "w13"],
|
||||
x14: reg = ["x14", "w14"],
|
||||
x15: reg = ["x15", "w15"],
|
||||
x16: reg = ["x16", "w16"],
|
||||
x17: reg = ["x17", "w17"],
|
||||
x18: reg = ["x18", "w18"],
|
||||
x19: reg = ["x19", "w19"],
|
||||
x20: reg = ["x20", "w20"],
|
||||
x21: reg = ["x21", "w21"],
|
||||
x22: reg = ["x22", "w22"],
|
||||
x23: reg = ["x23", "w23"],
|
||||
x24: reg = ["x24", "w24"],
|
||||
x25: reg = ["x25", "w25"],
|
||||
x26: reg = ["x26", "w26"],
|
||||
x27: reg = ["x27", "w27"],
|
||||
x28: reg = ["x28", "w28"],
|
||||
x30: reg = ["x30", "w30", "lr"],
|
||||
v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"],
|
||||
v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"],
|
||||
v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"],
|
||||
v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3"],
|
||||
v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4"],
|
||||
v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5"],
|
||||
v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6"],
|
||||
v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7"],
|
||||
v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8"],
|
||||
v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9"],
|
||||
v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10"],
|
||||
v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11"],
|
||||
v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12"],
|
||||
v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13"],
|
||||
v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14"],
|
||||
v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15"],
|
||||
v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16"],
|
||||
v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17"],
|
||||
v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18"],
|
||||
v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19"],
|
||||
v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20"],
|
||||
v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21"],
|
||||
v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22"],
|
||||
v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23"],
|
||||
v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24"],
|
||||
v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25"],
|
||||
v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26"],
|
||||
v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27"],
|
||||
v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28"],
|
||||
v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"],
|
||||
v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"],
|
||||
v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"],
|
||||
#error = ["x29", "fp"] =>
|
||||
"the frame pointer cannot be used as an operand for inline asm",
|
||||
#error = ["sp", "wsp"] =>
|
||||
"the stack pointer cannot be used as an operand for inline asm",
|
||||
#error = ["xzr", "wzr"] =>
|
||||
"the zero register cannot be used as an operand for inline asm",
|
||||
}
|
||||
}
|
||||
|
||||
impl AArch64InlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
_arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
let (prefix, index) = if (self as u32) < Self::v0 as u32 {
|
||||
(modifier.unwrap_or('x'), self as u32 - Self::x0 as u32)
|
||||
} else {
|
||||
(modifier.unwrap_or('v'), self as u32 - Self::v0 as u32)
|
||||
};
|
||||
assert!(index < 32);
|
||||
write!(out, "{}{}", prefix, index)
|
||||
}
|
||||
}
|
298
compiler/rustc_target/src/asm/arm.rs
Normal file
298
compiler/rustc_target/src/asm/arm.rs
Normal file
|
@ -0,0 +1,298 @@
|
|||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use crate::spec::Target;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
Arm ArmInlineAsmRegClass {
|
||||
reg,
|
||||
reg_thumb,
|
||||
sreg,
|
||||
sreg_low16,
|
||||
dreg,
|
||||
dreg_low16,
|
||||
dreg_low8,
|
||||
qreg,
|
||||
qreg_low8,
|
||||
qreg_low4,
|
||||
}
|
||||
}
|
||||
|
||||
impl ArmInlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::qreg | Self::qreg_low8 | Self::qreg_low4 => &['e', 'f'],
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
_ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg | Self::reg_thumb => types! { _: I8, I16, I32, F32; },
|
||||
Self::sreg | Self::sreg_low16 => types! { "vfp2": I32, F32; },
|
||||
Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! {
|
||||
"vfp2": I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
|
||||
},
|
||||
Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
|
||||
"neon": VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This uses the same logic as useR7AsFramePointer in LLVM
|
||||
fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
|
||||
target.options.is_like_osx || (!target.options.is_like_windows && has_feature("thumb-mode"))
|
||||
}
|
||||
|
||||
fn frame_pointer_r11(
|
||||
_arch: InlineAsmArch,
|
||||
has_feature: impl FnMut(&str) -> bool,
|
||||
target: &Target,
|
||||
_allocating: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if !frame_pointer_is_r7(has_feature, target) {
|
||||
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_pointer_r7(
|
||||
_arch: InlineAsmArch,
|
||||
has_feature: impl FnMut(&str) -> bool,
|
||||
target: &Target,
|
||||
_allocating: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if frame_pointer_is_r7(has_feature, target) {
|
||||
Err("the frame pointer (r7) cannot be used as an operand for inline asm")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
Arm ArmInlineAsmReg ArmInlineAsmRegClass {
|
||||
r0: reg, reg_thumb = ["r0", "a1"],
|
||||
r1: reg, reg_thumb = ["r1", "a2"],
|
||||
r2: reg, reg_thumb = ["r2", "a3"],
|
||||
r3: reg, reg_thumb = ["r3", "a4"],
|
||||
r4: reg, reg_thumb = ["r4", "v1"],
|
||||
r5: reg, reg_thumb = ["r5", "v2"],
|
||||
r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
|
||||
r8: reg = ["r8", "v5"],
|
||||
r9: reg = ["r9", "v6", "rfp"],
|
||||
r10: reg = ["r10", "sl"],
|
||||
r11: reg = ["r11", "fp"] % frame_pointer_r11,
|
||||
r12: reg = ["r12", "ip"],
|
||||
r14: reg = ["r14", "lr"],
|
||||
s0: sreg, sreg_low16 = ["s0"],
|
||||
s1: sreg, sreg_low16 = ["s1"],
|
||||
s2: sreg, sreg_low16 = ["s2"],
|
||||
s3: sreg, sreg_low16 = ["s3"],
|
||||
s4: sreg, sreg_low16 = ["s4"],
|
||||
s5: sreg, sreg_low16 = ["s5"],
|
||||
s6: sreg, sreg_low16 = ["s6"],
|
||||
s7: sreg, sreg_low16 = ["s7"],
|
||||
s8: sreg, sreg_low16 = ["s8"],
|
||||
s9: sreg, sreg_low16 = ["s9"],
|
||||
s10: sreg, sreg_low16 = ["s10"],
|
||||
s11: sreg, sreg_low16 = ["s11"],
|
||||
s12: sreg, sreg_low16 = ["s12"],
|
||||
s13: sreg, sreg_low16 = ["s13"],
|
||||
s14: sreg, sreg_low16 = ["s14"],
|
||||
s15: sreg, sreg_low16 = ["s15"],
|
||||
s16: sreg = ["s16"],
|
||||
s17: sreg = ["s17"],
|
||||
s18: sreg = ["s18"],
|
||||
s19: sreg = ["s19"],
|
||||
s20: sreg = ["s20"],
|
||||
s21: sreg = ["s21"],
|
||||
s22: sreg = ["s22"],
|
||||
s23: sreg = ["s23"],
|
||||
s24: sreg = ["s24"],
|
||||
s25: sreg = ["s25"],
|
||||
s26: sreg = ["s26"],
|
||||
s27: sreg = ["s27"],
|
||||
s28: sreg = ["s28"],
|
||||
s29: sreg = ["s29"],
|
||||
s30: sreg = ["s30"],
|
||||
s31: sreg = ["s31"],
|
||||
d0: dreg, dreg_low16, dreg_low8 = ["d0"],
|
||||
d1: dreg, dreg_low16, dreg_low8 = ["d1"],
|
||||
d2: dreg, dreg_low16, dreg_low8 = ["d2"],
|
||||
d3: dreg, dreg_low16, dreg_low8 = ["d3"],
|
||||
d4: dreg, dreg_low16, dreg_low8 = ["d4"],
|
||||
d5: dreg, dreg_low16, dreg_low8 = ["d5"],
|
||||
d6: dreg, dreg_low16, dreg_low8 = ["d6"],
|
||||
d7: dreg, dreg_low16, dreg_low8 = ["d7"],
|
||||
d8: dreg, dreg_low16 = ["d8"],
|
||||
d9: dreg, dreg_low16 = ["d9"],
|
||||
d10: dreg, dreg_low16 = ["d10"],
|
||||
d11: dreg, dreg_low16 = ["d11"],
|
||||
d12: dreg, dreg_low16 = ["d12"],
|
||||
d13: dreg, dreg_low16 = ["d13"],
|
||||
d14: dreg, dreg_low16 = ["d14"],
|
||||
d15: dreg, dreg_low16 = ["d15"],
|
||||
d16: dreg = ["d16"],
|
||||
d17: dreg = ["d17"],
|
||||
d18: dreg = ["d18"],
|
||||
d19: dreg = ["d19"],
|
||||
d20: dreg = ["d20"],
|
||||
d21: dreg = ["d21"],
|
||||
d22: dreg = ["d22"],
|
||||
d23: dreg = ["d23"],
|
||||
d24: dreg = ["d24"],
|
||||
d25: dreg = ["d25"],
|
||||
d26: dreg = ["d26"],
|
||||
d27: dreg = ["d27"],
|
||||
d28: dreg = ["d28"],
|
||||
d29: dreg = ["d29"],
|
||||
d30: dreg = ["d30"],
|
||||
d31: dreg = ["d31"],
|
||||
q0: qreg, qreg_low8, qreg_low4 = ["q0"],
|
||||
q1: qreg, qreg_low8, qreg_low4 = ["q1"],
|
||||
q2: qreg, qreg_low8, qreg_low4 = ["q2"],
|
||||
q3: qreg, qreg_low8, qreg_low4 = ["q3"],
|
||||
q4: qreg, qreg_low8 = ["q4"],
|
||||
q5: qreg, qreg_low8 = ["q5"],
|
||||
q6: qreg, qreg_low8 = ["q6"],
|
||||
q7: qreg, qreg_low8 = ["q7"],
|
||||
q8: qreg = ["q8"],
|
||||
q9: qreg = ["q9"],
|
||||
q10: qreg = ["q10"],
|
||||
q11: qreg = ["q11"],
|
||||
q12: qreg = ["q12"],
|
||||
q13: qreg = ["q13"],
|
||||
q14: qreg = ["q14"],
|
||||
q15: qreg = ["q15"],
|
||||
#error = ["r6", "v3"] =>
|
||||
"r6 is used internally by LLVM and cannot be used as an operand for inline asm",
|
||||
#error = ["r13", "sp"] =>
|
||||
"the stack pointer cannot be used as an operand for inline asm",
|
||||
#error = ["r15", "pc"] =>
|
||||
"the program pointer cannot be used as an operand for inline asm",
|
||||
}
|
||||
}
|
||||
|
||||
impl ArmInlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
_arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
// Only qreg is allowed to have modifiers. This should have been
|
||||
// validated already by now.
|
||||
if let Some(modifier) = modifier {
|
||||
let index = self as u32 - Self::q0 as u32;
|
||||
assert!(index < 16);
|
||||
let index = index * 2 + (modifier == 'f') as u32;
|
||||
write!(out, "d{}", index)
|
||||
} else {
|
||||
out.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut cb: impl FnMut(ArmInlineAsmReg)) {
|
||||
cb(self);
|
||||
|
||||
macro_rules! reg_conflicts {
|
||||
(
|
||||
$(
|
||||
$q:ident : $d0:ident $d1:ident : $s0:ident $s1:ident $s2:ident $s3:ident
|
||||
),*;
|
||||
$(
|
||||
$q_high:ident : $d0_high:ident $d1_high:ident
|
||||
),*;
|
||||
) => {
|
||||
match self {
|
||||
$(
|
||||
Self::$q => {
|
||||
cb(Self::$d0);
|
||||
cb(Self::$d1);
|
||||
cb(Self::$s0);
|
||||
cb(Self::$s1);
|
||||
cb(Self::$s2);
|
||||
cb(Self::$s3);
|
||||
}
|
||||
Self::$d0 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$s0);
|
||||
cb(Self::$s1);
|
||||
}
|
||||
Self::$d1 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$s2);
|
||||
cb(Self::$s3);
|
||||
}
|
||||
Self::$s0 | Self::$s1 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$d0);
|
||||
}
|
||||
Self::$s2 | Self::$s3 => {
|
||||
cb(Self::$q);
|
||||
cb(Self::$d1);
|
||||
}
|
||||
)*
|
||||
$(
|
||||
Self::$q_high => {
|
||||
cb(Self::$d0_high);
|
||||
cb(Self::$d1_high);
|
||||
}
|
||||
Self::$d0_high | Self::$d1_high => {
|
||||
cb(Self::$q_high);
|
||||
}
|
||||
)*
|
||||
_ => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ARM's floating-point register file is interesting in that it can be
|
||||
// viewed as 16 128-bit registers, 32 64-bit registers or 32 32-bit
|
||||
// registers. Because these views overlap, the registers of different
|
||||
// widths will conflict (e.g. d0 overlaps with s0 and s1, and q1
|
||||
// overlaps with d2 and d3).
|
||||
//
|
||||
// See section E1.3.1 of the ARM Architecture Reference Manual for
|
||||
// ARMv8-A for more details.
|
||||
reg_conflicts! {
|
||||
q0 : d0 d1 : s0 s1 s2 s3,
|
||||
q1 : d2 d3 : s4 s5 s6 s7,
|
||||
q2 : d4 d5 : s8 s9 s10 s11,
|
||||
q3 : d6 d7 : s12 s13 s14 s15,
|
||||
q4 : d8 d9 : s16 s17 s18 s19,
|
||||
q5 : d10 d11 : s20 s21 s22 s23,
|
||||
q6 : d12 d13 : s24 s25 s26 s27,
|
||||
q7 : d14 d15 : s28 s29 s30 s31;
|
||||
q8 : d16 d17,
|
||||
q9 : d18 d19,
|
||||
q10 : d20 d21,
|
||||
q11 : d22 d23,
|
||||
q12 : d24 d25,
|
||||
q13 : d26 d27,
|
||||
q14 : d28 d29,
|
||||
q15 : d30 d31;
|
||||
}
|
||||
}
|
||||
}
|
93
compiler/rustc_target/src/asm/hexagon.rs
Normal file
93
compiler/rustc_target/src/asm/hexagon.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
Hexagon HexagonInlineAsmRegClass {
|
||||
reg,
|
||||
}
|
||||
}
|
||||
|
||||
impl HexagonInlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
&[]
|
||||
}
|
||||
|
||||
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
_ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg => types! { _: I8, I16, I32, F32; },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
Hexagon HexagonInlineAsmReg HexagonInlineAsmRegClass {
|
||||
r0: reg = ["r0"],
|
||||
r1: reg = ["r1"],
|
||||
r2: reg = ["r2"],
|
||||
r3: reg = ["r3"],
|
||||
r4: reg = ["r4"],
|
||||
r5: reg = ["r5"],
|
||||
r6: reg = ["r6"],
|
||||
r7: reg = ["r7"],
|
||||
r8: reg = ["r8"],
|
||||
r9: reg = ["r9"],
|
||||
r10: reg = ["r10"],
|
||||
r11: reg = ["r11"],
|
||||
r12: reg = ["r12"],
|
||||
r13: reg = ["r13"],
|
||||
r14: reg = ["r14"],
|
||||
r15: reg = ["r15"],
|
||||
r16: reg = ["r16"],
|
||||
r17: reg = ["r17"],
|
||||
r18: reg = ["r18"],
|
||||
r19: reg = ["r19"],
|
||||
r20: reg = ["r20"],
|
||||
r21: reg = ["r21"],
|
||||
r22: reg = ["r22"],
|
||||
r23: reg = ["r23"],
|
||||
r24: reg = ["r24"],
|
||||
r25: reg = ["r25"],
|
||||
r26: reg = ["r26"],
|
||||
r27: reg = ["r27"],
|
||||
r28: reg = ["r28"],
|
||||
#error = ["r29", "sp"] =>
|
||||
"the stack pointer cannot be used as an operand for inline asm",
|
||||
#error = ["r30", "fr"] =>
|
||||
"the frame register cannot be used as an operand for inline asm",
|
||||
#error = ["r31", "lr"] =>
|
||||
"the link register cannot be used as an operand for inline asm",
|
||||
}
|
||||
}
|
||||
|
||||
impl HexagonInlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
_arch: InlineAsmArch,
|
||||
_modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
out.write_str(self.name())
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {}
|
||||
}
|
549
compiler/rustc_target/src/asm/mod.rs
Normal file
549
compiler/rustc_target/src/asm/mod.rs
Normal file
|
@ -0,0 +1,549 @@
|
|||
use crate::abi::Size;
|
||||
use crate::spec::Target;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::Symbol;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! def_reg_class {
|
||||
($arch:ident $arch_regclass:ident {
|
||||
$(
|
||||
$class:ident,
|
||||
)*
|
||||
}) => {
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum $arch_regclass {
|
||||
$($class,)*
|
||||
}
|
||||
|
||||
impl $arch_regclass {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
$(Self::$class => stringify!($class),)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(_arch: super::InlineAsmArch, name: &str) -> Result<Self, &'static str> {
|
||||
match name {
|
||||
$(
|
||||
stringify!($class) => Ok(Self::$class),
|
||||
)*
|
||||
_ => Err("unknown register class"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn regclass_map() -> rustc_data_structures::fx::FxHashMap<
|
||||
super::InlineAsmRegClass,
|
||||
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
|
||||
> {
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use super::InlineAsmRegClass;
|
||||
let mut map = FxHashMap::default();
|
||||
$(
|
||||
map.insert(InlineAsmRegClass::$arch($arch_regclass::$class), FxHashSet::default());
|
||||
)*
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! def_regs {
|
||||
($arch:ident $arch_reg:ident $arch_regclass:ident {
|
||||
$(
|
||||
$reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?,
|
||||
)*
|
||||
$(
|
||||
#error = [$($bad_reg:literal),+] => $error:literal,
|
||||
)*
|
||||
}) => {
|
||||
#[allow(unreachable_code)]
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum $arch_reg {
|
||||
$($reg,)*
|
||||
}
|
||||
|
||||
impl $arch_reg {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
$(Self::$reg => $reg_name,)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reg_class(self) -> $arch_regclass {
|
||||
match self {
|
||||
$(Self::$reg => $arch_regclass::$class,)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(
|
||||
_arch: super::InlineAsmArch,
|
||||
mut _has_feature: impl FnMut(&str) -> bool,
|
||||
_target: &crate::spec::Target,
|
||||
name: &str,
|
||||
) -> Result<Self, &'static str> {
|
||||
match name {
|
||||
$(
|
||||
$($alias)|* | $reg_name => {
|
||||
$($filter(_arch, &mut _has_feature, _target, false)?;)?
|
||||
Ok(Self::$reg)
|
||||
}
|
||||
)*
|
||||
$(
|
||||
$($bad_reg)|* => Err($error),
|
||||
)*
|
||||
_ => Err("unknown register"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn fill_reg_map(
|
||||
_arch: super::InlineAsmArch,
|
||||
mut _has_feature: impl FnMut(&str) -> bool,
|
||||
_target: &crate::spec::Target,
|
||||
_map: &mut rustc_data_structures::fx::FxHashMap<
|
||||
super::InlineAsmRegClass,
|
||||
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
|
||||
>,
|
||||
) {
|
||||
#[allow(unused_imports)]
|
||||
use super::{InlineAsmReg, InlineAsmRegClass};
|
||||
$(
|
||||
if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true {
|
||||
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
|
||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||
}
|
||||
$(
|
||||
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) {
|
||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||
}
|
||||
)*
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
macro_rules! types {
|
||||
(
|
||||
$(_ : $($ty:expr),+;)?
|
||||
$($feature:literal: $($ty2:expr),+;)*
|
||||
) => {
|
||||
{
|
||||
use super::InlineAsmType::*;
|
||||
&[
|
||||
$($(
|
||||
($ty, None),
|
||||
)*)?
|
||||
$($(
|
||||
($ty2, Some($feature)),
|
||||
)*)*
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod aarch64;
|
||||
mod arm;
|
||||
mod hexagon;
|
||||
mod nvptx;
|
||||
mod riscv;
|
||||
mod x86;
|
||||
|
||||
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
|
||||
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
|
||||
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
|
||||
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
|
||||
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
|
||||
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum InlineAsmArch {
|
||||
X86,
|
||||
X86_64,
|
||||
Arm,
|
||||
AArch64,
|
||||
RiscV32,
|
||||
RiscV64,
|
||||
Nvptx64,
|
||||
Hexagon,
|
||||
}
|
||||
|
||||
impl FromStr for InlineAsmArch {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
|
||||
match s {
|
||||
"x86" => Ok(Self::X86),
|
||||
"x86_64" => Ok(Self::X86_64),
|
||||
"arm" => Ok(Self::Arm),
|
||||
"aarch64" => Ok(Self::AArch64),
|
||||
"riscv32" => Ok(Self::RiscV32),
|
||||
"riscv64" => Ok(Self::RiscV64),
|
||||
"nvptx64" => Ok(Self::Nvptx64),
|
||||
"hexagon" => Ok(Self::Hexagon),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
pub enum InlineAsmReg {
|
||||
X86(X86InlineAsmReg),
|
||||
Arm(ArmInlineAsmReg),
|
||||
AArch64(AArch64InlineAsmReg),
|
||||
RiscV(RiscVInlineAsmReg),
|
||||
Nvptx(NvptxInlineAsmReg),
|
||||
Hexagon(HexagonInlineAsmReg),
|
||||
}
|
||||
|
||||
impl InlineAsmReg {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::X86(r) => r.name(),
|
||||
Self::Arm(r) => r.name(),
|
||||
Self::AArch64(r) => r.name(),
|
||||
Self::RiscV(r) => r.name(),
|
||||
Self::Hexagon(r) => r.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reg_class(self) -> InlineAsmRegClass {
|
||||
match self {
|
||||
Self::X86(r) => InlineAsmRegClass::X86(r.reg_class()),
|
||||
Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
|
||||
Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
|
||||
Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
|
||||
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(
|
||||
arch: InlineAsmArch,
|
||||
has_feature: impl FnMut(&str) -> bool,
|
||||
target: &Target,
|
||||
name: Symbol,
|
||||
) -> Result<Self, &'static str> {
|
||||
// FIXME: use direct symbol comparison for register names
|
||||
// Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
|
||||
let name = name.as_str();
|
||||
Ok(match arch {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||
Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
|
||||
}
|
||||
InlineAsmArch::Arm => {
|
||||
Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
|
||||
}
|
||||
InlineAsmArch::AArch64 => {
|
||||
Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
|
||||
}
|
||||
InlineAsmArch::Nvptx64 => {
|
||||
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
|
||||
}
|
||||
InlineAsmArch::Hexagon => {
|
||||
Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: This function isn't used at the moment, but is needed to support
|
||||
// falling back to an external assembler.
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
match self {
|
||||
Self::X86(r) => r.emit(out, arch, modifier),
|
||||
Self::Arm(r) => r.emit(out, arch, modifier),
|
||||
Self::AArch64(r) => r.emit(out, arch, modifier),
|
||||
Self::RiscV(r) => r.emit(out, arch, modifier),
|
||||
Self::Hexagon(r) => r.emit(out, arch, modifier),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
|
||||
match self {
|
||||
Self::X86(r) => r.overlapping_regs(|r| cb(Self::X86(r))),
|
||||
Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
|
||||
Self::AArch64(_) => cb(self),
|
||||
Self::RiscV(_) => cb(self),
|
||||
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
pub enum InlineAsmRegClass {
|
||||
X86(X86InlineAsmRegClass),
|
||||
Arm(ArmInlineAsmRegClass),
|
||||
AArch64(AArch64InlineAsmRegClass),
|
||||
RiscV(RiscVInlineAsmRegClass),
|
||||
Nvptx(NvptxInlineAsmRegClass),
|
||||
Hexagon(HexagonInlineAsmRegClass),
|
||||
}
|
||||
|
||||
impl InlineAsmRegClass {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::X86(r) => r.name(),
|
||||
Self::Arm(r) => r.name(),
|
||||
Self::AArch64(r) => r.name(),
|
||||
Self::RiscV(r) => r.name(),
|
||||
Self::Nvptx(r) => r.name(),
|
||||
Self::Hexagon(r) => r.name(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a suggested register class to use for this type. This is called
|
||||
/// after type checking via `supported_types` fails to give a better error
|
||||
/// message to the user.
|
||||
pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
|
||||
match self {
|
||||
Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86),
|
||||
Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm),
|
||||
Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
|
||||
Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
|
||||
Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
|
||||
Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a suggested template modifier to use for this type and an
|
||||
/// example of a register named formatted with it.
|
||||
///
|
||||
/// Such suggestions are useful if a type smaller than the full register
|
||||
/// size is used and a modifier can be used to point to the subregister of
|
||||
/// the correct size.
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::X86(r) => r.suggest_modifier(arch, ty),
|
||||
Self::Arm(r) => r.suggest_modifier(arch, ty),
|
||||
Self::AArch64(r) => r.suggest_modifier(arch, ty),
|
||||
Self::RiscV(r) => r.suggest_modifier(arch, ty),
|
||||
Self::Nvptx(r) => r.suggest_modifier(arch, ty),
|
||||
Self::Hexagon(r) => r.suggest_modifier(arch, ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default modifier for this register and an example of a
|
||||
/// register named formatted with it.
|
||||
///
|
||||
/// This is only needed when the register class can suggest a modifier, so
|
||||
/// that the user can be shown how to get the default behavior without a
|
||||
/// warning.
|
||||
pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::X86(r) => r.default_modifier(arch),
|
||||
Self::Arm(r) => r.default_modifier(arch),
|
||||
Self::AArch64(r) => r.default_modifier(arch),
|
||||
Self::RiscV(r) => r.default_modifier(arch),
|
||||
Self::Nvptx(r) => r.default_modifier(arch),
|
||||
Self::Hexagon(r) => r.default_modifier(arch),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of supported types for this register class, each with a
|
||||
/// options target feature required to use this type.
|
||||
pub fn supported_types(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::X86(r) => r.supported_types(arch),
|
||||
Self::Arm(r) => r.supported_types(arch),
|
||||
Self::AArch64(r) => r.supported_types(arch),
|
||||
Self::RiscV(r) => r.supported_types(arch),
|
||||
Self::Nvptx(r) => r.supported_types(arch),
|
||||
Self::Hexagon(r) => r.supported_types(arch),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
|
||||
// FIXME: use direct symbol comparison for register class names
|
||||
name.with(|name| {
|
||||
Ok(match arch {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||
Self::X86(X86InlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(arch, name)?),
|
||||
InlineAsmArch::AArch64 => {
|
||||
Self::AArch64(AArch64InlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
|
||||
InlineAsmArch::Hexagon => {
|
||||
Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the list of template modifiers that can be used with this
|
||||
/// register class.
|
||||
pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::X86(r) => r.valid_modifiers(arch),
|
||||
Self::Arm(r) => r.valid_modifiers(arch),
|
||||
Self::AArch64(r) => r.valid_modifiers(arch),
|
||||
Self::RiscV(r) => r.valid_modifiers(arch),
|
||||
Self::Nvptx(r) => r.valid_modifiers(arch),
|
||||
Self::Hexagon(r) => r.valid_modifiers(arch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)]
|
||||
pub enum InlineAsmRegOrRegClass {
|
||||
Reg(InlineAsmReg),
|
||||
RegClass(InlineAsmRegClass),
|
||||
}
|
||||
|
||||
impl InlineAsmRegOrRegClass {
|
||||
pub fn reg_class(self) -> InlineAsmRegClass {
|
||||
match self {
|
||||
Self::Reg(r) => r.reg_class(),
|
||||
Self::RegClass(r) => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InlineAsmRegOrRegClass {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Reg(r) => write!(f, "\"{}\"", r.name()),
|
||||
Self::RegClass(r) => f.write_str(r.name()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set of types which can be used with a particular register class.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum InlineAsmType {
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
F32,
|
||||
F64,
|
||||
VecI8(u64),
|
||||
VecI16(u64),
|
||||
VecI32(u64),
|
||||
VecI64(u64),
|
||||
VecI128(u64),
|
||||
VecF32(u64),
|
||||
VecF64(u64),
|
||||
}
|
||||
|
||||
impl InlineAsmType {
|
||||
pub fn is_integer(self) -> bool {
|
||||
match self {
|
||||
Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(self) -> Size {
|
||||
Size::from_bytes(match self {
|
||||
Self::I8 => 1,
|
||||
Self::I16 => 2,
|
||||
Self::I32 => 4,
|
||||
Self::I64 => 8,
|
||||
Self::I128 => 16,
|
||||
Self::F32 => 4,
|
||||
Self::F64 => 8,
|
||||
Self::VecI8(n) => n * 1,
|
||||
Self::VecI16(n) => n * 2,
|
||||
Self::VecI32(n) => n * 4,
|
||||
Self::VecI64(n) => n * 8,
|
||||
Self::VecI128(n) => n * 16,
|
||||
Self::VecF32(n) => n * 4,
|
||||
Self::VecF64(n) => n * 8,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InlineAsmType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Self::I8 => f.write_str("i8"),
|
||||
Self::I16 => f.write_str("i16"),
|
||||
Self::I32 => f.write_str("i32"),
|
||||
Self::I64 => f.write_str("i64"),
|
||||
Self::I128 => f.write_str("i128"),
|
||||
Self::F32 => f.write_str("f32"),
|
||||
Self::F64 => f.write_str("f64"),
|
||||
Self::VecI8(n) => write!(f, "i8x{}", n),
|
||||
Self::VecI16(n) => write!(f, "i16x{}", n),
|
||||
Self::VecI32(n) => write!(f, "i32x{}", n),
|
||||
Self::VecI64(n) => write!(f, "i64x{}", n),
|
||||
Self::VecI128(n) => write!(f, "i128x{}", n),
|
||||
Self::VecF32(n) => write!(f, "f32x{}", n),
|
||||
Self::VecF64(n) => write!(f, "f64x{}", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the full set of allocatable registers for a given architecture.
|
||||
///
|
||||
/// The registers are structured as a map containing the set of allocatable
|
||||
/// registers in each register class. A particular register may be allocatable
|
||||
/// from multiple register classes, in which case it will appear multiple times
|
||||
/// in the map.
|
||||
// NOTE: This function isn't used at the moment, but is needed to support
|
||||
// falling back to an external assembler.
|
||||
pub fn allocatable_registers(
|
||||
arch: InlineAsmArch,
|
||||
has_feature: impl FnMut(&str) -> bool,
|
||||
target: &crate::spec::Target,
|
||||
) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
|
||||
match arch {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||
let mut map = x86::regclass_map();
|
||||
x86::fill_reg_map(arch, has_feature, target, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::Arm => {
|
||||
let mut map = arm::regclass_map();
|
||||
arm::fill_reg_map(arch, has_feature, target, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::AArch64 => {
|
||||
let mut map = aarch64::regclass_map();
|
||||
aarch64::fill_reg_map(arch, has_feature, target, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
let mut map = riscv::regclass_map();
|
||||
riscv::fill_reg_map(arch, has_feature, target, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::Nvptx64 => {
|
||||
let mut map = nvptx::regclass_map();
|
||||
nvptx::fill_reg_map(arch, has_feature, target, &mut map);
|
||||
map
|
||||
}
|
||||
InlineAsmArch::Hexagon => {
|
||||
let mut map = hexagon::regclass_map();
|
||||
hexagon::fill_reg_map(arch, has_feature, target, &mut map);
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
49
compiler/rustc_target/src/asm/nvptx.rs
Normal file
49
compiler/rustc_target/src/asm/nvptx.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
def_reg_class! {
|
||||
Nvptx NvptxInlineAsmRegClass {
|
||||
reg16,
|
||||
reg32,
|
||||
reg64,
|
||||
}
|
||||
}
|
||||
|
||||
impl NvptxInlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
|
||||
&[]
|
||||
}
|
||||
|
||||
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
_ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg16 => types! { _: I8, I16; },
|
||||
Self::reg32 => types! { _: I8, I16, I32, F32; },
|
||||
Self::reg64 => types! { _: I8, I16, I32, F32, I64, F64; },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
// Registers in PTX are declared in the assembly.
|
||||
// There are no predefined registers that one can use.
|
||||
Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass {}
|
||||
}
|
147
compiler/rustc_target/src/asm/riscv.rs
Normal file
147
compiler/rustc_target/src/asm/riscv.rs
Normal file
|
@ -0,0 +1,147 @@
|
|||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use crate::spec::Target;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
RiscV RiscVInlineAsmRegClass {
|
||||
reg,
|
||||
freg,
|
||||
}
|
||||
}
|
||||
|
||||
impl RiscVInlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
&[]
|
||||
}
|
||||
|
||||
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
_arch: InlineAsmArch,
|
||||
_ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg => {
|
||||
if arch == InlineAsmArch::RiscV64 {
|
||||
types! { _: I8, I16, I32, I64, F32, F64; }
|
||||
} else {
|
||||
types! { _: I8, I16, I32, F32; }
|
||||
}
|
||||
}
|
||||
Self::freg => types! { "f": F32; "d": F64; },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn not_e(
|
||||
_arch: InlineAsmArch,
|
||||
mut has_feature: impl FnMut(&str) -> bool,
|
||||
_target: &Target,
|
||||
_allocating: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if has_feature("e") {
|
||||
Err("register can't be used with the `e` target feature")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
RiscV RiscVInlineAsmReg RiscVInlineAsmRegClass {
|
||||
x1: reg = ["x1", "ra"],
|
||||
x5: reg = ["x5", "t0"],
|
||||
x6: reg = ["x6", "t1"],
|
||||
x7: reg = ["x7", "t2"],
|
||||
x9: reg = ["x9", "s1"],
|
||||
x10: reg = ["x10", "a0"],
|
||||
x11: reg = ["x11", "a1"],
|
||||
x12: reg = ["x12", "a2"],
|
||||
x13: reg = ["x13", "a3"],
|
||||
x14: reg = ["x14", "a4"],
|
||||
x15: reg = ["x15", "a5"],
|
||||
x16: reg = ["x16", "a6"] % not_e,
|
||||
x17: reg = ["x17", "a7"] % not_e,
|
||||
x18: reg = ["x18", "s2"] % not_e,
|
||||
x19: reg = ["x19", "s3"] % not_e,
|
||||
x20: reg = ["x20", "s4"] % not_e,
|
||||
x21: reg = ["x21", "s5"] % not_e,
|
||||
x22: reg = ["x22", "s6"] % not_e,
|
||||
x23: reg = ["x23", "s7"] % not_e,
|
||||
x24: reg = ["x24", "s8"] % not_e,
|
||||
x25: reg = ["x25", "s9"] % not_e,
|
||||
x26: reg = ["x26", "s10"] % not_e,
|
||||
x27: reg = ["x27", "s11"] % not_e,
|
||||
x28: reg = ["x28", "t3"] % not_e,
|
||||
x29: reg = ["x29", "t4"] % not_e,
|
||||
x30: reg = ["x30", "t5"] % not_e,
|
||||
x31: reg = ["x31", "t6"] % not_e,
|
||||
f0: freg = ["f0", "ft0"],
|
||||
f1: freg = ["f1", "ft1"],
|
||||
f2: freg = ["f2", "ft2"],
|
||||
f3: freg = ["f3", "ft3"],
|
||||
f4: freg = ["f4", "ft4"],
|
||||
f5: freg = ["f5", "ft5"],
|
||||
f6: freg = ["f6", "ft6"],
|
||||
f7: freg = ["f7", "ft7"],
|
||||
f8: freg = ["f8", "fs0"],
|
||||
f9: freg = ["f9", "fs1"],
|
||||
f10: freg = ["f10", "fa0"],
|
||||
f11: freg = ["f11", "fa1"],
|
||||
f12: freg = ["f12", "fa2"],
|
||||
f13: freg = ["f13", "fa3"],
|
||||
f14: freg = ["f14", "fa4"],
|
||||
f15: freg = ["f15", "fa5"],
|
||||
f16: freg = ["f16", "fa6"],
|
||||
f17: freg = ["f17", "fa7"],
|
||||
f18: freg = ["f18", "fs2"],
|
||||
f19: freg = ["f19", "fs3"],
|
||||
f20: freg = ["f20", "fs4"],
|
||||
f21: freg = ["f21", "fs5"],
|
||||
f22: freg = ["f22", "fs6"],
|
||||
f23: freg = ["f23", "fs7"],
|
||||
f24: freg = ["f24", "fs8"],
|
||||
f25: freg = ["f25", "fs9"],
|
||||
f26: freg = ["f26", "fs10"],
|
||||
f27: freg = ["f27", "fs11"],
|
||||
f28: freg = ["f28", "ft8"],
|
||||
f29: freg = ["f29", "ft9"],
|
||||
f30: freg = ["f30", "ft10"],
|
||||
f31: freg = ["f31", "ft11"],
|
||||
#error = ["x8", "s0", "fp"] =>
|
||||
"the frame pointer cannot be used as an operand for inline asm",
|
||||
#error = ["x2", "sp"] =>
|
||||
"the stack pointer cannot be used as an operand for inline asm",
|
||||
#error = ["x3", "gp"] =>
|
||||
"the global pointer cannot be used as an operand for inline asm",
|
||||
#error = ["x4", "tp"] =>
|
||||
"the thread pointer cannot be used as an operand for inline asm" ,
|
||||
#error = ["x0", "zero"] =>
|
||||
"the zero register cannot be used as an operand for inline asm",
|
||||
}
|
||||
}
|
||||
|
||||
impl RiscVInlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
_arch: InlineAsmArch,
|
||||
_modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
out.write_str(self.name())
|
||||
}
|
||||
}
|
427
compiler/rustc_target/src/asm/x86.rs
Normal file
427
compiler/rustc_target/src/asm/x86.rs
Normal file
|
@ -0,0 +1,427 @@
|
|||
use super::{InlineAsmArch, InlineAsmType};
|
||||
use crate::spec::Target;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use std::fmt;
|
||||
|
||||
def_reg_class! {
|
||||
X86 X86InlineAsmRegClass {
|
||||
reg,
|
||||
reg_abcd,
|
||||
reg_byte,
|
||||
xmm_reg,
|
||||
ymm_reg,
|
||||
zmm_reg,
|
||||
kreg,
|
||||
}
|
||||
}
|
||||
|
||||
impl X86InlineAsmRegClass {
|
||||
pub fn valid_modifiers(self, arch: super::InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::reg => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
&['l', 'x', 'e', 'r']
|
||||
} else {
|
||||
&['x', 'e']
|
||||
}
|
||||
}
|
||||
Self::reg_abcd => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
&['l', 'h', 'x', 'e', 'r']
|
||||
} else {
|
||||
&['l', 'h', 'x', 'e']
|
||||
}
|
||||
}
|
||||
Self::reg_byte => &[],
|
||||
Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
|
||||
Self::kreg => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_class(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
|
||||
match self {
|
||||
Self::reg | Self::reg_abcd if ty.size().bits() == 8 => Some(Self::reg_byte),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_modifier(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
ty: InlineAsmType,
|
||||
) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::reg => match ty.size().bits() {
|
||||
16 => Some(('x', "ax")),
|
||||
32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
|
||||
_ => None,
|
||||
},
|
||||
Self::reg_abcd => match ty.size().bits() {
|
||||
16 => Some(('x', "ax")),
|
||||
32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
|
||||
_ => None,
|
||||
},
|
||||
Self::reg_byte => None,
|
||||
Self::xmm_reg => None,
|
||||
Self::ymm_reg => match ty.size().bits() {
|
||||
256 => None,
|
||||
_ => Some(('x', "xmm0")),
|
||||
},
|
||||
Self::zmm_reg => match ty.size().bits() {
|
||||
512 => None,
|
||||
256 => Some(('y', "ymm0")),
|
||||
_ => Some(('x', "xmm0")),
|
||||
},
|
||||
Self::kreg => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
|
||||
match self {
|
||||
Self::reg | Self::reg_abcd => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
Some(('r', "rax"))
|
||||
} else {
|
||||
Some(('e', "eax"))
|
||||
}
|
||||
}
|
||||
Self::reg_byte => None,
|
||||
Self::xmm_reg => Some(('x', "xmm0")),
|
||||
Self::ymm_reg => Some(('y', "ymm0")),
|
||||
Self::zmm_reg => Some(('z', "zmm0")),
|
||||
Self::kreg => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supported_types(
|
||||
self,
|
||||
arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<&'static str>)] {
|
||||
match self {
|
||||
Self::reg | Self::reg_abcd => {
|
||||
if arch == InlineAsmArch::X86_64 {
|
||||
types! { _: I16, I32, I64, F32, F64; }
|
||||
} else {
|
||||
types! { _: I16, I32, F32; }
|
||||
}
|
||||
}
|
||||
Self::reg_byte => types! { _: I8; },
|
||||
Self::xmm_reg => types! {
|
||||
"sse": I32, I64, F32, F64,
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
|
||||
},
|
||||
Self::ymm_reg => types! {
|
||||
"avx": I32, I64, F32, F64,
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
|
||||
VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4);
|
||||
},
|
||||
Self::zmm_reg => types! {
|
||||
"avx512f": I32, I64, F32, F64,
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
|
||||
VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4),
|
||||
VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8);
|
||||
},
|
||||
Self::kreg => types! {
|
||||
"avx512f": I8, I16;
|
||||
"avx512bw": I32, I64;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn x86_64_only(
|
||||
arch: InlineAsmArch,
|
||||
_has_feature: impl FnMut(&str) -> bool,
|
||||
_target: &Target,
|
||||
_allocating: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
match arch {
|
||||
InlineAsmArch::X86 => Err("register is only available on x86_64"),
|
||||
InlineAsmArch::X86_64 => Ok(()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn high_byte(
|
||||
arch: InlineAsmArch,
|
||||
_has_feature: impl FnMut(&str) -> bool,
|
||||
_target: &Target,
|
||||
allocating: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
match arch {
|
||||
InlineAsmArch::X86_64 if allocating => {
|
||||
// The error message isn't actually used...
|
||||
Err("high byte registers are not allocated by reg_byte")
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
X86 X86InlineAsmReg X86InlineAsmRegClass {
|
||||
ax: reg, reg_abcd = ["ax", "eax", "rax"],
|
||||
bx: reg, reg_abcd = ["bx", "ebx", "rbx"],
|
||||
cx: reg, reg_abcd = ["cx", "ecx", "rcx"],
|
||||
dx: reg, reg_abcd = ["dx", "edx", "rdx"],
|
||||
si: reg = ["si", "esi", "rsi"],
|
||||
di: reg = ["di", "edi", "rdi"],
|
||||
r8: reg = ["r8", "r8w", "r8d"] % x86_64_only,
|
||||
r9: reg = ["r9", "r9w", "r9d"] % x86_64_only,
|
||||
r10: reg = ["r10", "r10w", "r10d"] % x86_64_only,
|
||||
r11: reg = ["r11", "r11w", "r11d"] % x86_64_only,
|
||||
r12: reg = ["r12", "r12w", "r12d"] % x86_64_only,
|
||||
r13: reg = ["r13", "r13w", "r13d"] % x86_64_only,
|
||||
r14: reg = ["r14", "r14w", "r14d"] % x86_64_only,
|
||||
r15: reg = ["r15", "r15w", "r15d"] % x86_64_only,
|
||||
al: reg_byte = ["al"],
|
||||
ah: reg_byte = ["ah"] % high_byte,
|
||||
bl: reg_byte = ["bl"],
|
||||
bh: reg_byte = ["bh"] % high_byte,
|
||||
cl: reg_byte = ["cl"],
|
||||
ch: reg_byte = ["ch"] % high_byte,
|
||||
dl: reg_byte = ["dl"],
|
||||
dh: reg_byte = ["dh"] % high_byte,
|
||||
sil: reg_byte = ["sil"] % x86_64_only,
|
||||
dil: reg_byte = ["dil"] % x86_64_only,
|
||||
r8b: reg_byte = ["r8b"] % x86_64_only,
|
||||
r9b: reg_byte = ["r9b"] % x86_64_only,
|
||||
r10b: reg_byte = ["r10b"] % x86_64_only,
|
||||
r11b: reg_byte = ["r11b"] % x86_64_only,
|
||||
r12b: reg_byte = ["r12b"] % x86_64_only,
|
||||
r13b: reg_byte = ["r13b"] % x86_64_only,
|
||||
r14b: reg_byte = ["r14b"] % x86_64_only,
|
||||
r15b: reg_byte = ["r15b"] % x86_64_only,
|
||||
xmm0: xmm_reg = ["xmm0"],
|
||||
xmm1: xmm_reg = ["xmm1"],
|
||||
xmm2: xmm_reg = ["xmm2"],
|
||||
xmm3: xmm_reg = ["xmm3"],
|
||||
xmm4: xmm_reg = ["xmm4"],
|
||||
xmm5: xmm_reg = ["xmm5"],
|
||||
xmm6: xmm_reg = ["xmm6"],
|
||||
xmm7: xmm_reg = ["xmm7"],
|
||||
xmm8: xmm_reg = ["xmm8"] % x86_64_only,
|
||||
xmm9: xmm_reg = ["xmm9"] % x86_64_only,
|
||||
xmm10: xmm_reg = ["xmm10"] % x86_64_only,
|
||||
xmm11: xmm_reg = ["xmm11"] % x86_64_only,
|
||||
xmm12: xmm_reg = ["xmm12"] % x86_64_only,
|
||||
xmm13: xmm_reg = ["xmm13"] % x86_64_only,
|
||||
xmm14: xmm_reg = ["xmm14"] % x86_64_only,
|
||||
xmm15: xmm_reg = ["xmm15"] % x86_64_only,
|
||||
ymm0: ymm_reg = ["ymm0"],
|
||||
ymm1: ymm_reg = ["ymm1"],
|
||||
ymm2: ymm_reg = ["ymm2"],
|
||||
ymm3: ymm_reg = ["ymm3"],
|
||||
ymm4: ymm_reg = ["ymm4"],
|
||||
ymm5: ymm_reg = ["ymm5"],
|
||||
ymm6: ymm_reg = ["ymm6"],
|
||||
ymm7: ymm_reg = ["ymm7"],
|
||||
ymm8: ymm_reg = ["ymm8"] % x86_64_only,
|
||||
ymm9: ymm_reg = ["ymm9"] % x86_64_only,
|
||||
ymm10: ymm_reg = ["ymm10"] % x86_64_only,
|
||||
ymm11: ymm_reg = ["ymm11"] % x86_64_only,
|
||||
ymm12: ymm_reg = ["ymm12"] % x86_64_only,
|
||||
ymm13: ymm_reg = ["ymm13"] % x86_64_only,
|
||||
ymm14: ymm_reg = ["ymm14"] % x86_64_only,
|
||||
ymm15: ymm_reg = ["ymm15"] % x86_64_only,
|
||||
zmm0: zmm_reg = ["zmm0"],
|
||||
zmm1: zmm_reg = ["zmm1"],
|
||||
zmm2: zmm_reg = ["zmm2"],
|
||||
zmm3: zmm_reg = ["zmm3"],
|
||||
zmm4: zmm_reg = ["zmm4"],
|
||||
zmm5: zmm_reg = ["zmm5"],
|
||||
zmm6: zmm_reg = ["zmm6"],
|
||||
zmm7: zmm_reg = ["zmm7"],
|
||||
zmm8: zmm_reg = ["zmm8"] % x86_64_only,
|
||||
zmm9: zmm_reg = ["zmm9"] % x86_64_only,
|
||||
zmm10: zmm_reg = ["zmm10"] % x86_64_only,
|
||||
zmm11: zmm_reg = ["zmm11"] % x86_64_only,
|
||||
zmm12: zmm_reg = ["zmm12"] % x86_64_only,
|
||||
zmm13: zmm_reg = ["zmm13"] % x86_64_only,
|
||||
zmm14: zmm_reg = ["zmm14"] % x86_64_only,
|
||||
zmm15: zmm_reg = ["zmm15"] % x86_64_only,
|
||||
zmm16: zmm_reg = ["zmm16", "xmm16", "ymm16"] % x86_64_only,
|
||||
zmm17: zmm_reg = ["zmm17", "xmm17", "ymm17"] % x86_64_only,
|
||||
zmm18: zmm_reg = ["zmm18", "xmm18", "ymm18"] % x86_64_only,
|
||||
zmm19: zmm_reg = ["zmm19", "xmm19", "ymm19"] % x86_64_only,
|
||||
zmm20: zmm_reg = ["zmm20", "xmm20", "ymm20"] % x86_64_only,
|
||||
zmm21: zmm_reg = ["zmm21", "xmm21", "ymm21"] % x86_64_only,
|
||||
zmm22: zmm_reg = ["zmm22", "xmm22", "ymm22"] % x86_64_only,
|
||||
zmm23: zmm_reg = ["zmm23", "xmm23", "ymm23"] % x86_64_only,
|
||||
zmm24: zmm_reg = ["zmm24", "xmm24", "ymm24"] % x86_64_only,
|
||||
zmm25: zmm_reg = ["zmm25", "xmm25", "ymm25"] % x86_64_only,
|
||||
zmm26: zmm_reg = ["zmm26", "xmm26", "ymm26"] % x86_64_only,
|
||||
zmm27: zmm_reg = ["zmm27", "xmm27", "ymm27"] % x86_64_only,
|
||||
zmm28: zmm_reg = ["zmm28", "xmm28", "ymm28"] % x86_64_only,
|
||||
zmm29: zmm_reg = ["zmm29", "xmm29", "ymm29"] % x86_64_only,
|
||||
zmm30: zmm_reg = ["zmm30", "xmm30", "ymm30"] % x86_64_only,
|
||||
zmm31: zmm_reg = ["zmm31", "xmm31", "ymm31"] % x86_64_only,
|
||||
k1: kreg = ["k1"],
|
||||
k2: kreg = ["k2"],
|
||||
k3: kreg = ["k3"],
|
||||
k4: kreg = ["k4"],
|
||||
k5: kreg = ["k5"],
|
||||
k6: kreg = ["k6"],
|
||||
k7: kreg = ["k7"],
|
||||
#error = ["bp", "bpl", "ebp", "rbp"] =>
|
||||
"the frame pointer cannot be used as an operand for inline asm",
|
||||
#error = ["sp", "spl", "esp", "rsp"] =>
|
||||
"the stack pointer cannot be used as an operand for inline asm",
|
||||
#error = ["ip", "eip", "rip"] =>
|
||||
"the instruction pointer cannot be used as an operand for inline asm",
|
||||
#error = ["st", "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"] =>
|
||||
"x87 registers are not currently supported as operands for inline asm",
|
||||
#error = ["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"] =>
|
||||
"MMX registers are not currently supported as operands for inline asm",
|
||||
#error = ["k0"] =>
|
||||
"the k0 AVX mask register cannot be used as an operand for inline asm",
|
||||
}
|
||||
}
|
||||
|
||||
impl X86InlineAsmReg {
|
||||
pub fn emit(
|
||||
self,
|
||||
out: &mut dyn fmt::Write,
|
||||
arch: InlineAsmArch,
|
||||
modifier: Option<char>,
|
||||
) -> fmt::Result {
|
||||
let reg_default_modifier = match arch {
|
||||
InlineAsmArch::X86 => 'e',
|
||||
InlineAsmArch::X86_64 => 'r',
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if self as u32 <= Self::dx as u32 {
|
||||
let root = ['a', 'b', 'c', 'd'][self as usize - Self::ax as usize];
|
||||
match modifier.unwrap_or(reg_default_modifier) {
|
||||
'l' => write!(out, "{}l", root),
|
||||
'h' => write!(out, "{}h", root),
|
||||
'x' => write!(out, "{}x", root),
|
||||
'e' => write!(out, "e{}x", root),
|
||||
'r' => write!(out, "r{}x", root),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if self as u32 <= Self::di as u32 {
|
||||
let root = self.name();
|
||||
match modifier.unwrap_or(reg_default_modifier) {
|
||||
'l' => write!(out, "{}l", root),
|
||||
'x' => write!(out, "{}", root),
|
||||
'e' => write!(out, "e{}", root),
|
||||
'r' => write!(out, "r{}", root),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if self as u32 <= Self::r15 as u32 {
|
||||
let root = self.name();
|
||||
match modifier.unwrap_or(reg_default_modifier) {
|
||||
'l' => write!(out, "{}b", root),
|
||||
'x' => write!(out, "{}w", root),
|
||||
'e' => write!(out, "{}d", root),
|
||||
'r' => out.write_str(root),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else if self as u32 <= Self::r15b as u32 {
|
||||
out.write_str(self.name())
|
||||
} else if self as u32 <= Self::xmm15 as u32 {
|
||||
let prefix = modifier.unwrap_or('x');
|
||||
let index = self as u32 - Self::xmm0 as u32;
|
||||
write!(out, "{}{}", prefix, index)
|
||||
} else if self as u32 <= Self::ymm15 as u32 {
|
||||
let prefix = modifier.unwrap_or('y');
|
||||
let index = self as u32 - Self::ymm0 as u32;
|
||||
write!(out, "{}{}", prefix, index)
|
||||
} else if self as u32 <= Self::zmm31 as u32 {
|
||||
let prefix = modifier.unwrap_or('z');
|
||||
let index = self as u32 - Self::zmm0 as u32;
|
||||
write!(out, "{}{}", prefix, index)
|
||||
} else {
|
||||
out.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlapping_regs(self, mut cb: impl FnMut(X86InlineAsmReg)) {
|
||||
macro_rules! reg_conflicts {
|
||||
(
|
||||
$(
|
||||
$w:ident : $l:ident $h:ident
|
||||
),*;
|
||||
$(
|
||||
$w2:ident : $l2:ident
|
||||
),*;
|
||||
$(
|
||||
$x:ident : $y:ident : $z:ident
|
||||
),*;
|
||||
) => {
|
||||
match self {
|
||||
$(
|
||||
Self::$w => {
|
||||
cb(Self::$w);
|
||||
cb(Self::$l);
|
||||
cb(Self::$h);
|
||||
}
|
||||
Self::$l => {
|
||||
cb(Self::$w);
|
||||
cb(Self::$l);
|
||||
}
|
||||
Self::$h => {
|
||||
cb(Self::$w);
|
||||
cb(Self::$h);
|
||||
}
|
||||
)*
|
||||
$(
|
||||
Self::$w2 | Self::$l2 => {
|
||||
cb(Self::$w2);
|
||||
cb(Self::$l2);
|
||||
}
|
||||
)*
|
||||
$(
|
||||
Self::$x | Self::$y | Self::$z => {
|
||||
cb(Self::$x);
|
||||
cb(Self::$y);
|
||||
cb(Self::$z);
|
||||
}
|
||||
)*
|
||||
r => cb(r),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// XMM*, YMM* and ZMM* are all different views of the same register.
|
||||
//
|
||||
// See section 15.5 of the combined Intel® 64 and IA-32 Architectures
|
||||
// Software Developer’s Manual for more details.
|
||||
//
|
||||
// We don't need to specify conflicts for [x,y,z]mm[16-31] since these
|
||||
// registers are only available with AVX-512, so we just specify them
|
||||
// as aliases directly.
|
||||
reg_conflicts! {
|
||||
ax : al ah,
|
||||
bx : bl bh,
|
||||
cx : cl ch,
|
||||
dx : dl dh;
|
||||
si : sil,
|
||||
di : dil,
|
||||
r8 : r8b,
|
||||
r9 : r9b,
|
||||
r10 : r10b,
|
||||
r11 : r11b,
|
||||
r12 : r12b,
|
||||
r13 : r13b,
|
||||
r14 : r14b,
|
||||
r15 : r15b;
|
||||
xmm0 : ymm0 : zmm0,
|
||||
xmm1 : ymm1 : zmm1,
|
||||
xmm2 : ymm2 : zmm2,
|
||||
xmm3 : ymm3 : zmm3,
|
||||
xmm4 : ymm4 : zmm4,
|
||||
xmm5 : ymm5 : zmm5,
|
||||
xmm6 : ymm6 : zmm6,
|
||||
xmm7 : ymm7 : zmm7,
|
||||
xmm8 : ymm8 : zmm8,
|
||||
xmm9 : ymm9 : zmm9,
|
||||
xmm10 : ymm10 : zmm10,
|
||||
xmm11 : ymm11 : zmm11,
|
||||
xmm12 : ymm12 : zmm12,
|
||||
xmm13 : ymm13 : zmm13,
|
||||
xmm14 : ymm14 : zmm14,
|
||||
xmm15 : ymm15 : zmm15;
|
||||
}
|
||||
}
|
||||
}
|
32
compiler/rustc_target/src/lib.rs
Normal file
32
compiler/rustc_target/src/lib.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
//! Some stuff used by rustc that doesn't have many dependencies
|
||||
//!
|
||||
//! Originally extracted from rustc::back, which was nominally the
|
||||
//! compiler 'backend', though LLVM is rustc's backend, so rustc_target
|
||||
//! is really just odds-and-ends relating to code gen and linking.
|
||||
//! This crate mostly exists to make rustc smaller, so we might put
|
||||
//! more 'stuff' here in the future. It does not have a dependency on
|
||||
//! LLVM.
|
||||
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_panic)]
|
||||
#![feature(nll)]
|
||||
#![feature(never_type)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
pub mod abi;
|
||||
pub mod asm;
|
||||
pub mod spec;
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
/// instead of implementing everything in librustc_middle.
|
||||
pub trait HashStableContext {}
|
30
compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
Normal file
30
compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::apple_base::opts();
|
||||
base.cpu = "apple-a12".to_string();
|
||||
base.max_atomic_width = Some(128);
|
||||
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
|
||||
|
||||
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
|
||||
|
||||
// Clang automatically chooses a more specific target based on
|
||||
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
|
||||
// correctly, we do too.
|
||||
let arch = "aarch64";
|
||||
let llvm_target = super::apple_base::macos_llvm_target(&arch);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target,
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: arch.to_string(),
|
||||
target_os: "macos".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "apple".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
|
||||
})
|
||||
}
|
37
compiler/rustc_target/src/spec/aarch64_apple_ios.rs
Normal file
37
compiler/rustc_target/src/spec/aarch64_apple_ios.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use super::apple_sdk_base::{opts, AppleOS, Arch};
|
||||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = opts(Arch::Arm64, AppleOS::iOS)?;
|
||||
Ok(Target {
|
||||
llvm_target: "arm64-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "apple".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
features: "+neon,+fp-armv8,+apple-a7".to_string(),
|
||||
eliminate_frame_pointer: false,
|
||||
max_atomic_width: Some(128),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
forces_embed_bitcode: true,
|
||||
// Taken from a clang build on Xcode 11.4.1.
|
||||
// These arguments are not actually invoked - they just have
|
||||
// to look right to pass App Store validation.
|
||||
bitcode_llvm_cmdline: "-triple\0\
|
||||
arm64-apple-ios11.0.0\0\
|
||||
-emit-obj\0\
|
||||
-disable-llvm-passes\0\
|
||||
-target-abi\0\
|
||||
darwinpcs\0\
|
||||
-Os\0"
|
||||
.to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
26
compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
Normal file
26
compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use super::apple_sdk_base::{opts, AppleOS, Arch};
|
||||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = opts(Arch::Arm64, AppleOS::tvOS)?;
|
||||
Ok(Target {
|
||||
llvm_target: "arm64-apple-tvos".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "tvos".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "apple".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
features: "+neon,+fp-armv8,+apple-a7".to_string(),
|
||||
eliminate_frame_pointer: false,
|
||||
max_atomic_width: Some(128),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
forces_embed_bitcode: true,
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
20
compiler/rustc_target/src/spec/aarch64_fuchsia.rs
Normal file
20
compiler/rustc_target/src/spec/aarch64_fuchsia.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::fuchsia_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-fuchsia".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "fuchsia".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: String::new(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
|
||||
})
|
||||
}
|
25
compiler/rustc_target/src/spec/aarch64_linux_android.rs
Normal file
25
compiler/rustc_target/src/spec/aarch64_linux_android.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
// See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
|
||||
// for target ABI requirements.
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::android_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
// As documented in http://developer.android.com/ndk/guides/cpu-features.html
|
||||
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
|
||||
base.features = "+neon,+fp-armv8".to_string();
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-linux-android".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "android".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
|
||||
})
|
||||
}
|
22
compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
Normal file
22
compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::windows_msvc_base::opts();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.has_elf_tls = true;
|
||||
base.features = "+neon,+fp-armv8".to_string();
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-pc-windows-msvc".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "windows".to_string(),
|
||||
target_env: "msvc".to_string(),
|
||||
target_vendor: "pc".to_string(),
|
||||
linker_flavor: LinkerFlavor::Msvc,
|
||||
options: base,
|
||||
})
|
||||
}
|
22
compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
Normal file
22
compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::cloudabi_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
base.unsupported_abis = super::arm_base::unsupported_abis();
|
||||
base.linker = Some("aarch64-unknown-cloudabi-cc".to_string());
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-cloudabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "cloudabi".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: base,
|
||||
})
|
||||
}
|
20
compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
Normal file
20
compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::freebsd_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-freebsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "freebsd".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
|
||||
})
|
||||
}
|
20
compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
Normal file
20
compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::hermit_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-hermit".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "hermit".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
options: base,
|
||||
})
|
||||
}
|
24
compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
Normal file
24
compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::linux_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}_mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
24
compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
Normal file
24
compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::linux_musl_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-linux-musl".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}_mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
21
compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
Normal file
21
compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::netbsd_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
base.unsupported_abis = super::arm_base::unsupported_abis();
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-netbsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "netbsd".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
|
||||
})
|
||||
}
|
37
compiler/rustc_target/src/spec/aarch64_unknown_none.rs
Normal file
37
compiler/rustc_target/src/spec/aarch64_unknown_none.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Generic AArch64 target for bare-metal code - Floating point enabled
|
||||
//
|
||||
// Can be used in conjunction with the `target-feature` and
|
||||
// `target-cpu` compiler flags to opt-in more hardware-specific
|
||||
// features.
|
||||
//
|
||||
// For example, `-C target-cpu=cortex-a53`.
|
||||
|
||||
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Result<Target, String> {
|
||||
let opts = TargetOptions {
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
features: "+strict-align,+neon,+fp-armv8".to_string(),
|
||||
executables: true,
|
||||
relocation_model: RelocModel::Static,
|
||||
disable_redzone: true,
|
||||
linker_is_gnu: true,
|
||||
max_atomic_width: Some(128),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
..Default::default()
|
||||
};
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-none".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: String::new(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
options: opts,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// Generic AArch64 target for bare-metal code - Floating point disabled
|
||||
//
|
||||
// Can be used in conjunction with the `target-feature` and
|
||||
// `target-cpu` compiler flags to opt-in more hardware-specific
|
||||
// features.
|
||||
//
|
||||
// For example, `-C target-cpu=cortex-a53`.
|
||||
|
||||
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Result<Target, String> {
|
||||
let opts = TargetOptions {
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
features: "+strict-align,-neon,-fp-armv8".to_string(),
|
||||
executables: true,
|
||||
relocation_model: RelocModel::Static,
|
||||
disable_redzone: true,
|
||||
linker_is_gnu: true,
|
||||
max_atomic_width: Some(128),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
..Default::default()
|
||||
};
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-none".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: String::new(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
options: opts,
|
||||
})
|
||||
}
|
21
compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
Normal file
21
compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::openbsd_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
base.unsupported_abis = super::arm_base::unsupported_abis();
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-openbsd".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "openbsd".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: base,
|
||||
})
|
||||
}
|
20
compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
Normal file
20
compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::redox_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-redox".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "redox".to_string(),
|
||||
target_env: "relibc".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: base,
|
||||
})
|
||||
}
|
21
compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
Normal file
21
compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::windows_uwp_msvc_base::opts();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.has_elf_tls = true;
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-pc-windows-msvc".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "windows".to_string(),
|
||||
target_env: "msvc".to_string(),
|
||||
target_vendor: "uwp".to_string(),
|
||||
linker_flavor: LinkerFlavor::Msvc,
|
||||
options: base,
|
||||
})
|
||||
}
|
20
compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
Normal file
20
compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::vxworks_base::opts();
|
||||
base.max_atomic_width = Some(128);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "64".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
|
||||
arch: "aarch64".to_string(),
|
||||
target_os: "vxworks".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "wrs".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
|
||||
})
|
||||
}
|
125
compiler/rustc_target/src/spec/abi.rs
Normal file
125
compiler/rustc_target/src/spec/abi.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum Abi {
|
||||
// N.B., this ordering MUST match the AbiDatas array below.
|
||||
// (This is ensured by the test indices_are_correct().)
|
||||
|
||||
// Multiplatform / generic ABIs
|
||||
//
|
||||
// These ABIs come first because every time we add a new ABI, we
|
||||
// have to re-bless all the hashing tests. These are used in many
|
||||
// places, so giving them stable values reduces test churn. The
|
||||
// specific values are meaningless.
|
||||
Rust = 0,
|
||||
C = 1,
|
||||
|
||||
// Single platform ABIs
|
||||
Cdecl,
|
||||
Stdcall,
|
||||
Fastcall,
|
||||
Vectorcall,
|
||||
Thiscall,
|
||||
Aapcs,
|
||||
Win64,
|
||||
SysV64,
|
||||
PtxKernel,
|
||||
Msp430Interrupt,
|
||||
X86Interrupt,
|
||||
AmdGpuKernel,
|
||||
EfiApi,
|
||||
AvrInterrupt,
|
||||
AvrNonBlockingInterrupt,
|
||||
|
||||
// Multiplatform / generic ABIs
|
||||
System,
|
||||
RustIntrinsic,
|
||||
RustCall,
|
||||
PlatformIntrinsic,
|
||||
Unadjusted,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AbiData {
|
||||
abi: Abi,
|
||||
|
||||
/// Name of this ABI as we like it called.
|
||||
name: &'static str,
|
||||
|
||||
/// A generic ABI is supported on all platforms.
|
||||
generic: bool,
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const AbiDatas: &[AbiData] = &[
|
||||
// Cross-platform ABIs
|
||||
AbiData { abi: Abi::Rust, name: "Rust", generic: true },
|
||||
AbiData { abi: Abi::C, name: "C", generic: true },
|
||||
// Platform-specific ABIs
|
||||
AbiData { abi: Abi::Cdecl, name: "cdecl", generic: false },
|
||||
AbiData { abi: Abi::Stdcall, name: "stdcall", generic: false },
|
||||
AbiData { abi: Abi::Fastcall, name: "fastcall", generic: false },
|
||||
AbiData { abi: Abi::Vectorcall, name: "vectorcall", generic: false },
|
||||
AbiData { abi: Abi::Thiscall, name: "thiscall", generic: false },
|
||||
AbiData { abi: Abi::Aapcs, name: "aapcs", generic: false },
|
||||
AbiData { abi: Abi::Win64, name: "win64", generic: false },
|
||||
AbiData { abi: Abi::SysV64, name: "sysv64", generic: false },
|
||||
AbiData { abi: Abi::PtxKernel, name: "ptx-kernel", generic: false },
|
||||
AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt", generic: false },
|
||||
AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false },
|
||||
AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel", generic: false },
|
||||
AbiData { abi: Abi::EfiApi, name: "efiapi", generic: false },
|
||||
AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt", generic: false },
|
||||
AbiData {
|
||||
abi: Abi::AvrNonBlockingInterrupt,
|
||||
name: "avr-non-blocking-interrupt",
|
||||
generic: false,
|
||||
},
|
||||
// Cross-platform ABIs
|
||||
AbiData { abi: Abi::System, name: "system", generic: true },
|
||||
AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
|
||||
AbiData { abi: Abi::RustCall, name: "rust-call", generic: true },
|
||||
AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true },
|
||||
AbiData { abi: Abi::Unadjusted, name: "unadjusted", generic: true },
|
||||
];
|
||||
|
||||
/// Returns the ABI with the given name (if any).
|
||||
pub fn lookup(name: &str) -> Option<Abi> {
|
||||
AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi)
|
||||
}
|
||||
|
||||
pub fn all_names() -> Vec<&'static str> {
|
||||
AbiDatas.iter().map(|d| d.name).collect()
|
||||
}
|
||||
|
||||
impl Abi {
|
||||
#[inline]
|
||||
pub fn index(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn data(self) -> &'static AbiData {
|
||||
&AbiDatas[self.index()]
|
||||
}
|
||||
|
||||
pub fn name(self) -> &'static str {
|
||||
self.data().name
|
||||
}
|
||||
|
||||
pub fn generic(self) -> bool {
|
||||
self.data().generic
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Abi {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "\"{}\"", self.name())
|
||||
}
|
||||
}
|
27
compiler/rustc_target/src/spec/abi/tests.rs
Normal file
27
compiler/rustc_target/src/spec/abi/tests.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use super::*;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[test]
|
||||
fn lookup_Rust() {
|
||||
let abi = lookup("Rust");
|
||||
assert!(abi.is_some() && abi.unwrap().data().name == "Rust");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_cdecl() {
|
||||
let abi = lookup("cdecl");
|
||||
assert!(abi.is_some() && abi.unwrap().data().name == "cdecl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_baz() {
|
||||
let abi = lookup("baz");
|
||||
assert!(abi.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indices_are_correct() {
|
||||
for (i, abi_data) in AbiDatas.iter().enumerate() {
|
||||
assert_eq!(i, abi_data.abi.index());
|
||||
}
|
||||
}
|
16
compiler/rustc_target/src/spec/android_base.rs
Normal file
16
compiler/rustc_target/src/spec/android_base.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use crate::spec::{LinkerFlavor, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut base = super::linux_base::opts();
|
||||
// Many of the symbols defined in compiler-rt are also defined in libgcc.
|
||||
// Android's linker doesn't like that by default.
|
||||
base.pre_link_args
|
||||
.get_mut(&LinkerFlavor::Gcc)
|
||||
.unwrap()
|
||||
.push("-Wl,--allow-multiple-definition".to_string());
|
||||
base.is_like_android = true;
|
||||
base.position_independent_executables = true;
|
||||
base.has_elf_tls = false;
|
||||
base.requires_uwtable = true;
|
||||
base
|
||||
}
|
82
compiler/rustc_target/src/spec/apple_base.rs
Normal file
82
compiler/rustc_target/src/spec/apple_base.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use std::env;
|
||||
|
||||
use crate::spec::{LinkArgs, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
// ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
|
||||
// either the linker will complain if it is used or the binary will end up
|
||||
// segfaulting at runtime when run on 10.6. Rust by default supports macOS
|
||||
// 10.7+, but there is a standard environment variable,
|
||||
// MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
|
||||
// versions of macOS. For example compiling on 10.10 with
|
||||
// MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
|
||||
// warnings about the usage of ELF TLS.
|
||||
//
|
||||
// Here we detect what version is being requested, defaulting to 10.7. ELF
|
||||
// TLS is flagged as enabled if it looks to be supported.
|
||||
let version = macos_deployment_target();
|
||||
|
||||
TargetOptions {
|
||||
// macOS has -dead_strip, which doesn't rely on function_sections
|
||||
function_sections: false,
|
||||
dynamic_linking: true,
|
||||
executables: true,
|
||||
target_family: Some("unix".to_string()),
|
||||
is_like_osx: true,
|
||||
has_rpath: true,
|
||||
dll_prefix: "lib".to_string(),
|
||||
dll_suffix: ".dylib".to_string(),
|
||||
archive_format: "darwin".to_string(),
|
||||
pre_link_args: LinkArgs::new(),
|
||||
has_elf_tls: version >= (10, 7),
|
||||
abi_return_struct_as_int: true,
|
||||
emit_debug_gdb_scripts: false,
|
||||
eh_frame_header: false,
|
||||
|
||||
// This environment variable is pretty magical but is intended for
|
||||
// producing deterministic builds. This was first discovered to be used
|
||||
// by the `ar` tool as a way to control whether or not mtime entries in
|
||||
// the archive headers were set to zero or not. It appears that
|
||||
// eventually the linker got updated to do the same thing and now reads
|
||||
// this environment variable too in recent versions.
|
||||
//
|
||||
// For some more info see the commentary on #47086
|
||||
link_env: vec![("ZERO_AR_DATE".to_string(), "1".to_string())],
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn macos_deployment_target() -> (u32, u32) {
|
||||
let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
|
||||
let version = deployment_target
|
||||
.as_ref()
|
||||
.and_then(|s| {
|
||||
let mut i = s.splitn(2, '.');
|
||||
i.next().and_then(|a| i.next().map(|b| (a, b)))
|
||||
})
|
||||
.and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok());
|
||||
|
||||
version.unwrap_or((10, 7))
|
||||
}
|
||||
|
||||
pub fn macos_llvm_target(arch: &str) -> String {
|
||||
let (major, minor) = macos_deployment_target();
|
||||
format!("{}-apple-macosx{}.{}.0", arch, major, minor)
|
||||
}
|
||||
|
||||
pub fn macos_link_env_remove() -> Vec<String> {
|
||||
let mut env_remove = Vec::with_capacity(2);
|
||||
// Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
|
||||
// may occur when we're linking a custom build script while targeting iOS for example.
|
||||
if let Ok(sdkroot) = env::var("SDKROOT") {
|
||||
if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("iPhoneSimulator.platform") {
|
||||
env_remove.push("SDKROOT".to_string())
|
||||
}
|
||||
}
|
||||
// Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
|
||||
// "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
|
||||
// although this is apparently ignored when using the linker at "/usr/bin/ld".
|
||||
env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".to_string());
|
||||
env_remove
|
||||
}
|
151
compiler/rustc_target/src/spec/apple_sdk_base.rs
Normal file
151
compiler/rustc_target/src/spec/apple_sdk_base.rs
Normal file
|
@ -0,0 +1,151 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use Arch::*;
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Arch {
|
||||
Armv7,
|
||||
Armv7s,
|
||||
Arm64,
|
||||
I386,
|
||||
X86_64,
|
||||
X86_64_macabi,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum AppleOS {
|
||||
tvOS,
|
||||
iOS,
|
||||
}
|
||||
|
||||
impl Arch {
|
||||
pub fn to_string(self) -> &'static str {
|
||||
match self {
|
||||
Armv7 => "armv7",
|
||||
Armv7s => "armv7s",
|
||||
Arm64 => "arm64",
|
||||
I386 => "i386",
|
||||
X86_64 => "x86_64",
|
||||
X86_64_macabi => "x86_64",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
|
||||
// Following what clang does
|
||||
// (https://github.com/llvm/llvm-project/blob/
|
||||
// 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678)
|
||||
// to allow the SDK path to be set. (For clang, xcrun sets
|
||||
// SDKROOT; for rustc, the user or build system can set it, or we
|
||||
// can fall back to checking for xcrun on PATH.)
|
||||
if let Ok(sdkroot) = env::var("SDKROOT") {
|
||||
let p = Path::new(&sdkroot);
|
||||
match sdk_name {
|
||||
// Ignore `SDKROOT` if it's clearly set for the wrong platform.
|
||||
"appletvos"
|
||||
if sdkroot.contains("TVSimulator.platform")
|
||||
|| sdkroot.contains("MacOSX.platform") => {}
|
||||
"appletvsimulator"
|
||||
if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {}
|
||||
"iphoneos"
|
||||
if sdkroot.contains("iPhoneSimulator.platform")
|
||||
|| sdkroot.contains("MacOSX.platform") => {}
|
||||
"iphonesimulator"
|
||||
if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => {
|
||||
}
|
||||
"macosx10.15"
|
||||
if sdkroot.contains("iPhoneOS.platform")
|
||||
|| sdkroot.contains("iPhoneSimulator.platform") => {}
|
||||
// Ignore `SDKROOT` if it's not a valid path.
|
||||
_ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {}
|
||||
_ => return Ok(sdkroot),
|
||||
}
|
||||
}
|
||||
let res =
|
||||
Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then(
|
||||
|output| {
|
||||
if output.status.success() {
|
||||
Ok(String::from_utf8(output.stdout).unwrap())
|
||||
} else {
|
||||
let error = String::from_utf8(output.stderr);
|
||||
let error = format!("process exit with error: {}", error.unwrap());
|
||||
Err(io::Error::new(io::ErrorKind::Other, &error[..]))
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(output) => Ok(output.trim().to_string()),
|
||||
Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_pre_link_args(arch: Arch, os: AppleOS) -> Result<LinkArgs, String> {
|
||||
let sdk_name = match (arch, os) {
|
||||
(Arm64, AppleOS::tvOS) => "appletvos",
|
||||
(X86_64, AppleOS::tvOS) => "appletvsimulator",
|
||||
(Armv7, AppleOS::iOS) => "iphoneos",
|
||||
(Armv7s, AppleOS::iOS) => "iphoneos",
|
||||
(Arm64, AppleOS::iOS) => "iphoneos",
|
||||
(I386, AppleOS::iOS) => "iphonesimulator",
|
||||
(X86_64, AppleOS::iOS) => "iphonesimulator",
|
||||
(X86_64_macabi, AppleOS::iOS) => "macosx10.15",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let arch_name = arch.to_string();
|
||||
|
||||
let sdk_root = get_sdk_root(sdk_name)?;
|
||||
|
||||
let mut args = LinkArgs::new();
|
||||
args.insert(
|
||||
LinkerFlavor::Gcc,
|
||||
vec![
|
||||
"-arch".to_string(),
|
||||
arch_name.to_string(),
|
||||
"-isysroot".to_string(),
|
||||
sdk_root.clone(),
|
||||
"-Wl,-syslibroot".to_string(),
|
||||
sdk_root,
|
||||
],
|
||||
);
|
||||
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
fn target_cpu(arch: Arch) -> String {
|
||||
match arch {
|
||||
Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
|
||||
Armv7s => "cortex-a9",
|
||||
Arm64 => "apple-a7",
|
||||
I386 => "yonah",
|
||||
X86_64 => "core2",
|
||||
X86_64_macabi => "core2",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn link_env_remove(arch: Arch) -> Vec<String> {
|
||||
match arch {
|
||||
Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()],
|
||||
X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opts(arch: Arch, os: AppleOS) -> Result<TargetOptions, String> {
|
||||
let pre_link_args = build_pre_link_args(arch, os)?;
|
||||
Ok(TargetOptions {
|
||||
cpu: target_cpu(arch),
|
||||
executables: true,
|
||||
pre_link_args,
|
||||
link_env_remove: link_env_remove(arch),
|
||||
has_elf_tls: false,
|
||||
eliminate_frame_pointer: false,
|
||||
..super::apple_base::opts()
|
||||
})
|
||||
}
|
6
compiler/rustc_target/src/spec/arm_base.rs
Normal file
6
compiler/rustc_target/src/spec/arm_base.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
use crate::spec::abi::Abi;
|
||||
|
||||
// All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm
|
||||
pub fn unsupported_abis() -> Vec<Abi> {
|
||||
vec![Abi::Stdcall, Abi::Fastcall, Abi::Vectorcall, Abi::Thiscall, Abi::Win64, Abi::SysV64]
|
||||
}
|
22
compiler/rustc_target/src/spec/arm_linux_androideabi.rs
Normal file
22
compiler/rustc_target/src/spec/arm_linux_androideabi.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::android_base::opts();
|
||||
// https://developer.android.com/ndk/guides/abis.html#armeabi
|
||||
base.features = "+strict-align,+v5te".to_string();
|
||||
base.max_atomic_width = Some(32);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "arm-linux-androideabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "android".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
|
||||
})
|
||||
}
|
25
compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
Normal file
25
compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::linux_base::opts();
|
||||
base.max_atomic_width = Some(64);
|
||||
Ok(Target {
|
||||
llvm_target: "arm-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+strict-align,+v6".to_string(),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::linux_base::opts();
|
||||
base.max_atomic_width = Some(64);
|
||||
Ok(Target {
|
||||
llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+strict-align,+v6,+vfp2,-d32".to_string(),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
30
compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
Normal file
30
compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::linux_musl_base::opts();
|
||||
|
||||
// Most of these settings are copied from the arm_unknown_linux_gnueabi
|
||||
// target.
|
||||
base.features = "+strict-align,+v6".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
Ok(Target {
|
||||
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
|
||||
// to determine the calling convention and float ABI, and it doesn't
|
||||
// support the "musleabi" value.
|
||||
llvm_target: "arm-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::linux_musl_base::opts();
|
||||
|
||||
// Most of these settings are copied from the arm_unknown_linux_gnueabihf
|
||||
// target.
|
||||
base.features = "+strict-align,+v6,+vfp2,-d32".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
Ok(Target {
|
||||
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
|
||||
// uses it to determine the calling convention and float ABI, and it
|
||||
// doesn't support the "musleabihf" value.
|
||||
llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
30
compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
Normal file
30
compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
|
||||
|
||||
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
|
||||
use crate::spec::{Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
Ok(Target {
|
||||
llvm_target: "armebv7r-unknown-none-eabi".to_string(),
|
||||
target_endian: "big".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: "".to_string(),
|
||||
target_vendor: "".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
|
||||
options: TargetOptions {
|
||||
executables: true,
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
relocation_model: RelocModel::Static,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
max_atomic_width: Some(32),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
emit_debug_gdb_scripts: false,
|
||||
..Default::default()
|
||||
},
|
||||
})
|
||||
}
|
31
compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
Normal file
31
compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Targets the Cortex-R4F/R5F processor (ARMv7-R)
|
||||
|
||||
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
|
||||
use crate::spec::{Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
Ok(Target {
|
||||
llvm_target: "armebv7r-unknown-none-eabihf".to_string(),
|
||||
target_endian: "big".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: String::new(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
|
||||
options: TargetOptions {
|
||||
executables: true,
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
relocation_model: RelocModel::Static,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
features: "+vfp3,-d32,-fp16".to_string(),
|
||||
max_atomic_width: Some(32),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
emit_debug_gdb_scripts: false,
|
||||
..Default::default()
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::linux_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv4t-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+soft-float,+strict-align".to_string(),
|
||||
// Atomic operations provided by compiler-builtins
|
||||
max_atomic_width: Some(32),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::linux_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+soft-float,+strict-align".to_string(),
|
||||
// Atomic operations provided by compiler-builtins
|
||||
max_atomic_width: Some(32),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::linux_musl_base::opts();
|
||||
Ok(Target {
|
||||
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
|
||||
// uses it to determine the calling convention and float ABI, and LLVM
|
||||
// doesn't support the "musleabihf" value.
|
||||
llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+soft-float,+strict-align".to_string(),
|
||||
// Atomic operations provided by compiler-builtins
|
||||
max_atomic_width: Some(32),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
25
compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
Normal file
25
compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::freebsd_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "freebsd".to_string(),
|
||||
target_env: "gnueabihf".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v6,+vfp2,-d32".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::netbsd_base::opts();
|
||||
base.max_atomic_width = Some(64);
|
||||
Ok(Target {
|
||||
llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "netbsd".to_string(),
|
||||
target_env: "eabihf".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v6,+vfp2,-d32".to_string(),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "__mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
24
compiler/rustc_target/src/spec/armv7_apple_ios.rs
Normal file
24
compiler/rustc_target/src/spec/armv7_apple_ios.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use super::apple_sdk_base::{opts, AppleOS, Arch};
|
||||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = opts(Arch::Armv7, AppleOS::iOS)?;
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "apple".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
features: "+v7,+vfp3,+neon".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
30
compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
Normal file
30
compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
// This target if is for the baseline of the Android v7a ABI
|
||||
// in thumb mode. It's named armv7-* instead of thumbv7-*
|
||||
// for historical reasons. See the thumbv7neon variant for
|
||||
// enabling NEON.
|
||||
|
||||
// See https://developer.android.com/ndk/guides/abis.html#v7a
|
||||
// for target ABI requirements.
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::android_base::opts();
|
||||
base.features = "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-none-linux-android".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "android".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
|
||||
})
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::cloudabi_base::opts();
|
||||
base.cpu = "cortex-a8".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.features = "+v7,+vfp3,+neon".to_string();
|
||||
base.unsupported_abis = super::arm_base::unsupported_abis();
|
||||
base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string());
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "cloudabi".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
|
||||
})
|
||||
}
|
25
compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
Normal file
25
compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::freebsd_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "freebsd".to_string(),
|
||||
target_env: "gnueabihf".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
// This target is for glibc Linux on ARMv7 without thumb-mode, NEON or
|
||||
// hardfloat.
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::linux_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v7,+thumb2,+soft-float,-neon".to_string(),
|
||||
cpu: "generic".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
// This target is for glibc Linux on ARMv7 without NEON or
|
||||
// thumb-mode. See the thumbv7neon variant for enabling both.
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::linux_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
// Info about features at https://wiki.debian.org/ArmHardFloatPort
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
|
||||
cpu: "generic".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
// This target is for musl Linux on ARMv7 without thumb-mode, NEON or
|
||||
// hardfloat.
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::linux_musl_base::opts();
|
||||
// Most of these settings are copied from the armv7_unknown_linux_gnueabi
|
||||
// target.
|
||||
Ok(Target {
|
||||
// It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
|
||||
// to determine the calling convention and float ABI, and it doesn't
|
||||
// support the "musleabi" value.
|
||||
llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v7,+thumb2,+soft-float,-neon".to_string(),
|
||||
cpu: "generic".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
// This target is for musl Linux on ARMv7 without thumb-mode or NEON.
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::linux_musl_base::opts();
|
||||
Ok(Target {
|
||||
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
|
||||
// uses it to determine the calling convention and float ABI, and LLVM
|
||||
// doesn't support the "musleabihf" value.
|
||||
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
// Most of these settings are copied from the armv7_unknown_linux_gnueabihf
|
||||
// target.
|
||||
options: TargetOptions {
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
|
||||
cpu: "generic".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "\u{1}mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::netbsd_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-unknown-netbsdelf-eabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "netbsd".to_string(),
|
||||
target_env: "eabihf".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
|
||||
cpu: "generic".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
target_mcount: "__mcount".to_string(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
25
compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
Normal file
25
compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = super::vxworks_base::opts();
|
||||
Ok(Target {
|
||||
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "vxworks".to_string(),
|
||||
target_env: "gnu".to_string(),
|
||||
target_vendor: "wrs".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
// Info about features at https://wiki.debian.org/ArmHardFloatPort
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
|
||||
cpu: "generic".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
48
compiler/rustc_target/src/spec/armv7a_none_eabi.rs
Normal file
48
compiler/rustc_target/src/spec/armv7a_none_eabi.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Generic ARMv7-A target for bare-metal code - floating point disabled
|
||||
//
|
||||
// This is basically the `armv7-unknown-linux-gnueabi` target with some changes
|
||||
// (listed below) to bring it closer to the bare-metal `thumb` & `aarch64`
|
||||
// targets:
|
||||
//
|
||||
// - `TargetOptions.features`: added `+strict-align`. rationale: unaligned
|
||||
// memory access is disabled on boot on these cores
|
||||
// - linker changed to LLD. rationale: C is not strictly needed to build
|
||||
// bare-metal binaries (the `gcc` linker has the advantage that it knows where C
|
||||
// libraries and crt*.o are but it's not much of an advantage here); LLD is also
|
||||
// faster
|
||||
// - `target_os` set to `none`. rationale: matches `thumb` targets
|
||||
// - `target_{env,vendor}` set to an empty string. rationale: matches `thumb`
|
||||
// targets
|
||||
// - `panic_strategy` set to `abort`. rationale: matches `thumb` targets
|
||||
// - `relocation-model` set to `static`; also no PIE, no relro and no dynamic
|
||||
// linking. rationale: matches `thumb` targets
|
||||
|
||||
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Result<Target, String> {
|
||||
let opts = TargetOptions {
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
features: "+v7,+thumb2,+soft-float,-neon,+strict-align".to_string(),
|
||||
executables: true,
|
||||
relocation_model: RelocModel::Static,
|
||||
disable_redzone: true,
|
||||
max_atomic_width: Some(64),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
emit_debug_gdb_scripts: false,
|
||||
..Default::default()
|
||||
};
|
||||
Ok(Target {
|
||||
llvm_target: "armv7a-none-eabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: String::new(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
options: opts,
|
||||
})
|
||||
}
|
36
compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
Normal file
36
compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Generic ARMv7-A target for bare-metal code - floating point enabled (assumes
|
||||
// FPU is present and emits FPU instructions)
|
||||
//
|
||||
// This is basically the `armv7-unknown-linux-gnueabihf` target with some
|
||||
// changes (list in `armv7a_none_eabi.rs`) to bring it closer to the bare-metal
|
||||
// `thumb` & `aarch64` targets.
|
||||
|
||||
use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Result<Target, String> {
|
||||
let opts = TargetOptions {
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".to_string(),
|
||||
executables: true,
|
||||
relocation_model: RelocModel::Static,
|
||||
disable_redzone: true,
|
||||
max_atomic_width: Some(64),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
emit_debug_gdb_scripts: false,
|
||||
..Default::default()
|
||||
};
|
||||
Ok(Target {
|
||||
llvm_target: "armv7a-none-eabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: String::new(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
options: opts,
|
||||
})
|
||||
}
|
30
compiler/rustc_target/src/spec/armv7r_none_eabi.rs
Normal file
30
compiler/rustc_target/src/spec/armv7r_none_eabi.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
|
||||
|
||||
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
|
||||
use crate::spec::{Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
Ok(Target {
|
||||
llvm_target: "armv7r-unknown-none-eabi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: "".to_string(),
|
||||
target_vendor: "".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
|
||||
options: TargetOptions {
|
||||
executables: true,
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
relocation_model: RelocModel::Static,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
max_atomic_width: Some(32),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
emit_debug_gdb_scripts: false,
|
||||
..Default::default()
|
||||
},
|
||||
})
|
||||
}
|
31
compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
Normal file
31
compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
|
||||
|
||||
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
|
||||
use crate::spec::{Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
Ok(Target {
|
||||
llvm_target: "armv7r-unknown-none-eabihf".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "none".to_string(),
|
||||
target_env: "".to_string(),
|
||||
target_vendor: "".to_string(),
|
||||
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
|
||||
options: TargetOptions {
|
||||
executables: true,
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
relocation_model: RelocModel::Static,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
features: "+vfp3,-d32,-fp16".to_string(),
|
||||
max_atomic_width: Some(32),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
emit_debug_gdb_scripts: false,
|
||||
..Default::default()
|
||||
},
|
||||
})
|
||||
}
|
24
compiler/rustc_target/src/spec/armv7s_apple_ios.rs
Normal file
24
compiler/rustc_target/src/spec/armv7s_apple_ios.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use super::apple_sdk_base::{opts, AppleOS, Arch};
|
||||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = opts(Arch::Armv7s, AppleOS::iOS)?;
|
||||
Ok(Target {
|
||||
llvm_target: "armv7s-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
|
||||
arch: "arm".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "apple".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions {
|
||||
features: "+v7,+vfp4,+neon".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
unsupported_abis: super::arm_base::unsupported_abis(),
|
||||
..base
|
||||
},
|
||||
})
|
||||
}
|
12
compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
Normal file
12
compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use super::{wasm32_unknown_emscripten, LinkerFlavor, Target};
|
||||
|
||||
pub fn target() -> Result<Target, String> {
|
||||
let mut target = wasm32_unknown_emscripten::target()?;
|
||||
target
|
||||
.options
|
||||
.post_link_args
|
||||
.entry(LinkerFlavor::Em)
|
||||
.or_default()
|
||||
.extend(vec!["-s".to_string(), "WASM=0".to_string()]);
|
||||
Ok(target)
|
||||
}
|
51
compiler/rustc_target/src/spec/avr_gnu_base.rs
Normal file
51
compiler/rustc_target/src/spec/avr_gnu_base.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
/// A base target for AVR devices using the GNU toolchain.
|
||||
///
|
||||
/// Requires GNU avr-gcc and avr-binutils on the host system.
|
||||
pub fn target(target_cpu: String) -> TargetResult {
|
||||
Ok(Target {
|
||||
arch: "avr".to_string(),
|
||||
data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(),
|
||||
llvm_target: "avr-unknown-unknown".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "16".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
target_os: "unknown".to_string(),
|
||||
target_env: "".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
target_c_int_width: 16.to_string(),
|
||||
options: TargetOptions {
|
||||
cpu: target_cpu.clone(),
|
||||
exe_suffix: ".elf".to_string(),
|
||||
|
||||
linker: Some("avr-gcc".to_owned()),
|
||||
dynamic_linking: false,
|
||||
executables: true,
|
||||
linker_is_gnu: true,
|
||||
has_rpath: false,
|
||||
position_independent_executables: false,
|
||||
eh_frame_header: false,
|
||||
pre_link_args: vec![(
|
||||
LinkerFlavor::Gcc,
|
||||
vec![
|
||||
format!("-mmcu={}", target_cpu),
|
||||
// We want to be able to strip as much executable code as possible
|
||||
// from the linker command line, and this flag indicates to the
|
||||
// linker that it can avoid linking in dynamic libraries that don't
|
||||
// actually satisfy any symbols up to that point (as with many other
|
||||
// resolutions the linker does). This option only applies to all
|
||||
// following libraries so we're sure to pass it as one of the first
|
||||
// arguments.
|
||||
"-Wl,--as-needed".to_string(),
|
||||
],
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..TargetOptions::default()
|
||||
},
|
||||
})
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
use crate::spec::TargetResult;
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
super::avr_gnu_base::target("atmega328".to_owned())
|
||||
}
|
35
compiler/rustc_target/src/spec/cloudabi_base.rs
Normal file
35
compiler/rustc_target/src/spec/cloudabi_base.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions, TlsModel};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
args.insert(
|
||||
LinkerFlavor::Gcc,
|
||||
vec![
|
||||
"-Wl,-Bstatic".to_string(),
|
||||
"-Wl,--no-dynamic-linker".to_string(),
|
||||
"-Wl,--gc-sections".to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
executables: true,
|
||||
target_family: None,
|
||||
linker_is_gnu: true,
|
||||
pre_link_args: args,
|
||||
position_independent_executables: true,
|
||||
// As CloudABI only supports static linkage, there is no need
|
||||
// for dynamic TLS. The C library therefore does not provide
|
||||
// __tls_get_addr(), which is normally used to perform dynamic
|
||||
// TLS lookups by programs that make use of dlopen(). Only the
|
||||
// "local-exec" and "initial-exec" TLS models can be used.
|
||||
//
|
||||
// "local-exec" is more efficient than "initial-exec", as the
|
||||
// latter has one more level of indirection: it accesses the GOT
|
||||
// (Global Offset Table) to obtain the effective address of a
|
||||
// thread-local variable. Using a GOT is useful only when doing
|
||||
// dynamic linking.
|
||||
tls_model: TlsModel::LocalExec,
|
||||
relro_level: RelroLevel::Full,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
145
compiler/rustc_target/src/spec/crt_objects.rs
Normal file
145
compiler/rustc_target/src/spec/crt_objects.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
//! Object files providing support for basic runtime facilities and added to the produced binaries
|
||||
//! at the start and at the end of linking.
|
||||
//!
|
||||
//! Table of CRT objects for popular toolchains.
|
||||
//! The `crtx` ones are generally distributed with libc and the `begin/end` ones with gcc.
|
||||
//! See https://dev.gentoo.org/~vapier/crt.txt for some more details.
|
||||
//!
|
||||
//! | Pre-link CRT objects | glibc | musl | bionic | mingw | wasi |
|
||||
//! |----------------------|------------------------|------------------------|------------------|-------------------|------|
|
||||
//! | dynamic-nopic-exe | crt1, crti, crtbegin | crt1, crti, crtbegin | crtbegin_dynamic | crt2, crtbegin | crt1 |
|
||||
//! | dynamic-pic-exe | Scrt1, crti, crtbeginS | Scrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
|
||||
//! | static-nopic-exe | crt1, crti, crtbeginT | crt1, crti, crtbegin | crtbegin_static | crt2, crtbegin | crt1 |
|
||||
//! | static-pic-exe | rcrt1, crti, crtbeginS | rcrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
|
||||
//! | dynamic-dylib | crti, crtbeginS | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
|
||||
//! | static-dylib (gcc) | crti, crtbeginT | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
|
||||
//! | static-dylib (clang) | crti, crtbeginT | N/A | crtbegin_static | dllcrt2, crtbegin | - |
|
||||
//!
|
||||
//! | Post-link CRT objects | glibc | musl | bionic | mingw | wasi |
|
||||
//! |-----------------------|---------------|---------------|----------------|--------|------|
|
||||
//! | dynamic-nopic-exe | crtend, crtn | crtend, crtn | crtend_android | crtend | - |
|
||||
//! | dynamic-pic-exe | crtendS, crtn | crtendS, crtn | crtend_android | crtend | - |
|
||||
//! | static-nopic-exe | crtend, crtn | crtend, crtn | crtend_android | crtend | - |
|
||||
//! | static-pic-exe | crtendS, crtn | crtendS, crtn | crtend_android | crtend | - |
|
||||
//! | dynamic-dylib | crtendS, crtn | crtendS, crtn | crtend_so | crtend | - |
|
||||
//! | static-dylib (gcc) | crtend, crtn | crtendS, crtn | crtend_so | crtend | - |
|
||||
//! | static-dylib (clang) | crtendS, crtn | N/A | crtend_so | crtend | - |
|
||||
//!
|
||||
//! Use cases for rustc linking the CRT objects explicitly:
|
||||
//! - rustc needs to add its own Rust-specific objects (mingw is the example)
|
||||
//! - gcc wrapper cannot be used for some reason and linker like ld or lld is used directly.
|
||||
//! - gcc wrapper pulls wrong CRT objects (e.g. from glibc when we are targeting musl).
|
||||
//!
|
||||
//! In general it is preferable to rely on the target's native toolchain to pull the objects.
|
||||
//! However, for some targets (musl, mingw) rustc historically provides a more self-contained
|
||||
//! installation not requiring users to install the native target's toolchain.
|
||||
//! In that case rustc distributes the objects as a part of the target's Rust toolchain
|
||||
//! and falls back to linking with them manually.
|
||||
//! Unlike native toolchains, rustc only currently adds the libc's objects during linking,
|
||||
//! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
|
||||
//! when linking in self-contained mode.
|
||||
|
||||
use crate::spec::LinkOutputKind;
|
||||
use rustc_serialize::json::{Json, ToJson};
|
||||
use std::collections::BTreeMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub type CrtObjects = BTreeMap<LinkOutputKind, Vec<String>>;
|
||||
|
||||
pub(super) fn new(obj_table: &[(LinkOutputKind, &[&str])]) -> CrtObjects {
|
||||
obj_table.iter().map(|(z, k)| (*z, k.iter().map(|b| b.to_string()).collect())).collect()
|
||||
}
|
||||
|
||||
pub(super) fn all(obj: &str) -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &[obj]),
|
||||
(LinkOutputKind::DynamicPicExe, &[obj]),
|
||||
(LinkOutputKind::StaticNoPicExe, &[obj]),
|
||||
(LinkOutputKind::StaticPicExe, &[obj]),
|
||||
(LinkOutputKind::DynamicDylib, &[obj]),
|
||||
(LinkOutputKind::StaticDylib, &[obj]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn pre_musl_fallback() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["crt1.o", "crti.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["rcrt1.o", "crti.o"]),
|
||||
(LinkOutputKind::DynamicDylib, &["crti.o"]),
|
||||
(LinkOutputKind::StaticDylib, &["crti.o"]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_musl_fallback() -> CrtObjects {
|
||||
all("crtn.o")
|
||||
}
|
||||
|
||||
pub(super) fn pre_mingw_fallback() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["crt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::DynamicDylib, &["dllcrt2.o", "rsbegin.o"]),
|
||||
(LinkOutputKind::StaticDylib, &["dllcrt2.o", "rsbegin.o"]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_mingw_fallback() -> CrtObjects {
|
||||
all("rsend.o")
|
||||
}
|
||||
|
||||
pub(super) fn pre_mingw() -> CrtObjects {
|
||||
all("rsbegin.o")
|
||||
}
|
||||
|
||||
pub(super) fn post_mingw() -> CrtObjects {
|
||||
all("rsend.o")
|
||||
}
|
||||
|
||||
pub(super) fn pre_wasi_fallback() -> CrtObjects {
|
||||
new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["crt1.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["crt1.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["crt1.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["crt1.o"]),
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn post_wasi_fallback() -> CrtObjects {
|
||||
new(&[])
|
||||
}
|
||||
|
||||
/// Which logic to use to determine whether to fall back to the "self-contained" mode or not.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum CrtObjectsFallback {
|
||||
Musl,
|
||||
Mingw,
|
||||
Wasm,
|
||||
}
|
||||
|
||||
impl FromStr for CrtObjectsFallback {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<CrtObjectsFallback, ()> {
|
||||
Ok(match s {
|
||||
"musl" => CrtObjectsFallback::Musl,
|
||||
"mingw" => CrtObjectsFallback::Mingw,
|
||||
"wasm" => CrtObjectsFallback::Wasm,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for CrtObjectsFallback {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
CrtObjectsFallback::Musl => "musl",
|
||||
CrtObjectsFallback::Mingw => "mingw",
|
||||
CrtObjectsFallback::Wasm => "wasm",
|
||||
}
|
||||
.to_json()
|
||||
}
|
||||
}
|
29
compiler/rustc_target/src/spec/dragonfly_base.rs
Normal file
29
compiler/rustc_target/src/spec/dragonfly_base.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
args.insert(
|
||||
LinkerFlavor::Gcc,
|
||||
vec![
|
||||
// GNU-style linkers will use this to omit linking to libraries
|
||||
// which don't actually fulfill any relocations, but only for
|
||||
// libraries which follow this flag. Thus, use it before
|
||||
// specifying libraries to link to.
|
||||
"-Wl,--as-needed".to_string(),
|
||||
// Always enable NX protection when it is available
|
||||
"-Wl,-z,noexecstack".to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
dynamic_linking: true,
|
||||
executables: true,
|
||||
target_family: Some("unix".to_string()),
|
||||
linker_is_gnu: true,
|
||||
has_rpath: true,
|
||||
pre_link_args: args,
|
||||
position_independent_executables: true,
|
||||
relro_level: RelroLevel::Full,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
31
compiler/rustc_target/src/spec/freebsd_base.rs
Normal file
31
compiler/rustc_target/src/spec/freebsd_base.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
args.insert(
|
||||
LinkerFlavor::Gcc,
|
||||
vec![
|
||||
// GNU-style linkers will use this to omit linking to libraries
|
||||
// which don't actually fulfill any relocations, but only for
|
||||
// libraries which follow this flag. Thus, use it before
|
||||
// specifying libraries to link to.
|
||||
"-Wl,--as-needed".to_string(),
|
||||
// Always enable NX protection when it is available
|
||||
"-Wl,-z,noexecstack".to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
dynamic_linking: true,
|
||||
executables: true,
|
||||
target_family: Some("unix".to_string()),
|
||||
linker_is_gnu: true,
|
||||
has_rpath: true,
|
||||
pre_link_args: args,
|
||||
position_independent_executables: true,
|
||||
eliminate_frame_pointer: false, // FIXME 43575
|
||||
relro_level: RelroLevel::Full,
|
||||
abi_return_struct_as_int: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
42
compiler/rustc_target/src/spec/fuchsia_base.rs
Normal file
42
compiler/rustc_target/src/spec/fuchsia_base.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use crate::spec::{crt_objects, LinkArgs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut pre_link_args = LinkArgs::new();
|
||||
pre_link_args.insert(
|
||||
LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
vec![
|
||||
"--build-id".to_string(),
|
||||
"--hash-style=gnu".to_string(),
|
||||
"-z".to_string(),
|
||||
"max-page-size=4096".to_string(),
|
||||
"-z".to_string(),
|
||||
"now".to_string(),
|
||||
"-z".to_string(),
|
||||
"rodynamic".to_string(),
|
||||
"-z".to_string(),
|
||||
"separate-loadable-segments".to_string(),
|
||||
"--pack-dyn-relocs=relr".to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
lld_flavor: LldFlavor::Ld,
|
||||
dynamic_linking: true,
|
||||
executables: true,
|
||||
target_family: Some("unix".to_string()),
|
||||
is_like_fuchsia: true,
|
||||
linker_is_gnu: true,
|
||||
has_rpath: false,
|
||||
pre_link_args,
|
||||
pre_link_objects: crt_objects::new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["Scrt1.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["Scrt1.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["Scrt1.o"]),
|
||||
]),
|
||||
position_independent_executables: true,
|
||||
has_elf_tls: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
13
compiler/rustc_target/src/spec/haiku_base.rs
Normal file
13
compiler/rustc_target/src/spec/haiku_base.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use crate::spec::{RelroLevel, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
TargetOptions {
|
||||
dynamic_linking: true,
|
||||
executables: true,
|
||||
has_rpath: false,
|
||||
target_family: Some("unix".to_string()),
|
||||
relro_level: RelroLevel::Full,
|
||||
linker_is_gnu: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
25
compiler/rustc_target/src/spec/hermit_base.rs
Normal file
25
compiler/rustc_target/src/spec/hermit_base.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy};
|
||||
use crate::spec::{RelocModel, TargetOptions, TlsModel};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut pre_link_args = LinkArgs::new();
|
||||
pre_link_args.insert(
|
||||
LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
vec!["--build-id".to_string(), "--hash-style=gnu".to_string(), "--Bstatic".to_string()],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
executables: true,
|
||||
has_elf_tls: true,
|
||||
linker_is_gnu: true,
|
||||
pre_link_args,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
position_independent_executables: true,
|
||||
static_position_independent_executables: true,
|
||||
relocation_model: RelocModel::Pic,
|
||||
target_family: None,
|
||||
tls_model: TlsModel::InitialExec,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
26
compiler/rustc_target/src/spec/hermit_kernel_base.rs
Normal file
26
compiler/rustc_target/src/spec/hermit_kernel_base.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy};
|
||||
use crate::spec::{RelocModel, TargetOptions, TlsModel};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut pre_link_args = LinkArgs::new();
|
||||
pre_link_args.insert(
|
||||
LinkerFlavor::Lld(LldFlavor::Ld),
|
||||
vec!["--build-id".to_string(), "--hash-style=gnu".to_string(), "--Bstatic".to_string()],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
disable_redzone: true,
|
||||
linker: Some("rust-lld".to_owned()),
|
||||
executables: true,
|
||||
has_elf_tls: true,
|
||||
linker_is_gnu: true,
|
||||
pre_link_args,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
position_independent_executables: true,
|
||||
static_position_independent_executables: true,
|
||||
relocation_model: RelocModel::Pic,
|
||||
target_family: None,
|
||||
tls_model: TlsModel::InitialExec,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
39
compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
Normal file
39
compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, Target, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::linux_musl_base::opts();
|
||||
base.cpu = "hexagonv60".to_string();
|
||||
base.max_atomic_width = Some(32);
|
||||
// FIXME: HVX length defaults are per-CPU
|
||||
base.features = "-small-data,+hvx-length128b".to_string();
|
||||
|
||||
base.crt_static_default = false;
|
||||
base.atomic_cas = true;
|
||||
base.has_rpath = true;
|
||||
base.linker_is_gnu = false;
|
||||
base.dynamic_linking = true;
|
||||
base.executables = true;
|
||||
|
||||
base.pre_link_args = LinkArgs::new();
|
||||
base.post_link_args = LinkArgs::new();
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "hexagon-unknown-linux-musl".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: concat!(
|
||||
"e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32",
|
||||
":32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32",
|
||||
":32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048",
|
||||
":2048:2048"
|
||||
)
|
||||
.to_string(),
|
||||
arch: "hexagon".to_string(),
|
||||
target_os: "linux".to_string(),
|
||||
target_env: "musl".to_string(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: base,
|
||||
})
|
||||
}
|
21
compiler/rustc_target/src/spec/i386_apple_ios.rs
Normal file
21
compiler/rustc_target/src/spec/i386_apple_ios.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use super::apple_sdk_base::{opts, AppleOS, Arch};
|
||||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let base = opts(Arch::I386, AppleOS::iOS)?;
|
||||
Ok(Target {
|
||||
llvm_target: "i386-apple-ios".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
|
||||
f64:32:64-f80:128-n8:16:32-S128"
|
||||
.to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "ios".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "apple".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
|
||||
})
|
||||
}
|
8
compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
Normal file
8
compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
use crate::spec::TargetResult;
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::i686_pc_windows_msvc::target()?;
|
||||
base.options.cpu = "pentium".to_string();
|
||||
base.llvm_target = "i586-pc-windows-msvc".to_string();
|
||||
Ok(base)
|
||||
}
|
8
compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
Normal file
8
compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
use crate::spec::TargetResult;
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::i686_unknown_linux_gnu::target()?;
|
||||
base.options.cpu = "pentium".to_string();
|
||||
base.llvm_target = "i586-unknown-linux-gnu".to_string();
|
||||
Ok(base)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
use crate::spec::TargetResult;
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::i686_unknown_linux_musl::target()?;
|
||||
base.options.cpu = "pentium".to_string();
|
||||
base.llvm_target = "i586-unknown-linux-musl".to_string();
|
||||
Ok(base)
|
||||
}
|
33
compiler/rustc_target/src/spec/i686_apple_darwin.rs
Normal file
33
compiler/rustc_target/src/spec/i686_apple_darwin.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::apple_base::opts();
|
||||
base.cpu = "yonah".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
|
||||
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
|
||||
base.stack_probes = true;
|
||||
base.eliminate_frame_pointer = false;
|
||||
|
||||
// Clang automatically chooses a more specific target based on
|
||||
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
|
||||
// correctly, we do too.
|
||||
let arch = "i686";
|
||||
let llvm_target = super::apple_base::macos_llvm_target(&arch);
|
||||
|
||||
Ok(Target {
|
||||
llvm_target,
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
|
||||
f64:32:64-f80:128-n8:16:32-S128"
|
||||
.to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "macos".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "apple".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
|
||||
})
|
||||
}
|
31
compiler/rustc_target/src/spec/i686_linux_android.rs
Normal file
31
compiler/rustc_target/src/spec/i686_linux_android.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use crate::spec::{LinkerFlavor, Target, TargetResult};
|
||||
|
||||
// See https://developer.android.com/ndk/guides/abis.html#x86
|
||||
// for target ABI requirements.
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::android_base::opts();
|
||||
|
||||
base.max_atomic_width = Some(64);
|
||||
|
||||
// http://developer.android.com/ndk/guides/abis.html#x86
|
||||
base.cpu = "pentiumpro".to_string();
|
||||
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
|
||||
base.stack_probes = true;
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "i686-linux-android".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
target_pointer_width: "32".to_string(),
|
||||
target_c_int_width: "32".to_string(),
|
||||
data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
|
||||
f64:32:64-f80:32-n8:16:32-S128"
|
||||
.to_string(),
|
||||
arch: "x86".to_string(),
|
||||
target_os: "android".to_string(),
|
||||
target_env: String::new(),
|
||||
target_vendor: "unknown".to_string(),
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
options: base,
|
||||
})
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue