Skip to content

Commit

Permalink
Rollup merge of rust-lang#91003 - psumbera:sparc64-abi, r=nagisa
Browse files Browse the repository at this point in the history
fix sparc64 ABI for aggregates with floating point members

Fixes rust-lang#86163
  • Loading branch information
matthiaskrgr authored Nov 25, 2021
2 parents ae7e75a + edbdda3 commit 63c738d
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 58 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> {
.prefix
.iter()
.flatten()
.map(|&kind| reg_to_abi_param(Reg { kind, size: cast.prefix_chunk_size }))
.map(|&reg| reg_to_abi_param(reg))
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
.collect::<SmallVec<_>>();

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_gcc/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ impl GccType for CastTarget {
let mut args: Vec<_> = self
.prefix
.iter()
.flat_map(|option_kind| {
option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx))
.flat_map(|option_reg| {
option_reg.map(|reg| reg.gcc_type(cx))
})
.chain((0..rest_count).map(|_| rest_gcc_unit))
.collect();
Expand Down
22 changes: 15 additions & 7 deletions compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,7 @@ impl LlvmType for CastTarget {
let mut args: Vec<_> = self
.prefix
.iter()
.flat_map(|option_kind| {
option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
})
.flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)))
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();

Expand Down Expand Up @@ -466,6 +464,9 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
);
}
}
PassMode::Cast(cast) => {
cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
}
_ => {}
}
for arg in &self.args {
Expand Down Expand Up @@ -497,8 +498,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
apply(a);
apply(b);
}
PassMode::Cast(_) => {
apply(&ArgAttributes::new());
PassMode::Cast(cast) => {
apply(&cast.attrs);
}
}
}
Expand Down Expand Up @@ -533,6 +534,13 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
);
}
}
PassMode::Cast(cast) => {
cast.attrs.apply_attrs_to_callsite(
llvm::AttributePlace::ReturnValue,
&bx.cx,
callsite,
);
}
_ => {}
}
if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
Expand Down Expand Up @@ -577,8 +585,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
apply(bx.cx, a);
apply(bx.cx, b);
}
PassMode::Cast(_) => {
apply(bx.cx, &ArgAttributes::new());
PassMode::Cast(cast) => {
apply(bx.cx, &cast.attrs);
}
}
}
Expand Down
15 changes: 11 additions & 4 deletions compiler/rustc_target/src/abi/call/mips64.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
use crate::abi::call::{
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Reg, Uniform,
};
use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};

fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
Expand Down Expand Up @@ -115,15 +117,15 @@ where
for _ in 0..((offset - last_offset).bits() / 64)
.min((prefix.len() - prefix_index) as u64)
{
prefix[prefix_index] = Some(RegKind::Integer);
prefix[prefix_index] = Some(Reg::i64());
prefix_index += 1;
}

if prefix_index == prefix.len() {
break;
}

prefix[prefix_index] = Some(RegKind::Float);
prefix[prefix_index] = Some(Reg::f64());
prefix_index += 1;
last_offset = offset + Reg::f64().size;
}
Expand All @@ -137,8 +139,13 @@ where
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
arg.cast_to(CastTarget {
prefix,
prefix_chunk_size: Size::from_bytes(8),
rest: Uniform { unit: Reg::i64(), total: rest_size },
attrs: ArgAttributes {
regular: ArgAttribute::default(),
arg_ext: ArgExtension::None,
pointee_size: Size::ZERO,
pointee_align: None,
},
});
}

Expand Down
39 changes: 29 additions & 10 deletions compiler/rustc_target/src/abi/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ impl Uniform {

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct CastTarget {
pub prefix: [Option<RegKind>; 8],
pub prefix_chunk_size: Size,
pub prefix: [Option<Reg>; 8],
pub rest: Uniform,
pub attrs: ArgAttributes,
}

impl From<Reg> for CastTarget {
Expand All @@ -227,29 +227,48 @@ impl From<Reg> for CastTarget {

impl From<Uniform> for CastTarget {
fn from(uniform: Uniform) -> CastTarget {
CastTarget { prefix: [None; 8], prefix_chunk_size: Size::ZERO, rest: uniform }
CastTarget {
prefix: [None; 8],
rest: uniform,
attrs: ArgAttributes {
regular: ArgAttribute::default(),
arg_ext: ArgExtension::None,
pointee_size: Size::ZERO,
pointee_align: None,
},
}
}
}

impl CastTarget {
pub fn pair(a: Reg, b: Reg) -> CastTarget {
CastTarget {
prefix: [Some(a.kind), None, None, None, None, None, None, None],
prefix_chunk_size: a.size,
prefix: [Some(a), None, None, None, None, None, None, None],
rest: Uniform::from(b),
attrs: ArgAttributes {
regular: ArgAttribute::default(),
arg_ext: ArgExtension::None,
pointee_size: Size::ZERO,
pointee_align: None,
},
}
}

pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
(self.prefix_chunk_size * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
.align_to(self.rest.align(cx))
+ self.rest.total
pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
let mut size = self.rest.total;
for i in 0..self.prefix.iter().count() {
match self.prefix[i] {
Some(v) => size += Size { raw: v.size.bytes() },
None => {}
}
}
return size;
}

pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
self.prefix
.iter()
.filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk_size }.align(cx)))
.filter_map(|x| x.map(|reg| reg.align(cx)))
.fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
acc.max(align)
})
Expand Down
126 changes: 93 additions & 33 deletions compiler/rustc_target/src/abi/call/sparc64.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// FIXME: This needs an audit for correctness and completeness.

use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
use crate::abi::{HasDataLayout, TyAbiInterface};
use crate::abi::call::{
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Reg, RegKind, Uniform,
};
use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};

fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
where
Expand All @@ -16,41 +18,15 @@ where

let valid_unit = match unit.kind {
RegKind::Integer => false,
RegKind::Float => true,
RegKind::Float => false,
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: TyAbiInterface<'a, C> + Copy,
C: 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>)
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, in_registers_max: Size)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout,
Expand All @@ -60,13 +36,97 @@ where
return;
}

// This doesn't intentionally handle structures with floats which needs
// special care below.
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
arg.cast_to(uniform);
return;
}

if let abi::FieldsShape::Arbitrary { .. } = arg.layout.fields {
let dl = cx.data_layout();
let size = arg.layout.size;
let mut prefix = [None; 8];
let mut prefix_index = 0;
let mut last_offset = Size::ZERO;
let mut has_float = false;
let mut arg_attribute = ArgAttribute::default();

for i in 0..arg.layout.fields.count() {
let field = arg.layout.field(cx, i);
let offset = arg.layout.fields.offset(i);

if let abi::Abi::Scalar(scalar) = &field.abi {
if scalar.value == abi::F32 || scalar.value == abi::F64 {
has_float = true;

if !last_offset.is_aligned(dl.f64_align.abi) && last_offset < offset {
if prefix_index == prefix.len() {
break;
}
prefix[prefix_index] = Some(Reg::i32());
prefix_index += 1;
last_offset = last_offset + Reg::i32().size;
}

for _ in 0..((offset - last_offset).bits() / 64)
.min((prefix.len() - prefix_index) as u64)
{
prefix[prefix_index] = Some(Reg::i64());
prefix_index += 1;
last_offset = last_offset + Reg::i64().size;
}

if last_offset < offset {
if prefix_index == prefix.len() {
break;
}
prefix[prefix_index] = Some(Reg::i32());
prefix_index += 1;
last_offset = last_offset + Reg::i32().size;
}

if prefix_index == prefix.len() {
break;
}

if scalar.value == abi::F32 {
arg_attribute = ArgAttribute::InReg;
prefix[prefix_index] = Some(Reg::f32());
last_offset = offset + Reg::f32().size;
} else {
prefix[prefix_index] = Some(Reg::f64());
last_offset = offset + Reg::f64().size;
}
prefix_index += 1;
}
}
}

if has_float && arg.layout.size <= in_registers_max {
let mut rest_size = size - last_offset;

if (rest_size.raw % 8) != 0 && prefix_index < prefix.len() {
prefix[prefix_index] = Some(Reg::i32());
rest_size = rest_size - Reg::i32().size;
}

arg.cast_to(CastTarget {
prefix,
rest: Uniform { unit: Reg::i64(), total: rest_size },
attrs: ArgAttributes {
regular: arg_attribute,
arg_ext: ArgExtension::None,
pointee_size: Size::ZERO,
pointee_align: None,
},
});
return;
}
}

let total = arg.layout.size;
if total.bits() > 128 {
if total > in_registers_max {
arg.make_indirect();
return;
}
Expand All @@ -80,13 +140,13 @@ where
C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
classify_ret(cx, &mut fn_abi.ret);
classify_arg(cx, &mut fn_abi.ret, Size { raw: 32 });
}

for arg in &mut fn_abi.args {
if arg.is_ignore() {
continue;
}
classify_arg(cx, arg);
classify_arg(cx, arg, Size { raw: 16 });
}
}
Loading

0 comments on commit 63c738d

Please sign in to comment.