fix sparc64 ABI for aggregates with floating point members
This commit is contained in:
parent
6414e0b5b3
commit
128ceec92d
8 changed files with 272 additions and 58 deletions
|
@ -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) {
|
||||
|
@ -115,7 +117,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -123,7 +125,7 @@ where
|
|||
break;
|
||||
}
|
||||
|
||||
prefix[prefix_index] = Some(RegKind::Float);
|
||||
prefix[prefix_index] = Some(Reg::f64());
|
||||
prefix_index += 1;
|
||||
last_offset = offset + Reg::f64().size;
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
@ -16,7 +18,7 @@ where
|
|||
|
||||
let valid_unit = match unit.kind {
|
||||
RegKind::Integer => false,
|
||||
RegKind::Float => true,
|
||||
RegKind::Float => false,
|
||||
RegKind::Vector => arg.layout.size.bits() == 128,
|
||||
};
|
||||
|
||||
|
@ -24,33 +26,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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…
Add table
Add a link
Reference in a new issue