From 5059a3c7d4afd00458d5bd2f033a0b9c91bd8bf8 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 4 Sep 2019 19:44:58 +0300 Subject: [PATCH 1/7] rustc_codegen_ssa: move debuginfo-related things to a new mir::debuginfo module. --- .../debuginfo/create_scope_map.rs | 12 +- src/librustc_codegen_llvm/debuginfo/mod.rs | 11 +- .../debuginfo/source_loc.rs | 2 +- src/librustc_codegen_ssa/debuginfo/mod.rs | 82 +--------- src/librustc_codegen_ssa/mir/debuginfo.rs | 145 ++++++++++++++++++ src/librustc_codegen_ssa/mir/mod.rs | 65 +------- src/librustc_codegen_ssa/traits/debuginfo.rs | 4 +- 7 files changed, 165 insertions(+), 156 deletions(-) create mode 100644 src/librustc_codegen_ssa/mir/debuginfo.rs diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index bdb7467a1010c..abd6827680e06 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -1,4 +1,4 @@ -use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, FunctionDebugContextData, MirDebugScope}; +use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, FunctionDebugContextData, DebugScope}; use super::metadata::file_metadata; use super::utils::{DIB, span_start}; @@ -22,8 +22,8 @@ pub fn create_mir_scopes( cx: &CodegenCx<'ll, '_>, mir: &Body<'_>, debug_context: &FunctionDebugContext<&'ll DISubprogram>, -) -> IndexVec> { - let null_scope = MirDebugScope { +) -> IndexVec> { + let null_scope = DebugScope { scope_metadata: None, file_start_pos: BytePos(0), file_end_pos: BytePos(0) @@ -59,7 +59,7 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>, has_variables: &BitSet, debug_context: &FunctionDebugContextData<&'ll DISubprogram>, scope: SourceScope, - scopes: &mut IndexVec>) { + scopes: &mut IndexVec>) { if scopes[scope].is_valid() { return; } @@ -71,7 +71,7 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>, } else { // The root is the function itself. let loc = span_start(cx, mir.span); - scopes[scope] = MirDebugScope { + scopes[scope] = DebugScope { scope_metadata: Some(debug_context.fn_metadata), file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_pos, @@ -105,7 +105,7 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>, loc.line as c_uint, loc.col.to_usize() as c_uint)) }; - scopes[scope] = MirDebugScope { + scopes[scope] = DebugScope { scope_metadata, file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_pos, diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 5b59f4c28de20..d7706b3251bb0 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -1,8 +1,8 @@ // See doc.rs for documentation. mod doc; -use rustc_codegen_ssa::debuginfo::VariableAccess::*; -use rustc_codegen_ssa::debuginfo::VariableKind::*; +use rustc_codegen_ssa::mir::debuginfo::VariableAccess::*; +use rustc_codegen_ssa::mir::debuginfo::VariableKind::*; use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; use self::namespace::mangled_name_of_instance; @@ -27,8 +27,9 @@ use rustc::session::config::{self, DebugInfo}; use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_index::vec::IndexVec; -use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, - VariableKind, FunctionDebugContextData, type_names}; +use rustc_codegen_ssa::debuginfo::type_names; +use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope, VariableAccess, + VariableKind, FunctionDebugContextData}; use libc::c_uint; use std::cell::RefCell; @@ -553,7 +554,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { &self, mir: &mir::Body<'_>, debug_context: &mut FunctionDebugContext<&'ll DISubprogram>, - ) -> IndexVec> { + ) -> IndexVec> { create_scope_map::create_mir_scopes(self, mir, debug_context) } diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs index dec93a65dbaf4..014c1d285d285 100644 --- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -2,7 +2,7 @@ use self::InternalDebugLocation::*; use super::utils::{debug_context, span_start}; use super::metadata::UNKNOWN_COLUMN_NUMBER; -use rustc_codegen_ssa::debuginfo::FunctionDebugContext; +use rustc_codegen_ssa::mir::debuginfo::FunctionDebugContext; use crate::llvm; use crate::llvm::debuginfo::DIScope; diff --git a/src/librustc_codegen_ssa/debuginfo/mod.rs b/src/librustc_codegen_ssa/debuginfo/mod.rs index c9b1c0260e8c3..d1a0cf78d6a2e 100644 --- a/src/librustc_codegen_ssa/debuginfo/mod.rs +++ b/src/librustc_codegen_ssa/debuginfo/mod.rs @@ -1,82 +1,2 @@ -use syntax_pos::{BytePos, Span}; -use rustc::hir::def_id::CrateNum; - +// FIXME(eddyb) find a place for this (or a way to replace it). pub mod type_names; - -pub enum FunctionDebugContext { - RegularContext(FunctionDebugContextData), - DebugInfoDisabled, - FunctionWithoutDebugInfo, -} - -impl FunctionDebugContext { - pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData { - match *self { - FunctionDebugContext::RegularContext(ref data) => data, - FunctionDebugContext::DebugInfoDisabled => { - span_bug!( - span, - "debuginfo: Error trying to access FunctionDebugContext \ - although debug info is disabled!", - ); - } - FunctionDebugContext::FunctionWithoutDebugInfo => { - span_bug!( - span, - "debuginfo: Error trying to access FunctionDebugContext \ - for function that should be ignored by debug info!", - ); - } - } - } -} - -/// Enables emitting source locations for the given functions. -/// -/// Since we don't want source locations to be emitted for the function prelude, -/// they are disabled when beginning to codegen a new function. This functions -/// switches source location emitting on and must therefore be called before the -/// first real statement/expression of the function is codegened. -pub fn start_emitting_source_locations(dbg_context: &mut FunctionDebugContext) { - match *dbg_context { - FunctionDebugContext::RegularContext(ref mut data) => { - data.source_locations_enabled = true; - }, - _ => { /* safe to ignore */ } - } -} - -pub struct FunctionDebugContextData { - pub fn_metadata: D, - pub source_locations_enabled: bool, - pub defining_crate: CrateNum, -} - -pub enum VariableAccess<'a, V> { - // The llptr given is an alloca containing the variable's value - DirectVariable { alloca: V }, - // The llptr given is an alloca containing the start of some pointer chain - // leading to the variable's content. - IndirectVariable { alloca: V, address_operations: &'a [i64] } -} - -pub enum VariableKind { - ArgumentVariable(usize /*index*/), - LocalVariable, -} - - -#[derive(Clone, Copy, Debug)] -pub struct MirDebugScope { - pub scope_metadata: Option, - // Start and end offsets of the file to which this DIScope belongs. - // These are used to quickly determine whether some span refers to the same file. - pub file_start_pos: BytePos, - pub file_end_pos: BytePos, -} - -impl MirDebugScope { - pub fn is_valid(&self) -> bool { - !self.scope_metadata.is_none() - } -} diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs new file mode 100644 index 0000000000000..a253523f18120 --- /dev/null +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -0,0 +1,145 @@ +use rustc::hir::def_id::CrateNum; +use rustc::mir; +use crate::traits::*; + +use syntax_pos::{DUMMY_SP, BytePos, Span}; + +use super::FunctionCx; + +pub enum FunctionDebugContext { + RegularContext(FunctionDebugContextData), + DebugInfoDisabled, + FunctionWithoutDebugInfo, +} + +impl FunctionDebugContext { + pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData { + match *self { + FunctionDebugContext::RegularContext(ref data) => data, + FunctionDebugContext::DebugInfoDisabled => { + span_bug!( + span, + "debuginfo: Error trying to access FunctionDebugContext \ + although debug info is disabled!", + ); + } + FunctionDebugContext::FunctionWithoutDebugInfo => { + span_bug!( + span, + "debuginfo: Error trying to access FunctionDebugContext \ + for function that should be ignored by debug info!", + ); + } + } + } +} + +/// Enables emitting source locations for the given functions. +/// +/// Since we don't want source locations to be emitted for the function prelude, +/// they are disabled when beginning to codegen a new function. This functions +/// switches source location emitting on and must therefore be called before the +/// first real statement/expression of the function is codegened. +pub fn start_emitting_source_locations(dbg_context: &mut FunctionDebugContext) { + match *dbg_context { + FunctionDebugContext::RegularContext(ref mut data) => { + data.source_locations_enabled = true; + }, + _ => { /* safe to ignore */ } + } +} + +pub struct FunctionDebugContextData { + pub fn_metadata: D, + pub source_locations_enabled: bool, + pub defining_crate: CrateNum, +} + +pub enum VariableAccess<'a, V> { + // The llptr given is an alloca containing the variable's value + DirectVariable { alloca: V }, + // The llptr given is an alloca containing the start of some pointer chain + // leading to the variable's content. + IndirectVariable { alloca: V, address_operations: &'a [i64] } +} + +pub enum VariableKind { + ArgumentVariable(usize /*index*/), + LocalVariable, +} + + +#[derive(Clone, Copy, Debug)] +pub struct DebugScope { + pub scope_metadata: Option, + // Start and end offsets of the file to which this DIScope belongs. + // These are used to quickly determine whether some span refers to the same file. + pub file_start_pos: BytePos, + pub file_end_pos: BytePos, +} + +impl DebugScope { + pub fn is_valid(&self) -> bool { + !self.scope_metadata.is_none() + } +} + +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + pub fn set_debug_loc( + &mut self, + bx: &mut Bx, + source_info: mir::SourceInfo + ) { + let (scope, span) = self.debug_loc(source_info); + bx.set_source_location(&mut self.debug_context, scope, span); + } + + pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option, Span) { + // Bail out if debug info emission is not enabled. + match self.debug_context { + FunctionDebugContext::DebugInfoDisabled | + FunctionDebugContext::FunctionWithoutDebugInfo => { + return (self.scopes[source_info.scope].scope_metadata, source_info.span); + } + FunctionDebugContext::RegularContext(_) =>{} + } + + // In order to have a good line stepping behavior in debugger, we overwrite debug + // locations of macro expansions with that of the outermost expansion site + // (unless the crate is being compiled with `-Z debug-macros`). + if !source_info.span.from_expansion() || + self.cx.sess().opts.debugging_opts.debug_macros { + let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo()); + (scope, source_info.span) + } else { + // Walk up the macro expansion chain until we reach a non-expanded span. + // We also stop at the function body level because no line stepping can occur + // at the level above that. + let span = syntax_pos::hygiene::walk_chain(source_info.span, self.mir.span.ctxt()); + let scope = self.scope_metadata_for_loc(source_info.scope, span.lo()); + // Use span of the outermost expansion site, while keeping the original lexical scope. + (scope, span) + } + } + + // DILocations inherit source file name from the parent DIScope. Due to macro expansions + // it may so happen that the current span belongs to a different file than the DIScope + // corresponding to span's containing source scope. If so, we need to create a DIScope + // "extension" into that file. + fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos) + -> Option { + let scope_metadata = self.scopes[scope_id].scope_metadata; + if pos < self.scopes[scope_id].file_start_pos || + pos >= self.scopes[scope_id].file_end_pos { + let sm = self.cx.sess().source_map(); + let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate; + Some(self.cx.extend_scope_to_file( + scope_metadata.unwrap(), + &sm.lookup_char_pos(pos).file, + defining_crate + )) + } else { + scope_metadata + } + } +} diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 1a2e796a5b7be..650584fbdf7bd 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -5,10 +5,9 @@ use rustc::session::config::DebugInfo; use rustc_target::abi::call::{FnType, PassMode}; use rustc_target::abi::{Variants, VariantIdx}; use crate::base; -use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext}; use crate::traits::*; -use syntax_pos::{DUMMY_SP, BytePos, Span}; +use syntax_pos::DUMMY_SP; use syntax::symbol::kw; use std::iter; @@ -17,6 +16,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use self::analyze::CleanupKind; +use self::debuginfo::{VariableAccess, VariableKind, FunctionDebugContext}; use self::place::PlaceRef; use rustc::mir::traversal; @@ -80,7 +80,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { locals: IndexVec>, /// Debug information for MIR scopes. - scopes: IndexVec>, + scopes: IndexVec>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -93,64 +93,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { value, ) } - - pub fn set_debug_loc( - &mut self, - bx: &mut Bx, - source_info: mir::SourceInfo - ) { - let (scope, span) = self.debug_loc(source_info); - bx.set_source_location(&mut self.debug_context, scope, span); - } - - pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option, Span) { - // Bail out if debug info emission is not enabled. - match self.debug_context { - FunctionDebugContext::DebugInfoDisabled | - FunctionDebugContext::FunctionWithoutDebugInfo => { - return (self.scopes[source_info.scope].scope_metadata, source_info.span); - } - FunctionDebugContext::RegularContext(_) =>{} - } - - // In order to have a good line stepping behavior in debugger, we overwrite debug - // locations of macro expansions with that of the outermost expansion site - // (unless the crate is being compiled with `-Z debug-macros`). - if !source_info.span.from_expansion() || - self.cx.sess().opts.debugging_opts.debug_macros { - let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo()); - (scope, source_info.span) - } else { - // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occur - // at the level above that. - let span = syntax_pos::hygiene::walk_chain(source_info.span, self.mir.span.ctxt()); - let scope = self.scope_metadata_for_loc(source_info.scope, span.lo()); - // Use span of the outermost expansion site, while keeping the original lexical scope. - (scope, span) - } - } - - // DILocations inherit source file name from the parent DIScope. Due to macro expansions - // it may so happen that the current span belongs to a different file than the DIScope - // corresponding to span's containing source scope. If so, we need to create a DIScope - // "extension" into that file. - fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos) - -> Option { - let scope_metadata = self.scopes[scope_id].scope_metadata; - if pos < self.scopes[scope_id].file_start_pos || - pos >= self.scopes[scope_id].file_end_pos { - let sm = self.cx.sess().source_map(); - let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate; - Some(self.cx.extend_scope_to_file( - scope_metadata.unwrap(), - &sm.lookup_char_pos(pos).file, - defining_crate - )) - } else { - scope_metadata - } - } } enum LocalRef<'tcx, V> { @@ -721,6 +663,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( mod analyze; mod block; pub mod constant; +pub mod debuginfo; pub mod place; pub mod operand; mod rvalue; diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index 989e6cf9dcaf1..244fe845d7ddf 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use crate::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind}; +use crate::mir::debuginfo::{FunctionDebugContext, DebugScope, VariableAccess, VariableKind}; use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::ty::{self, Ty, Instance}; @@ -28,7 +28,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { &self, mir: &mir::Body<'_>, debug_context: &mut FunctionDebugContext, - ) -> IndexVec>; + ) -> IndexVec>; fn extend_scope_to_file( &self, scope_metadata: Self::DIScope, From c58e6b5752058760263fa85cd4057d8784f3b852 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 13 Sep 2019 10:28:14 +0300 Subject: [PATCH 2/7] rustc_codegen_ssa: move local variable debuginfo to mir::debuginfo. --- src/librustc_codegen_ssa/mir/analyze.rs | 22 +- src/librustc_codegen_ssa/mir/debuginfo.rs | 179 ++++++++++++++- src/librustc_codegen_ssa/mir/mod.rs | 263 +++------------------- src/librustc_codegen_ssa/mir/place.rs | 4 + 4 files changed, 227 insertions(+), 241 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 604deffcf949b..2e5dc3db31af9 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -7,6 +7,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc::mir::{self, Location, TerminatorKind}; use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext}; use rustc::mir::traversal; +use rustc::session::config::DebugInfo; use rustc::ty; use rustc::ty::layout::{LayoutOf, HasTyCtxt}; use syntax_pos::DUMMY_SP; @@ -21,13 +22,20 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( analyzer.visit_body(mir); - for (index, (ty, span)) in mir.local_decls.iter() - .map(|l| (l.ty, l.source_info.span)) - .enumerate() + for (local, decl) in mir.local_decls.iter_enumerated() { - let ty = fx.monomorphize(&ty); - debug!("local {} has type {:?}", index, ty); - let layout = fx.cx.spanned_layout_of(ty, span); + // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead + // of putting everything in allocas just so we can use llvm.dbg.declare. + if fx.cx.sess().opts.debuginfo == DebugInfo::Full { + if mir.local_kind(local) == mir::LocalKind::Arg || decl.name.is_some() { + analyzer.not_ssa(local); + continue; + } + } + + let ty = fx.monomorphize(&decl.ty); + debug!("local {:?} has type `{}`", local, ty); + let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); if fx.cx.is_backend_immediate(layout) { // These sorts of types are immediates that we can store // in an Value without an alloca. @@ -40,7 +48,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // (e.g., structs) into an alloca unconditionally, just so // that we don't have to deal with having two pathways // (gep vs extractvalue etc). - analyzer.not_ssa(mir::Local::new(index)); + analyzer.not_ssa(local); } } diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index a253523f18120..d6b91c1f6bbb8 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -1,10 +1,16 @@ +use rustc_index::vec::Idx; use rustc::hir::def_id::CrateNum; use rustc::mir; +use rustc::session::config::DebugInfo; +use rustc::ty::{self, UpvarSubsts}; +use rustc::ty::layout::HasTyCtxt; +use rustc_target::abi::{Variants, VariantIdx}; use crate::traits::*; use syntax_pos::{DUMMY_SP, BytePos, Span}; +use syntax::symbol::kw; -use super::FunctionCx; +use super::{FunctionCx, LocalRef}; pub enum FunctionDebugContext { RegularContext(FunctionDebugContextData), @@ -142,4 +148,175 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { scope_metadata } } + + pub fn debug_declare_locals(&self, bx: &mut Bx) { + let tcx = self.cx.tcx(); + let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use; + + if bx.sess().opts.debuginfo != DebugInfo::Full { + return; + } + + for (local, local_ref) in self.locals.iter_enumerated() { + if local == mir::RETURN_PLACE { + continue; + } + + // FIXME(eddyb) add debuginfo for unsized places too. + let place = match local_ref { + LocalRef::Place(place) => place, + _ => continue, + }; + + let decl = &self.mir.local_decls[local]; + let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg { + let arg_index = local.index() - 1; + + // Add debuginfo even to unnamed arguments. + // FIXME(eddyb) is this really needed? + let name = if arg_index == 0 && !upvar_debuginfo.is_empty() { + // Hide closure environments from debuginfo. + // FIXME(eddyb) shouldn't `ArgumentVariable` indices + // be offset to account for the hidden environment? + None + } else { + Some(decl.name.unwrap_or(kw::Invalid)) + }; + (name, VariableKind::ArgumentVariable(arg_index + 1)) + } else { + (decl.name, VariableKind::LocalVariable) + }; + if let Some(name) = name { + let (scope, span) = self.debug_loc(mir::SourceInfo { + span: decl.source_info.span, + scope: decl.visibility_scope, + }); + if let Some(scope) = scope { + bx.declare_local(&self.debug_context, name, place.layout.ty, scope, + VariableAccess::DirectVariable { alloca: place.llval }, + kind, span); + } + } + } + + // Declare closure captures as if they were local variables. + // FIXME(eddyb) generalize this to `name => place` mappings. + let upvar_scope = if !upvar_debuginfo.is_empty() { + self.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata + } else { + None + }; + if let Some(scope) = upvar_scope { + let place = match self.locals[mir::Local::new(1)] { + LocalRef::Place(place) => place, + _ => bug!(), + }; + + let pin_did = tcx.lang_items().pin_type(); + let (closure_layout, env_ref) = match place.layout.ty.kind { + ty::RawPtr(ty::TypeAndMut { ty, .. }) | + ty::Ref(_, ty, _) => (bx.layout_of(ty), true), + ty::Adt(def, substs) if Some(def.did) == pin_did => { + match substs.type_at(0).kind { + ty::Ref(_, ty, _) => (bx.layout_of(ty), true), + _ => (place.layout, false), + } + } + _ => (place.layout, false) + }; + + let (def_id, upvar_substs) = match closure_layout.ty.kind { + ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), + ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), + _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty) + }; + let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); + + let extra_locals = { + let upvars = upvar_debuginfo + .iter() + .zip(upvar_tys) + .enumerate() + .map(|(i, (upvar, ty))| { + (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP) + }); + + let generator_fields = self.mir.generator_layout.as_ref().map(|generator_layout| { + let (def_id, gen_substs) = match closure_layout.ty.kind { + ty::Generator(def_id, substs, _) => (def_id, substs), + _ => bug!("generator layout without generator substs"), + }; + let state_tys = gen_substs.as_generator().state_tys(def_id, tcx); + + generator_layout.variant_fields.iter() + .zip(state_tys) + .enumerate() + .flat_map(move |(variant_idx, (fields, tys))| { + let variant_idx = Some(VariantIdx::from(variant_idx)); + fields.iter() + .zip(tys) + .enumerate() + .filter_map(move |(i, (field, ty))| { + let decl = &generator_layout. + __local_debuginfo_codegen_only_do_not_use[*field]; + if let Some(name) = decl.name { + let ty = self.monomorphize(&ty); + let (var_scope, var_span) = self.debug_loc(mir::SourceInfo { + span: decl.source_info.span, + scope: decl.visibility_scope, + }); + let var_scope = var_scope.unwrap_or(scope); + Some((variant_idx, i, name, false, ty, var_scope, var_span)) + } else { + None + } + }) + }) + }).into_iter().flatten(); + + upvars.chain(generator_fields) + }; + + for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals { + let fields = match variant_idx { + Some(variant_idx) => { + match &closure_layout.variants { + Variants::Multiple { variants, .. } => { + &variants[variant_idx].fields + }, + _ => bug!("variant index on univariant layout"), + } + } + None => &closure_layout.fields, + }; + let byte_offset_of_var_in_env = fields.offset(field).bytes(); + + let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env); + + // The environment and the capture can each be indirect. + let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; + + let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) { + ty + } else { + ops = &ops[..ops.len() - 1]; + ty + }; + + let variable_access = VariableAccess::IndirectVariable { + alloca: place.llval, + address_operations: &ops + }; + bx.declare_local( + &self.debug_context, + name, + ty, + var_scope, + variable_access, + VariableKind::LocalVariable, + var_span + ); + } + } + } } diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 650584fbdf7bd..8e9e21393738f 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -1,22 +1,17 @@ -use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts, Instance}; +use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Body}; -use rustc::session::config::DebugInfo; use rustc_target::abi::call::{FnType, PassMode}; -use rustc_target::abi::{Variants, VariantIdx}; use crate::base; use crate::traits::*; -use syntax_pos::DUMMY_SP; -use syntax::symbol::kw; - use std::iter; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use self::analyze::CleanupKind; -use self::debuginfo::{VariableAccess, VariableKind, FunctionDebugContext}; +use self::debuginfo::FunctionDebugContext; use self::place::PlaceRef; use rustc::mir::traversal; @@ -189,62 +184,38 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let layout = bx.layout_of(fx.monomorphize(&decl.ty)); assert!(!layout.ty.has_erasable_regions()); - if let Some(name) = decl.name { - // User variable - let debug_scope = fx.scopes[decl.visibility_scope]; - let dbg = debug_scope.is_valid() && - bx.sess().opts.debuginfo == DebugInfo::Full; + if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { + debug!("alloc: {:?} (return place) -> place", local); + let llretptr = bx.get_param(0); + return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); + } - if !memory_locals.contains(local) && !dbg { - debug!("alloc: {:?} ({}) -> operand", local, name); - return LocalRef::new_operand(&mut bx, layout); - } + let decl_name = decl.name.map(|name| name.as_str()); + let decl_name = decl_name.as_ref().map(|name| &name[..]); + let name; + let name = if let Some(name) = decl_name { + name + } else { + // FIXME(eddyb) compute something else for the name so no work is done + // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`). + name = format!("{:?}", local); + &name + }; + if memory_locals.contains(local) { debug!("alloc: {:?} ({}) -> place", local, name); if layout.is_unsized() { - let indirect_place = - PlaceRef::alloca_unsized_indirect(&mut bx, layout); + let indirect_place = PlaceRef::alloca_unsized_indirect(&mut bx, layout); bx.set_var_name(indirect_place.llval, name); - // FIXME: add an appropriate debuginfo LocalRef::UnsizedPlace(indirect_place) } else { let place = PlaceRef::alloca(&mut bx, layout); bx.set_var_name(place.llval, name); - if dbg { - let (scope, span) = fx.debug_loc(mir::SourceInfo { - span: decl.source_info.span, - scope: decl.visibility_scope, - }); - bx.declare_local(&fx.debug_context, name, layout.ty, scope.unwrap(), - VariableAccess::DirectVariable { alloca: place.llval }, - VariableKind::LocalVariable, span); - } LocalRef::Place(place) } } else { - // Temporary or return place - if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { - debug!("alloc: {:?} (return place) -> place", local); - let llretptr = bx.get_param(0); - LocalRef::Place(PlaceRef::new_sized(llretptr, layout)) - } else if memory_locals.contains(local) { - debug!("alloc: {:?} -> place", local); - if layout.is_unsized() { - let indirect_place = PlaceRef::alloca_unsized_indirect(&mut bx, layout); - bx.set_var_name(indirect_place.llval, format_args!("{:?}", local)); - LocalRef::UnsizedPlace(indirect_place) - } else { - let place = PlaceRef::alloca(&mut bx, layout); - bx.set_var_name(place.llval, format_args!("{:?}", local)); - LocalRef::Place(place) - } - } else { - // If this is an immediate local, we do not create an - // alloca in advance. Instead we wait until we see the - // definition and update the operand there. - debug!("alloc: {:?} -> operand", local); - LocalRef::new_operand(&mut bx, layout) - } + debug!("alloc: {:?} ({}) -> operand", local, name); + LocalRef::new_operand(&mut bx, layout) } }; @@ -255,6 +226,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( .collect() }; + // Apply debuginfo to the newly allocated locals. + fx.debug_declare_locals(&mut bx); + // Branch to the START block, if it's not the entry block. if reentrant_start_block { bx.br(fx.blocks[mir::START_BLOCK]); @@ -363,18 +337,9 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( memory_locals: &BitSet, ) -> Vec> { let mir = fx.mir; - let tcx = fx.cx.tcx(); let mut idx = 0; let mut llarg_idx = fx.fn_ty.ret.is_indirect() as usize; - // Get the argument scope, if it exists and if we need it. - let arg_scope = fx.scopes[mir::OUTERMOST_SOURCE_SCOPE]; - let arg_scope = if bx.sess().opts.debuginfo == DebugInfo::Full { - arg_scope.scope_metadata - } else { - None - }; - mir.args_iter().enumerate().map(|(arg_index, local)| { let arg_decl = &mir.local_decls[local]; @@ -409,22 +374,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.store_fn_arg(arg, &mut llarg_idx, pr_field); } - // Now that we have one alloca that contains the aggregate value, - // we can create one debuginfo entry for the argument. - arg_scope.map(|scope| { - let variable_access = VariableAccess::DirectVariable { - alloca: place.llval - }; - bx.declare_local( - &fx.debug_context, - arg_decl.name.unwrap_or(kw::Invalid), - arg_ty, scope, - variable_access, - VariableKind::ArgumentVariable(arg_index + 1), - DUMMY_SP - ); - }); - return LocalRef::Place(place); } @@ -435,21 +384,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.set_var_name(va_list.llval, name); bx.va_start(va_list.llval); - arg_scope.map(|scope| { - let variable_access = VariableAccess::DirectVariable { - alloca: va_list.llval - }; - bx.declare_local( - &fx.debug_context, - arg_decl.name.unwrap_or(kw::Invalid), - va_list.layout.ty, - scope, - variable_access, - VariableKind::ArgumentVariable(arg_index + 1), - DUMMY_SP - ); - }); - return LocalRef::Place(va_list); } @@ -459,7 +393,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( llarg_idx += 1; } - if arg_scope.is_none() && !memory_locals.contains(local) { + if !memory_locals.contains(local) { // We don't have to cast or keep the argument in the alloca. // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead // of putting everything in allocas just so we can use llvm.dbg.declare. @@ -493,14 +427,14 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } - let place = if arg.is_sized_indirect() { + if arg.is_sized_indirect() { // Don't copy an indirect argument to an alloca, the caller // already put it in a temporary alloca and gave it up. // FIXME: lifetimes let llarg = bx.get_param(llarg_idx); bx.set_var_name(llarg, &name); llarg_idx += 1; - PlaceRef::new_sized(llarg, arg.layout) + LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout)) } else if arg.is_unsized_indirect() { // As the storage for the indirect argument lives during // the whole function call, we just copy the fat pointer. @@ -513,149 +447,12 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout); bx.set_var_name(tmp.llval, name); indirect_operand.store(bx, tmp); - tmp + LocalRef::UnsizedPlace(tmp) } else { let tmp = PlaceRef::alloca(bx, arg.layout); bx.set_var_name(tmp.llval, name); bx.store_fn_arg(arg, &mut llarg_idx, tmp); - tmp - }; - let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use; - arg_scope.map(|scope| { - // Is this a regular argument? - if arg_index > 0 || upvar_debuginfo.is_empty() { - // The Rust ABI passes indirect variables using a pointer and a manual copy, so we - // need to insert a deref here, but the C ABI uses a pointer and a copy using the - // byval attribute, for which LLVM always does the deref itself, - // so we must not add it. - let variable_access = VariableAccess::DirectVariable { - alloca: place.llval - }; - - bx.declare_local( - &fx.debug_context, - arg_decl.name.unwrap_or(kw::Invalid), - arg.layout.ty, - scope, - variable_access, - VariableKind::ArgumentVariable(arg_index + 1), - DUMMY_SP - ); - return; - } - - let pin_did = tcx.lang_items().pin_type(); - // Or is it the closure environment? - let (closure_layout, env_ref) = match arg.layout.ty.kind { - ty::RawPtr(ty::TypeAndMut { ty, .. }) | - ty::Ref(_, ty, _) => (bx.layout_of(ty), true), - ty::Adt(def, substs) if Some(def.did) == pin_did => { - match substs.type_at(0).kind { - ty::Ref(_, ty, _) => (bx.layout_of(ty), true), - _ => (arg.layout, false), - } - } - _ => (arg.layout, false) - }; - - let (def_id, upvar_substs) = match closure_layout.ty.kind { - ty::Closure(def_id, substs) => (def_id, - UpvarSubsts::Closure(substs)), - ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), - _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty) - }; - let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); - - let extra_locals = { - let upvars = upvar_debuginfo - .iter() - .zip(upvar_tys) - .enumerate() - .map(|(i, (upvar, ty))| { - (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP) - }); - - let generator_fields = mir.generator_layout.as_ref().map(|generator_layout| { - let (def_id, gen_substs) = match closure_layout.ty.kind { - ty::Generator(def_id, substs, _) => (def_id, substs), - _ => bug!("generator layout without generator substs"), - }; - let state_tys = gen_substs.as_generator().state_tys(def_id, tcx); - - generator_layout.variant_fields.iter() - .zip(state_tys) - .enumerate() - .flat_map(move |(variant_idx, (fields, tys))| { - let variant_idx = Some(VariantIdx::from(variant_idx)); - fields.iter() - .zip(tys) - .enumerate() - .filter_map(move |(i, (field, ty))| { - let decl = &generator_layout. - __local_debuginfo_codegen_only_do_not_use[*field]; - if let Some(name) = decl.name { - let ty = fx.monomorphize(&ty); - let (var_scope, var_span) = fx.debug_loc(mir::SourceInfo { - span: decl.source_info.span, - scope: decl.visibility_scope, - }); - let var_scope = var_scope.unwrap_or(scope); - Some((variant_idx, i, name, false, ty, var_scope, var_span)) - } else { - None - } - }) - }) - }).into_iter().flatten(); - - upvars.chain(generator_fields) - }; - - for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals { - let fields = match variant_idx { - Some(variant_idx) => { - match &closure_layout.variants { - Variants::Multiple { variants, .. } => { - &variants[variant_idx].fields - }, - _ => bug!("variant index on univariant layout"), - } - } - None => &closure_layout.fields, - }; - let byte_offset_of_var_in_env = fields.offset(field).bytes(); - - let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env); - - // The environment and the capture can each be indirect. - let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; - - let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) { - ty - } else { - ops = &ops[..ops.len() - 1]; - ty - }; - - let variable_access = VariableAccess::IndirectVariable { - alloca: place.llval, - address_operations: &ops - }; - bx.declare_local( - &fx.debug_context, - name, - ty, - var_scope, - variable_access, - VariableKind::LocalVariable, - var_span - ); - } - }); - if arg.is_unsized_indirect() { - LocalRef::UnsizedPlace(place) - } else { - LocalRef::Place(place) + LocalRef::Place(tmp) } }).collect() } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 1d1bc2a81a2ca..3e7c4ef49fb5a 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -68,6 +68,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } } + // FIXME(eddyb) pass something else for the name so no work is done + // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`). pub fn alloca>( bx: &mut Bx, layout: TyLayout<'tcx>, @@ -78,6 +80,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } /// Returns a place for an indirect reference to an unsized place. + // FIXME(eddyb) pass something else for the name so no work is done + // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`). pub fn alloca_unsized_indirect>( bx: &mut Bx, layout: TyLayout<'tcx>, From 5f4ee36e0330ef6db36f3cf2fe4d3ea19f1f0eb4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 13 Sep 2019 20:04:54 +0300 Subject: [PATCH 3/7] rustc_codegen_ssa: move all set_var_name calls to mir::debuginfo. --- src/librustc_codegen_ssa/mir/debuginfo.rs | 146 +++++++++++---- src/librustc_codegen_ssa/mir/mod.rs | 44 +---- src/librustc_codegen_ssa/mir/statement.rs | 15 +- src/test/codegen/optimize-attr-1.rs | 6 +- ...intrinsic-generic-arithmetic-saturating.rs | 167 +++++++++--------- .../simd-intrinsic-generic-bitmask.rs | 12 +- 6 files changed, 217 insertions(+), 173 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index d6b91c1f6bbb8..cd209717cc4d7 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -7,10 +7,12 @@ use rustc::ty::layout::HasTyCtxt; use rustc_target::abi::{Variants, VariantIdx}; use crate::traits::*; +use std::fmt; use syntax_pos::{DUMMY_SP, BytePos, Span}; use syntax::symbol::kw; use super::{FunctionCx, LocalRef}; +use super::OperandValue; pub enum FunctionDebugContext { RegularContext(FunctionDebugContextData), @@ -90,6 +92,29 @@ impl DebugScope { } } +// HACK(eddyb) helpers for `set_var_name` calls, move elsewhere? +enum Either { + Left(T), + Right(U), +} + +impl fmt::Display for Either { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Either::Left(x) => x.fmt(f), + Either::Right(x) => x.fmt(f), + } + } +} + +struct DisplayViaDebug(T); + +impl fmt::Display for DisplayViaDebug { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn set_debug_loc( &mut self, @@ -149,54 +174,107 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - pub fn debug_declare_locals(&self, bx: &mut Bx) { - let tcx = self.cx.tcx(); + /// Apply debuginfo and/or name, after creating the `alloca` for a local, + /// or initializing the local with an operand (whichever applies). + // FIXME(eddyb) use `llvm.dbg.value` (which would work for operands), + // not just `llvm.dbg.declare` (which requires `alloca`). + pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use; - if bx.sess().opts.debuginfo != DebugInfo::Full { + // FIXME(eddyb) maybe name the return place as `_0` or `return`? + if local == mir::RETURN_PLACE { return; } - for (local, local_ref) in self.locals.iter_enumerated() { - if local == mir::RETURN_PLACE { - continue; + let decl = &self.mir.local_decls[local]; + let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg { + let arg_index = local.index() - 1; + + // Add debuginfo even to unnamed arguments. + // FIXME(eddyb) is this really needed? + let name = if arg_index == 0 && !upvar_debuginfo.is_empty() { + // Hide closure environments from debuginfo. + // FIXME(eddyb) shouldn't `ArgumentVariable` indices + // be offset to account for the hidden environment? + None + } else { + Some(decl.name.unwrap_or(kw::Invalid)) + }; + (name, VariableKind::ArgumentVariable(arg_index + 1)) + } else { + (decl.name, VariableKind::LocalVariable) + }; + + let local_ref = &self.locals[local]; + + { + let name = match name { + Some(name) if name != kw::Invalid => Either::Left(name), + _ => Either::Right(DisplayViaDebug(local)), + }; + match local_ref { + LocalRef::Place(place) | + LocalRef::UnsizedPlace(place) => { + bx.set_var_name(place.llval, name); + } + LocalRef::Operand(Some(operand)) => match operand.val { + OperandValue::Ref(x, ..) | + OperandValue::Immediate(x) => { + bx.set_var_name(x, name); + } + OperandValue::Pair(a, b) => { + // FIXME(eddyb) these are scalar components, + // maybe extract the high-level fields? + bx.set_var_name(a, format_args!("{}.0", name)); + bx.set_var_name(b, format_args!("{}.1", name)); + } + } + LocalRef::Operand(None) => {} + } + } + + if let Some(name) = name { + if bx.sess().opts.debuginfo != DebugInfo::Full { + return; } // FIXME(eddyb) add debuginfo for unsized places too. let place = match local_ref { LocalRef::Place(place) => place, - _ => continue, + _ => return, }; - let decl = &self.mir.local_decls[local]; - let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg { - let arg_index = local.index() - 1; - - // Add debuginfo even to unnamed arguments. - // FIXME(eddyb) is this really needed? - let name = if arg_index == 0 && !upvar_debuginfo.is_empty() { - // Hide closure environments from debuginfo. - // FIXME(eddyb) shouldn't `ArgumentVariable` indices - // be offset to account for the hidden environment? - None - } else { - Some(decl.name.unwrap_or(kw::Invalid)) - }; - (name, VariableKind::ArgumentVariable(arg_index + 1)) - } else { - (decl.name, VariableKind::LocalVariable) - }; - if let Some(name) = name { - let (scope, span) = self.debug_loc(mir::SourceInfo { - span: decl.source_info.span, - scope: decl.visibility_scope, - }); - if let Some(scope) = scope { - bx.declare_local(&self.debug_context, name, place.layout.ty, scope, - VariableAccess::DirectVariable { alloca: place.llval }, - kind, span); + let (scope, span) = self.debug_loc(mir::SourceInfo { + span: decl.source_info.span, + scope: decl.visibility_scope, + }); + if let Some(scope) = scope { + bx.declare_local(&self.debug_context, name, place.layout.ty, scope, + VariableAccess::DirectVariable { alloca: place.llval }, + kind, span); + } + } + } + + pub fn debug_introduce_locals(&self, bx: &mut Bx) { + let tcx = self.cx.tcx(); + let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use; + + if bx.sess().opts.debuginfo != DebugInfo::Full { + // HACK(eddyb) figure out a way to perhaps disentangle + // the use of `declare_local` and `set_var_name`. + // Or maybe just running this loop always is not that expensive? + if !bx.sess().fewer_names() { + for local in self.locals.indices() { + self.debug_introduce_local(bx, local); } } + + return; + } + + for local in self.locals.indices() { + self.debug_introduce_local(bx, local); } // Declare closure captures as if they were local variables. diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 8e9e21393738f..4e0974e6b85c8 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -190,31 +190,15 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); } - let decl_name = decl.name.map(|name| name.as_str()); - let decl_name = decl_name.as_ref().map(|name| &name[..]); - let name; - let name = if let Some(name) = decl_name { - name - } else { - // FIXME(eddyb) compute something else for the name so no work is done - // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`). - name = format!("{:?}", local); - &name - }; - if memory_locals.contains(local) { - debug!("alloc: {:?} ({}) -> place", local, name); + debug!("alloc: {:?} -> place", local); if layout.is_unsized() { - let indirect_place = PlaceRef::alloca_unsized_indirect(&mut bx, layout); - bx.set_var_name(indirect_place.llval, name); - LocalRef::UnsizedPlace(indirect_place) + LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut bx, layout)) } else { - let place = PlaceRef::alloca(&mut bx, layout); - bx.set_var_name(place.llval, name); - LocalRef::Place(place) + LocalRef::Place(PlaceRef::alloca(&mut bx, layout)) } } else { - debug!("alloc: {:?} ({}) -> operand", local, name); + debug!("alloc: {:?} -> operand", local); LocalRef::new_operand(&mut bx, layout) } }; @@ -227,7 +211,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( }; // Apply debuginfo to the newly allocated locals. - fx.debug_declare_locals(&mut bx); + fx.debug_introduce_locals(&mut bx); // Branch to the START block, if it's not the entry block. if reentrant_start_block { @@ -343,13 +327,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( mir.args_iter().enumerate().map(|(arg_index, local)| { let arg_decl = &mir.local_decls[local]; - // FIXME(eddyb) don't allocate a `String` unless it gets used. - let name = if let Some(name) = arg_decl.name { - name.as_str().to_string() - } else { - format!("{:?}", local) - }; - if Some(local) == 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 @@ -363,7 +340,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( }; let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); - bx.set_var_name(place.llval, name); for i in 0..tupled_arg_tys.len() { let arg = &fx.fn_ty.args[idx]; idx += 1; @@ -381,7 +357,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let arg_ty = fx.monomorphize(&arg_decl.ty); let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); - bx.set_var_name(va_list.llval, name); bx.va_start(va_list.llval); return LocalRef::Place(va_list); @@ -404,7 +379,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } PassMode::Direct(_) => { let llarg = bx.get_param(llarg_idx); - bx.set_var_name(llarg, &name); llarg_idx += 1; return local( OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout)); @@ -413,11 +387,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let (a, b) = (bx.get_param(llarg_idx), bx.get_param(llarg_idx + 1)); llarg_idx += 2; - // FIXME(eddyb) these are scalar components, - // maybe extract the high-level fields? - bx.set_var_name(a, format_args!("{}.0", name)); - bx.set_var_name(b, format_args!("{}.1", name)); - return local(OperandRef { val: OperandValue::Pair(a, b), layout: arg.layout @@ -432,7 +401,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // already put it in a temporary alloca and gave it up. // FIXME: lifetimes let llarg = bx.get_param(llarg_idx); - bx.set_var_name(llarg, &name); llarg_idx += 1; LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout)) } else if arg.is_unsized_indirect() { @@ -445,12 +413,10 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let indirect_operand = OperandValue::Pair(llarg, llextra); let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout); - bx.set_var_name(tmp.llval, name); indirect_operand.store(bx, tmp); LocalRef::UnsizedPlace(tmp) } else { let tmp = PlaceRef::alloca(bx, arg.layout); - bx.set_var_name(tmp.llval, name); bx.store_fn_arg(arg, &mut llarg_idx, tmp); LocalRef::Place(tmp) } diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 43d5c2570b705..d11601be0b4ab 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -27,21 +27,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } LocalRef::Operand(None) => { let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); - if let Some(name) = self.mir.local_decls[index].name { - match operand.val { - OperandValue::Ref(x, ..) | - OperandValue::Immediate(x) => { - bx.set_var_name(x, name); - } - OperandValue::Pair(a, b) => { - // FIXME(eddyb) these are scalar components, - // maybe extract the high-level fields? - bx.set_var_name(a, format_args!("{}.0", name)); - bx.set_var_name(b, format_args!("{}.1", name)); - } - } - } self.locals[index] = LocalRef::Operand(Some(operand)); + self.debug_introduce_local(&mut bx, index); bx } LocalRef::Operand(Some(op)) => { diff --git a/src/test/codegen/optimize-attr-1.rs b/src/test/codegen/optimize-attr-1.rs index 376447e5b5db0..4a5b7c05231dc 100644 --- a/src/test/codegen/optimize-attr-1.rs +++ b/src/test/codegen/optimize-attr-1.rs @@ -8,7 +8,7 @@ // CHECK-LABEL: define i32 @nothing // CHECK-SAME: [[NOTHING_ATTRS:#[0-9]+]] -// NO-OPT: ret i32 %1 +// NO-OPT: ret i32 %_1.0 // SIZE-OPT: ret i32 4 // SPEEC-OPT: ret i32 4 #[no_mangle] @@ -18,7 +18,7 @@ pub fn nothing() -> i32 { // CHECK-LABEL: define i32 @size // CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]] -// NO-OPT: ret i32 %1 +// NO-OPT: ret i32 %_1.0 // SIZE-OPT: ret i32 6 // SPEED-OPT: ret i32 6 #[optimize(size)] @@ -31,7 +31,7 @@ pub fn size() -> i32 { // NO-OPT-SAME: [[NOTHING_ATTRS]] // SPEED-OPT-SAME: [[NOTHING_ATTRS]] // SIZE-OPT-SAME: [[SPEED_ATTRS:#[0-9]+]] -// NO-OPT: ret i32 %1 +// NO-OPT: ret i32 %_1.0 // SIZE-OPT: ret i32 8 // SPEED-OPT: ret i32 8 #[optimize(speed)] diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs index 237d15a5c68cf..267c995e0704f 100644 --- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs @@ -116,143 +116,150 @@ extern "platform-intrinsic" { fn simd_saturating_sub(x: T, y: T) -> T; } +// NOTE(eddyb) `%{{x|_3}}` is used because on some targets (e.g. WASM) +// SIMD vectors are passed directly, resulting in `%x` being a vector, +// while on others they're passed indirectly, resulting in `%x` being +// a pointer to a vector, and `%_3` a vector loaded from that pointer. +// This is controlled by the target spec option `simd_types_indirect`. +// The same applies to `%{{y|_4}}` as well. + // CHECK-LABEL: @sadd_i8x2 #[no_mangle] pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x4 #[no_mangle] pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x8 #[no_mangle] pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x16 #[no_mangle] pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x32 #[no_mangle] pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x64 #[no_mangle] pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x2 #[no_mangle] pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x4 #[no_mangle] pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x8 #[no_mangle] pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x16 #[no_mangle] pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x32 #[no_mangle] pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x2 #[no_mangle] pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x4 #[no_mangle] pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x8 #[no_mangle] pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x16 #[no_mangle] pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i64x2 #[no_mangle] pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i64x4 #[no_mangle] pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i64x8 #[no_mangle] pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i128x2 #[no_mangle] pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i128x4 #[no_mangle] pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}}) simd_saturating_add(x, y) } @@ -261,140 +268,140 @@ pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 { // CHECK-LABEL: @uadd_u8x2 #[no_mangle] pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x4 #[no_mangle] pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x8 #[no_mangle] pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x16 #[no_mangle] pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x32 #[no_mangle] pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x64 #[no_mangle] pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x2 #[no_mangle] pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x4 #[no_mangle] pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x8 #[no_mangle] pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x16 #[no_mangle] pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x32 #[no_mangle] pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x2 #[no_mangle] pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x4 #[no_mangle] pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x8 #[no_mangle] pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x16 #[no_mangle] pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u64x2 #[no_mangle] pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u64x4 #[no_mangle] pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u64x8 #[no_mangle] pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u128x2 #[no_mangle] pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u128x4 #[no_mangle] pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}}) simd_saturating_add(x, y) } @@ -405,140 +412,140 @@ pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 { // CHECK-LABEL: @ssub_i8x2 #[no_mangle] pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x4 #[no_mangle] pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x8 #[no_mangle] pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x16 #[no_mangle] pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x32 #[no_mangle] pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x64 #[no_mangle] pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x2 #[no_mangle] pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x4 #[no_mangle] pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x8 #[no_mangle] pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x16 #[no_mangle] pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x32 #[no_mangle] pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x2 #[no_mangle] pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x4 #[no_mangle] pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x8 #[no_mangle] pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x16 #[no_mangle] pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i64x2 #[no_mangle] pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i64x4 #[no_mangle] pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i64x8 #[no_mangle] pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i128x2 #[no_mangle] pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i128x4 #[no_mangle] pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}}) simd_saturating_sub(x, y) } @@ -547,139 +554,139 @@ pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 { // CHECK-LABEL: @usub_u8x2 #[no_mangle] pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x4 #[no_mangle] pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x8 #[no_mangle] pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x16 #[no_mangle] pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x32 #[no_mangle] pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x64 #[no_mangle] pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x2 #[no_mangle] pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x4 #[no_mangle] pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x8 #[no_mangle] pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x16 #[no_mangle] pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x32 #[no_mangle] pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x2 #[no_mangle] pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x4 #[no_mangle] pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x8 #[no_mangle] pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x16 #[no_mangle] pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u64x2 #[no_mangle] pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u64x4 #[no_mangle] pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u64x8 #[no_mangle] pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u128x2 #[no_mangle] pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u128x4 #[no_mangle] pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}}) simd_saturating_sub(x, y) } diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs index 543664014868c..87c8b0d87d8bb 100644 --- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs +++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs @@ -26,10 +26,16 @@ extern "platform-intrinsic" { fn simd_bitmask(x: T) -> U; } +// NOTE(eddyb) `%{{x|_2}}` is used because on some targets (e.g. WASM) +// SIMD vectors are passed directly, resulting in `%x` being a vector, +// while on others they're passed indirectly, resulting in `%x` being +// a pointer to a vector, and `%_2` a vector loaded from that pointer. +// This is controlled by the target spec option `simd_types_indirect`. + // CHECK-LABEL: @bitmask_int #[no_mangle] pub unsafe fn bitmask_int(x: i32x2) -> u8 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 @@ -39,7 +45,7 @@ pub unsafe fn bitmask_int(x: i32x2) -> u8 { // CHECK-LABEL: @bitmask_uint #[no_mangle] pub unsafe fn bitmask_uint(x: u32x2) -> u8 { - // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, + // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1> // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2 // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8 @@ -49,7 +55,7 @@ pub unsafe fn bitmask_uint(x: u32x2) -> u8 { // CHECK-LABEL: @bitmask_int16 #[no_mangle] pub unsafe fn bitmask_int16(x: i8x16) -> u16 { - // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9a-z]+}}, + // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|_2}}, // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1> // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16 // CHECK-NOT: zext From 06869b8d17d06818d8e2ac36834ba21827443985 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 22 Oct 2019 12:36:00 +0300 Subject: [PATCH 4/7] rustc_codegen_ssa: change set_var_name back to taking a &str. --- src/librustc_codegen_llvm/debuginfo/mod.rs | 4 +-- src/librustc_codegen_ssa/mir/debuginfo.rs | 38 ++++---------------- src/librustc_codegen_ssa/traits/debuginfo.rs | 2 +- 3 files changed, 10 insertions(+), 34 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index d7706b3251bb0..0e6269fc7e1b1 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -225,7 +225,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } - fn set_var_name(&mut self, value: &'ll Value, name: impl ToString) { + fn set_var_name(&mut self, value: &'ll Value, name: &str) { // Avoid wasting time if LLVM value names aren't even enabled. if self.sess().fewer_names() { return; @@ -255,7 +255,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { Err(_) => return, } - let cname = CString::new(name.to_string()).unwrap(); + let cname = SmallCStr::new(name); unsafe { llvm::LLVMSetValueName(value, cname.as_ptr()); } diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index cd209717cc4d7..29c0d70b58a90 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -7,7 +7,6 @@ use rustc::ty::layout::HasTyCtxt; use rustc_target::abi::{Variants, VariantIdx}; use crate::traits::*; -use std::fmt; use syntax_pos::{DUMMY_SP, BytePos, Span}; use syntax::symbol::kw; @@ -92,29 +91,6 @@ impl DebugScope { } } -// HACK(eddyb) helpers for `set_var_name` calls, move elsewhere? -enum Either { - Left(T), - Right(U), -} - -impl fmt::Display for Either { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Either::Left(x) => x.fmt(f), - Either::Right(x) => x.fmt(f), - } - } -} - -struct DisplayViaDebug(T); - -impl fmt::Display for DisplayViaDebug { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn set_debug_loc( &mut self, @@ -207,26 +183,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let local_ref = &self.locals[local]; - { + if !bx.sess().fewer_names() { let name = match name { - Some(name) if name != kw::Invalid => Either::Left(name), - _ => Either::Right(DisplayViaDebug(local)), + Some(name) if name != kw::Invalid => name.to_string(), + _ => format!("{:?}", local), }; match local_ref { LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => { - bx.set_var_name(place.llval, name); + bx.set_var_name(place.llval, &name); } LocalRef::Operand(Some(operand)) => match operand.val { OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { - bx.set_var_name(x, name); + bx.set_var_name(x, &name); } OperandValue::Pair(a, b) => { // FIXME(eddyb) these are scalar components, // maybe extract the high-level fields? - bx.set_var_name(a, format_args!("{}.0", name)); - bx.set_var_name(b, format_args!("{}.1", name)); + bx.set_var_name(a, &(name.clone() + ".0")); + bx.set_var_name(b, &(name + ".1")); } } LocalRef::Operand(None) => {} diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index 244fe845d7ddf..4712eff67963e 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -57,5 +57,5 @@ pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { span: Span, ); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); - fn set_var_name(&mut self, value: Self::Value, name: impl ToString); + fn set_var_name(&mut self, value: Self::Value, name: &str); } From c2e7743da8ba6062c89b700957fda01f54732c30 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 11 Sep 2019 17:52:39 +0300 Subject: [PATCH 5/7] rustc_codegen_ssa: move debuginfo scopes into FunctionDebugContext. --- .../debuginfo/create_scope_map.rs | 58 +++++-------- src/librustc_codegen_llvm/debuginfo/mod.rs | 51 +++++------ .../debuginfo/source_loc.rs | 15 +--- src/librustc_codegen_ssa/mir/debuginfo.rs | 87 ++++++------------- src/librustc_codegen_ssa/mir/mod.rs | 15 ++-- src/librustc_codegen_ssa/traits/debuginfo.rs | 16 +--- 6 files changed, 88 insertions(+), 154 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index abd6827680e06..6ee76b71fced6 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -1,4 +1,4 @@ -use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, FunctionDebugContextData, DebugScope}; +use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope}; use super::metadata::file_metadata; use super::utils::{DIB, span_start}; @@ -12,34 +12,20 @@ use libc::c_uint; use syntax_pos::Pos; use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; - -use syntax_pos::BytePos; +use rustc_index::vec::Idx; /// Produces DIScope DIEs for each MIR Scope which has variables defined in it. -/// If debuginfo is disabled, the returned vector is empty. -pub fn create_mir_scopes( +pub fn compute_mir_scopes( cx: &CodegenCx<'ll, '_>, mir: &Body<'_>, - debug_context: &FunctionDebugContext<&'ll DISubprogram>, -) -> IndexVec> { - let null_scope = DebugScope { - scope_metadata: None, - file_start_pos: BytePos(0), - file_end_pos: BytePos(0) - }; - let mut scopes = IndexVec::from_elem(null_scope, &mir.source_scopes); - - let debug_context = match *debug_context { - FunctionDebugContext::RegularContext(ref data) => data, - FunctionDebugContext::DebugInfoDisabled | - FunctionDebugContext::FunctionWithoutDebugInfo => { - return scopes; - } - }; - + fn_metadata: &'ll DISubprogram, + debug_context: &mut FunctionDebugContext<&'ll DIScope>, +) { // Find all the scopes with variables defined in them. let mut has_variables = BitSet::new_empty(mir.source_scopes.len()); + // FIXME(eddyb) base this on `decl.name`, or even better, on debuginfo. + // FIXME(eddyb) take into account that arguments always have debuginfo, + // irrespective of their name (assuming full debuginfo is enabled). for var in mir.vars_iter() { let decl = &mir.local_decls[var]; has_variables.insert(decl.visibility_scope); @@ -48,31 +34,29 @@ pub fn create_mir_scopes( // Instantiate all scopes. for idx in 0..mir.source_scopes.len() { let scope = SourceScope::new(idx); - make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes); + make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope); } - - scopes } fn make_mir_scope(cx: &CodegenCx<'ll, '_>, mir: &Body<'_>, + fn_metadata: &'ll DISubprogram, has_variables: &BitSet, - debug_context: &FunctionDebugContextData<&'ll DISubprogram>, - scope: SourceScope, - scopes: &mut IndexVec>) { - if scopes[scope].is_valid() { + debug_context: &mut FunctionDebugContext<&'ll DISubprogram>, + scope: SourceScope) { + if debug_context.scopes[scope].is_valid() { return; } let scope_data = &mir.source_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { - make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes); - scopes[parent] + make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent); + debug_context.scopes[parent] } else { // The root is the function itself. let loc = span_start(cx, mir.span); - scopes[scope] = DebugScope { - scope_metadata: Some(debug_context.fn_metadata), + debug_context.scopes[scope] = DebugScope { + scope_metadata: Some(fn_metadata), file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_pos, }; @@ -86,8 +70,8 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>, // However, we don't skip creating a nested scope if // our parent is the root, because we might want to // put arguments in the root and not have shadowing. - if parent_scope.scope_metadata.unwrap() != debug_context.fn_metadata { - scopes[scope] = parent_scope; + if parent_scope.scope_metadata.unwrap() != fn_metadata { + debug_context.scopes[scope] = parent_scope; return; } } @@ -105,7 +89,7 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>, loc.line as c_uint, loc.col.to_usize() as c_uint)) }; - scopes[scope] = DebugScope { + debug_context.scopes[scope] = DebugScope { scope_metadata, file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_pos, diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 0e6269fc7e1b1..01563a3eed3a8 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -11,7 +11,7 @@ use self::metadata::{type_metadata, file_metadata, TypeMap}; use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use crate::llvm; -use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags, +use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DIArray, DIFlags, DISPFlags, DILexicalBlock}; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; @@ -29,13 +29,13 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc_index::vec::IndexVec; use rustc_codegen_ssa::debuginfo::type_names; use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope, VariableAccess, - VariableKind, FunctionDebugContextData}; + VariableKind}; use libc::c_uint; use std::cell::RefCell; use std::ffi::{CStr, CString}; -use syntax_pos::{self, Span, Pos}; +use syntax_pos::{self, BytePos, Span, Pos}; use syntax::ast; use syntax::symbol::Symbol; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; @@ -48,7 +48,7 @@ pub mod metadata; mod create_scope_map; mod source_loc; -pub use self::create_scope_map::{create_mir_scopes}; +pub use self::create_scope_map::compute_mir_scopes; pub use self::metadata::create_global_var_metadata; pub use self::metadata::extend_scope_to_file; pub use self::source_loc::set_source_location; @@ -149,7 +149,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn declare_local( &mut self, - dbg_context: &FunctionDebugContext<&'ll DISubprogram>, + dbg_context: &FunctionDebugContext<&'ll DIScope>, variable_name: ast::Name, variable_type: Ty<'tcx>, scope_metadata: &'ll DIScope, @@ -157,13 +157,13 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { variable_kind: VariableKind, span: Span, ) { - assert!(!dbg_context.get_ref(span).source_locations_enabled); + assert!(!dbg_context.source_locations_enabled); let cx = self.cx(); let file = span_start(cx, span).file; let file_metadata = file_metadata(cx, &file.name, - dbg_context.get_ref(span).defining_crate); + dbg_context.defining_crate); let loc = span_start(cx, span); let type_metadata = type_metadata(cx, variable_type, span); @@ -215,8 +215,8 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn set_source_location( &mut self, - debug_context: &mut FunctionDebugContext<&'ll DISubprogram>, - scope: Option<&'ll DIScope>, + debug_context: &mut FunctionDebugContext<&'ll DIScope>, + scope: &'ll DIScope, span: Span, ) { set_source_location(debug_context, &self, scope, span) @@ -269,14 +269,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { sig: ty::FnSig<'tcx>, llfn: &'ll Value, mir: &mir::Body<'_>, - ) -> FunctionDebugContext<&'ll DISubprogram> { + ) -> Option> { if self.sess().opts.debuginfo == DebugInfo::None { - return FunctionDebugContext::DebugInfoDisabled; + return None; } if let InstanceDef::Item(def_id) = instance.def { if self.tcx().codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) { - return FunctionDebugContext::FunctionWithoutDebugInfo; + return None; } } @@ -285,7 +285,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // This can be the case for functions inlined from another crate if span.is_dummy() { // FIXME(simulacrum): Probably can't happen; remove. - return FunctionDebugContext::FunctionWithoutDebugInfo; + return None; } let def_id = instance.def_id(); @@ -358,14 +358,23 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { None) }; - // Initialize fn debug context (including scope map and namespace map) - let fn_debug_context = FunctionDebugContextData { - fn_metadata, + // Initialize fn debug context (including scopes). + // FIXME(eddyb) figure out a way to not need `Option` for `scope_metadata`. + let null_scope = DebugScope { + scope_metadata: None, + file_start_pos: BytePos(0), + file_end_pos: BytePos(0) + }; + let mut fn_debug_context = FunctionDebugContext { + scopes: IndexVec::from_elem(null_scope, &mir.source_scopes), source_locations_enabled: false, defining_crate: def_id.krate, }; - return FunctionDebugContext::RegularContext(fn_debug_context); + // Fill in all the scopes, with the information from the MIR body. + compute_mir_scopes(self, mir, fn_metadata, &mut fn_debug_context); + + return Some(fn_debug_context); fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, @@ -550,14 +559,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { metadata::create_vtable_metadata(self, ty, vtable) } - fn create_mir_scopes( - &self, - mir: &mir::Body<'_>, - debug_context: &mut FunctionDebugContext<&'ll DISubprogram>, - ) -> IndexVec> { - create_scope_map::create_mir_scopes(self, mir, debug_context) - } - fn extend_scope_to_file( &self, scope_metadata: &'ll DIScope, diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs index 014c1d285d285..ccb3bde1cbe4e 100644 --- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -18,22 +18,13 @@ use syntax_pos::{Span, Pos}; pub fn set_source_location( debug_context: &FunctionDebugContext, bx: &Builder<'_, 'll, '_>, - scope: Option<&'ll DIScope>, + scope: &'ll DIScope, span: Span, ) { - let function_debug_context = match *debug_context { - FunctionDebugContext::DebugInfoDisabled => return, - FunctionDebugContext::FunctionWithoutDebugInfo => { - set_debug_location(bx, UnknownLocation); - return; - } - FunctionDebugContext::RegularContext(ref data) => data - }; - - let dbg_loc = if function_debug_context.source_locations_enabled { + let dbg_loc = if debug_context.source_locations_enabled { debug!("set_source_location: {}", bx.sess().source_map().span_to_string(span)); let loc = span_start(bx.cx(), span); - InternalDebugLocation::new(scope.unwrap(), loc.line, loc.col.to_usize()) + InternalDebugLocation::new(scope, loc.line, loc.col.to_usize()) } else { UnknownLocation }; diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index 29c0d70b58a90..f6c7a37881139 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -1,4 +1,4 @@ -use rustc_index::vec::Idx; +use rustc_index::vec::{Idx, IndexVec}; use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::session::config::DebugInfo; @@ -13,51 +13,8 @@ use syntax::symbol::kw; use super::{FunctionCx, LocalRef}; use super::OperandValue; -pub enum FunctionDebugContext { - RegularContext(FunctionDebugContextData), - DebugInfoDisabled, - FunctionWithoutDebugInfo, -} - -impl FunctionDebugContext { - pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData { - match *self { - FunctionDebugContext::RegularContext(ref data) => data, - FunctionDebugContext::DebugInfoDisabled => { - span_bug!( - span, - "debuginfo: Error trying to access FunctionDebugContext \ - although debug info is disabled!", - ); - } - FunctionDebugContext::FunctionWithoutDebugInfo => { - span_bug!( - span, - "debuginfo: Error trying to access FunctionDebugContext \ - for function that should be ignored by debug info!", - ); - } - } - } -} - -/// Enables emitting source locations for the given functions. -/// -/// Since we don't want source locations to be emitted for the function prelude, -/// they are disabled when beginning to codegen a new function. This functions -/// switches source location emitting on and must therefore be called before the -/// first real statement/expression of the function is codegened. -pub fn start_emitting_source_locations(dbg_context: &mut FunctionDebugContext) { - match *dbg_context { - FunctionDebugContext::RegularContext(ref mut data) => { - data.source_locations_enabled = true; - }, - _ => { /* safe to ignore */ } - } -} - -pub struct FunctionDebugContextData { - pub fn_metadata: D, +pub struct FunctionDebugContext { + pub scopes: IndexVec>, pub source_locations_enabled: bool, pub defining_crate: CrateNum, } @@ -75,7 +32,6 @@ pub enum VariableKind { LocalVariable, } - #[derive(Clone, Copy, Debug)] pub struct DebugScope { pub scope_metadata: Option, @@ -98,17 +54,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { source_info: mir::SourceInfo ) { let (scope, span) = self.debug_loc(source_info); - bx.set_source_location(&mut self.debug_context, scope, span); + if let Some(debug_context) = &mut self.debug_context { + // FIXME(eddyb) get rid of this unwrap somehow. + bx.set_source_location(debug_context, scope.unwrap(), span); + } } pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option, Span) { // Bail out if debug info emission is not enabled. match self.debug_context { - FunctionDebugContext::DebugInfoDisabled | - FunctionDebugContext::FunctionWithoutDebugInfo => { - return (self.scopes[source_info.scope].scope_metadata, source_info.span); - } - FunctionDebugContext::RegularContext(_) =>{} + None => return (None, source_info.span), + Some(_) => {} } // In order to have a good line stepping behavior in debugger, we overwrite debug @@ -135,11 +91,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // "extension" into that file. fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos) -> Option { - let scope_metadata = self.scopes[scope_id].scope_metadata; - if pos < self.scopes[scope_id].file_start_pos || - pos >= self.scopes[scope_id].file_end_pos { + let debug_context = self.debug_context.as_ref()?; + let scope_metadata = debug_context.scopes[scope_id].scope_metadata; + if pos < debug_context.scopes[scope_id].file_start_pos || + pos >= debug_context.scopes[scope_id].file_end_pos { let sm = self.cx.sess().source_map(); - let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate; + let defining_crate = debug_context.defining_crate; Some(self.cx.extend_scope_to_file( scope_metadata.unwrap(), &sm.lookup_char_pos(pos).file, @@ -214,6 +171,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + let debug_context = match &self.debug_context { + Some(debug_context) => debug_context, + None => return, + }; + // FIXME(eddyb) add debuginfo for unsized places too. let place = match local_ref { LocalRef::Place(place) => place, @@ -225,7 +187,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { scope: decl.visibility_scope, }); if let Some(scope) = scope { - bx.declare_local(&self.debug_context, name, place.layout.ty, scope, + bx.declare_local(debug_context, name, place.layout.ty, scope, VariableAccess::DirectVariable { alloca: place.llval }, kind, span); } @@ -249,6 +211,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + let debug_context = match &self.debug_context { + Some(debug_context) => debug_context, + None => return, + }; + for local in self.locals.indices() { self.debug_introduce_local(bx, local); } @@ -256,7 +223,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Declare closure captures as if they were local variables. // FIXME(eddyb) generalize this to `name => place` mappings. let upvar_scope = if !upvar_debuginfo.is_empty() { - self.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata + debug_context.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata } else { None }; @@ -362,7 +329,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { address_operations: &ops }; bx.declare_local( - &self.debug_context, + debug_context, name, ty, var_scope, diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 4e0974e6b85c8..0e790e51a4c88 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -23,7 +23,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { mir: &'a mir::Body<'tcx>, - debug_context: FunctionDebugContext, + debug_context: Option>, llfn: Bx::Function, @@ -74,8 +74,6 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// notably `expect`. locals: IndexVec>, - /// Debug information for MIR scopes. - scopes: IndexVec>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -129,8 +127,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let fn_ty = FnType::new(cx, sig, &[]); debug!("fn_ty: {:?}", fn_ty); - let mut debug_context = + + let debug_context = cx.create_function_debug_context(instance, sig, llfn, mir); + let mut bx = Bx::new_block(cx, llfn, "start"); if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) { @@ -152,8 +152,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } }).collect(); - // Compute debuginfo scopes from MIR scopes. - let scopes = cx.create_mir_scopes(mir, &mut debug_context); let (landing_pads, funclets) = create_funclets(mir, &mut bx, &cleanup_kinds, &block_bxs); let mut fx = FunctionCx { @@ -168,7 +166,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cleanup_kinds, landing_pads, funclets, - scopes, locals: IndexVec::new(), debug_context, }; @@ -221,7 +218,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Up until here, IR instructions for this function have explicitly not been annotated with // source code location, so we don't step into call setup code. From here on, source location // emitting should be enabled. - debuginfo::start_emitting_source_locations(&mut fx.debug_context); + if let Some(debug_context) = &mut fx.debug_context { + debug_context.source_locations_enabled = true; + } let rpo = traversal::reverse_postorder(&mir); let mut visited = BitSet::new_empty(mir.basic_blocks().len()); diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index 4712eff67963e..ac4e1b94d7f5a 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -1,9 +1,8 @@ use super::BackendTypes; -use crate::mir::debuginfo::{FunctionDebugContext, DebugScope, VariableAccess, VariableKind}; +use crate::mir::debuginfo::{FunctionDebugContext, VariableAccess, VariableKind}; use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::ty::{self, Ty, Instance}; -use rustc_index::vec::IndexVec; use syntax::ast::Name; use syntax_pos::{SourceFile, Span}; @@ -13,22 +12,15 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { /// Creates the function-specific debug context. /// /// Returns the FunctionDebugContext for the function which holds state needed - /// for debug info creation. The function may also return another variant of the - /// FunctionDebugContext enum which indicates why no debuginfo should be created - /// for the function. + /// for debug info creation, if it is enabled. fn create_function_debug_context( &self, instance: Instance<'tcx>, sig: ty::FnSig<'tcx>, llfn: Self::Function, mir: &mir::Body<'_>, - ) -> FunctionDebugContext; + ) -> Option>; - fn create_mir_scopes( - &self, - mir: &mir::Body<'_>, - debug_context: &mut FunctionDebugContext, - ) -> IndexVec>; fn extend_scope_to_file( &self, scope_metadata: Self::DIScope, @@ -53,7 +45,7 @@ pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { fn set_source_location( &mut self, debug_context: &mut FunctionDebugContext, - scope: Option, + scope: Self::DIScope, span: Span, ); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); From 1e42072673929227239215bb2f3333f5351f88ca Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 12 Sep 2019 12:29:46 +0300 Subject: [PATCH 6/7] rustc_codegen_ssa: hide address ops from the declare_local interface. --- src/librustc_codegen_llvm/debuginfo/mod.rs | 101 ++++++++++--------- src/librustc_codegen_llvm/lib.rs | 1 + src/librustc_codegen_ssa/mir/debuginfo.rs | 38 ++++--- src/librustc_codegen_ssa/traits/debuginfo.rs | 9 +- 4 files changed, 77 insertions(+), 72 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 01563a3eed3a8..7713fe47004b9 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -1,7 +1,6 @@ // See doc.rs for documentation. mod doc; -use rustc_codegen_ssa::mir::debuginfo::VariableAccess::*; use rustc_codegen_ssa::mir::debuginfo::VariableKind::*; use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; @@ -28,17 +27,18 @@ use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_index::vec::IndexVec; use rustc_codegen_ssa::debuginfo::type_names; -use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope, VariableAccess, +use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope, VariableKind}; use libc::c_uint; use std::cell::RefCell; use std::ffi::{CStr, CString}; +use smallvec::SmallVec; use syntax_pos::{self, BytePos, Span, Pos}; use syntax::ast; use syntax::symbol::Symbol; -use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; +use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Size}; use rustc_codegen_ssa::traits::*; pub mod gdb; @@ -153,7 +153,9 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { variable_name: ast::Name, variable_type: Ty<'tcx>, scope_metadata: &'ll DIScope, - variable_access: VariableAccess<'_, &'ll Value>, + variable_alloca: Self::Value, + direct_offset: Size, + indirect_offsets: &[Size], variable_kind: VariableKind, span: Span, ) { @@ -174,43 +176,55 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { }; let align = cx.align_of(variable_type); - let name = SmallCStr::new(&variable_name.as_str()); - match (variable_access, &[][..]) { - (DirectVariable { alloca }, address_operations) | - (IndirectVariable {alloca, address_operations}, _) => { - let metadata = unsafe { - llvm::LLVMRustDIBuilderCreateVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name.as_ptr(), - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess().opts.optimize != config::OptLevel::No, - DIFlags::FlagZero, - argument_index, - align.bytes() as u32, - ) - }; - source_loc::set_debug_location(self, - InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); - unsafe { - let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder); - let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( - DIB(cx), - alloca, - metadata, - address_operations.as_ptr(), - address_operations.len() as c_uint, - debug_loc, - self.llbb()); - - llvm::LLVMSetInstDebugLocation(self.llbuilder, instr); - } - source_loc::set_debug_location(self, UnknownLocation); + // Convert the direct and indirect offsets to address ops. + let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() }; + let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() }; + let mut addr_ops = SmallVec::<[_; 8]>::new(); + + if direct_offset.bytes() > 0 { + addr_ops.push(op_plus_uconst()); + addr_ops.push(direct_offset.bytes() as i64); + } + for &offset in indirect_offsets { + addr_ops.push(op_deref()); + if offset.bytes() > 0 { + addr_ops.push(op_plus_uconst()); + addr_ops.push(offset.bytes() as i64); } } + + let name = SmallCStr::new(&variable_name.as_str()); + let metadata = unsafe { + llvm::LLVMRustDIBuilderCreateVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::OptLevel::No, + DIFlags::FlagZero, + argument_index, + align.bytes() as u32, + ) + }; + source_loc::set_debug_location(self, + InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); + unsafe { + let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder); + let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( + DIB(cx), + variable_alloca, + metadata, + addr_ops.as_ptr(), + addr_ops.len() as c_uint, + debug_loc, + self.llbb()); + + llvm::LLVMSetInstDebugLocation(self.llbuilder, instr); + } + source_loc::set_debug_location(self, UnknownLocation); } fn set_source_location( @@ -571,13 +585,4 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn debuginfo_finalize(&self) { finalize(self) } - - fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] { - unsafe { - [llvm::LLVMRustDIBuilderCreateOpDeref(), - llvm::LLVMRustDIBuilderCreateOpPlusUconst(), - byte_offset_of_var_in_env as i64, - llvm::LLVMRustDIBuilderCreateOpDeref()] - } - } } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 2ad6c28cd0838..e7562c399b222 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -38,6 +38,7 @@ extern crate rustc_fs_util; extern crate rustc_driver as _; #[macro_use] extern crate log; +extern crate smallvec; extern crate syntax; extern crate syntax_pos; extern crate rustc_errors as errors; diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index f6c7a37881139..4e9d859c5c526 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -3,7 +3,7 @@ use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::session::config::DebugInfo; use rustc::ty::{self, UpvarSubsts}; -use rustc::ty::layout::HasTyCtxt; +use rustc::ty::layout::{HasTyCtxt, Size}; use rustc_target::abi::{Variants, VariantIdx}; use crate::traits::*; @@ -19,14 +19,6 @@ pub struct FunctionDebugContext { pub defining_crate: CrateNum, } -pub enum VariableAccess<'a, V> { - // The llptr given is an alloca containing the variable's value - DirectVariable { alloca: V }, - // The llptr given is an alloca containing the start of some pointer chain - // leading to the variable's content. - IndirectVariable { alloca: V, address_operations: &'a [i64] } -} - pub enum VariableKind { ArgumentVariable(usize /*index*/), LocalVariable, @@ -188,8 +180,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }); if let Some(scope) = scope { bx.declare_local(debug_context, name, place.layout.ty, scope, - VariableAccess::DirectVariable { alloca: place.llval }, - kind, span); + place.llval, Size::ZERO, &[], kind, span); } } } @@ -310,30 +301,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } None => &closure_layout.fields, }; - let byte_offset_of_var_in_env = fields.offset(field).bytes(); - - let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env); // The environment and the capture can each be indirect. - let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; + let mut direct_offset = Size::ZERO; + let indirect_offsets = [ + fields.offset(field), + Size::ZERO, + ]; + let mut indirect_offsets = &indirect_offsets[..]; + + if !env_ref { + direct_offset = indirect_offsets[0]; + indirect_offsets = &indirect_offsets[1..]; + } let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) { ty } else { - ops = &ops[..ops.len() - 1]; + indirect_offsets = &indirect_offsets[..indirect_offsets.len() - 1]; ty }; - let variable_access = VariableAccess::IndirectVariable { - alloca: place.llval, - address_operations: &ops - }; bx.declare_local( debug_context, name, ty, var_scope, - variable_access, + place.llval, + direct_offset, + indirect_offsets, VariableKind::LocalVariable, var_span ); diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index ac4e1b94d7f5a..802eaaa357ac0 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -1,8 +1,9 @@ use super::BackendTypes; -use crate::mir::debuginfo::{FunctionDebugContext, VariableAccess, VariableKind}; +use crate::mir::debuginfo::{FunctionDebugContext, VariableKind}; use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::ty::{self, Ty, Instance}; +use rustc::ty::layout::Size; use syntax::ast::Name; use syntax_pos::{SourceFile, Span}; @@ -28,7 +29,6 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { defining_crate: CrateNum, ) -> Self::DIScope; fn debuginfo_finalize(&self); - fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4]; } pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { @@ -38,7 +38,10 @@ pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { variable_name: Name, variable_type: Ty<'tcx>, scope_metadata: Self::DIScope, - variable_access: VariableAccess<'_, Self::Value>, + variable_alloca: Self::Value, + direct_offset: Size, + // NB: each offset implies a deref (i.e. they're steps in a pointer chain). + indirect_offsets: &[Size], variable_kind: VariableKind, span: Span, ); From 60a22665c8c6aff406ffa453965b011eca50ef0c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 23 Oct 2019 13:12:11 +0300 Subject: [PATCH 7/7] rustc_codegen_ssa: introduce MIR VarDebugInfo, but only for codegen. --- src/librustc_codegen_ssa/mir/debuginfo.rs | 322 ++++++++++++---------- src/librustc_codegen_ssa/mir/mod.rs | 2 + 2 files changed, 186 insertions(+), 138 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index 4e9d859c5c526..c215db34ccbc8 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -2,12 +2,11 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::session::config::DebugInfo; -use rustc::ty::{self, UpvarSubsts}; -use rustc::ty::layout::{HasTyCtxt, Size}; -use rustc_target::abi::{Variants, VariantIdx}; +use rustc::ty::{self, TyCtxt}; +use rustc::ty::layout::{LayoutOf, Size, VariantIdx}; use crate::traits::*; -use syntax_pos::{DUMMY_SP, BytePos, Span}; +use syntax_pos::{BytePos, Span, Symbol}; use syntax::symbol::kw; use super::{FunctionCx, LocalRef}; @@ -19,6 +18,7 @@ pub struct FunctionDebugContext { pub defining_crate: CrateNum, } +#[derive(Copy, Clone)] pub enum VariableKind { ArgumentVariable(usize /*index*/), LocalVariable, @@ -104,37 +104,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(eddyb) use `llvm.dbg.value` (which would work for operands), // not just `llvm.dbg.declare` (which requires `alloca`). pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { - let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use; - // FIXME(eddyb) maybe name the return place as `_0` or `return`? if local == mir::RETURN_PLACE { return; } - let decl = &self.mir.local_decls[local]; - let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg { + let vars = match &self.per_local_var_debug_info { + Some(per_local) => &per_local[local], + None => return, + }; + let whole_local_var = vars.iter().find(|var| { + var.place.projection.is_empty() + }); + let has_proj = || vars.iter().any(|var| { + !var.place.projection.is_empty() + }); + + let (fallback_var, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg { let arg_index = local.index() - 1; // Add debuginfo even to unnamed arguments. // FIXME(eddyb) is this really needed? - let name = if arg_index == 0 && !upvar_debuginfo.is_empty() { + let var = if arg_index == 0 && has_proj() { // Hide closure environments from debuginfo. // FIXME(eddyb) shouldn't `ArgumentVariable` indices // be offset to account for the hidden environment? None } else { - Some(decl.name.unwrap_or(kw::Invalid)) + Some(VarDebugInfo { + name: kw::Invalid, + source_info: self.mir.local_decls[local].source_info, + place: local.into(), + }) }; - (name, VariableKind::ArgumentVariable(arg_index + 1)) + (var, VariableKind::ArgumentVariable(arg_index + 1)) } else { - (decl.name, VariableKind::LocalVariable) + (None, VariableKind::LocalVariable) }; let local_ref = &self.locals[local]; if !bx.sess().fewer_names() { - let name = match name { - Some(name) if name != kw::Invalid => name.to_string(), + let name = match whole_local_var.or(fallback_var.as_ref()) { + Some(var) if var.name != kw::Invalid => var.name.to_string(), _ => format!("{:?}", local), }; match local_ref { @@ -158,127 +170,161 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - if let Some(name) = name { - if bx.sess().opts.debuginfo != DebugInfo::Full { - return; - } + if bx.sess().opts.debuginfo != DebugInfo::Full { + return; + } - let debug_context = match &self.debug_context { - Some(debug_context) => debug_context, - None => return, - }; + let debug_context = match &self.debug_context { + Some(debug_context) => debug_context, + None => return, + }; + + // FIXME(eddyb) add debuginfo for unsized places too. + let base = match local_ref { + LocalRef::Place(place) => place, + _ => return, + }; + + let vars = vars.iter().chain(if whole_local_var.is_none() { + fallback_var.as_ref() + } else { + None + }); - // FIXME(eddyb) add debuginfo for unsized places too. - let place = match local_ref { - LocalRef::Place(place) => place, - _ => return, + for var in vars { + let mut layout = base.layout; + let mut direct_offset = Size::ZERO; + // FIXME(eddyb) use smallvec here. + let mut indirect_offsets = vec![]; + + let kind = if var.place.projection.is_empty() { + kind + } else { + VariableKind::LocalVariable }; - let (scope, span) = self.debug_loc(mir::SourceInfo { - span: decl.source_info.span, - scope: decl.visibility_scope, - }); + for elem in &var.place.projection[..] { + match *elem { + mir::ProjectionElem::Deref => { + indirect_offsets.push(Size::ZERO); + layout = bx.cx().layout_of( + layout.ty.builtin_deref(true) + .unwrap_or_else(|| { + span_bug!( + var.source_info.span, + "cannot deref `{}`", + layout.ty, + ) + }).ty, + ); + } + mir::ProjectionElem::Field(field, _) => { + let i = field.index(); + let offset = indirect_offsets.last_mut() + .unwrap_or(&mut direct_offset); + *offset += layout.fields.offset(i); + layout = layout.field(bx.cx(), i); + } + mir::ProjectionElem::Downcast(_, variant) => { + layout = layout.for_variant(bx.cx(), variant); + } + _ => span_bug!( + var.source_info.span, + "unsupported var debuginfo place `{:?}`", + var.place, + ), + } + } + + let (scope, span) = self.debug_loc(var.source_info); if let Some(scope) = scope { - bx.declare_local(debug_context, name, place.layout.ty, scope, - place.llval, Size::ZERO, &[], kind, span); + bx.declare_local(debug_context, var.name, layout.ty, scope, + base.llval, direct_offset, &indirect_offsets, kind, span); } } } pub fn debug_introduce_locals(&self, bx: &mut Bx) { - let tcx = self.cx.tcx(); - let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use; - - if bx.sess().opts.debuginfo != DebugInfo::Full { - // HACK(eddyb) figure out a way to perhaps disentangle - // the use of `declare_local` and `set_var_name`. - // Or maybe just running this loop always is not that expensive? - if !bx.sess().fewer_names() { - for local in self.locals.indices() { - self.debug_introduce_local(bx, local); - } + if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() { + for local in self.locals.indices() { + self.debug_introduce_local(bx, local); } - - return; } + } +} - let debug_context = match &self.debug_context { - Some(debug_context) => debug_context, - None => return, - }; - - for local in self.locals.indices() { - self.debug_introduce_local(bx, local); +pub fn per_local_var_debug_info( + tcx: TyCtxt<'tcx>, + body: &mir::Body<'tcx>, +) -> Option>>> { + if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() { + let mut per_local = IndexVec::from_elem(vec![], &body.local_decls); + for (local, decl) in body.local_decls.iter_enumerated() { + if let Some(name) = decl.name { + per_local[local].push(VarDebugInfo { + name, + source_info: mir::SourceInfo { + span: decl.source_info.span, + scope: decl.visibility_scope, + }, + place: local.into(), + }); + } } - // Declare closure captures as if they were local variables. - // FIXME(eddyb) generalize this to `name => place` mappings. - let upvar_scope = if !upvar_debuginfo.is_empty() { - debug_context.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata - } else { - None - }; - if let Some(scope) = upvar_scope { - let place = match self.locals[mir::Local::new(1)] { - LocalRef::Place(place) => place, - _ => bug!(), - }; + let upvar_debuginfo = &body.__upvar_debuginfo_codegen_only_do_not_use; + if !upvar_debuginfo.is_empty() { + + let env_arg = mir::Local::new(1); + let mut env_projs = vec![]; let pin_did = tcx.lang_items().pin_type(); - let (closure_layout, env_ref) = match place.layout.ty.kind { - ty::RawPtr(ty::TypeAndMut { ty, .. }) | - ty::Ref(_, ty, _) => (bx.layout_of(ty), true), + match body.local_decls[env_arg].ty.kind { + ty::RawPtr(_) | + ty::Ref(..) => { + env_projs.push(mir::ProjectionElem::Deref); + } ty::Adt(def, substs) if Some(def.did) == pin_did => { - match substs.type_at(0).kind { - ty::Ref(_, ty, _) => (bx.layout_of(ty), true), - _ => (place.layout, false), + if let ty::Ref(..) = substs.type_at(0).kind { + env_projs.push(mir::ProjectionElem::Field( + mir::Field::new(0), + // HACK(eddyb) field types aren't used or needed here. + tcx.types.err, + )); + env_projs.push(mir::ProjectionElem::Deref); } } - _ => (place.layout, false) - }; - - let (def_id, upvar_substs) = match closure_layout.ty.kind { - ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), - ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), - _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty) - }; - let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); + _ => {} + } let extra_locals = { let upvars = upvar_debuginfo .iter() - .zip(upvar_tys) .enumerate() - .map(|(i, (upvar, ty))| { - (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP) + .map(|(i, upvar)| { + let source_info = mir::SourceInfo { + span: body.span, + scope: mir::OUTERMOST_SOURCE_SCOPE, + }; + (None, i, upvar.debug_name, upvar.by_ref, source_info) }); - let generator_fields = self.mir.generator_layout.as_ref().map(|generator_layout| { - let (def_id, gen_substs) = match closure_layout.ty.kind { - ty::Generator(def_id, substs, _) => (def_id, substs), - _ => bug!("generator layout without generator substs"), - }; - let state_tys = gen_substs.as_generator().state_tys(def_id, tcx); - + let generator_fields = body.generator_layout.as_ref().map(|generator_layout| { generator_layout.variant_fields.iter() - .zip(state_tys) .enumerate() - .flat_map(move |(variant_idx, (fields, tys))| { + .flat_map(move |(variant_idx, fields)| { let variant_idx = Some(VariantIdx::from(variant_idx)); fields.iter() - .zip(tys) .enumerate() - .filter_map(move |(i, (field, ty))| { + .filter_map(move |(i, field)| { let decl = &generator_layout. __local_debuginfo_codegen_only_do_not_use[*field]; if let Some(name) = decl.name { - let ty = self.monomorphize(&ty); - let (var_scope, var_span) = self.debug_loc(mir::SourceInfo { + let source_info = mir::SourceInfo { span: decl.source_info.span, scope: decl.visibility_scope, - }); - let var_scope = var_scope.unwrap_or(scope); - Some((variant_idx, i, name, false, ty, var_scope, var_span)) + }; + Some((variant_idx, i, name, false, source_info)) } else { None } @@ -289,51 +335,51 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { upvars.chain(generator_fields) }; - for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals { - let fields = match variant_idx { - Some(variant_idx) => { - match &closure_layout.variants { - Variants::Multiple { variants, .. } => { - &variants[variant_idx].fields - }, - _ => bug!("variant index on univariant layout"), - } - } - None => &closure_layout.fields, - }; - - // The environment and the capture can each be indirect. - let mut direct_offset = Size::ZERO; - let indirect_offsets = [ - fields.offset(field), - Size::ZERO, - ]; - let mut indirect_offsets = &indirect_offsets[..]; - - if !env_ref { - direct_offset = indirect_offsets[0]; - indirect_offsets = &indirect_offsets[1..]; + for (variant_idx, field, name, by_ref, source_info) in extra_locals { + let mut projs = env_projs.clone(); + + if let Some(variant_idx) = variant_idx { + projs.push(mir::ProjectionElem::Downcast(None, variant_idx)); } - let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) { - ty - } else { - indirect_offsets = &indirect_offsets[..indirect_offsets.len() - 1]; - ty - }; + projs.push(mir::ProjectionElem::Field( + mir::Field::new(field), + // HACK(eddyb) field types aren't used or needed here. + tcx.types.err, + )); - bx.declare_local( - debug_context, + if by_ref { + projs.push(mir::ProjectionElem::Deref); + } + + per_local[env_arg].push(VarDebugInfo { name, - ty, - var_scope, - place.llval, - direct_offset, - indirect_offsets, - VariableKind::LocalVariable, - var_span - ); + source_info, + place: mir::Place { + base: mir::PlaceBase::Local(env_arg), + projection: tcx.intern_place_elems(&projs), + }, + }); } } + + Some(per_local) + } else { + None } } + +/// Debug information relatating to an user variable. +// FIXME(eddyb) move this to the MIR bodies themselves. +#[derive(Clone)] +pub struct VarDebugInfo<'tcx> { + pub name: Symbol, + + /// Source info of the user variable, including the scope + /// within which the variable is visible (to debuginfo) + /// (see `LocalDecl`'s `source_info` field for more details). + pub source_info: mir::SourceInfo, + + /// Where the data for this user variable is to be found. + pub place: mir::Place<'tcx>, +} diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 0e790e51a4c88..5ad14456285ba 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -74,6 +74,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// notably `expect`. locals: IndexVec>, + per_local_var_debug_info: Option>>>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -168,6 +169,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( funclets, locals: IndexVec::new(), debug_context, + per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir), }; let memory_locals = analyze::non_ssa_locals(&fx);