Don't depend on FnAbi for intrinsics

Intrinsics are not real functions and as such don't have any calling
convention. Trying to compute a calling convention for an intrinsic
anyway is a nonsensical operation.
This commit is contained in:
bjorn3
2025-05-22 17:49:28 +00:00
parent 0a14e1b2e7
commit 7122648e34

View File

@@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, List, Ty}; use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_session::config::OptLevel; use rustc_session::config::OptLevel;
use rustc_span::Span; use rustc_span::Span;
@@ -941,37 +941,55 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return merging_succ; return merging_succ;
} }
let fn_abi = bx.fn_abi_of_instance(instance, List::empty()); let result_layout =
self.cx.layout_of(self.monomorphized_place_ty(destination.as_ref()));
let mut llargs = Vec::with_capacity(1); let (result, store_in_local) = if result_layout.is_zst() {
let ret_dest = self.make_return_dest( (
bx, PlaceRef::new_sized(bx.const_undef(bx.type_ptr()), result_layout),
destination, None,
&fn_abi.ret, )
&mut llargs, } else if let Some(local) = destination.as_local() {
Some(intrinsic), match self.locals[local] {
); LocalRef::Place(dest) => (dest, None),
let dest = match ret_dest { LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
_ if fn_abi.ret.is_indirect() => llargs[0], LocalRef::PendingOperand => {
ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), // Currently, intrinsics always need a location to store
ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => { // the result, so we create a temporary `alloca` for the
dst.val.llval // result.
} let tmp = PlaceRef::alloca(bx, result_layout);
ReturnDest::DirectOperand(_) => { tmp.storage_live(bx);
bug!("Cannot use direct operand with an intrinsic call") (tmp, Some(local))
}
LocalRef::Operand(_) => {
bug!("place local already assigned to");
}
} }
} else {
(self.codegen_place(bx, destination.as_ref()), None)
}; };
if result.val.align < result.layout.align.abi {
// Currently, MIR code generation does not create calls
// that store directly to fields of packed structs (in
// fact, the calls it creates write only to temps).
//
// If someone changes that, please update this code path
// to create a temporary.
span_bug!(self.mir.span, "can't directly store to unaligned value");
}
let args: Vec<_> = let args: Vec<_> =
args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect();
let result = PlaceRef::new_sized(dest, fn_abi.ret.layout);
match self.codegen_intrinsic_call(bx, instance, &args, result, source_info) match self.codegen_intrinsic_call(bx, instance, &args, result, source_info)
{ {
Ok(()) => { Ok(()) => {
if let ReturnDest::IndirectOperand(dst, _) = ret_dest { if let Some(local) = store_in_local {
self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); let op = bx.load_operand(result);
result.storage_dead(bx);
self.overwrite_local(local, LocalRef::Operand(op));
self.debug_introduce_local(bx, local);
} }
return if let Some(target) = target { return if let Some(target) = target {
@@ -1026,7 +1044,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// We still need to call `make_return_dest` even if there's no `target`, since // We still need to call `make_return_dest` even if there's no `target`, since
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited, // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
// and `make_return_dest` adds the return-place indirect pointer to `llargs`. // and `make_return_dest` adds the return-place indirect pointer to `llargs`.
let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, None); let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs);
let destination = target.map(|target| (return_dest, target)); let destination = target.map(|target| (return_dest, target));
// Split the rust-call tupled arguments off. // Split the rust-call tupled arguments off.
@@ -1857,7 +1875,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
dest: mir::Place<'tcx>, dest: mir::Place<'tcx>,
fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, fn_ret: &ArgAbi<'tcx, Ty<'tcx>>,
llargs: &mut Vec<Bx::Value>, llargs: &mut Vec<Bx::Value>,
intrinsic: Option<ty::IntrinsicDef>,
) -> ReturnDest<'tcx, Bx::Value> { ) -> ReturnDest<'tcx, Bx::Value> {
// If the return is ignored, we can just return a do-nothing `ReturnDest`. // If the return is ignored, we can just return a do-nothing `ReturnDest`.
if fn_ret.is_ignore() { if fn_ret.is_ignore() {
@@ -1877,13 +1894,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
tmp.storage_live(bx); tmp.storage_live(bx);
llargs.push(tmp.val.llval); llargs.push(tmp.val.llval);
ReturnDest::IndirectOperand(tmp, index) ReturnDest::IndirectOperand(tmp, index)
} else if intrinsic.is_some() {
// Currently, intrinsics always need a location to store
// the result, so we create a temporary `alloca` for the
// result.
let tmp = PlaceRef::alloca(bx, fn_ret.layout);
tmp.storage_live(bx);
ReturnDest::IndirectOperand(tmp, index)
} else { } else {
ReturnDest::DirectOperand(index) ReturnDest::DirectOperand(index)
}; };
@@ -1893,7 +1903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
} }
} else { } else {
self.codegen_place(bx, mir::PlaceRef { local: dest.local, projection: dest.projection }) self.codegen_place(bx, dest.as_ref())
}; };
if fn_ret.is_indirect() { if fn_ret.is_indirect() {
if dest.val.align < dest.layout.align.abi { if dest.val.align < dest.layout.align.abi {