Fix RISC-V C function ABI when passing/returning structs containing floats

This commit is contained in:
beetrees
2025-04-03 23:53:06 +01:00
parent 68ac5abb06
commit 5723c9997c
13 changed files with 537 additions and 134 deletions

View File

@@ -1,6 +1,6 @@
use std::cmp;
use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
use rustc_ast as ast;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::packed::Pu128;
@@ -13,7 +13,7 @@ use rustc_middle::{bug, span_bug};
use rustc_session::config::OptLevel;
use rustc_span::Span;
use rustc_span::source_map::Spanned;
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode};
use tracing::{debug, info};
use super::operand::OperandRef;
@@ -558,8 +558,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
};
let ty = bx.cast_backend_type(cast_ty);
bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi)
load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi)
}
};
bx.ret(llval);
@@ -1618,8 +1617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
MemFlags::empty(),
);
// ...and then load it with the ABI type.
let cast_ty = bx.cast_backend_type(cast);
llval = bx.load(cast_ty, llscratch, scratch_align);
llval = load_cast(bx, cast, llscratch, scratch_align);
bx.lifetime_end(llscratch, scratch_size);
} else {
// We can't use `PlaceRef::load` here because the argument
@@ -1969,3 +1967,47 @@ enum ReturnDest<'tcx, V> {
/// Store a direct return value to an operand local place.
DirectOperand(mir::Local),
}
fn load_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
cast: &CastTarget,
ptr: Bx::Value,
align: Align,
) -> Bx::Value {
let cast_ty = bx.cast_backend_type(cast);
if let Some(offset_from_start) = cast.rest_offset {
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
assert_eq!(cast.rest.unit.size, cast.rest.total);
let first_ty = bx.reg_backend_type(&cast.prefix[0].unwrap());
let second_ty = bx.reg_backend_type(&cast.rest.unit);
let first = bx.load(first_ty, ptr, align);
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
let second = bx.load(second_ty, second_ptr, align.restrict_for_offset(offset_from_start));
let res = bx.cx().const_poison(cast_ty);
let res = bx.insert_value(res, first, 0);
bx.insert_value(res, second, 1)
} else {
bx.load(cast_ty, ptr, align)
}
}
pub fn store_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
cast: &CastTarget,
value: Bx::Value,
ptr: Bx::Value,
align: Align,
) {
if let Some(offset_from_start) = cast.rest_offset {
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
assert_eq!(cast.rest.unit.size, cast.rest.total);
assert!(cast.prefix[0].is_some());
let first = bx.extract_value(value, 0);
let second = bx.extract_value(value, 1);
bx.store(first, ptr, align);
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
bx.store(second, second_ptr, align.restrict_for_offset(offset_from_start));
} else {
bx.store(value, ptr, align);
};
}

View File

@@ -26,6 +26,7 @@ pub mod place;
mod rvalue;
mod statement;
pub use self::block::store_cast;
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
use self::operand::{OperandRef, OperandValue};
use self::place::PlaceRef;
@@ -259,7 +260,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
PassMode::Cast { ref cast, .. } => {
debug!("alloc: {:?} (return place) -> place", local);
let size = cast.size(&start_bx);
let size = cast.size(&start_bx).max(layout.size);
return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
}
_ => {}