2020-09-23 13:13:49 +00:00
|
|
|
//! Handling of everything related to the calling convention. Also fills `fx.local_map`.
|
|
|
|
|
2019-08-30 12:21:24 +00:00
|
|
|
mod comments;
|
2019-08-30 09:58:52 +00:00
|
|
|
mod pass_mode;
|
2019-08-31 17:28:09 +00:00
|
|
|
mod returning;
|
2019-08-30 09:58:52 +00:00
|
|
|
|
2023-03-15 14:41:48 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
2022-07-25 14:07:57 +00:00
|
|
|
use cranelift_module::ModuleError;
|
2020-05-29 09:06:29 +00:00
|
|
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
2021-09-01 21:09:34 +00:00
|
|
|
use rustc_middle::ty::layout::FnAbiOf;
|
2023-01-24 17:56:42 +00:00
|
|
|
use rustc_session::Session;
|
2021-02-01 09:11:46 +00:00
|
|
|
use rustc_target::abi::call::{Conv, FnAbi};
|
2020-08-28 10:10:48 +00:00
|
|
|
use rustc_target::spec::abi::Abi;
|
2018-07-19 17:33:42 +00:00
|
|
|
|
2021-08-06 14:26:56 +00:00
|
|
|
use cranelift_codegen::ir::{AbiParam, SigRef};
|
2019-12-24 11:40:18 +00:00
|
|
|
|
2019-08-30 09:58:52 +00:00
|
|
|
use self::pass_mode::*;
|
2019-08-31 17:28:09 +00:00
|
|
|
use crate::prelude::*;
|
2018-09-08 16:00:06 +00:00
|
|
|
|
2021-08-06 14:26:56 +00:00
|
|
|
pub(crate) use self::returning::codegen_return;
|
2019-08-30 10:30:57 +00:00
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
fn clif_sig_from_fn_abi<'tcx>(
|
2019-08-31 17:28:09 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2021-12-20 17:56:35 +00:00
|
|
|
default_call_conv: CallConv,
|
2021-02-01 09:11:46 +00:00
|
|
|
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
2019-08-31 17:28:09 +00:00
|
|
|
) -> Signature {
|
2023-01-24 17:56:42 +00:00
|
|
|
let call_conv = conv_to_call_conv(tcx.sess, fn_abi.conv, default_call_conv);
|
2022-11-17 09:29:32 +00:00
|
|
|
|
2023-03-15 14:41:48 +00:00
|
|
|
let inputs = fn_abi.args.iter().flat_map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter());
|
2022-11-17 09:29:32 +00:00
|
|
|
|
|
|
|
let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx);
|
2023-09-28 08:15:41 +00:00
|
|
|
// Sometimes the first param is a pointer to the place where the return value needs to be stored.
|
2022-11-17 09:29:32 +00:00
|
|
|
let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect();
|
|
|
|
|
|
|
|
Signature { params, returns, call_conv }
|
|
|
|
}
|
|
|
|
|
2023-01-24 17:56:42 +00:00
|
|
|
pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
|
2022-11-17 09:29:32 +00:00
|
|
|
match c {
|
2022-05-29 17:50:51 +00:00
|
|
|
Conv::Rust | Conv::C => default_call_conv,
|
2023-08-27 00:42:59 +00:00
|
|
|
Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold,
|
2021-02-01 09:11:46 +00:00
|
|
|
Conv::X86_64SysV => CallConv::SystemV,
|
|
|
|
Conv::X86_64Win64 => CallConv::WindowsFastcall,
|
2023-01-24 17:56:42 +00:00
|
|
|
|
|
|
|
// Should already get a back compat warning
|
|
|
|
Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => {
|
|
|
|
default_call_conv
|
|
|
|
}
|
|
|
|
|
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.
```rust
static mut CNT: usize = 0;
pub extern "riscv-interrupt-m" fn isr_m() {
unsafe {
CNT += 1;
}
}
```
to produce highly effective assembly like:
```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0: 1141 addi sp,sp,-16
unsafe {
CNT += 1;
420003a2: c62a sw a0,12(sp)
420003a4: c42e sw a1,8(sp)
420003a6: 3fc80537 lui a0,0x3fc80
420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae: 0585 addi a1,a1,1
420003b0: 62b52e23 sw a1,1596(a0)
}
}
420003b4: 4532 lw a0,12(sp)
420003b6: 45a2 lw a1,8(sp)
420003b8: 0141 addi sp,sp,16
420003ba: 30200073 mret
```
(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)
This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.
At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).
This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].
Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.
Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).
[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 22:08:23 +00:00
|
|
|
Conv::X86Intr | Conv::RiscvInterrupt { .. } => {
|
|
|
|
sess.fatal(format!("interrupt call conv {c:?} not yet implemented"))
|
|
|
|
}
|
2023-01-24 17:56:42 +00:00
|
|
|
|
|
|
|
Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"),
|
|
|
|
Conv::CCmseNonSecureCall => {
|
|
|
|
sess.fatal("C-cmse-nonsecure-call call conv is not yet implemented");
|
|
|
|
}
|
|
|
|
|
|
|
|
Conv::Msp430Intr
|
2021-02-01 09:11:46 +00:00
|
|
|
| Conv::PtxKernel
|
|
|
|
| Conv::AmdGpuKernel
|
|
|
|
| Conv::AvrInterrupt
|
2023-01-24 17:56:42 +00:00
|
|
|
| Conv::AvrNonBlockingInterrupt => {
|
|
|
|
unreachable!("tried to use {c:?} call conv which only exists on an unsupported target");
|
|
|
|
}
|
2022-11-17 09:29:32 +00:00
|
|
|
}
|
2018-07-19 17:33:42 +00:00
|
|
|
}
|
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
pub(crate) fn get_function_sig<'tcx>(
|
2019-06-16 09:13:49 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2022-12-14 18:30:46 +00:00
|
|
|
default_call_conv: CallConv,
|
2018-08-11 11:59:08 +00:00
|
|
|
inst: Instance<'tcx>,
|
2021-02-01 09:11:46 +00:00
|
|
|
) -> Signature {
|
2023-07-11 21:35:29 +00:00
|
|
|
assert!(!inst.args.has_infer());
|
2021-09-01 21:29:15 +00:00
|
|
|
clif_sig_from_fn_abi(
|
|
|
|
tcx,
|
2022-12-14 18:30:46 +00:00
|
|
|
default_call_conv,
|
2021-09-01 21:29:15 +00:00
|
|
|
&RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
|
|
|
|
)
|
2018-08-11 11:59:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-02 11:20:32 +00:00
|
|
|
/// Instance must be monomorphized
|
2020-03-27 11:14:45 +00:00
|
|
|
pub(crate) fn import_function<'tcx>(
|
2019-06-16 09:13:49 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2021-03-05 18:12:59 +00:00
|
|
|
module: &mut dyn Module,
|
2019-01-02 11:20:32 +00:00
|
|
|
inst: Instance<'tcx>,
|
|
|
|
) -> FuncId {
|
2021-04-30 12:49:58 +00:00
|
|
|
let name = tcx.symbol_name(inst).name;
|
2022-12-14 18:30:46 +00:00
|
|
|
let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst);
|
2022-07-25 14:07:57 +00:00
|
|
|
match module.declare_function(name, Linkage::Import, &sig) {
|
|
|
|
Ok(func_id) => func_id,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
|
|
|
Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(format!(
|
2022-07-25 14:07:57 +00:00
|
|
|
"attempt to declare `{name}` as function, but it was already declared as static"
|
|
|
|
)),
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
|
|
|
Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.sess.fatal(format!(
|
2022-07-25 14:07:57 +00:00
|
|
|
"attempt to declare `{name}` with signature {new_sig:?}, \
|
|
|
|
but it was already declared with signature {prev_sig:?}"
|
|
|
|
)),
|
|
|
|
Err(err) => Err::<_, _>(err).unwrap(),
|
|
|
|
}
|
2019-01-02 11:20:32 +00:00
|
|
|
}
|
2018-09-08 16:00:06 +00:00
|
|
|
|
2021-03-05 18:12:59 +00:00
|
|
|
impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
2018-09-08 16:00:06 +00:00
|
|
|
/// Instance must be monomorphized
|
2020-03-27 11:14:45 +00:00
|
|
|
pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
|
2021-04-30 12:49:58 +00:00
|
|
|
let func_id = import_function(self.tcx, self.module, inst);
|
|
|
|
let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
|
2018-12-28 16:07:40 +00:00
|
|
|
|
2021-03-29 08:45:09 +00:00
|
|
|
if self.clif_comments.enabled() {
|
|
|
|
self.add_comment(func_ref, format!("{:?}", inst));
|
|
|
|
}
|
2018-12-28 16:07:40 +00:00
|
|
|
|
2018-12-27 09:59:01 +00:00
|
|
|
func_ref
|
2018-07-19 17:33:42 +00:00
|
|
|
}
|
2018-07-20 11:36:53 +00:00
|
|
|
|
2020-04-25 17:07:25 +00:00
|
|
|
pub(crate) fn lib_call(
|
2018-07-30 13:34:34 +00:00
|
|
|
&mut self,
|
|
|
|
name: &str,
|
2021-02-01 09:11:46 +00:00
|
|
|
params: Vec<AbiParam>,
|
|
|
|
returns: Vec<AbiParam>,
|
2018-07-30 13:34:34 +00:00
|
|
|
args: &[Value],
|
2023-03-15 14:41:48 +00:00
|
|
|
) -> Cow<'_, [Value]> {
|
|
|
|
if self.tcx.sess.target.is_like_windows {
|
|
|
|
let (mut params, mut args): (Vec<_>, Vec<_>) =
|
|
|
|
params
|
|
|
|
.into_iter()
|
|
|
|
.zip(args)
|
|
|
|
.map(|(param, &arg)| {
|
|
|
|
if param.value_type == types::I128 {
|
|
|
|
let arg_ptr = Pointer::stack_slot(self.bcx.create_sized_stack_slot(
|
|
|
|
StackSlotData { kind: StackSlotKind::ExplicitSlot, size: 16 },
|
|
|
|
));
|
|
|
|
arg_ptr.store(self, arg, MemFlags::trusted());
|
|
|
|
(AbiParam::new(self.pointer_type), arg_ptr.get_addr(self))
|
|
|
|
} else {
|
|
|
|
(param, arg)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.unzip();
|
|
|
|
|
|
|
|
let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128;
|
|
|
|
|
|
|
|
if indirect_ret_val {
|
|
|
|
params.insert(0, AbiParam::new(self.pointer_type));
|
|
|
|
let ret_ptr =
|
|
|
|
Pointer::stack_slot(self.bcx.create_sized_stack_slot(StackSlotData {
|
|
|
|
kind: StackSlotKind::ExplicitSlot,
|
|
|
|
size: 16,
|
|
|
|
}));
|
|
|
|
args.insert(0, ret_ptr.get_addr(self));
|
|
|
|
self.lib_call_unadjusted(name, params, vec![], &args);
|
|
|
|
return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]);
|
|
|
|
} else {
|
|
|
|
return self.lib_call_unadjusted(name, params, returns, &args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.lib_call_unadjusted(name, params, returns, args)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn lib_call_unadjusted(
|
|
|
|
&mut self,
|
|
|
|
name: &str,
|
|
|
|
params: Vec<AbiParam>,
|
|
|
|
returns: Vec<AbiParam>,
|
|
|
|
args: &[Value],
|
|
|
|
) -> Cow<'_, [Value]> {
|
2021-12-20 17:56:35 +00:00
|
|
|
let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv };
|
2021-04-30 12:49:58 +00:00
|
|
|
let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
|
|
|
|
let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
|
2022-03-20 15:55:21 +00:00
|
|
|
if self.clif_comments.enabled() {
|
|
|
|
self.add_comment(func_ref, format!("{:?}", name));
|
|
|
|
}
|
2018-07-30 13:34:34 +00:00
|
|
|
let call_inst = self.bcx.ins().call(func_ref, args);
|
2021-03-29 08:45:09 +00:00
|
|
|
if self.clif_comments.enabled() {
|
2023-03-15 14:41:48 +00:00
|
|
|
self.add_comment(call_inst, format!("lib_call {}", name));
|
2019-07-30 13:00:15 +00:00
|
|
|
}
|
2018-07-30 13:34:34 +00:00
|
|
|
let results = self.bcx.inst_results(call_inst);
|
2019-07-20 15:57:00 +00:00
|
|
|
assert!(results.len() <= 2, "{}", results.len());
|
2023-03-15 14:41:48 +00:00
|
|
|
Cow::Borrowed(results)
|
2018-07-30 13:34:34 +00:00
|
|
|
}
|
2018-07-19 17:33:42 +00:00
|
|
|
}
|
|
|
|
|
2020-09-23 13:13:49 +00:00
|
|
|
/// Make a [`CPlace`] capable of holding value of the specified type.
|
2020-09-16 16:45:19 +00:00
|
|
|
fn make_local_place<'tcx>(
|
2021-03-05 18:12:59 +00:00
|
|
|
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
2018-12-25 15:47:33 +00:00
|
|
|
local: Local,
|
2020-03-30 17:00:24 +00:00
|
|
|
layout: TyAndLayout<'tcx>,
|
2018-12-25 15:47:33 +00:00
|
|
|
is_ssa: bool,
|
|
|
|
) -> CPlace<'tcx> {
|
2023-01-24 17:56:42 +00:00
|
|
|
if layout.is_unsized() {
|
|
|
|
fx.tcx.sess.span_fatal(
|
|
|
|
fx.mir.local_decls[local].source_info.span,
|
|
|
|
"unsized locals are not yet supported",
|
|
|
|
);
|
|
|
|
}
|
2018-12-25 15:47:33 +00:00
|
|
|
let place = if is_ssa {
|
2020-07-02 22:23:21 +00:00
|
|
|
if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi {
|
|
|
|
CPlace::new_var_pair(fx, local, layout)
|
|
|
|
} else {
|
|
|
|
CPlace::new_var(fx, local, layout)
|
|
|
|
}
|
2018-12-25 15:47:33 +00:00
|
|
|
} else {
|
2020-01-15 12:17:09 +00:00
|
|
|
CPlace::new_stack_slot(fx, layout)
|
2018-12-25 15:47:33 +00:00
|
|
|
};
|
|
|
|
|
2019-08-30 12:21:24 +00:00
|
|
|
self::comments::add_local_place_comments(fx, place, local);
|
|
|
|
|
2020-09-16 16:45:19 +00:00
|
|
|
place
|
2018-12-25 15:47:33 +00:00
|
|
|
}
|
|
|
|
|
2021-03-05 18:12:59 +00:00
|
|
|
pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_block: Block) {
|
2021-02-01 09:11:46 +00:00
|
|
|
fx.bcx.append_block_params_for_function_params(start_block);
|
|
|
|
|
|
|
|
fx.bcx.switch_to_block(start_block);
|
|
|
|
fx.bcx.ins().nop();
|
|
|
|
|
2018-08-09 08:46:56 +00:00
|
|
|
let ssa_analyzed = crate::analyze::analyze(fx);
|
2018-12-28 16:07:40 +00:00
|
|
|
|
2019-08-30 13:07:15 +00:00
|
|
|
self::comments::add_args_header_comment(fx);
|
2018-12-27 09:59:01 +00:00
|
|
|
|
2021-03-05 18:12:59 +00:00
|
|
|
let mut block_params_iter = fx.bcx.func.dfg.block_params(start_block).to_vec().into_iter();
|
2021-02-01 09:11:46 +00:00
|
|
|
let ret_place =
|
|
|
|
self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter);
|
2020-09-16 16:45:19 +00:00
|
|
|
assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE);
|
2019-08-30 10:30:57 +00:00
|
|
|
|
2019-03-26 18:53:04 +00:00
|
|
|
// None means pass_mode == NoPass
|
2018-12-27 09:59:01 +00:00
|
|
|
enum ArgKind<'tcx> {
|
2019-03-26 18:53:04 +00:00
|
|
|
Normal(Option<CValue<'tcx>>),
|
|
|
|
Spread(Vec<Option<CValue<'tcx>>>),
|
2018-07-27 17:27:20 +00:00
|
|
|
}
|
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
let fn_abi = fx.fn_abi.take().unwrap();
|
2022-07-25 14:07:57 +00:00
|
|
|
|
|
|
|
// FIXME implement variadics in cranelift
|
|
|
|
if fn_abi.c_variadic {
|
|
|
|
fx.tcx.sess.span_fatal(
|
|
|
|
fx.mir.span,
|
|
|
|
"Defining variadic functions is not yet supported by Cranelift",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
let mut arg_abis_iter = fn_abi.args.iter();
|
|
|
|
|
2018-08-14 10:13:07 +00:00
|
|
|
let func_params = fx
|
|
|
|
.mir
|
|
|
|
.args_iter()
|
|
|
|
.map(|local| {
|
2020-10-28 07:25:06 +00:00
|
|
|
let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty);
|
2018-08-14 10:13:07 +00:00
|
|
|
|
|
|
|
// Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
|
|
|
|
if Some(local) == fx.mir.spread_arg {
|
|
|
|
// This argument (e.g. the last argument in the "rust-call" ABI)
|
|
|
|
// is a tuple that was spread at the ABI level and now we have
|
|
|
|
// to reconstruct it into a tuple local variable, from multiple
|
|
|
|
// individual function arguments.
|
|
|
|
|
2020-09-05 08:38:49 +00:00
|
|
|
let tupled_arg_tys = match arg_ty.kind() {
|
2018-08-24 12:51:02 +00:00
|
|
|
ty::Tuple(ref tys) => tys,
|
2018-08-14 10:13:07 +00:00
|
|
|
_ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty),
|
|
|
|
};
|
|
|
|
|
2018-12-27 09:59:01 +00:00
|
|
|
let mut params = Vec::new();
|
2022-02-07 15:06:31 +00:00
|
|
|
for (i, _arg_ty) in tupled_arg_tys.iter().enumerate() {
|
2021-02-01 09:11:46 +00:00
|
|
|
let arg_abi = arg_abis_iter.next().unwrap();
|
|
|
|
let param =
|
|
|
|
cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter);
|
2018-12-27 09:59:01 +00:00
|
|
|
params.push(param);
|
2018-08-14 10:13:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-27 09:59:01 +00:00
|
|
|
(local, ArgKind::Spread(params), arg_ty)
|
2018-08-14 10:13:07 +00:00
|
|
|
} else {
|
2021-02-01 09:11:46 +00:00
|
|
|
let arg_abi = arg_abis_iter.next().unwrap();
|
|
|
|
let param =
|
|
|
|
cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter);
|
2019-02-21 14:06:09 +00:00
|
|
|
(local, ArgKind::Normal(param), arg_ty)
|
2018-07-27 17:27:20 +00:00
|
|
|
}
|
2018-10-10 17:07:13 +00:00
|
|
|
})
|
2020-04-05 11:48:26 +00:00
|
|
|
.collect::<Vec<(Local, ArgKind<'tcx>, Ty<'tcx>)>>();
|
2018-07-27 17:27:20 +00:00
|
|
|
|
2020-01-11 15:49:42 +00:00
|
|
|
assert!(fx.caller_location.is_none());
|
2020-08-22 14:47:31 +00:00
|
|
|
if fx.instance.def.requires_caller_location(fx.tcx) {
|
2020-01-11 15:49:42 +00:00
|
|
|
// Store caller location for `#[track_caller]`.
|
2021-02-01 09:11:46 +00:00
|
|
|
let arg_abi = arg_abis_iter.next().unwrap();
|
|
|
|
fx.caller_location =
|
|
|
|
Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap());
|
2020-01-11 15:49:42 +00:00
|
|
|
}
|
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind");
|
|
|
|
fx.fn_abi = Some(fn_abi);
|
|
|
|
assert!(block_params_iter.next().is_none(), "arg_value left behind");
|
2018-08-14 16:52:43 +00:00
|
|
|
|
2019-08-30 13:07:15 +00:00
|
|
|
self::comments::add_locals_header_comment(fx);
|
|
|
|
|
2018-07-27 17:27:20 +00:00
|
|
|
for (local, arg_kind, ty) in func_params {
|
2020-01-25 15:23:54 +00:00
|
|
|
// While this is normally an optimization to prevent an unnecessary copy when an argument is
|
|
|
|
// not mutated by the current function, this is necessary to support unsized arguments.
|
2020-11-03 10:00:04 +00:00
|
|
|
if let ArgKind::Normal(Some(val)) = arg_kind {
|
|
|
|
if let Some((addr, meta)) = val.try_to_ptr() {
|
2021-08-06 14:26:56 +00:00
|
|
|
// Ownership of the value at the backing storage for an argument is passed to the
|
|
|
|
// callee per the ABI, so it is fine to borrow the backing storage of this argument
|
|
|
|
// to prevent a copy.
|
|
|
|
|
|
|
|
let place = if let Some(meta) = meta {
|
|
|
|
CPlace::for_ptr_with_extra(addr, meta, val.layout())
|
|
|
|
} else {
|
|
|
|
CPlace::for_ptr(addr, val.layout())
|
|
|
|
};
|
|
|
|
|
|
|
|
self::comments::add_local_place_comments(fx, place, local);
|
|
|
|
|
|
|
|
assert_eq!(fx.local_map.push(place), local);
|
|
|
|
continue;
|
2019-08-30 13:41:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-15 14:41:48 +00:00
|
|
|
let layout = fx.layout_of(ty);
|
|
|
|
let is_ssa = ssa_analyzed[local].is_ssa(fx, ty);
|
2020-09-16 16:45:19 +00:00
|
|
|
let place = make_local_place(fx, local, layout, is_ssa);
|
|
|
|
assert_eq!(fx.local_map.push(place), local);
|
2018-12-26 10:15:42 +00:00
|
|
|
|
2018-12-22 16:42:38 +00:00
|
|
|
match arg_kind {
|
2018-12-27 09:59:01 +00:00
|
|
|
ArgKind::Normal(param) => {
|
2019-03-26 18:53:04 +00:00
|
|
|
if let Some(param) = param {
|
|
|
|
place.write_cvalue(fx, param);
|
|
|
|
}
|
2018-12-22 16:42:38 +00:00
|
|
|
}
|
2018-12-27 09:59:01 +00:00
|
|
|
ArgKind::Spread(params) => {
|
|
|
|
for (i, param) in params.into_iter().enumerate() {
|
2019-03-26 18:53:04 +00:00
|
|
|
if let Some(param) = param {
|
2023-03-28 19:32:57 +00:00
|
|
|
place.place_field(fx, FieldIdx::new(i)).write_cvalue(fx, param);
|
2019-03-26 18:53:04 +00:00
|
|
|
}
|
2018-07-27 17:27:20 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-19 17:33:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-24 09:54:11 +00:00
|
|
|
for local in fx.mir.vars_and_temps_iter() {
|
2020-10-28 07:25:06 +00:00
|
|
|
let ty = fx.monomorphize(fx.mir.local_decls[local].ty);
|
2020-06-24 09:54:11 +00:00
|
|
|
let layout = fx.layout_of(ty);
|
2018-08-09 08:46:56 +00:00
|
|
|
|
2023-03-15 14:41:48 +00:00
|
|
|
let is_ssa = ssa_analyzed[local].is_ssa(fx, ty);
|
2018-08-09 08:46:56 +00:00
|
|
|
|
2020-09-16 16:45:19 +00:00
|
|
|
let place = make_local_place(fx, local, layout, is_ssa);
|
|
|
|
assert_eq!(fx.local_map.push(place), local);
|
2018-07-19 17:33:42 +00:00
|
|
|
}
|
2018-08-14 16:52:43 +00:00
|
|
|
|
2021-03-05 18:12:59 +00:00
|
|
|
fx.bcx.ins().jump(*fx.block_map.get(START_BLOCK).unwrap(), &[]);
|
2018-07-19 17:33:42 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 14:26:56 +00:00
|
|
|
struct CallArgument<'tcx> {
|
|
|
|
value: CValue<'tcx>,
|
|
|
|
is_owned: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME avoid intermediate `CValue` before calling `adjust_arg_for_abi`
|
|
|
|
fn codegen_call_argument_operand<'tcx>(
|
|
|
|
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
|
|
|
operand: &Operand<'tcx>,
|
|
|
|
) -> CallArgument<'tcx> {
|
|
|
|
CallArgument {
|
|
|
|
value: codegen_operand(fx, operand),
|
|
|
|
is_owned: matches!(operand, Operand::Move(_)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-27 11:14:45 +00:00
|
|
|
pub(crate) fn codegen_terminator_call<'tcx>(
|
2021-03-05 18:12:59 +00:00
|
|
|
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
2022-05-15 10:32:19 +00:00
|
|
|
source_info: mir::SourceInfo,
|
2018-07-19 17:33:42 +00:00
|
|
|
func: &Operand<'tcx>,
|
|
|
|
args: &[Operand<'tcx>],
|
2022-04-16 13:27:54 +00:00
|
|
|
destination: Place<'tcx>,
|
|
|
|
target: Option<BasicBlock>,
|
2018-07-20 11:51:34 +00:00
|
|
|
) {
|
2022-12-14 18:30:46 +00:00
|
|
|
let func = codegen_operand(fx, func);
|
|
|
|
let fn_sig = func.layout().ty.fn_sig(fx.tcx);
|
2018-07-21 16:38:08 +00:00
|
|
|
|
2022-04-16 13:27:54 +00:00
|
|
|
let ret_place = codegen_place(fx, destination);
|
2018-09-11 17:27:57 +00:00
|
|
|
|
2022-08-18 02:13:37 +00:00
|
|
|
// Handle special calls like intrinsics and empty drop glue.
|
2023-07-11 21:35:29 +00:00
|
|
|
let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() {
|
2022-12-11 19:46:58 +00:00
|
|
|
let instance =
|
2023-07-11 21:35:29 +00:00
|
|
|
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args)
|
2022-12-11 19:46:58 +00:00
|
|
|
.polymorphize(fx.tcx);
|
2018-12-20 13:57:21 +00:00
|
|
|
|
2020-08-22 14:47:31 +00:00
|
|
|
if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
|
2020-03-27 11:14:45 +00:00
|
|
|
crate::intrinsics::codegen_llvm_intrinsic_call(
|
2019-08-31 17:28:09 +00:00
|
|
|
fx,
|
2020-08-22 14:47:31 +00:00
|
|
|
&fx.tcx.symbol_name(instance).name,
|
2023-07-11 21:35:29 +00:00
|
|
|
fn_args,
|
2019-08-31 17:28:09 +00:00
|
|
|
args,
|
2022-04-16 13:27:54 +00:00
|
|
|
ret_place,
|
|
|
|
target,
|
2019-08-31 17:28:09 +00:00
|
|
|
);
|
2019-07-28 07:54:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-20 13:57:21 +00:00
|
|
|
match instance.def {
|
|
|
|
InstanceDef::Intrinsic(_) => {
|
2022-05-15 10:32:19 +00:00
|
|
|
crate::intrinsics::codegen_intrinsic_call(
|
|
|
|
fx,
|
|
|
|
instance,
|
|
|
|
args,
|
2022-04-16 13:27:54 +00:00
|
|
|
ret_place,
|
|
|
|
target,
|
2022-05-15 10:32:19 +00:00
|
|
|
source_info,
|
|
|
|
);
|
2018-12-20 13:57:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
InstanceDef::DropGlue(_, None) => {
|
|
|
|
// empty drop glue - a nop.
|
2022-04-16 13:27:54 +00:00
|
|
|
let dest = target.expect("Non terminating drop_in_place_real???");
|
2020-02-14 17:23:29 +00:00
|
|
|
let ret_block = fx.get_block(dest);
|
|
|
|
fx.bcx.ins().jump(ret_block, &[]);
|
2018-12-20 13:57:21 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-08-28 10:10:48 +00:00
|
|
|
_ => Some(instance),
|
2018-09-11 17:27:57 +00:00
|
|
|
}
|
2020-04-13 17:12:44 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2018-10-03 16:21:52 +00:00
|
|
|
|
2022-12-14 18:30:46 +00:00
|
|
|
let extra_args = &args[fn_sig.inputs().skip_binder().len()..];
|
2023-02-17 03:33:08 +00:00
|
|
|
let extra_args = fx.tcx.mk_type_list_from_iter(
|
|
|
|
extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))),
|
|
|
|
);
|
2021-02-01 09:11:46 +00:00
|
|
|
let fn_abi = if let Some(instance) = instance {
|
2021-09-01 21:29:15 +00:00
|
|
|
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
|
2021-02-01 09:11:46 +00:00
|
|
|
} else {
|
2022-12-14 18:30:46 +00:00
|
|
|
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
|
2021-02-01 09:11:46 +00:00
|
|
|
};
|
|
|
|
|
2022-12-14 18:30:46 +00:00
|
|
|
let is_cold = if fn_sig.abi() == Abi::RustCold {
|
2022-07-25 14:07:57 +00:00
|
|
|
true
|
|
|
|
} else {
|
2023-05-24 14:33:43 +00:00
|
|
|
instance.is_some_and(|inst| {
|
|
|
|
fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)
|
|
|
|
})
|
2022-07-25 14:07:57 +00:00
|
|
|
};
|
2020-05-29 09:06:29 +00:00
|
|
|
if is_cold {
|
2022-03-20 15:55:21 +00:00
|
|
|
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
|
2022-04-16 13:27:54 +00:00
|
|
|
if let Some(destination_block) = target {
|
2022-03-20 15:55:21 +00:00
|
|
|
fx.bcx.set_cold_block(fx.get_block(destination_block));
|
|
|
|
}
|
2020-05-29 09:06:29 +00:00
|
|
|
}
|
|
|
|
|
2019-07-28 09:24:33 +00:00
|
|
|
// Unpack arguments tuple for closures
|
2022-12-14 18:30:46 +00:00
|
|
|
let mut args = if fn_sig.abi() == Abi::RustCall {
|
2023-07-22 13:32:34 +00:00
|
|
|
let (self_arg, pack_arg) = match args {
|
|
|
|
[pack_arg] => (None, codegen_call_argument_operand(fx, pack_arg)),
|
|
|
|
[self_arg, pack_arg] => (
|
|
|
|
Some(codegen_call_argument_operand(fx, self_arg)),
|
|
|
|
codegen_call_argument_operand(fx, pack_arg),
|
|
|
|
),
|
|
|
|
_ => panic!("rust-call abi requires one or two arguments"),
|
|
|
|
};
|
2020-04-13 17:12:44 +00:00
|
|
|
|
2021-08-06 14:26:56 +00:00
|
|
|
let tupled_arguments = match pack_arg.value.layout().ty.kind() {
|
2020-08-28 10:10:48 +00:00
|
|
|
ty::Tuple(ref tupled_arguments) => tupled_arguments,
|
2019-07-28 09:24:33 +00:00
|
|
|
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
|
2020-04-13 17:12:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut args = Vec::with_capacity(1 + tupled_arguments.len());
|
2023-07-22 13:32:34 +00:00
|
|
|
args.extend(self_arg);
|
2020-04-13 17:12:44 +00:00
|
|
|
for i in 0..tupled_arguments.len() {
|
2021-08-06 14:26:56 +00:00
|
|
|
args.push(CallArgument {
|
2023-03-28 19:32:57 +00:00
|
|
|
value: pack_arg.value.value_field(fx, FieldIdx::new(i)),
|
2021-08-06 14:26:56 +00:00
|
|
|
is_owned: pack_arg.is_owned,
|
|
|
|
});
|
2019-07-28 09:24:33 +00:00
|
|
|
}
|
|
|
|
args
|
|
|
|
} else {
|
2021-08-06 14:26:56 +00:00
|
|
|
args.iter().map(|arg| codegen_call_argument_operand(fx, arg)).collect::<Vec<_>>()
|
2019-07-28 09:24:33 +00:00
|
|
|
};
|
|
|
|
|
2021-08-06 14:26:56 +00:00
|
|
|
// Pass the caller location for `#[track_caller]`.
|
2023-05-24 14:33:43 +00:00
|
|
|
if instance.is_some_and(|inst| inst.def.requires_caller_location(fx.tcx)) {
|
2022-05-15 10:32:19 +00:00
|
|
|
let caller_location = fx.get_caller_location(source_info);
|
2021-08-06 14:26:56 +00:00
|
|
|
args.push(CallArgument { value: caller_location, is_owned: false });
|
|
|
|
}
|
|
|
|
|
|
|
|
let args = args;
|
|
|
|
assert_eq!(fn_abi.args.len(), args.len());
|
|
|
|
|
|
|
|
enum CallTarget {
|
|
|
|
Direct(FuncRef),
|
|
|
|
Indirect(SigRef, Value),
|
|
|
|
}
|
|
|
|
|
|
|
|
let (func_ref, first_arg_override) = match instance {
|
2019-02-07 19:28:55 +00:00
|
|
|
// Trait object call
|
2021-03-05 18:12:59 +00:00
|
|
|
Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => {
|
2021-03-29 08:45:09 +00:00
|
|
|
if fx.clif_comments.enabled() {
|
2019-06-16 12:47:01 +00:00
|
|
|
let nop_inst = fx.bcx.ins().nop();
|
|
|
|
fx.add_comment(
|
|
|
|
nop_inst,
|
2021-08-06 14:26:56 +00:00
|
|
|
format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0]),
|
2019-06-16 12:47:01 +00:00
|
|
|
);
|
|
|
|
}
|
2021-08-06 14:26:56 +00:00
|
|
|
|
|
|
|
let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0].value, idx);
|
2021-12-20 17:56:35 +00:00
|
|
|
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
2021-08-06 14:26:56 +00:00
|
|
|
let sig = fx.bcx.import_signature(sig);
|
|
|
|
|
2022-10-23 14:22:55 +00:00
|
|
|
(CallTarget::Indirect(sig, method), Some(ptr.get_addr(fx)))
|
2019-02-07 19:28:55 +00:00
|
|
|
}
|
2018-09-08 16:00:06 +00:00
|
|
|
|
2019-02-07 19:28:55 +00:00
|
|
|
// Normal call
|
2021-08-06 14:26:56 +00:00
|
|
|
Some(instance) => {
|
|
|
|
let func_ref = fx.get_function_ref(instance);
|
|
|
|
(CallTarget::Direct(func_ref), None)
|
|
|
|
}
|
2019-02-07 19:28:55 +00:00
|
|
|
|
|
|
|
// Indirect call
|
|
|
|
None => {
|
2021-03-29 08:45:09 +00:00
|
|
|
if fx.clif_comments.enabled() {
|
2019-06-16 12:47:01 +00:00
|
|
|
let nop_inst = fx.bcx.ins().nop();
|
|
|
|
fx.add_comment(nop_inst, "indirect call");
|
|
|
|
}
|
2021-08-06 14:26:56 +00:00
|
|
|
|
2022-12-14 18:30:46 +00:00
|
|
|
let func = func.load_scalar(fx);
|
2021-12-20 17:56:35 +00:00
|
|
|
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
2021-08-06 14:26:56 +00:00
|
|
|
let sig = fx.bcx.import_signature(sig);
|
|
|
|
|
|
|
|
(CallTarget::Indirect(sig, func), None)
|
2018-10-10 17:07:13 +00:00
|
|
|
}
|
2018-09-08 16:00:06 +00:00
|
|
|
};
|
|
|
|
|
2021-08-06 14:26:56 +00:00
|
|
|
self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| {
|
|
|
|
let call_args = return_ptr
|
|
|
|
.into_iter()
|
|
|
|
.chain(first_arg_override.into_iter())
|
|
|
|
.chain(
|
|
|
|
args.into_iter()
|
|
|
|
.enumerate()
|
|
|
|
.skip(if first_arg_override.is_some() { 1 } else { 0 })
|
2023-03-15 14:41:48 +00:00
|
|
|
.flat_map(|(i, arg)| {
|
2021-08-06 14:26:56 +00:00
|
|
|
adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter()
|
2023-03-15 14:41:48 +00:00
|
|
|
}),
|
2021-08-06 14:26:56 +00:00
|
|
|
)
|
|
|
|
.collect::<Vec<Value>>();
|
|
|
|
|
|
|
|
let call_inst = match func_ref {
|
|
|
|
CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
|
|
|
|
CallTarget::Indirect(sig, func_ptr) => {
|
|
|
|
fx.bcx.ins().call_indirect(sig, func_ptr, &call_args)
|
2020-01-11 15:49:42 +00:00
|
|
|
}
|
2021-08-06 14:26:56 +00:00
|
|
|
};
|
2020-01-11 15:49:42 +00:00
|
|
|
|
2021-08-06 14:26:56 +00:00
|
|
|
// FIXME find a cleaner way to support varargs
|
2022-12-14 18:30:46 +00:00
|
|
|
if fn_sig.c_variadic() {
|
|
|
|
if !matches!(fn_sig.abi(), Abi::C { .. }) {
|
2022-05-15 10:32:19 +00:00
|
|
|
fx.tcx.sess.span_fatal(
|
|
|
|
source_info.span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
|
|
|
format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
|
2022-05-15 10:32:19 +00:00
|
|
|
);
|
2021-08-06 14:26:56 +00:00
|
|
|
}
|
|
|
|
let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
|
|
|
|
let abi_params = call_args
|
|
|
|
.into_iter()
|
|
|
|
.map(|arg| {
|
|
|
|
let ty = fx.bcx.func.dfg.value_type(arg);
|
|
|
|
if !ty.is_int() {
|
|
|
|
// FIXME set %al to upperbound on float args once floats are supported
|
2022-05-15 10:32:19 +00:00
|
|
|
fx.tcx.sess.span_fatal(
|
|
|
|
source_info.span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 03:26:58 +00:00
|
|
|
format!("Non int ty {:?} for variadic call", ty),
|
2022-05-15 10:32:19 +00:00
|
|
|
);
|
2021-08-06 14:26:56 +00:00
|
|
|
}
|
|
|
|
AbiParam::new(ty)
|
|
|
|
})
|
|
|
|
.collect::<Vec<AbiParam>>();
|
|
|
|
fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
|
2019-02-11 18:18:52 +00:00
|
|
|
}
|
2021-08-06 14:26:56 +00:00
|
|
|
|
|
|
|
call_inst
|
|
|
|
});
|
2020-04-13 15:38:17 +00:00
|
|
|
|
2022-04-16 13:27:54 +00:00
|
|
|
if let Some(dest) = target {
|
2020-04-13 15:38:17 +00:00
|
|
|
let ret_block = fx.get_block(dest);
|
|
|
|
fx.bcx.ins().jump(ret_block, &[]);
|
|
|
|
} else {
|
2022-03-20 15:55:21 +00:00
|
|
|
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
2020-04-13 15:38:17 +00:00
|
|
|
}
|
2018-07-19 17:33:42 +00:00
|
|
|
}
|
2018-08-10 17:20:13 +00:00
|
|
|
|
2020-03-27 11:14:45 +00:00
|
|
|
pub(crate) fn codegen_drop<'tcx>(
|
2021-03-05 18:12:59 +00:00
|
|
|
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
2022-05-15 10:32:19 +00:00
|
|
|
source_info: mir::SourceInfo,
|
2020-01-11 15:49:42 +00:00
|
|
|
drop_place: CPlace<'tcx>,
|
|
|
|
) {
|
2019-06-16 13:57:53 +00:00
|
|
|
let ty = drop_place.layout().ty;
|
2021-02-01 09:11:46 +00:00
|
|
|
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
|
2019-02-07 19:45:15 +00:00
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def {
|
2019-06-16 13:57:53 +00:00
|
|
|
// we don't actually need to drop anything
|
|
|
|
} else {
|
2020-09-05 08:38:49 +00:00
|
|
|
match ty.kind() {
|
2022-10-23 14:22:55 +00:00
|
|
|
ty::Dynamic(_, _, ty::Dyn) => {
|
|
|
|
// IN THIS ARM, WE HAVE:
|
|
|
|
// ty = *mut (dyn Trait)
|
|
|
|
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
|
|
|
|
// args[0] args[1]
|
|
|
|
//
|
|
|
|
// args = ( Data, Vtable )
|
|
|
|
// |
|
|
|
|
// v
|
|
|
|
// /-------\
|
|
|
|
// | ... |
|
|
|
|
// \-------/
|
|
|
|
//
|
2023-04-29 12:00:43 +00:00
|
|
|
let (ptr, vtable) = drop_place.to_ptr_unsized();
|
2019-12-20 18:10:08 +00:00
|
|
|
let ptr = ptr.get_addr(fx);
|
2023-04-29 12:00:43 +00:00
|
|
|
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
|
2019-02-07 19:45:15 +00:00
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
// FIXME(eddyb) perhaps move some of this logic into
|
|
|
|
// `Instance::resolve_drop_in_place`?
|
|
|
|
let virtual_drop = Instance {
|
|
|
|
def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
|
2023-07-11 21:35:29 +00:00
|
|
|
args: drop_instance.args,
|
2021-02-01 09:11:46 +00:00
|
|
|
};
|
2021-09-01 21:29:15 +00:00
|
|
|
let fn_abi =
|
|
|
|
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
|
2021-02-01 09:11:46 +00:00
|
|
|
|
2021-12-20 17:56:35 +00:00
|
|
|
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
2019-12-17 14:03:32 +00:00
|
|
|
let sig = fx.bcx.import_signature(sig);
|
2019-06-16 13:57:53 +00:00
|
|
|
fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
|
|
|
|
}
|
2022-10-23 14:22:55 +00:00
|
|
|
ty::Dynamic(_, _, ty::DynStar) => {
|
|
|
|
// IN THIS ARM, WE HAVE:
|
|
|
|
// ty = *mut (dyn* Trait)
|
|
|
|
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
|
|
|
|
//
|
|
|
|
// args = [ * ]
|
|
|
|
// |
|
|
|
|
// v
|
|
|
|
// ( Data, Vtable )
|
|
|
|
// |
|
|
|
|
// v
|
|
|
|
// /-------\
|
|
|
|
// | ... |
|
|
|
|
// \-------/
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
|
|
|
|
//
|
|
|
|
// data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
|
|
|
|
// vtable = (*args[0]).1 // loads the vtable out
|
|
|
|
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
|
|
|
|
//
|
|
|
|
// SO THEN WE CAN USE THE ABOVE CODE.
|
|
|
|
let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx);
|
|
|
|
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
|
|
|
|
|
|
|
|
let virtual_drop = Instance {
|
|
|
|
def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
|
2023-07-11 21:35:29 +00:00
|
|
|
args: drop_instance.args,
|
2022-10-23 14:22:55 +00:00
|
|
|
};
|
|
|
|
let fn_abi =
|
|
|
|
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
|
|
|
|
|
|
|
|
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
|
|
|
let sig = fx.bcx.import_signature(sig);
|
|
|
|
fx.bcx.ins().call_indirect(sig, drop_fn, &[data]);
|
|
|
|
}
|
2019-06-16 13:57:53 +00:00
|
|
|
_ => {
|
2021-02-01 09:11:46 +00:00
|
|
|
assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
|
|
|
|
|
2021-09-01 21:29:15 +00:00
|
|
|
let fn_abi =
|
|
|
|
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
|
2020-04-13 15:31:35 +00:00
|
|
|
|
2020-08-28 10:10:48 +00:00
|
|
|
let arg_value = drop_place.place_ref(
|
|
|
|
fx,
|
2023-07-05 19:13:26 +00:00
|
|
|
fx.layout_of(Ty::new_ref(
|
|
|
|
fx.tcx,
|
2022-01-28 00:25:15 +00:00
|
|
|
fx.tcx.lifetimes.re_erased,
|
2021-03-05 18:12:59 +00:00
|
|
|
TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
|
2020-08-28 10:10:48 +00:00
|
|
|
)),
|
|
|
|
);
|
2021-08-06 14:26:56 +00:00
|
|
|
let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0], true);
|
2020-04-13 15:31:35 +00:00
|
|
|
|
|
|
|
let mut call_args: Vec<Value> = arg_value.into_iter().collect::<Vec<_>>();
|
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
if drop_instance.def.requires_caller_location(fx.tcx) {
|
2020-04-13 15:31:35 +00:00
|
|
|
// Pass the caller location for `#[track_caller]`.
|
2022-05-15 10:32:19 +00:00
|
|
|
let caller_location = fx.get_caller_location(source_info);
|
2021-02-01 09:11:46 +00:00
|
|
|
call_args.extend(
|
2021-08-06 14:26:56 +00:00
|
|
|
adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(),
|
2021-02-01 09:11:46 +00:00
|
|
|
);
|
2020-04-13 15:31:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-01 09:11:46 +00:00
|
|
|
let func_ref = fx.get_function_ref(drop_instance);
|
2020-04-13 15:31:35 +00:00
|
|
|
fx.bcx.ins().call(func_ref, &call_args);
|
2019-06-16 13:57:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-07 19:45:15 +00:00
|
|
|
}
|