codegen: fix OperandRef
subtype handling
This commit is contained in:
parent
be33ad8848
commit
46af169ec5
6 changed files with 101 additions and 29 deletions
|
@ -4,6 +4,7 @@
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(int_roundings)]
|
#![feature(int_roundings)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
#![feature(negative_impls)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
|
|
|
@ -1729,7 +1729,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
IndirectOperand(tmp, index) => {
|
IndirectOperand(tmp, index) => {
|
||||||
let op = bx.load_operand(tmp);
|
let op = bx.load_operand(tmp);
|
||||||
tmp.storage_dead(bx);
|
tmp.storage_dead(bx);
|
||||||
self.locals[index] = LocalRef::Operand(op);
|
self.overwrite_local(index, LocalRef::Operand(op));
|
||||||
self.debug_introduce_local(bx, index);
|
self.debug_introduce_local(bx, index);
|
||||||
}
|
}
|
||||||
DirectOperand(index) => {
|
DirectOperand(index) => {
|
||||||
|
@ -1744,7 +1744,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
} else {
|
} else {
|
||||||
OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
|
OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
|
||||||
};
|
};
|
||||||
self.locals[index] = LocalRef::Operand(op);
|
self.overwrite_local(index, LocalRef::Operand(op));
|
||||||
self.debug_introduce_local(bx, index);
|
self.debug_introduce_local(bx, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spill_operand_to_stack(
|
fn spill_operand_to_stack(
|
||||||
operand: &OperandRef<'tcx, Bx::Value>,
|
operand: OperandRef<'tcx, Bx::Value>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
) -> PlaceRef<'tcx, Bx::Value> {
|
) -> PlaceRef<'tcx, Bx::Value> {
|
||||||
|
@ -375,7 +375,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::spill_operand_to_stack(operand, name, bx)
|
Self::spill_operand_to_stack(*operand, name, bx)
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalRef::Place(place) => *place,
|
LocalRef::Place(place) => *place,
|
||||||
|
@ -550,7 +550,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
|
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
|
||||||
self.set_debug_loc(bx, var.source_info);
|
self.set_debug_loc(bx, var.source_info);
|
||||||
let base = Self::spill_operand_to_stack(
|
let base = Self::spill_operand_to_stack(
|
||||||
&operand,
|
operand,
|
||||||
Some(var.name.to_string()),
|
Some(var.name.to_string()),
|
||||||
bx,
|
bx,
|
||||||
);
|
);
|
||||||
|
|
74
compiler/rustc_codegen_ssa/src/mir/locals.rs
Normal file
74
compiler/rustc_codegen_ssa/src/mir/locals.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
//! Locals are in a private module as updating `LocalRef::Operand` has to
|
||||||
|
//! be careful wrt to subtyping. To deal with this we only allow updates by using
|
||||||
|
//! `FunctionCx::overwrite_local` which handles it automatically.
|
||||||
|
use crate::mir::{FunctionCx, LocalRef};
|
||||||
|
use crate::traits::BuilderMethods;
|
||||||
|
use rustc_index::IndexVec;
|
||||||
|
use rustc_middle::mir;
|
||||||
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
pub(super) struct Locals<'tcx, V> {
|
||||||
|
values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, V> Index<mir::Local> for Locals<'tcx, V> {
|
||||||
|
type Output = LocalRef<'tcx, V>;
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: mir::Local) -> &LocalRef<'tcx, V> {
|
||||||
|
&self.values[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// To mutate locals, use `FunctionCx::overwrite_local` instead.
|
||||||
|
impl<'tcx, V, Idx: ?Sized> !IndexMut<Idx> for Locals<'tcx, V> {}
|
||||||
|
|
||||||
|
impl<'tcx, V> Locals<'tcx, V> {
|
||||||
|
pub(super) fn empty() -> Locals<'tcx, V> {
|
||||||
|
Locals { values: IndexVec::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn indices(&self) -> impl DoubleEndedIterator<Item = mir::Local> + Clone + 'tcx {
|
||||||
|
self.values.indices()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
|
pub(super) fn initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>) {
|
||||||
|
assert!(self.locals.values.is_empty());
|
||||||
|
|
||||||
|
for (local, value) in values.into_iter().enumerate() {
|
||||||
|
match value {
|
||||||
|
LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
|
||||||
|
LocalRef::Operand(op) => {
|
||||||
|
let local = mir::Local::from_usize(local);
|
||||||
|
let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
|
||||||
|
assert_eq!(expected_ty, op.layout.ty, "unexpected initial operand type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.locals.values.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn overwrite_local(
|
||||||
|
&mut self,
|
||||||
|
local: mir::Local,
|
||||||
|
mut value: LocalRef<'tcx, Bx::Value>,
|
||||||
|
) {
|
||||||
|
match value {
|
||||||
|
LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
|
||||||
|
LocalRef::Operand(ref mut op) => {
|
||||||
|
let local_ty = self.monomorphize(self.mir.local_decls[local].ty);
|
||||||
|
if local_ty != op.layout.ty {
|
||||||
|
debug!("updating type of operand due to subtyping");
|
||||||
|
with_no_trimmed_paths!(debug!(?op.layout.ty));
|
||||||
|
with_no_trimmed_paths!(debug!(?local_ty));
|
||||||
|
op.layout.ty = local_ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.locals.values[local] = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,31 @@
|
||||||
use crate::base;
|
use crate::base;
|
||||||
use crate::traits::*;
|
use crate::traits::*;
|
||||||
|
use rustc_index::bit_set::BitSet;
|
||||||
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
|
use rustc_middle::mir::traversal;
|
||||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
|
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
|
||||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||||
use rustc_target::abi::call::{FnAbi, PassMode};
|
use rustc_target::abi::call::{FnAbi, PassMode};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use rustc_index::bit_set::BitSet;
|
mod analyze;
|
||||||
use rustc_index::IndexVec;
|
mod block;
|
||||||
|
pub mod constant;
|
||||||
|
pub mod coverageinfo;
|
||||||
|
pub mod debuginfo;
|
||||||
|
mod intrinsic;
|
||||||
|
mod locals;
|
||||||
|
pub mod operand;
|
||||||
|
pub mod place;
|
||||||
|
mod rvalue;
|
||||||
|
mod statement;
|
||||||
|
|
||||||
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
|
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
|
||||||
use self::place::PlaceRef;
|
|
||||||
use rustc_middle::mir::traversal;
|
|
||||||
|
|
||||||
use self::operand::{OperandRef, OperandValue};
|
use self::operand::{OperandRef, OperandValue};
|
||||||
|
use self::place::PlaceRef;
|
||||||
|
|
||||||
// Used for tracking the state of generated basic blocks.
|
// Used for tracking the state of generated basic blocks.
|
||||||
enum CachedLlbb<T> {
|
enum CachedLlbb<T> {
|
||||||
|
@ -91,7 +101,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||||
///
|
///
|
||||||
/// Avoiding allocs can also be important for certain intrinsics,
|
/// Avoiding allocs can also be important for certain intrinsics,
|
||||||
/// notably `expect`.
|
/// notably `expect`.
|
||||||
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
|
locals: locals::Locals<'tcx, Bx::Value>,
|
||||||
|
|
||||||
/// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
|
/// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
|
||||||
/// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed.
|
/// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed.
|
||||||
|
@ -192,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
cleanup_kinds,
|
cleanup_kinds,
|
||||||
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
||||||
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
||||||
locals: IndexVec::new(),
|
locals: locals::Locals::empty(),
|
||||||
debug_context,
|
debug_context,
|
||||||
per_local_var_debug_info: None,
|
per_local_var_debug_info: None,
|
||||||
caller_location: None,
|
caller_location: None,
|
||||||
|
@ -223,7 +233,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
let memory_locals = analyze::non_ssa_locals(&fx);
|
let memory_locals = analyze::non_ssa_locals(&fx);
|
||||||
|
|
||||||
// Allocate variable and temp allocas
|
// Allocate variable and temp allocas
|
||||||
fx.locals = {
|
let local_values = {
|
||||||
let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
|
let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
|
||||||
|
|
||||||
let mut allocate_local = |local| {
|
let mut allocate_local = |local| {
|
||||||
|
@ -256,6 +266,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
.chain(mir.vars_and_temps_iter().map(allocate_local))
|
.chain(mir.vars_and_temps_iter().map(allocate_local))
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
fx.initialize_locals(local_values);
|
||||||
|
|
||||||
// Apply debuginfo to the newly allocated locals.
|
// Apply debuginfo to the newly allocated locals.
|
||||||
fx.debug_introduce_locals(&mut start_bx);
|
fx.debug_introduce_locals(&mut start_bx);
|
||||||
|
@ -289,14 +300,13 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(arg_index, local)| {
|
.map(|(arg_index, local)| {
|
||||||
let arg_decl = &mir.local_decls[local];
|
let arg_decl = &mir.local_decls[local];
|
||||||
|
let arg_ty = fx.monomorphize(arg_decl.ty);
|
||||||
|
|
||||||
if Some(local) == mir.spread_arg {
|
if Some(local) == mir.spread_arg {
|
||||||
// This argument (e.g., the last argument in the "rust-call" ABI)
|
// 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
|
// is a tuple that was spread at the ABI level and now we have
|
||||||
// to reconstruct it into a tuple local variable, from multiple
|
// to reconstruct it into a tuple local variable, from multiple
|
||||||
// individual LLVM function arguments.
|
// individual LLVM function arguments.
|
||||||
|
|
||||||
let arg_ty = fx.monomorphize(arg_decl.ty);
|
|
||||||
let ty::Tuple(tupled_arg_tys) = arg_ty.kind() else {
|
let ty::Tuple(tupled_arg_tys) = arg_ty.kind() else {
|
||||||
bug!("spread argument isn't a tuple?!");
|
bug!("spread argument isn't a tuple?!");
|
||||||
};
|
};
|
||||||
|
@ -331,8 +341,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
|
if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
|
||||||
let arg_ty = fx.monomorphize(arg_decl.ty);
|
|
||||||
|
|
||||||
let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
|
let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
|
||||||
bx.va_start(va_list.llval);
|
bx.va_start(va_list.llval);
|
||||||
|
|
||||||
|
@ -429,14 +437,3 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
|
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
|
|
||||||
mod analyze;
|
|
||||||
mod block;
|
|
||||||
pub mod constant;
|
|
||||||
pub mod coverageinfo;
|
|
||||||
pub mod debuginfo;
|
|
||||||
mod intrinsic;
|
|
||||||
pub mod operand;
|
|
||||||
pub mod place;
|
|
||||||
mod rvalue;
|
|
||||||
mod statement;
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
LocalRef::PendingOperand => {
|
LocalRef::PendingOperand => {
|
||||||
let operand = self.codegen_rvalue_operand(bx, rvalue);
|
let operand = self.codegen_rvalue_operand(bx, rvalue);
|
||||||
self.locals[index] = LocalRef::Operand(operand);
|
self.overwrite_local(index, LocalRef::Operand(operand));
|
||||||
self.debug_introduce_local(bx, index);
|
self.debug_introduce_local(bx, index);
|
||||||
}
|
}
|
||||||
LocalRef::Operand(op) => {
|
LocalRef::Operand(op) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue