-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Introduce debuginfo to statements in MIR #142771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
83c20f3
678cd04
97ddf91
e3ecfa3
ecf4538
de65379
635ae63
0a0b3c1
1e903d1
6e997fa
0e8c053
84d42cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,17 @@ | ||
use rustc_middle::mir::{self, NonDivergingIntrinsic}; | ||
use rustc_middle::span_bug; | ||
use rustc_middle::mir::{self, NonDivergingIntrinsic, RETURN_PLACE, StmtDebugInfo}; | ||
use rustc_middle::{bug, span_bug}; | ||
use rustc_target::callconv::PassMode; | ||
use tracing::instrument; | ||
|
||
use super::{FunctionCx, LocalRef}; | ||
use crate::common::TypeKind; | ||
use crate::mir::place::PlaceRef; | ||
use crate::traits::*; | ||
|
||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | ||
#[instrument(level = "debug", skip(self, bx))] | ||
pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) { | ||
self.codegen_stmt_debuginfos(bx, &statement.debuginfos); | ||
self.set_debug_loc(bx, statement.source_info); | ||
match statement.kind { | ||
mir::StatementKind::Assign(box (ref place, ref rvalue)) => { | ||
|
@@ -101,4 +105,69 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | |
| mir::StatementKind::Nop => {} | ||
} | ||
} | ||
|
||
pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) { | ||
match debuginfo { | ||
StmtDebugInfo::AssignRef(dest, place) => { | ||
let local_ref = match self.locals[place.local] { | ||
LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => { | ||
Some(place_ref) | ||
} | ||
LocalRef::Operand(operand_ref) => operand_ref | ||
.val | ||
.try_pointer_parts() | ||
.map(|(pointer, _)| PlaceRef::new_sized(pointer, operand_ref.layout)), | ||
LocalRef::PendingOperand => None, | ||
} | ||
.filter(|place_ref| { | ||
// For the reference of an argument (e.x. `&_1`), it's only valid if the pass mode is indirect, and its reference is | ||
// llval. | ||
let local_ref_pass_mode = place.as_local().and_then(|local| { | ||
if local == RETURN_PLACE { | ||
None | ||
} else { | ||
self.fn_abi.args.get(local.as_usize() - 1).map(|arg| &arg.mode) | ||
} | ||
}); | ||
matches!(local_ref_pass_mode, Some(&PassMode::Indirect {..}) | None) && | ||
// Drop unsupported projections. | ||
place.projection.iter().all(|p| p.can_use_in_debuginfo()) && | ||
// Only pointers can be calculated addresses. | ||
bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer | ||
}); | ||
if let Some(local_ref) = local_ref { | ||
let (base_layout, projection) = if place.is_indirect_first_projection() { | ||
// For `_n = &((*_1).0: i32);`, we are calculating the address of `_1.0`, so | ||
// we should drop the deref projection. | ||
let projected_ty = local_ref | ||
.layout | ||
.ty | ||
.builtin_deref(true) | ||
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", local_ref)); | ||
let layout = bx.cx().layout_of(projected_ty); | ||
(layout, &place.projection[1..]) | ||
} else { | ||
(local_ref.layout, place.projection.as_slice()) | ||
}; | ||
self.debug_new_val_to_local(bx, *dest, local_ref.val, base_layout, projection); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we do simpler and use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, we cannot emit any IR that is a non-debug value here. I think we will know a general code when we handle all rvalue. |
||
} else { | ||
// If the address cannot be computed, use poison to indicate that the value has been optimized out. | ||
self.debug_poison_to_local(bx, *dest); | ||
} | ||
} | ||
StmtDebugInfo::InvalidAssign(local) => { | ||
self.debug_poison_to_local(bx, *local); | ||
} | ||
} | ||
} | ||
|
||
pub(crate) fn codegen_stmt_debuginfos( | ||
&mut self, | ||
bx: &mut Bx, | ||
debuginfos: &[StmtDebugInfo<'tcx>], | ||
) { | ||
for debuginfo in debuginfos { | ||
self.codegen_stmt_debuginfo(bx, debuginfo); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to move all debuginfo to
DbgValue
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, but it's very complicated. It might be better to let LLVM do it.
LLVM might also preserve the declare: https://rust.godbolt.org/z/GKWYeT7rK, but this seems like it could be dropped.