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
This commit is contained in:
commit
01e5d91482
14 changed files with 654 additions and 652 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, FunctionDebugContextData, MirDebugScope};
|
||||
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<SourceScope, MirDebugScope<&'ll DIScope>> {
|
||||
let null_scope = MirDebugScope {
|
||||
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<SourceScope>,
|
||||
debug_context: &FunctionDebugContextData<&'ll DISubprogram>,
|
||||
scope: SourceScope,
|
||||
scopes: &mut IndexVec<SourceScope, MirDebugScope<&'ll DIScope>>) {
|
||||
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] = MirDebugScope {
|
||||
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] = MirDebugScope {
|
||||
debug_context.scopes[scope] = DebugScope {
|
||||
scope_metadata,
|
||||
file_start_pos: loc.file.start_pos,
|
||||
file_end_pos: loc.file.end_pos,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
// 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::VariableKind::*;
|
||||
|
||||
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
|
||||
use self::namespace::mangled_name_of_instance;
|
||||
|
|
@ -11,7 +10,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};
|
||||
|
|
@ -27,17 +26,19 @@ 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,
|
||||
VariableKind};
|
||||
|
||||
use libc::c_uint;
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use syntax_pos::{self, Span, Pos};
|
||||
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;
|
||||
|
|
@ -47,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;
|
||||
|
|
@ -148,21 +149,23 @@ 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,
|
||||
variable_access: VariableAccess<'_, &'ll Value>,
|
||||
variable_alloca: Self::Value,
|
||||
direct_offset: Size,
|
||||
indirect_offsets: &[Size],
|
||||
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);
|
||||
|
|
@ -173,49 +176,61 @@ 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());
|
||||
// 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();
|
||||
|
||||
llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
|
||||
}
|
||||
source_loc::set_debug_location(self, UnknownLocation);
|
||||
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(
|
||||
&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)
|
||||
|
|
@ -224,7 +239,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;
|
||||
|
|
@ -254,7 +269,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());
|
||||
}
|
||||
|
|
@ -268,14 +283,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
sig: ty::FnSig<'tcx>,
|
||||
llfn: &'ll Value,
|
||||
mir: &mir::Body<'_>,
|
||||
) -> FunctionDebugContext<&'ll DISubprogram> {
|
||||
) -> Option<FunctionDebugContext<&'ll DIScope>> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +299,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();
|
||||
|
|
@ -357,14 +372,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>,
|
||||
|
|
@ -549,14 +573,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<mir::SourceScope, MirDebugScope<&'ll DIScope>> {
|
||||
create_scope_map::create_mir_scopes(self, mir, debug_context)
|
||||
}
|
||||
|
||||
fn extend_scope_to_file(
|
||||
&self,
|
||||
scope_metadata: &'ll DIScope,
|
||||
|
|
@ -569,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()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -18,22 +18,13 @@ use syntax_pos::{Span, Pos};
|
|||
pub fn set_source_location<D>(
|
||||
debug_context: &FunctionDebugContext<D>,
|
||||
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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<D> {
|
||||
RegularContext(FunctionDebugContextData<D>),
|
||||
DebugInfoDisabled,
|
||||
FunctionWithoutDebugInfo,
|
||||
}
|
||||
|
||||
impl<D> FunctionDebugContext<D> {
|
||||
pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData<D> {
|
||||
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<D>(dbg_context: &mut FunctionDebugContext<D>) {
|
||||
match *dbg_context {
|
||||
FunctionDebugContext::RegularContext(ref mut data) => {
|
||||
data.source_locations_enabled = true;
|
||||
},
|
||||
_ => { /* safe to ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionDebugContextData<D> {
|
||||
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<D> {
|
||||
pub scope_metadata: Option<D>,
|
||||
// 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<D> MirDebugScope<D> {
|
||||
pub fn is_valid(&self) -> bool {
|
||||
!self.scope_metadata.is_none()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
385
src/librustc_codegen_ssa/mir/debuginfo.rs
Normal file
385
src/librustc_codegen_ssa/mir/debuginfo.rs
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc::hir::def_id::CrateNum;
|
||||
use rustc::mir;
|
||||
use rustc::session::config::DebugInfo;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::layout::{LayoutOf, Size, VariantIdx};
|
||||
use crate::traits::*;
|
||||
|
||||
use syntax_pos::{BytePos, Span, Symbol};
|
||||
use syntax::symbol::kw;
|
||||
|
||||
use super::{FunctionCx, LocalRef};
|
||||
use super::OperandValue;
|
||||
|
||||
pub struct FunctionDebugContext<D> {
|
||||
pub scopes: IndexVec<mir::SourceScope, DebugScope<D>>,
|
||||
pub source_locations_enabled: bool,
|
||||
pub defining_crate: CrateNum,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum VariableKind {
|
||||
ArgumentVariable(usize /*index*/),
|
||||
LocalVariable,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct DebugScope<D> {
|
||||
pub scope_metadata: Option<D>,
|
||||
// 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<D> DebugScope<D> {
|
||||
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);
|
||||
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<Bx::DIScope>, Span) {
|
||||
// Bail out if debug info emission is not enabled.
|
||||
match self.debug_context {
|
||||
None => return (None, source_info.span),
|
||||
Some(_) => {}
|
||||
}
|
||||
|
||||
// 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<Bx::DIScope> {
|
||||
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 = debug_context.defining_crate;
|
||||
Some(self.cx.extend_scope_to_file(
|
||||
scope_metadata.unwrap(),
|
||||
&sm.lookup_char_pos(pos).file,
|
||||
defining_crate
|
||||
))
|
||||
} else {
|
||||
scope_metadata
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
// FIXME(eddyb) maybe name the return place as `_0` or `return`?
|
||||
if local == mir::RETURN_PLACE {
|
||||
return;
|
||||
}
|
||||
|
||||
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 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(VarDebugInfo {
|
||||
name: kw::Invalid,
|
||||
source_info: self.mir.local_decls[local].source_info,
|
||||
place: local.into(),
|
||||
})
|
||||
};
|
||||
(var, VariableKind::ArgumentVariable(arg_index + 1))
|
||||
} else {
|
||||
(None, VariableKind::LocalVariable)
|
||||
};
|
||||
|
||||
let local_ref = &self.locals[local];
|
||||
|
||||
if !bx.sess().fewer_names() {
|
||||
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 {
|
||||
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, &(name.clone() + ".0"));
|
||||
bx.set_var_name(b, &(name + ".1"));
|
||||
}
|
||||
}
|
||||
LocalRef::Operand(None) => {}
|
||||
}
|
||||
}
|
||||
|
||||
if bx.sess().opts.debuginfo != DebugInfo::Full {
|
||||
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
|
||||
});
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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, var.name, layout.ty, scope,
|
||||
base.llval, direct_offset, &indirect_offsets, kind, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug_introduce_locals(&self, bx: &mut Bx) {
|
||||
if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
|
||||
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<IndexVec<mir::Local, Vec<VarDebugInfo<'tcx>>>> {
|
||||
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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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 => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let extra_locals = {
|
||||
let upvars = upvar_debuginfo
|
||||
.iter()
|
||||
.enumerate()
|
||||
.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 = body.generator_layout.as_ref().map(|generator_layout| {
|
||||
generator_layout.variant_fields.iter()
|
||||
.enumerate()
|
||||
.flat_map(move |(variant_idx, fields)| {
|
||||
let variant_idx = Some(VariantIdx::from(variant_idx));
|
||||
fields.iter()
|
||||
.enumerate()
|
||||
.filter_map(move |(i, field)| {
|
||||
let decl = &generator_layout.
|
||||
__local_debuginfo_codegen_only_do_not_use[*field];
|
||||
if let Some(name) = decl.name {
|
||||
let source_info = mir::SourceInfo {
|
||||
span: decl.source_info.span,
|
||||
scope: decl.visibility_scope,
|
||||
};
|
||||
Some((variant_idx, i, name, false, source_info))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
}).into_iter().flatten();
|
||||
|
||||
upvars.chain(generator_fields)
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
projs.push(mir::ProjectionElem::Field(
|
||||
mir::Field::new(field),
|
||||
// HACK(eddyb) field types aren't used or needed here.
|
||||
tcx.types.err,
|
||||
));
|
||||
|
||||
if by_ref {
|
||||
projs.push(mir::ProjectionElem::Deref);
|
||||
}
|
||||
|
||||
per_local[env_arg].push(VarDebugInfo {
|
||||
name,
|
||||
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>,
|
||||
}
|
||||
|
|
@ -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::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext};
|
||||
use crate::traits::*;
|
||||
|
||||
use syntax_pos::{DUMMY_SP, BytePos, Span};
|
||||
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::FunctionDebugContext;
|
||||
use self::place::PlaceRef;
|
||||
use rustc::mir::traversal;
|
||||
|
||||
|
|
@ -28,7 +23,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
|||
|
||||
mir: &'a mir::Body<'tcx>,
|
||||
|
||||
debug_context: FunctionDebugContext<Bx::DIScope>,
|
||||
debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
|
||||
|
||||
llfn: Bx::Function,
|
||||
|
||||
|
|
@ -79,8 +74,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
|||
/// notably `expect`.
|
||||
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
|
||||
|
||||
/// Debug information for MIR scopes.
|
||||
scopes: IndexVec<mir::SourceScope, debuginfo::MirDebugScope<Bx::DIScope>>,
|
||||
per_local_var_debug_info: Option<IndexVec<mir::Local, Vec<debuginfo::VarDebugInfo<'tcx>>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
|
|
@ -93,64 +87,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<Bx::DIScope>, 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<Bx::DIScope> {
|
||||
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> {
|
||||
|
|
@ -192,8 +128,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) {
|
||||
|
|
@ -215,8 +153,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 {
|
||||
|
|
@ -231,9 +167,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
cleanup_kinds,
|
||||
landing_pads,
|
||||
funclets,
|
||||
scopes,
|
||||
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);
|
||||
|
|
@ -247,62 +183,22 @@ 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);
|
||||
}
|
||||
|
||||
debug!("alloc: {:?} ({}) -> place", local, name);
|
||||
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, name);
|
||||
// FIXME: add an appropriate debuginfo
|
||||
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);
|
||||
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)
|
||||
LocalRef::Place(PlaceRef::alloca(&mut bx, layout))
|
||||
}
|
||||
} 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);
|
||||
LocalRef::new_operand(&mut bx, layout)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -313,6 +209,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
.collect()
|
||||
};
|
||||
|
||||
// Apply debuginfo to the newly allocated locals.
|
||||
fx.debug_introduce_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]);
|
||||
|
|
@ -321,7 +220,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());
|
||||
|
|
@ -421,28 +322,12 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
memory_locals: &BitSet<mir::Local>,
|
||||
) -> Vec<LocalRef<'tcx, Bx::Value>> {
|
||||
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];
|
||||
|
||||
// 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
|
||||
|
|
@ -456,7 +341,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;
|
||||
|
|
@ -467,22 +351,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);
|
||||
}
|
||||
|
||||
|
|
@ -490,24 +358,8 @@ 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -517,7 +369,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.
|
||||
|
|
@ -528,7 +380,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));
|
||||
|
|
@ -537,11 +388,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
|
||||
|
|
@ -551,14 +397,13 @@ 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.
|
||||
|
|
@ -569,151 +414,12 @@ 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);
|
||||
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()
|
||||
}
|
||||
|
|
@ -721,6 +427,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;
|
||||
|
|
|
|||
|
|
@ -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: BuilderMethods<'a, 'tcx, Value = V>>(
|
||||
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: BuilderMethods<'a, 'tcx, Value = V>>(
|
||||
bx: &mut Bx,
|
||||
layout: TyLayout<'tcx>,
|
||||
|
|
|
|||
|
|
@ -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)) => {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use super::BackendTypes;
|
||||
use crate::debuginfo::{FunctionDebugContext, MirDebugScope, 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_index::vec::IndexVec;
|
||||
use rustc::ty::layout::Size;
|
||||
use syntax::ast::Name;
|
||||
use syntax_pos::{SourceFile, Span};
|
||||
|
||||
|
|
@ -13,22 +13,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<Self::DIScope>;
|
||||
) -> Option<FunctionDebugContext<Self::DIScope>>;
|
||||
|
||||
fn create_mir_scopes(
|
||||
&self,
|
||||
mir: &mir::Body<'_>,
|
||||
debug_context: &mut FunctionDebugContext<Self::DIScope>,
|
||||
) -> IndexVec<mir::SourceScope, MirDebugScope<Self::DIScope>>;
|
||||
fn extend_scope_to_file(
|
||||
&self,
|
||||
scope_metadata: Self::DIScope,
|
||||
|
|
@ -36,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 {
|
||||
|
|
@ -46,16 +38,19 @@ 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,
|
||||
);
|
||||
fn set_source_location(
|
||||
&mut self,
|
||||
debug_context: &mut FunctionDebugContext<Self::DIScope>,
|
||||
scope: Option<Self::DIScope>,
|
||||
scope: Self::DIScope,
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -116,143 +116,150 @@ extern "platform-intrinsic" {
|
|||
fn simd_saturating_sub<T>(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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,16 @@ extern "platform-intrinsic" {
|
|||
fn simd_bitmask<T, U>(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]+}}, <i32 31, i32 31>
|
||||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, <i32 31, i32 31>
|
||||
// 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]+}}, <i32 31, i32 31>
|
||||
// CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, <i32 31, i32 31>
|
||||
// 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]+}}, <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>
|
||||
// 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>
|
||||
// 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue