Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 01e5d91

Browse files
committedNov 1, 2019
Auto merge of #65718 - eddyb:codegen-var-debuginfo, r=nikomatsakis
rustc_codegen_ssa: introduce MIR VarDebugInfo, but only for codegen. These are all the codegen changes necessary for #56231. The refactors were performed locally to codegen, and in several steps, to ease reviewing and avoid introducing changes in behavior (as I'm not sure our debuginfo tests cover enough). r? @michaelwoerister cc @nagisa @rkruppe @oli-obk
2 parents 253fc0e + 60a2266 commit 01e5d91

File tree

14 files changed

+655
-653
lines changed

14 files changed

+655
-653
lines changed
 

‎src/librustc_codegen_llvm/debuginfo/create_scope_map.rs

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, FunctionDebugContextData, MirDebugScope};
1+
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope};
22
use super::metadata::file_metadata;
33
use super::utils::{DIB, span_start};
44

@@ -12,34 +12,20 @@ use libc::c_uint;
1212
use syntax_pos::Pos;
1313

1414
use rustc_index::bit_set::BitSet;
15-
use rustc_index::vec::{Idx, IndexVec};
16-
17-
use syntax_pos::BytePos;
15+
use rustc_index::vec::Idx;
1816

1917
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
20-
/// If debuginfo is disabled, the returned vector is empty.
21-
pub fn create_mir_scopes(
18+
pub fn compute_mir_scopes(
2219
cx: &CodegenCx<'ll, '_>,
2320
mir: &Body<'_>,
24-
debug_context: &FunctionDebugContext<&'ll DISubprogram>,
25-
) -> IndexVec<SourceScope, MirDebugScope<&'ll DIScope>> {
26-
let null_scope = MirDebugScope {
27-
scope_metadata: None,
28-
file_start_pos: BytePos(0),
29-
file_end_pos: BytePos(0)
30-
};
31-
let mut scopes = IndexVec::from_elem(null_scope, &mir.source_scopes);
32-
33-
let debug_context = match *debug_context {
34-
FunctionDebugContext::RegularContext(ref data) => data,
35-
FunctionDebugContext::DebugInfoDisabled |
36-
FunctionDebugContext::FunctionWithoutDebugInfo => {
37-
return scopes;
38-
}
39-
};
40-
21+
fn_metadata: &'ll DISubprogram,
22+
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
23+
) {
4124
// Find all the scopes with variables defined in them.
4225
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
26+
// FIXME(eddyb) base this on `decl.name`, or even better, on debuginfo.
27+
// FIXME(eddyb) take into account that arguments always have debuginfo,
28+
// irrespective of their name (assuming full debuginfo is enabled).
4329
for var in mir.vars_iter() {
4430
let decl = &mir.local_decls[var];
4531
has_variables.insert(decl.visibility_scope);
@@ -48,31 +34,29 @@ pub fn create_mir_scopes(
4834
// Instantiate all scopes.
4935
for idx in 0..mir.source_scopes.len() {
5036
let scope = SourceScope::new(idx);
51-
make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes);
37+
make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope);
5238
}
53-
54-
scopes
5539
}
5640

5741
fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
5842
mir: &Body<'_>,
43+
fn_metadata: &'ll DISubprogram,
5944
has_variables: &BitSet<SourceScope>,
60-
debug_context: &FunctionDebugContextData<&'ll DISubprogram>,
61-
scope: SourceScope,
62-
scopes: &mut IndexVec<SourceScope, MirDebugScope<&'ll DIScope>>) {
63-
if scopes[scope].is_valid() {
45+
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
46+
scope: SourceScope) {
47+
if debug_context.scopes[scope].is_valid() {
6448
return;
6549
}
6650

6751
let scope_data = &mir.source_scopes[scope];
6852
let parent_scope = if let Some(parent) = scope_data.parent_scope {
69-
make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes);
70-
scopes[parent]
53+
make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent);
54+
debug_context.scopes[parent]
7155
} else {
7256
// The root is the function itself.
7357
let loc = span_start(cx, mir.span);
74-
scopes[scope] = MirDebugScope {
75-
scope_metadata: Some(debug_context.fn_metadata),
58+
debug_context.scopes[scope] = DebugScope {
59+
scope_metadata: Some(fn_metadata),
7660
file_start_pos: loc.file.start_pos,
7761
file_end_pos: loc.file.end_pos,
7862
};
@@ -86,8 +70,8 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
8670
// However, we don't skip creating a nested scope if
8771
// our parent is the root, because we might want to
8872
// put arguments in the root and not have shadowing.
89-
if parent_scope.scope_metadata.unwrap() != debug_context.fn_metadata {
90-
scopes[scope] = parent_scope;
73+
if parent_scope.scope_metadata.unwrap() != fn_metadata {
74+
debug_context.scopes[scope] = parent_scope;
9175
return;
9276
}
9377
}
@@ -105,7 +89,7 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
10589
loc.line as c_uint,
10690
loc.col.to_usize() as c_uint))
10791
};
108-
scopes[scope] = MirDebugScope {
92+
debug_context.scopes[scope] = DebugScope {
10993
scope_metadata,
11094
file_start_pos: loc.file.start_pos,
11195
file_end_pos: loc.file.end_pos,

‎src/librustc_codegen_llvm/debuginfo/mod.rs

Lines changed: 83 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// See doc.rs for documentation.
22
mod doc;
33

4-
use rustc_codegen_ssa::debuginfo::VariableAccess::*;
5-
use rustc_codegen_ssa::debuginfo::VariableKind::*;
4+
use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
65

76
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
87
use self::namespace::mangled_name_of_instance;
@@ -11,7 +10,7 @@ use self::metadata::{type_metadata, file_metadata, TypeMap};
1110
use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
1211

1312
use crate::llvm;
14-
use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags,
13+
use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DIArray, DIFlags,
1514
DISPFlags, DILexicalBlock};
1615
use rustc::hir::CodegenFnAttrFlags;
1716
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
@@ -27,17 +26,19 @@ use rustc::session::config::{self, DebugInfo};
2726
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
2827
use rustc_data_structures::small_c_str::SmallCStr;
2928
use rustc_index::vec::IndexVec;
30-
use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess,
31-
VariableKind, FunctionDebugContextData, type_names};
29+
use rustc_codegen_ssa::debuginfo::type_names;
30+
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope,
31+
VariableKind};
3232

3333
use libc::c_uint;
3434
use std::cell::RefCell;
3535
use std::ffi::{CStr, CString};
3636

37-
use syntax_pos::{self, Span, Pos};
37+
use smallvec::SmallVec;
38+
use syntax_pos::{self, BytePos, Span, Pos};
3839
use syntax::ast;
3940
use syntax::symbol::Symbol;
40-
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
41+
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Size};
4142
use rustc_codegen_ssa::traits::*;
4243

4344
pub mod gdb;
@@ -47,7 +48,7 @@ pub mod metadata;
4748
mod create_scope_map;
4849
mod source_loc;
4950

50-
pub use self::create_scope_map::{create_mir_scopes};
51+
pub use self::create_scope_map::compute_mir_scopes;
5152
pub use self::metadata::create_global_var_metadata;
5253
pub use self::metadata::extend_scope_to_file;
5354
pub use self::source_loc::set_source_location;
@@ -148,21 +149,23 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
148149
impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
149150
fn declare_local(
150151
&mut self,
151-
dbg_context: &FunctionDebugContext<&'ll DISubprogram>,
152+
dbg_context: &FunctionDebugContext<&'ll DIScope>,
152153
variable_name: ast::Name,
153154
variable_type: Ty<'tcx>,
154155
scope_metadata: &'ll DIScope,
155-
variable_access: VariableAccess<'_, &'ll Value>,
156+
variable_alloca: Self::Value,
157+
direct_offset: Size,
158+
indirect_offsets: &[Size],
156159
variable_kind: VariableKind,
157160
span: Span,
158161
) {
159-
assert!(!dbg_context.get_ref(span).source_locations_enabled);
162+
assert!(!dbg_context.source_locations_enabled);
160163
let cx = self.cx();
161164

162165
let file = span_start(cx, span).file;
163166
let file_metadata = file_metadata(cx,
164167
&file.name,
165-
dbg_context.get_ref(span).defining_crate);
168+
dbg_context.defining_crate);
166169

167170
let loc = span_start(cx, span);
168171
let type_metadata = type_metadata(cx, variable_type, span);
@@ -173,49 +176,61 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
173176
};
174177
let align = cx.align_of(variable_type);
175178

176-
let name = SmallCStr::new(&variable_name.as_str());
177-
match (variable_access, &[][..]) {
178-
(DirectVariable { alloca }, address_operations) |
179-
(IndirectVariable {alloca, address_operations}, _) => {
180-
let metadata = unsafe {
181-
llvm::LLVMRustDIBuilderCreateVariable(
182-
DIB(cx),
183-
dwarf_tag,
184-
scope_metadata,
185-
name.as_ptr(),
186-
file_metadata,
187-
loc.line as c_uint,
188-
type_metadata,
189-
cx.sess().opts.optimize != config::OptLevel::No,
190-
DIFlags::FlagZero,
191-
argument_index,
192-
align.bytes() as u32,
193-
)
194-
};
195-
source_loc::set_debug_location(self,
196-
InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
197-
unsafe {
198-
let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder);
199-
let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
200-
DIB(cx),
201-
alloca,
202-
metadata,
203-
address_operations.as_ptr(),
204-
address_operations.len() as c_uint,
205-
debug_loc,
206-
self.llbb());
207-
208-
llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
209-
}
210-
source_loc::set_debug_location(self, UnknownLocation);
179+
// Convert the direct and indirect offsets to address ops.
180+
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
181+
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
182+
let mut addr_ops = SmallVec::<[_; 8]>::new();
183+
184+
if direct_offset.bytes() > 0 {
185+
addr_ops.push(op_plus_uconst());
186+
addr_ops.push(direct_offset.bytes() as i64);
187+
}
188+
for &offset in indirect_offsets {
189+
addr_ops.push(op_deref());
190+
if offset.bytes() > 0 {
191+
addr_ops.push(op_plus_uconst());
192+
addr_ops.push(offset.bytes() as i64);
211193
}
212194
}
195+
196+
let name = SmallCStr::new(&variable_name.as_str());
197+
let metadata = unsafe {
198+
llvm::LLVMRustDIBuilderCreateVariable(
199+
DIB(cx),
200+
dwarf_tag,
201+
scope_metadata,
202+
name.as_ptr(),
203+
file_metadata,
204+
loc.line as c_uint,
205+
type_metadata,
206+
cx.sess().opts.optimize != config::OptLevel::No,
207+
DIFlags::FlagZero,
208+
argument_index,
209+
align.bytes() as u32,
210+
)
211+
};
212+
source_loc::set_debug_location(self,
213+
InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
214+
unsafe {
215+
let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder);
216+
let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
217+
DIB(cx),
218+
variable_alloca,
219+
metadata,
220+
addr_ops.as_ptr(),
221+
addr_ops.len() as c_uint,
222+
debug_loc,
223+
self.llbb());
224+
225+
llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
226+
}
227+
source_loc::set_debug_location(self, UnknownLocation);
213228
}
214229

215230
fn set_source_location(
216231
&mut self,
217-
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
218-
scope: Option<&'ll DIScope>,
232+
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
233+
scope: &'ll DIScope,
219234
span: Span,
220235
) {
221236
set_source_location(debug_context, &self, scope, span)
@@ -224,7 +239,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
224239
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
225240
}
226241

227-
fn set_var_name(&mut self, value: &'ll Value, name: impl ToString) {
242+
fn set_var_name(&mut self, value: &'ll Value, name: &str) {
228243
// Avoid wasting time if LLVM value names aren't even enabled.
229244
if self.sess().fewer_names() {
230245
return;
@@ -254,7 +269,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
254269
Err(_) => return,
255270
}
256271

257-
let cname = CString::new(name.to_string()).unwrap();
272+
let cname = SmallCStr::new(name);
258273
unsafe {
259274
llvm::LLVMSetValueName(value, cname.as_ptr());
260275
}
@@ -268,14 +283,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
268283
sig: ty::FnSig<'tcx>,
269284
llfn: &'ll Value,
270285
mir: &mir::Body<'_>,
271-
) -> FunctionDebugContext<&'ll DISubprogram> {
286+
) -> Option<FunctionDebugContext<&'ll DIScope>> {
272287
if self.sess().opts.debuginfo == DebugInfo::None {
273-
return FunctionDebugContext::DebugInfoDisabled;
288+
return None;
274289
}
275290

276291
if let InstanceDef::Item(def_id) = instance.def {
277292
if self.tcx().codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) {
278-
return FunctionDebugContext::FunctionWithoutDebugInfo;
293+
return None;
279294
}
280295
}
281296

@@ -284,7 +299,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
284299
// This can be the case for functions inlined from another crate
285300
if span.is_dummy() {
286301
// FIXME(simulacrum): Probably can't happen; remove.
287-
return FunctionDebugContext::FunctionWithoutDebugInfo;
302+
return None;
288303
}
289304

290305
let def_id = instance.def_id();
@@ -357,14 +372,23 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
357372
None)
358373
};
359374

360-
// Initialize fn debug context (including scope map and namespace map)
361-
let fn_debug_context = FunctionDebugContextData {
362-
fn_metadata,
375+
// Initialize fn debug context (including scopes).
376+
// FIXME(eddyb) figure out a way to not need `Option` for `scope_metadata`.
377+
let null_scope = DebugScope {
378+
scope_metadata: None,
379+
file_start_pos: BytePos(0),
380+
file_end_pos: BytePos(0)
381+
};
382+
let mut fn_debug_context = FunctionDebugContext {
383+
scopes: IndexVec::from_elem(null_scope, &mir.source_scopes),
363384
source_locations_enabled: false,
364385
defining_crate: def_id.krate,
365386
};
366387

367-
return FunctionDebugContext::RegularContext(fn_debug_context);
388+
// Fill in all the scopes, with the information from the MIR body.
389+
compute_mir_scopes(self, mir, fn_metadata, &mut fn_debug_context);
390+
391+
return Some(fn_debug_context);
368392

369393
fn get_function_signature<'ll, 'tcx>(
370394
cx: &CodegenCx<'ll, 'tcx>,
@@ -549,14 +573,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
549573
metadata::create_vtable_metadata(self, ty, vtable)
550574
}
551575

552-
fn create_mir_scopes(
553-
&self,
554-
mir: &mir::Body<'_>,
555-
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
556-
) -> IndexVec<mir::SourceScope, MirDebugScope<&'ll DIScope>> {
557-
create_scope_map::create_mir_scopes(self, mir, debug_context)
558-
}
559-
560576
fn extend_scope_to_file(
561577
&self,
562578
scope_metadata: &'ll DIScope,
@@ -569,13 +585,4 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
569585
fn debuginfo_finalize(&self) {
570586
finalize(self)
571587
}
572-
573-
fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] {
574-
unsafe {
575-
[llvm::LLVMRustDIBuilderCreateOpDeref(),
576-
llvm::LLVMRustDIBuilderCreateOpPlusUconst(),
577-
byte_offset_of_var_in_env as i64,
578-
llvm::LLVMRustDIBuilderCreateOpDeref()]
579-
}
580-
}
581588
}

‎src/librustc_codegen_llvm/debuginfo/source_loc.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use self::InternalDebugLocation::*;
22

33
use super::utils::{debug_context, span_start};
44
use super::metadata::UNKNOWN_COLUMN_NUMBER;
5-
use rustc_codegen_ssa::debuginfo::FunctionDebugContext;
5+
use rustc_codegen_ssa::mir::debuginfo::FunctionDebugContext;
66

77
use crate::llvm;
88
use crate::llvm::debuginfo::DIScope;
@@ -18,22 +18,13 @@ use syntax_pos::{Span, Pos};
1818
pub fn set_source_location<D>(
1919
debug_context: &FunctionDebugContext<D>,
2020
bx: &Builder<'_, 'll, '_>,
21-
scope: Option<&'ll DIScope>,
21+
scope: &'ll DIScope,
2222
span: Span,
2323
) {
24-
let function_debug_context = match *debug_context {
25-
FunctionDebugContext::DebugInfoDisabled => return,
26-
FunctionDebugContext::FunctionWithoutDebugInfo => {
27-
set_debug_location(bx, UnknownLocation);
28-
return;
29-
}
30-
FunctionDebugContext::RegularContext(ref data) => data
31-
};
32-
33-
let dbg_loc = if function_debug_context.source_locations_enabled {
24+
let dbg_loc = if debug_context.source_locations_enabled {
3425
debug!("set_source_location: {}", bx.sess().source_map().span_to_string(span));
3526
let loc = span_start(bx.cx(), span);
36-
InternalDebugLocation::new(scope.unwrap(), loc.line, loc.col.to_usize())
27+
InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
3728
} else {
3829
UnknownLocation
3930
};

‎src/librustc_codegen_llvm/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern crate rustc_fs_util;
3838
extern crate rustc_driver as _;
3939

4040
#[macro_use] extern crate log;
41+
extern crate smallvec;
4142
extern crate syntax;
4243
extern crate syntax_pos;
4344
extern crate rustc_errors as errors;
Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,2 @@
1-
use syntax_pos::{BytePos, Span};
2-
use rustc::hir::def_id::CrateNum;
3-
1+
// FIXME(eddyb) find a place for this (or a way to replace it).
42
pub mod type_names;
5-
6-
pub enum FunctionDebugContext<D> {
7-
RegularContext(FunctionDebugContextData<D>),
8-
DebugInfoDisabled,
9-
FunctionWithoutDebugInfo,
10-
}
11-
12-
impl<D> FunctionDebugContext<D> {
13-
pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData<D> {
14-
match *self {
15-
FunctionDebugContext::RegularContext(ref data) => data,
16-
FunctionDebugContext::DebugInfoDisabled => {
17-
span_bug!(
18-
span,
19-
"debuginfo: Error trying to access FunctionDebugContext \
20-
although debug info is disabled!",
21-
);
22-
}
23-
FunctionDebugContext::FunctionWithoutDebugInfo => {
24-
span_bug!(
25-
span,
26-
"debuginfo: Error trying to access FunctionDebugContext \
27-
for function that should be ignored by debug info!",
28-
);
29-
}
30-
}
31-
}
32-
}
33-
34-
/// Enables emitting source locations for the given functions.
35-
///
36-
/// Since we don't want source locations to be emitted for the function prelude,
37-
/// they are disabled when beginning to codegen a new function. This functions
38-
/// switches source location emitting on and must therefore be called before the
39-
/// first real statement/expression of the function is codegened.
40-
pub fn start_emitting_source_locations<D>(dbg_context: &mut FunctionDebugContext<D>) {
41-
match *dbg_context {
42-
FunctionDebugContext::RegularContext(ref mut data) => {
43-
data.source_locations_enabled = true;
44-
},
45-
_ => { /* safe to ignore */ }
46-
}
47-
}
48-
49-
pub struct FunctionDebugContextData<D> {
50-
pub fn_metadata: D,
51-
pub source_locations_enabled: bool,
52-
pub defining_crate: CrateNum,
53-
}
54-
55-
pub enum VariableAccess<'a, V> {
56-
// The llptr given is an alloca containing the variable's value
57-
DirectVariable { alloca: V },
58-
// The llptr given is an alloca containing the start of some pointer chain
59-
// leading to the variable's content.
60-
IndirectVariable { alloca: V, address_operations: &'a [i64] }
61-
}
62-
63-
pub enum VariableKind {
64-
ArgumentVariable(usize /*index*/),
65-
LocalVariable,
66-
}
67-
68-
69-
#[derive(Clone, Copy, Debug)]
70-
pub struct MirDebugScope<D> {
71-
pub scope_metadata: Option<D>,
72-
// Start and end offsets of the file to which this DIScope belongs.
73-
// These are used to quickly determine whether some span refers to the same file.
74-
pub file_start_pos: BytePos,
75-
pub file_end_pos: BytePos,
76-
}
77-
78-
impl<D> MirDebugScope<D> {
79-
pub fn is_valid(&self) -> bool {
80-
!self.scope_metadata.is_none()
81-
}
82-
}

‎src/librustc_codegen_ssa/mir/analyze.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_index::vec::{Idx, IndexVec};
77
use rustc::mir::{self, Location, TerminatorKind};
88
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
99
use rustc::mir::traversal;
10+
use rustc::session::config::DebugInfo;
1011
use rustc::ty;
1112
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
1213
use syntax_pos::DUMMY_SP;
@@ -21,13 +22,20 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
2122

2223
analyzer.visit_body(mir);
2324

24-
for (index, (ty, span)) in mir.local_decls.iter()
25-
.map(|l| (l.ty, l.source_info.span))
26-
.enumerate()
25+
for (local, decl) in mir.local_decls.iter_enumerated()
2726
{
28-
let ty = fx.monomorphize(&ty);
29-
debug!("local {} has type {:?}", index, ty);
30-
let layout = fx.cx.spanned_layout_of(ty, span);
27+
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
28+
// of putting everything in allocas just so we can use llvm.dbg.declare.
29+
if fx.cx.sess().opts.debuginfo == DebugInfo::Full {
30+
if mir.local_kind(local) == mir::LocalKind::Arg || decl.name.is_some() {
31+
analyzer.not_ssa(local);
32+
continue;
33+
}
34+
}
35+
36+
let ty = fx.monomorphize(&decl.ty);
37+
debug!("local {:?} has type `{}`", local, ty);
38+
let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
3139
if fx.cx.is_backend_immediate(layout) {
3240
// These sorts of types are immediates that we can store
3341
// in an Value without an alloca.
@@ -40,7 +48,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
4048
// (e.g., structs) into an alloca unconditionally, just so
4149
// that we don't have to deal with having two pathways
4250
// (gep vs extractvalue etc).
43-
analyzer.not_ssa(mir::Local::new(index));
51+
analyzer.not_ssa(local);
4452
}
4553
}
4654

Lines changed: 385 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,385 @@
1+
use rustc_index::vec::{Idx, IndexVec};
2+
use rustc::hir::def_id::CrateNum;
3+
use rustc::mir;
4+
use rustc::session::config::DebugInfo;
5+
use rustc::ty::{self, TyCtxt};
6+
use rustc::ty::layout::{LayoutOf, Size, VariantIdx};
7+
use crate::traits::*;
8+
9+
use syntax_pos::{BytePos, Span, Symbol};
10+
use syntax::symbol::kw;
11+
12+
use super::{FunctionCx, LocalRef};
13+
use super::OperandValue;
14+
15+
pub struct FunctionDebugContext<D> {
16+
pub scopes: IndexVec<mir::SourceScope, DebugScope<D>>,
17+
pub source_locations_enabled: bool,
18+
pub defining_crate: CrateNum,
19+
}
20+
21+
#[derive(Copy, Clone)]
22+
pub enum VariableKind {
23+
ArgumentVariable(usize /*index*/),
24+
LocalVariable,
25+
}
26+
27+
#[derive(Clone, Copy, Debug)]
28+
pub struct DebugScope<D> {
29+
pub scope_metadata: Option<D>,
30+
// Start and end offsets of the file to which this DIScope belongs.
31+
// These are used to quickly determine whether some span refers to the same file.
32+
pub file_start_pos: BytePos,
33+
pub file_end_pos: BytePos,
34+
}
35+
36+
impl<D> DebugScope<D> {
37+
pub fn is_valid(&self) -> bool {
38+
!self.scope_metadata.is_none()
39+
}
40+
}
41+
42+
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
43+
pub fn set_debug_loc(
44+
&mut self,
45+
bx: &mut Bx,
46+
source_info: mir::SourceInfo
47+
) {
48+
let (scope, span) = self.debug_loc(source_info);
49+
if let Some(debug_context) = &mut self.debug_context {
50+
// FIXME(eddyb) get rid of this unwrap somehow.
51+
bx.set_source_location(debug_context, scope.unwrap(), span);
52+
}
53+
}
54+
55+
pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option<Bx::DIScope>, Span) {
56+
// Bail out if debug info emission is not enabled.
57+
match self.debug_context {
58+
None => return (None, source_info.span),
59+
Some(_) => {}
60+
}
61+
62+
// In order to have a good line stepping behavior in debugger, we overwrite debug
63+
// locations of macro expansions with that of the outermost expansion site
64+
// (unless the crate is being compiled with `-Z debug-macros`).
65+
if !source_info.span.from_expansion() ||
66+
self.cx.sess().opts.debugging_opts.debug_macros {
67+
let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo());
68+
(scope, source_info.span)
69+
} else {
70+
// Walk up the macro expansion chain until we reach a non-expanded span.
71+
// We also stop at the function body level because no line stepping can occur
72+
// at the level above that.
73+
let span = syntax_pos::hygiene::walk_chain(source_info.span, self.mir.span.ctxt());
74+
let scope = self.scope_metadata_for_loc(source_info.scope, span.lo());
75+
// Use span of the outermost expansion site, while keeping the original lexical scope.
76+
(scope, span)
77+
}
78+
}
79+
80+
// DILocations inherit source file name from the parent DIScope. Due to macro expansions
81+
// it may so happen that the current span belongs to a different file than the DIScope
82+
// corresponding to span's containing source scope. If so, we need to create a DIScope
83+
// "extension" into that file.
84+
fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos)
85+
-> Option<Bx::DIScope> {
86+
let debug_context = self.debug_context.as_ref()?;
87+
let scope_metadata = debug_context.scopes[scope_id].scope_metadata;
88+
if pos < debug_context.scopes[scope_id].file_start_pos ||
89+
pos >= debug_context.scopes[scope_id].file_end_pos {
90+
let sm = self.cx.sess().source_map();
91+
let defining_crate = debug_context.defining_crate;
92+
Some(self.cx.extend_scope_to_file(
93+
scope_metadata.unwrap(),
94+
&sm.lookup_char_pos(pos).file,
95+
defining_crate
96+
))
97+
} else {
98+
scope_metadata
99+
}
100+
}
101+
102+
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
103+
/// or initializing the local with an operand (whichever applies).
104+
// FIXME(eddyb) use `llvm.dbg.value` (which would work for operands),
105+
// not just `llvm.dbg.declare` (which requires `alloca`).
106+
pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
107+
// FIXME(eddyb) maybe name the return place as `_0` or `return`?
108+
if local == mir::RETURN_PLACE {
109+
return;
110+
}
111+
112+
let vars = match &self.per_local_var_debug_info {
113+
Some(per_local) => &per_local[local],
114+
None => return,
115+
};
116+
let whole_local_var = vars.iter().find(|var| {
117+
var.place.projection.is_empty()
118+
});
119+
let has_proj = || vars.iter().any(|var| {
120+
!var.place.projection.is_empty()
121+
});
122+
123+
let (fallback_var, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg {
124+
let arg_index = local.index() - 1;
125+
126+
// Add debuginfo even to unnamed arguments.
127+
// FIXME(eddyb) is this really needed?
128+
let var = if arg_index == 0 && has_proj() {
129+
// Hide closure environments from debuginfo.
130+
// FIXME(eddyb) shouldn't `ArgumentVariable` indices
131+
// be offset to account for the hidden environment?
132+
None
133+
} else {
134+
Some(VarDebugInfo {
135+
name: kw::Invalid,
136+
source_info: self.mir.local_decls[local].source_info,
137+
place: local.into(),
138+
})
139+
};
140+
(var, VariableKind::ArgumentVariable(arg_index + 1))
141+
} else {
142+
(None, VariableKind::LocalVariable)
143+
};
144+
145+
let local_ref = &self.locals[local];
146+
147+
if !bx.sess().fewer_names() {
148+
let name = match whole_local_var.or(fallback_var.as_ref()) {
149+
Some(var) if var.name != kw::Invalid => var.name.to_string(),
150+
_ => format!("{:?}", local),
151+
};
152+
match local_ref {
153+
LocalRef::Place(place) |
154+
LocalRef::UnsizedPlace(place) => {
155+
bx.set_var_name(place.llval, &name);
156+
}
157+
LocalRef::Operand(Some(operand)) => match operand.val {
158+
OperandValue::Ref(x, ..) |
159+
OperandValue::Immediate(x) => {
160+
bx.set_var_name(x, &name);
161+
}
162+
OperandValue::Pair(a, b) => {
163+
// FIXME(eddyb) these are scalar components,
164+
// maybe extract the high-level fields?
165+
bx.set_var_name(a, &(name.clone() + ".0"));
166+
bx.set_var_name(b, &(name + ".1"));
167+
}
168+
}
169+
LocalRef::Operand(None) => {}
170+
}
171+
}
172+
173+
if bx.sess().opts.debuginfo != DebugInfo::Full {
174+
return;
175+
}
176+
177+
let debug_context = match &self.debug_context {
178+
Some(debug_context) => debug_context,
179+
None => return,
180+
};
181+
182+
// FIXME(eddyb) add debuginfo for unsized places too.
183+
let base = match local_ref {
184+
LocalRef::Place(place) => place,
185+
_ => return,
186+
};
187+
188+
let vars = vars.iter().chain(if whole_local_var.is_none() {
189+
fallback_var.as_ref()
190+
} else {
191+
None
192+
});
193+
194+
for var in vars {
195+
let mut layout = base.layout;
196+
let mut direct_offset = Size::ZERO;
197+
// FIXME(eddyb) use smallvec here.
198+
let mut indirect_offsets = vec![];
199+
200+
let kind = if var.place.projection.is_empty() {
201+
kind
202+
} else {
203+
VariableKind::LocalVariable
204+
};
205+
206+
for elem in &var.place.projection[..] {
207+
match *elem {
208+
mir::ProjectionElem::Deref => {
209+
indirect_offsets.push(Size::ZERO);
210+
layout = bx.cx().layout_of(
211+
layout.ty.builtin_deref(true)
212+
.unwrap_or_else(|| {
213+
span_bug!(
214+
var.source_info.span,
215+
"cannot deref `{}`",
216+
layout.ty,
217+
)
218+
}).ty,
219+
);
220+
}
221+
mir::ProjectionElem::Field(field, _) => {
222+
let i = field.index();
223+
let offset = indirect_offsets.last_mut()
224+
.unwrap_or(&mut direct_offset);
225+
*offset += layout.fields.offset(i);
226+
layout = layout.field(bx.cx(), i);
227+
}
228+
mir::ProjectionElem::Downcast(_, variant) => {
229+
layout = layout.for_variant(bx.cx(), variant);
230+
}
231+
_ => span_bug!(
232+
var.source_info.span,
233+
"unsupported var debuginfo place `{:?}`",
234+
var.place,
235+
),
236+
}
237+
}
238+
239+
let (scope, span) = self.debug_loc(var.source_info);
240+
if let Some(scope) = scope {
241+
bx.declare_local(debug_context, var.name, layout.ty, scope,
242+
base.llval, direct_offset, &indirect_offsets, kind, span);
243+
}
244+
}
245+
}
246+
247+
pub fn debug_introduce_locals(&self, bx: &mut Bx) {
248+
if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
249+
for local in self.locals.indices() {
250+
self.debug_introduce_local(bx, local);
251+
}
252+
}
253+
}
254+
}
255+
256+
pub fn per_local_var_debug_info(
257+
tcx: TyCtxt<'tcx>,
258+
body: &mir::Body<'tcx>,
259+
) -> Option<IndexVec<mir::Local, Vec<VarDebugInfo<'tcx>>>> {
260+
if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
261+
let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
262+
for (local, decl) in body.local_decls.iter_enumerated() {
263+
if let Some(name) = decl.name {
264+
per_local[local].push(VarDebugInfo {
265+
name,
266+
source_info: mir::SourceInfo {
267+
span: decl.source_info.span,
268+
scope: decl.visibility_scope,
269+
},
270+
place: local.into(),
271+
});
272+
}
273+
}
274+
275+
let upvar_debuginfo = &body.__upvar_debuginfo_codegen_only_do_not_use;
276+
if !upvar_debuginfo.is_empty() {
277+
278+
let env_arg = mir::Local::new(1);
279+
let mut env_projs = vec![];
280+
281+
let pin_did = tcx.lang_items().pin_type();
282+
match body.local_decls[env_arg].ty.kind {
283+
ty::RawPtr(_) |
284+
ty::Ref(..) => {
285+
env_projs.push(mir::ProjectionElem::Deref);
286+
}
287+
ty::Adt(def, substs) if Some(def.did) == pin_did => {
288+
if let ty::Ref(..) = substs.type_at(0).kind {
289+
env_projs.push(mir::ProjectionElem::Field(
290+
mir::Field::new(0),
291+
// HACK(eddyb) field types aren't used or needed here.
292+
tcx.types.err,
293+
));
294+
env_projs.push(mir::ProjectionElem::Deref);
295+
}
296+
}
297+
_ => {}
298+
}
299+
300+
let extra_locals = {
301+
let upvars = upvar_debuginfo
302+
.iter()
303+
.enumerate()
304+
.map(|(i, upvar)| {
305+
let source_info = mir::SourceInfo {
306+
span: body.span,
307+
scope: mir::OUTERMOST_SOURCE_SCOPE,
308+
};
309+
(None, i, upvar.debug_name, upvar.by_ref, source_info)
310+
});
311+
312+
let generator_fields = body.generator_layout.as_ref().map(|generator_layout| {
313+
generator_layout.variant_fields.iter()
314+
.enumerate()
315+
.flat_map(move |(variant_idx, fields)| {
316+
let variant_idx = Some(VariantIdx::from(variant_idx));
317+
fields.iter()
318+
.enumerate()
319+
.filter_map(move |(i, field)| {
320+
let decl = &generator_layout.
321+
__local_debuginfo_codegen_only_do_not_use[*field];
322+
if let Some(name) = decl.name {
323+
let source_info = mir::SourceInfo {
324+
span: decl.source_info.span,
325+
scope: decl.visibility_scope,
326+
};
327+
Some((variant_idx, i, name, false, source_info))
328+
} else {
329+
None
330+
}
331+
})
332+
})
333+
}).into_iter().flatten();
334+
335+
upvars.chain(generator_fields)
336+
};
337+
338+
for (variant_idx, field, name, by_ref, source_info) in extra_locals {
339+
let mut projs = env_projs.clone();
340+
341+
if let Some(variant_idx) = variant_idx {
342+
projs.push(mir::ProjectionElem::Downcast(None, variant_idx));
343+
}
344+
345+
projs.push(mir::ProjectionElem::Field(
346+
mir::Field::new(field),
347+
// HACK(eddyb) field types aren't used or needed here.
348+
tcx.types.err,
349+
));
350+
351+
if by_ref {
352+
projs.push(mir::ProjectionElem::Deref);
353+
}
354+
355+
per_local[env_arg].push(VarDebugInfo {
356+
name,
357+
source_info,
358+
place: mir::Place {
359+
base: mir::PlaceBase::Local(env_arg),
360+
projection: tcx.intern_place_elems(&projs),
361+
},
362+
});
363+
}
364+
}
365+
366+
Some(per_local)
367+
} else {
368+
None
369+
}
370+
}
371+
372+
/// Debug information relatating to an user variable.
373+
// FIXME(eddyb) move this to the MIR bodies themselves.
374+
#[derive(Clone)]
375+
pub struct VarDebugInfo<'tcx> {
376+
pub name: Symbol,
377+
378+
/// Source info of the user variable, including the scope
379+
/// within which the variable is visible (to debuginfo)
380+
/// (see `LocalDecl`'s `source_info` field for more details).
381+
pub source_info: mir::SourceInfo,
382+
383+
/// Where the data for this user variable is to be found.
384+
pub place: mir::Place<'tcx>,
385+
}

‎src/librustc_codegen_ssa/mir/mod.rs

Lines changed: 31 additions & 324 deletions
Large diffs are not rendered by default.

‎src/librustc_codegen_ssa/mir/place.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
6868
}
6969
}
7070

71+
// FIXME(eddyb) pass something else for the name so no work is done
72+
// unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
7173
pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
7274
bx: &mut Bx,
7375
layout: TyLayout<'tcx>,
@@ -78,6 +80,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
7880
}
7981

8082
/// Returns a place for an indirect reference to an unsized place.
83+
// FIXME(eddyb) pass something else for the name so no work is done
84+
// unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
8185
pub fn alloca_unsized_indirect<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
8286
bx: &mut Bx,
8387
layout: TyLayout<'tcx>,

‎src/librustc_codegen_ssa/mir/statement.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2727
}
2828
LocalRef::Operand(None) => {
2929
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
30-
if let Some(name) = self.mir.local_decls[index].name {
31-
match operand.val {
32-
OperandValue::Ref(x, ..) |
33-
OperandValue::Immediate(x) => {
34-
bx.set_var_name(x, name);
35-
}
36-
OperandValue::Pair(a, b) => {
37-
// FIXME(eddyb) these are scalar components,
38-
// maybe extract the high-level fields?
39-
bx.set_var_name(a, format_args!("{}.0", name));
40-
bx.set_var_name(b, format_args!("{}.1", name));
41-
}
42-
}
43-
}
4430
self.locals[index] = LocalRef::Operand(Some(operand));
31+
self.debug_introduce_local(&mut bx, index);
4532
bx
4633
}
4734
LocalRef::Operand(Some(op)) => {
Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use super::BackendTypes;
2-
use crate::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind};
2+
use crate::mir::debuginfo::{FunctionDebugContext, VariableKind};
33
use rustc::hir::def_id::CrateNum;
44
use rustc::mir;
55
use rustc::ty::{self, Ty, Instance};
6-
use rustc_index::vec::IndexVec;
6+
use rustc::ty::layout::Size;
77
use syntax::ast::Name;
88
use syntax_pos::{SourceFile, Span};
99

@@ -13,30 +13,22 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
1313
/// Creates the function-specific debug context.
1414
///
1515
/// Returns the FunctionDebugContext for the function which holds state needed
16-
/// for debug info creation. The function may also return another variant of the
17-
/// FunctionDebugContext enum which indicates why no debuginfo should be created
18-
/// for the function.
16+
/// for debug info creation, if it is enabled.
1917
fn create_function_debug_context(
2018
&self,
2119
instance: Instance<'tcx>,
2220
sig: ty::FnSig<'tcx>,
2321
llfn: Self::Function,
2422
mir: &mir::Body<'_>,
25-
) -> FunctionDebugContext<Self::DIScope>;
23+
) -> Option<FunctionDebugContext<Self::DIScope>>;
2624

27-
fn create_mir_scopes(
28-
&self,
29-
mir: &mir::Body<'_>,
30-
debug_context: &mut FunctionDebugContext<Self::DIScope>,
31-
) -> IndexVec<mir::SourceScope, MirDebugScope<Self::DIScope>>;
3225
fn extend_scope_to_file(
3326
&self,
3427
scope_metadata: Self::DIScope,
3528
file: &SourceFile,
3629
defining_crate: CrateNum,
3730
) -> Self::DIScope;
3831
fn debuginfo_finalize(&self);
39-
fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4];
4032
}
4133

4234
pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes {
@@ -46,16 +38,19 @@ pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes {
4638
variable_name: Name,
4739
variable_type: Ty<'tcx>,
4840
scope_metadata: Self::DIScope,
49-
variable_access: VariableAccess<'_, Self::Value>,
41+
variable_alloca: Self::Value,
42+
direct_offset: Size,
43+
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
44+
indirect_offsets: &[Size],
5045
variable_kind: VariableKind,
5146
span: Span,
5247
);
5348
fn set_source_location(
5449
&mut self,
5550
debug_context: &mut FunctionDebugContext<Self::DIScope>,
56-
scope: Option<Self::DIScope>,
51+
scope: Self::DIScope,
5752
span: Span,
5853
);
5954
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
60-
fn set_var_name(&mut self, value: Self::Value, name: impl ToString);
55+
fn set_var_name(&mut self, value: Self::Value, name: &str);
6156
}

‎src/test/codegen/optimize-attr-1.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// CHECK-LABEL: define i32 @nothing
1010
// CHECK-SAME: [[NOTHING_ATTRS:#[0-9]+]]
11-
// NO-OPT: ret i32 %1
11+
// NO-OPT: ret i32 %_1.0
1212
// SIZE-OPT: ret i32 4
1313
// SPEEC-OPT: ret i32 4
1414
#[no_mangle]
@@ -18,7 +18,7 @@ pub fn nothing() -> i32 {
1818

1919
// CHECK-LABEL: define i32 @size
2020
// CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]]
21-
// NO-OPT: ret i32 %1
21+
// NO-OPT: ret i32 %_1.0
2222
// SIZE-OPT: ret i32 6
2323
// SPEED-OPT: ret i32 6
2424
#[optimize(size)]
@@ -31,7 +31,7 @@ pub fn size() -> i32 {
3131
// NO-OPT-SAME: [[NOTHING_ATTRS]]
3232
// SPEED-OPT-SAME: [[NOTHING_ATTRS]]
3333
// SIZE-OPT-SAME: [[SPEED_ATTRS:#[0-9]+]]
34-
// NO-OPT: ret i32 %1
34+
// NO-OPT: ret i32 %_1.0
3535
// SIZE-OPT: ret i32 8
3636
// SPEED-OPT: ret i32 8
3737
#[optimize(speed)]

‎src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs

Lines changed: 87 additions & 80 deletions
Large diffs are not rendered by default.

‎src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ extern "platform-intrinsic" {
2626
fn simd_bitmask<T, U>(x: T) -> U;
2727
}
2828

29+
// NOTE(eddyb) `%{{x|_2}}` is used because on some targets (e.g. WASM)
30+
// SIMD vectors are passed directly, resulting in `%x` being a vector,
31+
// while on others they're passed indirectly, resulting in `%x` being
32+
// a pointer to a vector, and `%_2` a vector loaded from that pointer.
33+
// This is controlled by the target spec option `simd_types_indirect`.
34+
2935
// CHECK-LABEL: @bitmask_int
3036
#[no_mangle]
3137
pub unsafe fn bitmask_int(x: i32x2) -> u8 {
32-
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
38+
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, <i32 31, i32 31>
3339
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
3440
// CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
3541
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@@ -39,7 +45,7 @@ pub unsafe fn bitmask_int(x: i32x2) -> u8 {
3945
// CHECK-LABEL: @bitmask_uint
4046
#[no_mangle]
4147
pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
42-
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
48+
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, <i32 31, i32 31>
4349
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
4450
// CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
4551
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@@ -49,7 +55,7 @@ pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
4955
// CHECK-LABEL: @bitmask_int16
5056
#[no_mangle]
5157
pub unsafe fn bitmask_int16(x: i8x16) -> u16 {
52-
// CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9a-z]+}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
58+
// CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|_2}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
5359
// CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
5460
// CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
5561
// CHECK-NOT: zext

0 commit comments

Comments
 (0)
Please sign in to comment.