|
1 |
| -use rustc_middle::mir::{self, NonDivergingIntrinsic}; |
2 |
| -use rustc_middle::span_bug; |
| 1 | +use rustc_middle::mir::{self, NonDivergingIntrinsic, RETURN_PLACE, StmtDebugInfo}; |
| 2 | +use rustc_middle::{bug, span_bug}; |
| 3 | +use rustc_target::callconv::PassMode; |
3 | 4 | use tracing::instrument;
|
4 | 5 |
|
5 | 6 | use super::{FunctionCx, LocalRef};
|
| 7 | +use crate::common::TypeKind; |
| 8 | +use crate::mir::place::PlaceRef; |
6 | 9 | use crate::traits::*;
|
7 | 10 |
|
8 | 11 | impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
9 | 12 | #[instrument(level = "debug", skip(self, bx))]
|
10 | 13 | pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) {
|
| 14 | + self.codegen_stmt_debuginfos(bx, &statement.debuginfos); |
11 | 15 | self.set_debug_loc(bx, statement.source_info);
|
12 | 16 | match statement.kind {
|
13 | 17 | mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
|
@@ -101,4 +105,66 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
101 | 105 | | mir::StatementKind::Nop => {}
|
102 | 106 | }
|
103 | 107 | }
|
| 108 | + |
| 109 | + pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) { |
| 110 | + match debuginfo { |
| 111 | + StmtDebugInfo::AssignRef(dest, place) => { |
| 112 | + let local_ref = match self.locals[place.local] { |
| 113 | + LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { |
| 114 | + Some(place_ref) |
| 115 | + } |
| 116 | + LocalRef::Operand(operand_ref) => operand_ref |
| 117 | + .val |
| 118 | + .try_pointer_parts() |
| 119 | + .map(|(pointer, _)| PlaceRef::new_sized(pointer, operand_ref.layout)), |
| 120 | + LocalRef::PendingOperand => None, |
| 121 | + } |
| 122 | + .filter(|place_ref| { |
| 123 | + // For the reference of an argument (e.x. `&_1`), it's only valid if the pass mode is indirect, and its reference is |
| 124 | + // llval. |
| 125 | + let local_ref_pass_mode = place.as_local().and_then(|local| { |
| 126 | + if local == RETURN_PLACE { |
| 127 | + None |
| 128 | + } else { |
| 129 | + self.fn_abi.args.get(local.as_usize() - 1).map(|arg| &arg.mode) |
| 130 | + } |
| 131 | + }); |
| 132 | + matches!(local_ref_pass_mode, Some(&PassMode::Indirect {..}) | None) && |
| 133 | + // Drop unsupported projections. |
| 134 | + place.projection.iter().all(|p| p.can_use_in_debuginfo()) && |
| 135 | + // Only pointers can be calculated addresses. |
| 136 | + bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer |
| 137 | + }); |
| 138 | + if let Some(local_ref) = local_ref { |
| 139 | + let (base_layout, projection) = if place.is_indirect_first_projection() { |
| 140 | + // For `_n = &((*_1).0: i32);`, we are calculating the address of `_1.0`, so |
| 141 | + // we should drop the deref projection. |
| 142 | + let projected_ty = local_ref |
| 143 | + .layout |
| 144 | + .ty |
| 145 | + .builtin_deref(true) |
| 146 | + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", local_ref)); |
| 147 | + let layout = bx.cx().layout_of(projected_ty); |
| 148 | + (layout, &place.projection[1..]) |
| 149 | + } else { |
| 150 | + (local_ref.layout, place.projection.as_slice()) |
| 151 | + }; |
| 152 | + self.debug_new_val_to_local(bx, *dest, local_ref.val, base_layout, projection); |
| 153 | + } else { |
| 154 | + // If the address cannot be computed, use poison to indicate that the value has been optimized out. |
| 155 | + self.debug_poison_to_local(bx, *dest); |
| 156 | + } |
| 157 | + } |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + pub(crate) fn codegen_stmt_debuginfos( |
| 162 | + &mut self, |
| 163 | + bx: &mut Bx, |
| 164 | + debuginfos: &[StmtDebugInfo<'tcx>], |
| 165 | + ) { |
| 166 | + for debuginfo in debuginfos { |
| 167 | + self.codegen_stmt_debuginfo(bx, debuginfo); |
| 168 | + } |
| 169 | + } |
104 | 170 | }
|
0 commit comments