From dc2fc34bedb9218aae1044d53d4eb60e87439157 Mon Sep 17 00:00:00 2001 From: Jan Civlin <30603832+jcivlin@users.noreply.github.com> Date: Mon, 4 Mar 2024 10:21:54 -0800 Subject: [PATCH] Dwarf: debug_info for call instruction and tracing locals (#415) --- .../move-to-solana/src/stackless/dwarf.rs | 761 +++++++++++++----- .../src/stackless/entrypoint.rs | 1 - .../move-to-solana/src/stackless/llvm.rs | 104 ++- .../src/stackless/module_context.rs | 2 +- .../move-to-solana/src/stackless/rttydesc.rs | 4 +- .../move-to-solana/src/stackless/translate.rs | 43 +- .../tools/move-mv-llvm-compiler/src/main.rs | 3 +- .../0x1__signer.ll.debug_info.expected | 46 +- .../0xcafe__BasicCoin.ll.debug_info.expected | 6 +- .../0x101__M.ll.debug_info.expected | 162 +++- .../0x201__M.ll.debug_info.expected | 132 ++- .../0x101__M.ll.debug_info.expected | 131 ++- .../0x201__M.ll.debug_info.expected | 108 ++- .../0x100__M.ll.debug_info.expected | 131 ++- .../0x101__vector.ll.debug_info.expected | 266 +++++- 15 files changed, 1438 insertions(+), 462 deletions(-) diff --git a/language/solana/move-to-solana/src/stackless/dwarf.rs b/language/solana/move-to-solana/src/stackless/dwarf.rs index 275ddc8e2e..7dca03f87e 100644 --- a/language/solana/move-to-solana/src/stackless/dwarf.rs +++ b/language/solana/move-to-solana/src/stackless/dwarf.rs @@ -5,26 +5,30 @@ //! Dwarf routines. //! -use crate::stackless::{extensions::FunctionEnvExt, llvm::Module, FunctionContext, TargetData}; +use crate::stackless::{ + extensions::FunctionEnvExt, llvm::Module, Alloca, FunctionContext, ModuleContext, TargetData, +}; use anyhow::{Context, Result}; use codespan::Location; use itertools::enumerate; use llvm_sys::{ core::*, debuginfo::{ - LLVMCreateDIBuilder, LLVMDIBuilderCreateBasicType, LLVMDIBuilderCreateCompileUnit, - LLVMDIBuilderCreateFile, LLVMDIBuilderCreateFunction, LLVMDIBuilderCreateLexicalBlock, - LLVMDIBuilderCreateMemberType, LLVMDIBuilderCreateModule, LLVMDIBuilderCreateNameSpace, - LLVMDIBuilderCreateParameterVariable, LLVMDIBuilderCreatePointerType, + LLVMCreateDIBuilder, LLVMDIBuilderCreateAutoVariable, LLVMDIBuilderCreateBasicType, + LLVMDIBuilderCreateCompileUnit, LLVMDIBuilderCreateDebugLocation, + LLVMDIBuilderCreateExpression, LLVMDIBuilderCreateFile, LLVMDIBuilderCreateFunction, + LLVMDIBuilderCreateLexicalBlock, LLVMDIBuilderCreateMemberType, + LLVMDIBuilderCreateNameSpace, LLVMDIBuilderCreatePointerType, LLVMDIBuilderCreateStructType, LLVMDIBuilderCreateSubroutineType, LLVMDIBuilderCreateUnspecifiedType, LLVMDIBuilderCreateVectorType, LLVMDIBuilderFinalize, - LLVMDIBuilderGetOrCreateSubrange, LLVMDIFlagObjcClassComplete, LLVMDIFlagZero, LLVMDIFlags, + LLVMDIBuilderFinalizeSubprogram, LLVMDIBuilderGetOrCreateSubrange, + LLVMDIBuilderInsertDeclareAtEnd, LLVMDIFlagObjcClassComplete, LLVMDIFlagZero, LLVMDIFlags, LLVMDITypeGetName, LLVMDWARFEmissionKind, LLVMDWARFSourceLanguage::LLVMDWARFSourceLanguageRust, LLVMDWARFTypeEncoding, - LLVMGetMetadataKind, LLVMMetadataKind, + LLVMGetMetadataKind, LLVMInstructionSetDebugLoc, LLVMMetadataKind, LLVMSetSubprogram, }, prelude::*, - LLVMValue, + LLVMModule, LLVMOpaqueMetadata, LLVMValue, }; use log::{debug, error, warn}; @@ -44,6 +48,36 @@ use super::{GlobalContext, StructType, Type}; use move_model::ty as mty; +macro_rules! to_cstring { + ($x:expr) => {{ + let cstr = match std::ffi::CString::new($x) { + Ok(cstr) => cstr, + Err(_) => std::ffi::CString::new("unknown").expect("Failed to create CString"), + }; + cstr + }}; +} + +// macro reserved for debugging +macro_rules! _add_meta_operand { + ($ll_mod:expr, $ll_ctx:expr, $md:expr) => { + let md_name = stringify!($md).to_owned() + "_info"; + let name = format!("{}", md_name); + let name_cstr = to_cstring!(name.to_string().as_str()); + let (nm_ptr, _nm_len) = (name_cstr.as_ptr(), name_cstr.as_bytes().len()); + let md_as_ll_val = LLVMMetadataAsValue($ll_ctx, $md); + LLVMAddNamedMetadataOperand($ll_mod, nm_ptr, md_as_ll_val); + }; +} +macro_rules! dbg_meta_operand { + ($ll_mod:expr, $ll_ctx:expr, $md:expr, $dbg_name:expr, $func_name: expr) => { + let md_name = stringify!($md).to_owned() + "_info"; + let md_as_ll_val = LLVMMetadataAsValue($ll_ctx, $md); + let md_info = print_to_str(md_as_ll_val); + debug!(target: $dbg_name, "{} {} starting at next line and until line starting with !!!\n{md_info}\n!!!\n", $func_name, md_name); + }; +} + // Similar to llvm::Context, lives in GlobalContext, used for keeping persistent objects pub struct DIContext { // Used for resolving types in nested structs @@ -69,16 +103,16 @@ impl DIContext { // Main structure used for dwarf generation, one per Module. // Use DIBuilder for public api. #[derive(Clone)] -struct DIBuilderCore<'up> { +pub struct DIBuilderCore<'up> { g_ctx: &'up GlobalContext<'up>, module_di: LLVMModuleRef, // ref to the new module created here for DI purpose builder_ref: LLVMDIBuilderRef, // fields below reserved for future usage builder_file: LLVMMetadataRef, compiled_unit: LLVMMetadataRef, - compiled_module: LLVMMetadataRef, - module_ref: LLVMModuleRef, // ref to existed "Builder" Module, which was used in 'new' + producer: String, module_source: String, + current_function: RefCell<*mut LLVMOpaqueMetadata>, // basic types type_unspecified: LLVMMetadataRef, type_u8: LLVMMetadataRef, @@ -101,15 +135,43 @@ pub enum UnresolvedPrintLogLevel { struct Instruction<'up> { bc: &'up Bytecode, func_ctx: &'up FunctionContext<'up, 'up>, + // NOTE: no need to keep here di_builder: &'up DIBuilder<'up>, since it is in func_ctx.m_ctx loc: move_model::model::Loc, } // Public interface to Instruction, must be used in each particular call, like for example create_load_store -pub struct PublicInstruction<'a>(Instruction<'a>); +pub struct PublicInstruction<'a>(Option>); impl<'up> PublicInstruction<'up> { pub fn debug(&self) { - self.0.debug(); + if let Some(instruction) = &self.0 { + instruction.debug(); + } + } + + pub fn create_load_store( + &self, + load: *mut LLVMValue, + store: *mut LLVMValue, + mty: &mty::Type, + ty: Type, + src: Alloca, + dst: Alloca, + ) { + if let Some(instruction) = &self.0 { + instruction.create_load_store(load, store, mty, ty, src, dst); + } + } + + pub fn create_call(&self, call_instr: *mut LLVMValue) { + if let Some(instruction) = &self.0 { + instruction.create_call(call_instr); + } + } + + pub fn none() -> PublicInstruction<'up> { + let none = PublicInstruction(None); + none } } @@ -132,15 +194,187 @@ impl<'up> Instruction<'up> { .unwrap_or("String not found".to_string()); debug!(target: "bytecode", "file {:#?}[{start}-{end}]:{start_line}.{start_column}-{end_line}.{end_column} {substring}", file); } + + // returns text in source code associated with this instruction + fn source(&self) -> String { + let bc = self.bc; + let loc = &self.loc; + let (file, _line, _column, start, end) = self.loc_display(); + debug!(target: "bytecode", "{:#?} loc {:#?}", bc, loc); + read_substring(&file, start as usize, end as usize).unwrap_or("".to_string()) + } + fn loc_display(&self) -> (String, u32, u32, u32, u32) { let g_env = self.func_ctx.module_cx.env.env; let loc = &self.loc; loc_display(loc, g_env) } - fn create_load_store(&self, _load: *mut LLVMValue, _store: *mut LLVMValue, mty: &mty::Type) { - let bc = self.bc; - let loc = &self.loc; - debug!(target: "bytecode", "create_load_store {:#?} loc {:#?} mty {:#?}", bc, loc, mty); + + fn create_load_store( + &self, + load: *mut LLVMValue, + store: *mut LLVMValue, + mty: &mty::Type, + ty: Type, + src: Alloca, + dst: Alloca, + ) { + let source = self.source(); + debug!(target: "instruction", "create_load_store {source}"); + + // a simple reminder how to get debug_info + let _bc = self.bc; + let _loc = &self.loc; + let (_file, _line, _column, _start, _end) = self.loc_display(); + + self.create_instr_with_local(load, mty, ty, src); + self.create_instr_with_local(store, mty, ty, dst); + } + + fn create_call(&self, call_instr: *mut LLVMValue) { + let source = self.source(); + debug!(target: "instruction", "create_call {source}"); + self.create_naked_instr(call_instr); + } + + fn create_naked_instr(&self, instr: *mut LLVMValue) { + self.create_instr_impl(instr, None); + } + + fn create_instr_with_local( + &self, + instr: *mut LLVMValue, + mty: &mty::Type, + ty: Type, + alloca: Alloca, + ) { + self.create_instr_impl(instr, Some((mty, ty, alloca))); + } + + // Note: This function needs ty: *mut LLVMOpaqueMetadata, we calculate it from &mty::Type. + // Type is reserved and not used now. + fn create_instr_impl(&self, instr: *mut LLVMValue, more: Option<(&mty::Type, Type, Alloca)>) { + let _bc = self.bc; + let _loc = &self.loc; + let (file, line, column, _start, _end) = self.loc_display(); + let source = self.source(); + + let instr_info = print_to_str(instr); + debug!(target: "instruction", "create_instr_impl instruction info starting at next line and until line starting with !!!\n{instr_info}\n!!!\n"); + + unsafe { + let module_cx = self.func_ctx.module_cx; + let di_builder = &module_cx.llvm_di_builder; + let _core = di_builder.core(); + let ll_ctx = module_cx.llvm_cx.0; + let module_ref = module_cx.llvm_module; + let ll_mod = module_ref.0; + assert!( + ll_mod == di_builder.module_di().unwrap(), + "LLVM modules must be the same" + ); + let module_info = module_ref.print_to_str(); + debug!(target: "instruction", "create_instr_impl Module starting at next line and until line starting with !!!\n{module_info}\n!!!\n"); + + assert!( + ll_ctx == LLVMGetModuleContext(module_ref.0), + "Modules must be the same" + ); + + let _file_name = std::ffi::CString::new(file.clone()).unwrap(); + let _dir_name = std::ffi::CString::new("".to_string()).unwrap(); + + let builder_ref = di_builder.builder_ref().unwrap(); + let di_builder_file = di_builder.builder_file().unwrap(); + + let name = format!("load_store_{file}_{line}_{source}"); + let name_cstr = to_cstring!(name.to_string().as_str()); + let (nm_ptr, nm_len) = (name_cstr.as_ptr(), name_cstr.as_bytes().len()); + + let basic_block: *mut llvm_sys::LLVMBasicBlock = LLVMGetInstructionParent(instr); + let bb_info = print_bb_to_str(basic_block); + debug!(target: "instruction", "create_instr_impl basic block starting at next line and until line starting with !!!\n{bb_info}\n!!!\n"); + + let parent_function = LLVMGetBasicBlockParent(basic_block); + + let function_module = LLVMGetGlobalParent(parent_function); + let module_context = LLVMGetModuleContext(function_module); + assert!(ll_ctx == module_context, "Modules are different"); + + assert!( + ll_mod == di_builder.module_di().unwrap(), + "LLVM modules must be the same" + ); + + let current_function = *di_builder.core().current_function.borrow_mut(); + + let debug_location = LLVMDIBuilderCreateDebugLocation( + module_context, + line, + column, + current_function, + std::ptr::null_mut(), // Inlined at + ); + dbg_meta_operand!( + ll_mod, + ll_ctx, + debug_location, + "instruction", + "create_instr_impl" + ); + + LLVMInstructionSetDebugLoc(instr, debug_location); + + if let Some((mty, _ty, alloca)) = more { + let lexical_block = LLVMDIBuilderCreateLexicalBlock( + builder_ref, + current_function, + di_builder_file, + line, + column, + ); + dbg_meta_operand!( + ll_mod, + ll_ctx, + lexical_block, + "instruction", + "create_instr_impl" + ); + + let ty: *mut llvm_sys::LLVMOpaqueMetadata = di_builder.get_type(mty.clone(), &name); + + let loc = LLVMDIBuilderCreateAutoVariable( + builder_ref, + lexical_block, /* scope */ + nm_ptr, + nm_len, + di_builder_file, + line, + ty, + 0, + 0, + 0, + ); + + // TODO: empty expression. It is used by dbg for accessing local and may need to be better than empty. + let expression = + LLVMDIBuilderCreateExpression(builder_ref, std::ptr::null_mut(), 0); + + // NOTE: code below inserts llvm.dbg.declare after instruction, but it is not needed for a call instruction + let instr_debug = LLVMDIBuilderInsertDeclareAtEnd( + builder_ref, + alloca.get0(), // local variable we trace in dbg + loc, + expression, // may be std::ptr::null_mut(), + debug_location, + basic_block, + ); + debug!(target: "instruction", "create_instr_impl instr_debug starting at next line and until line starting with !!!\n{:#?}\n!!!\n", instr_debug); + } + + let module_info = module_ref.print_to_str(); + debug!(target: "instruction", "\ncreate_instr_with_options eof Module starting at next line and until line starting with !!!\n{module_info}\n!!!\n"); + }; } } @@ -220,16 +454,6 @@ impl<'up> DIBuilderCore<'up> { #[derive(Clone)] pub struct DIBuilder<'up>(Option>); -macro_rules! to_cstring { - ($x:expr) => {{ - let cstr = match std::ffi::CString::new($x) { - Ok(cstr) => cstr, - Err(_) => std::ffi::CString::new("unknown").expect("Failed to create CString"), - }; - cstr - }}; -} - pub fn from_raw_slice_to_string(raw_ptr: *const i8, raw_len: ::libc::size_t) -> String { let byte_slice: &[i8] = unsafe { std::slice::from_raw_parts(raw_ptr, raw_len) }; let byte_slice: &[u8] = @@ -250,23 +474,30 @@ fn relative_to_absolute(relative_path: &str) -> std::io::Result { impl<'up> DIBuilder<'up> { pub fn new( g_ctx: &'up GlobalContext, - module: &mut Module, + module: &Module, source: &str, debug: bool, ) -> DIBuilder<'up> { if debug { + let llmod = module.0; let module_ref_name = module.get_module_id(); - let module_ref = module.as_mut(); - // create new module - let module_name = module_ref_name + ".dbg_info"; + // do not create a new module, rather use existing compilation module + let module_name = module_ref_name; let cstr = to_cstring!(module_name.as_str()); - let (mut mod_nm_ptr, mut mod_nm_len) = (cstr.as_ptr(), cstr.as_bytes().len()); - let module_di = - unsafe { LLVMModuleCreateWithName(mod_nm_ptr as *const ::libc::c_char) }; + let (mut _mod_nm_ptr, mut mod_nm_len) = (cstr.as_ptr(), cstr.as_bytes().len()); + + // We do not create own module for debug and instead produce debug info in the existing compilation module. + // Notice that it is possible to use a separate debug module, but then adding locations for locals become a problem, + // since this by llvm debug technology requires adding nodes in the compilation unit. + // + let module_di: *mut LLVMModule = llmod; + + let module_di_info = print_module_to_str(&module_di); + debug!(target: "dwarf", "DIBuilder bof DI starting at next line and until line starting with !!!\n{module_di_info}\n!!!\n"); // check dbg module name - mod_nm_ptr = unsafe { LLVMGetModuleIdentifier(module_di, &mut mod_nm_len) }; + let mod_nm_ptr = unsafe { LLVMGetModuleIdentifier(module_di, &mut mod_nm_len) }; let module_di_name = &from_raw_slice_to_string(mod_nm_ptr, mod_nm_len); debug!(target: "dwarf", "Created dbg module {:#?}", module_di_name); @@ -303,75 +534,10 @@ impl<'up> DIBuilder<'up> { let (mod_nm_ptr, mod_nm_len, dir_ptr, dir_len) = (filename_ptr, filename_len, dir_ptr, dir_len); - let builder_file = unsafe { + let builder_file: *mut LLVMOpaqueMetadata = unsafe { LLVMDIBuilderCreateFile(builder_ref, mod_nm_ptr, mod_nm_len, dir_ptr, dir_len) }; - // create compile unit - let producer = "move-mv-llvm-compiler".to_string(); - let cstr = to_cstring!(producer); - let (producer_ptr, producer_len) = (cstr.as_ptr(), cstr.as_bytes().len()); - - let flags = "".to_string(); - let cstr = to_cstring!(flags); - let (flags_ptr, flags_len) = (cstr.as_ptr(), cstr.as_bytes().len()); - - let slash = "/".to_string(); - let cstr = to_cstring!(slash); - let (slash_ptr, slash_len) = (cstr.as_ptr(), cstr.as_bytes().len()); - - let none = String::new(); - let cstr = to_cstring!(none); - let (none_ptr, none_len) = (cstr.as_ptr(), cstr.as_bytes().len()); - - let compiled_unit = unsafe { - LLVMDIBuilderCreateCompileUnit( - builder_ref, - LLVMDWARFSourceLanguageRust, - builder_file, - producer_ptr, - producer_len, - 0, /* is_optimized */ - flags_ptr, - flags_len, - 0, /* runtime_version */ - std::ptr::null(), /* *const i8 */ - 0, /* usize */ - LLVMDWARFEmissionKind::LLVMDWARFEmissionKindFull, - 0, /* u32 */ - 0, /* i32 */ - 0, /* i32 */ - slash_ptr, /* *const i8 */ - slash_len, /* usize */ - none_ptr, /* *const i8 */ - none_len, /* usize */ - ) - }; - - // create di module - let parent_scope = compiled_unit; - let name = module_name; - let cstr = to_cstring!(name); - let (name_ptr, name_len) = (cstr.as_ptr(), cstr.as_bytes().len()); - - let (config_macros_ptr, config_macros_len) = (none_ptr, none_len); - let (include_path_ptr, include_path_len) = (none_ptr, none_len); - let (api_notes_file_ptr, api_notes_file_len) = (none_ptr, none_len); - let compiled_module = unsafe { - LLVMDIBuilderCreateModule( - builder_ref, - parent_scope, - name_ptr, - name_len, - config_macros_ptr, - config_macros_len, - include_path_ptr, - include_path_len, - api_notes_file_ptr, - api_notes_file_len, - ) - }; - fn create_type( builder_ref: LLVMDIBuilderRef, name: &str, @@ -399,6 +565,11 @@ impl<'up> DIBuilder<'up> { unsafe { LLVMDIBuilderCreateUnspecifiedType(builder_ref, name_ptr, name_len) } } + // create compile unit + let producer = "move-mv-llvm-compiler".to_string(); + let compiled_unit = + Self::create_compiled_unit(builder_ref, builder_file, producer.clone()); + // store all control fields for future usage let builder_core = DIBuilderCore { g_ctx, @@ -406,9 +577,9 @@ impl<'up> DIBuilder<'up> { builder_ref, builder_file, compiled_unit, - compiled_module, - module_ref, + producer: producer.clone(), module_source: source.to_string(), + current_function: RefCell::new(std::ptr::null_mut::()), type_unspecified: create_unspecified_type(builder_ref), type_u8: create_type(builder_ref, "u8", 8, 0, LLVMDIFlagZero), type_u16: create_type(builder_ref, "u16", 16, 0, LLVMDIFlagZero), @@ -419,6 +590,10 @@ impl<'up> DIBuilder<'up> { type_bool: create_type(builder_ref, "bool", 8, 0, LLVMDIFlagZero), type_address: create_type(builder_ref, "address", 256, 0, LLVMDIFlagZero), }; + let module_di_info = print_module_to_str(&module_di); + debug!(target: "dwarf", "DIBuilder bof DI starting at next line and until line starting with !!!\n{module_di_info}\n!!!\n"); + + module.verify(); DIBuilder(Some(builder_core)) } else { @@ -446,18 +621,18 @@ impl<'up> DIBuilder<'up> { self.0.as_ref().map(|x| x.compiled_unit) } - pub fn compiled_module(&self) -> Option { - self.0.as_ref().map(|x| x.compiled_module) - } - pub fn module_ref(&self) -> Option { - self.0.as_ref().map(|x| x.module_ref) + self.0.as_ref().map(|x| x.module_di) } pub fn module_source(&self) -> Option { self.0.as_ref().map(|x| x.module_source.clone()) } + pub fn producer(&self) -> Option { + self.0.as_ref().map(|x| x.producer.clone()) + } + fn core(&self) -> &DIBuilderCore { self.0.as_ref().unwrap() } @@ -539,10 +714,10 @@ impl<'up> DIBuilder<'up> { if Self::is_named_type(metadata) { type_get_name(metadata) } else { - "unknown name".to_string() + "unknown_name".to_string() } } else { - "unknown name".to_string() + "unknown_name".to_string() } } @@ -554,10 +729,39 @@ impl<'up> DIBuilder<'up> { let name_cstr = unsafe { std::ffi::CStr::from_ptr(name_ptr) }; name_cstr.to_string_lossy().into_owned() } else { - "unknown name".to_string() + "unknown_name".to_string() + } + } + + pub fn get_operand_name(instruction: LLVMValueRef, idx: u32) -> String { + let operand_value = unsafe { LLVMGetOperand(instruction, idx) }; // operands are counted from 0 + if !operand_value.is_null() { + let mut length: ::libc::size_t = 0; + let name_ptr = unsafe { LLVMGetValueName2(operand_value, &mut length) }; + let name_cstr = unsafe { std::ffi::CStr::from_ptr(name_ptr) }; + name_cstr.to_string_lossy().into_owned() + } else { + "unknown_name".to_string() } } + pub fn get_operand_names(instruction: LLVMValueRef) -> Vec { + let num_operands = unsafe { LLVMGetNumOperands(instruction) } as u32; + (0..num_operands) + .map(|idx| Self::get_operand_name(instruction, idx)) + .collect() + } + + pub fn get_operands(instruction: LLVMValueRef) -> Vec<*mut LLVMValue> { + let num_operands = unsafe { LLVMGetNumOperands(instruction) } as u32; + let mut v = vec![]; + for idx in 0..num_operands { + let x = unsafe { LLVMGetOperand(instruction, idx) }; + v.push(x) + } + v + } + pub fn set_name(&self, value: LLVMValueRef, name: &str) { if self.0.is_some() { let cstr = std::ffi::CString::new(name).expect("Failed to create CString"); @@ -587,6 +791,7 @@ impl<'up> DIBuilder<'up> { pub fn create_vector( &self, + m_ctx: &ModuleContext, mvec: &[mty::Type], llvec: &Type, llmod: &Module, @@ -598,6 +803,19 @@ impl<'up> DIBuilder<'up> { if let Some(_di_builder_core) = &self.0 { let di_builder = self.builder_ref().unwrap(); + let module_di_test = &self.module_di().unwrap(); + let module_di = &m_ctx.llvm_module.0; + assert!( + module_di == module_di_test, + "Module context should be the same" + ); + unsafe { + LLVMDumpModule(*module_di); + } + let module_di_info = print_module_to_str(module_di); + debug!(target: "dwarf", "\ncreate_vector bof DI starting at next line and until line starting with !!!\n{module_di_info}\n!!!\n"); + + let module_ctx = unsafe { LLVMGetModuleContext(*module_di) }; let mty = mvec.get(0).unwrap(); // exists since !mvec.is_empty() let vec_di_type = self.get_type(mty.clone(), &"unnamed-vector".to_string()); @@ -631,8 +849,6 @@ impl<'up> DIBuilder<'up> { n_elements as u32, ); - let module_di = &self.module_di().unwrap(); - let module_ctx = LLVMGetModuleContext(*module_di); let meta_as_value = LLVMMetadataAsValue(module_ctx, vector_di_type); LLVMAddNamedMetadataOperand(*module_di, vec_name_c_str, meta_as_value); @@ -649,10 +865,10 @@ impl<'up> DIBuilder<'up> { pub fn create_function( &self, func_ctx: &FunctionContext<'_, '_>, - _parent: Option, - ) { - if let Some(_di_builder_core) = &self.0 { - let di_builder = self.builder_ref().unwrap(); + _parent: Option, // reserved for future usage + ) -> Option<*mut LLVMOpaqueMetadata> { + if let Some(di_builder_core) = &self.0 { + let di_builder: *mut llvm_sys::LLVMOpaqueDIBuilder = self.builder_ref().unwrap(); let di_builder_file = self.builder_file().unwrap(); let fn_env = &func_ctx.env; @@ -663,18 +879,35 @@ impl<'up> DIBuilder<'up> { .get_file_and_location(loc) .unwrap_or(("unknown".to_string(), Location::new(0, 0))); let lineno = location.line.0; + let column = location.column.0; + + let module_cx = &func_ctx.module_cx; + let ll_ctx = module_cx.llvm_cx.0; + let module = module_cx.llvm_module; + + let compiled_unit = self.compiled_unit().unwrap(); + + unsafe { + dbg_meta_operand!( + ll_mod, + ll_ctx, + compiled_unit, + "functions", + "create_function" + ); + }; - let mod_cx = &func_ctx.module_cx; - let module = mod_cx.llvm_module; let data_layout = module.get_module_data_layout(); + let module_di = &self.module_di().unwrap(); + let module_ctx = unsafe { LLVMGetModuleContext(*module_di) }; + let param_count = func_ctx.env.get_parameter_count(); - let ll_fn = func_ctx - .module_cx + let ll_fn = module_cx .lookup_move_fn_decl(fn_env.get_qualified_inst_id(func_ctx.type_params.to_vec())); let fn_name = fn_env.get_name_str(); - debug!(target: "functions", "Create DI for function {fn_name} {file}:{lineno} with {param_count} parameters"); + debug!(target: "functions", "Create DI for function {fn_name} {:#?} {file}:{lineno} with {param_count} parameters", ll_fn.0); let ll_params = (0..param_count).map(|i| ll_fn.get_param(i)); let parameters: Vec<_> = ll_params.clone().zip(func_ctx.locals.iter()).collect(); @@ -683,68 +916,66 @@ impl<'up> DIBuilder<'up> { let mty = &local.mty(); let mty_info = mty.display(&fn_env.get_type_display_ctx()).to_string(); let llty = local.llty(); - let llty1 = local.llval().llvm_type(); + let llty_alter = local.llval().llvm_type(); // currently names with _alter are only for debugging let properties = llty.dump_properties_to_str(data_layout); - let properties1 = llty1.dump_properties_to_str(data_layout); + let properties_alter = llty_alter.dump_properties_to_str(data_layout); let llval = ll_param.0; - let llval1 = local.llval().get0(); - let param_name = func_ctx.module_cx.llvm_di_builder.get_name(llval); - let param_name1 = func_ctx.module_cx.llvm_di_builder.get_name(llval1); + let llval_alter = local.llval().get0(); + let param_name = module_cx.llvm_di_builder.get_name(llval); + let param_name_alter = module_cx.llvm_di_builder.get_name(llval_alter); debug!(target: "functions", "param {idx}: {param_name} {mty_info} {properties}"); // use upper, not lower - debug!(target: "functions", "param {idx}: {param_name1} {mty_info} {properties1}"); + debug!(target: "functions", "param {idx}: {param_name_alter} {mty_info} {properties_alter}"); } let name_cstr = to_cstring!(fn_name.clone()); let (fn_nm_ptr, fn_nm_len) = (name_cstr.as_ptr(), name_cstr.as_bytes().len()); + // NOTE. Explanation of the numbers used below. + // Despite some existing freedom in choosing parameter values ​​(for example, the 'scope' in different places + // may be either file, or function, or logical scope, or basic block) the final result may vary and even be illegal, + // so the module verification may fail. + // When debigging and experimenting with parameters on a step, it is convenient to have a reference to the step, + // and the step number is used as that reference. + // Notice that the actual order of LLVM function calls below may be changed as long as the parameter dependency is preserved. + // + // -5. let name_space = unsafe { LLVMDIBuilderCreateNameSpace(di_builder, di_builder_file, fn_nm_ptr, fn_nm_len, 0) }; - let mut fn_params: Vec = enumerate(parameters) - .scan(0, |_state, (idx, (ll_param, local))| { + // -4. + let mut ty_params: Vec = enumerate(¶meters) + .scan(0, |_state, (_idx, (ll_param, local))| { let llval = ll_param.0; - let param_name = func_ctx.module_cx.llvm_di_builder.get_name(llval); - let name_cstr = to_cstring!(param_name.clone()); - let (param_nm_ptr, param_nm_len) = - (name_cstr.as_ptr(), name_cstr.as_bytes().len()); + let param_name = module_cx.llvm_di_builder.get_name(llval); let mty = local.mty(); - let param_type = self.get_type(mty.clone(), ¶m_name); - - let fn_param = unsafe { - LLVMDIBuilderCreateParameterVariable( - di_builder, - name_space, - param_nm_ptr, - param_nm_len, - idx as u32, - di_builder_file, - idx as u32, - param_type, - 0, - 0, - ) - }; + let fn_param = self.get_type(mty.clone(), ¶m_name); + + let fn_param_value = unsafe { LLVMMetadataAsValue(module_ctx, fn_param) }; + let fn_param_info = print_to_str(fn_param_value); + debug!(target: "functions", "\ncreate_function fn_param starting at next line and until line starting with !!!\n{fn_param_info}\n!!!\n"); Some(fn_param) }) .collect(); - let fn_params_mut: *mut LLVMMetadataRef = fn_params.as_mut_ptr(); + let ty_params_mut: *mut LLVMMetadataRef = ty_params.as_mut_ptr(); + // -3. let subroutine_ty = unsafe { LLVMDIBuilderCreateSubroutineType( di_builder, di_builder_file, - fn_params_mut, - fn_params.len() as u32, + ty_params_mut, + ty_params.len() as u32, 0, ) }; + // -2. let function = unsafe { LLVMDIBuilderCreateFunction( di_builder, - name_space, + di_builder_file, fn_nm_ptr, fn_nm_len, fn_nm_ptr, @@ -759,9 +990,14 @@ impl<'up> DIBuilder<'up> { 0, // IsOptimized: TODO: may need change ) }; + let mut current_function = di_builder_core.current_function.borrow_mut(); + *current_function = function; + unsafe { + dbg_meta_operand!(ll_mod, ll_ctx, function, "functions", "create_function"); + }; - // reserved for future usage - let _lexical_block = unsafe { + // -1. + let lexical_block = unsafe { LLVMDIBuilderCreateLexicalBlock( di_builder, function, @@ -771,28 +1007,131 @@ impl<'up> DIBuilder<'up> { ) }; - let llvm_builder = &mod_cx.llvm_builder; + let module_context = unsafe { LLVMGetModuleContext(module.0) }; + let debug_location = unsafe { + LLVMDIBuilderCreateDebugLocation( + module_context, + lineno, + column, + /* Scope */ lexical_block, + std::ptr::null_mut(), // Inlined at + ) + }; - let entry_bb = llvm_builder.get_entry_basic_block(ll_fn); - dbg!(entry_bb); + unsafe { + LLVMSetSubprogram(ll_fn.0, function); + }; - let module_di = &self.module_di().unwrap(); - let module_ctx = unsafe { LLVMGetModuleContext(*module_di) }; + let llvm_builder = &module_cx.llvm_builder; + + let _entry_bb = llvm_builder.get_entry_basic_block(ll_fn); + + // 0. No need to set compiled_unit, it was set in new() + + // 1. Setting function let meta_as_value = unsafe { LLVMMetadataAsValue(module_ctx, function) }; unsafe { LLVMAddNamedMetadataOperand(*module_di, fn_nm_ptr, meta_as_value) }; - let out = unsafe { LLVMPrintModuleToString(*module_di) }; - let c_string: *mut i8 = out; - let c_str = unsafe { - CStr::from_ptr(c_string) - .to_str() - .expect("Cannot convert to &str") + // 2. No need to set subroutine_ty, it was set in 1. + + // 3. Setting lexical block. Not used now. + let meta_as_value = unsafe { LLVMMetadataAsValue(module_ctx, lexical_block) }; + unsafe { LLVMAddNamedMetadataOperand(*module_di, fn_nm_ptr, meta_as_value) }; + + // 4. Setting name_space. Not used now. + let meta_as_value = unsafe { LLVMMetadataAsValue(module_ctx, name_space) }; + unsafe { LLVMAddNamedMetadataOperand(*module_di, fn_nm_ptr, meta_as_value) }; + + // 5. Setting debug location. + let meta_as_value = unsafe { LLVMMetadataAsValue(module_ctx, debug_location) }; + unsafe { LLVMAddNamedMetadataOperand(*module_di, fn_nm_ptr, meta_as_value) }; + + // Note: do NOT call module verify at this point, since building function is not done, call verify after function_finalize. + + return Some(function); + } + None + } + + pub fn finalize_function( + &self, + func_ctx: &FunctionContext<'_, '_>, + function: Option<*mut LLVMOpaqueMetadata>, + ) { + if let (Some(_di_builder_core), Some(function)) = (&self.0, function) { + let di_builder = func_ctx.module_cx.llvm_di_builder.builder_ref().unwrap(); + unsafe { + LLVMDIBuilderFinalizeSubprogram(di_builder, function); }; - debug!(target: "functions", "function {fn_name}: DI content: starting at next line and until line starting with !!!\n{}\n!!!\n", c_str); } } - pub fn create_type_subroutine( + pub fn set_compile_unit(&self, m_ctx: &ModuleContext<'_, '_>) { + if let Some(_di_builder_core) = &self.0 { + let module_di: &*mut LLVMModule = &m_ctx.llvm_module.0; + let module_ctx: *mut llvm_sys::LLVMContext = + unsafe { LLVMGetModuleContext(*module_di) }; + let compiled_unit: *mut LLVMOpaqueMetadata = + m_ctx.llvm_di_builder.compiled_unit().unwrap(); + + let m_env: &move_model::model::ModuleEnv<'_> = &m_ctx.env; + let m_name: String = m_env.get_name().display(m_env.symbol_pool()).to_string(); + let name_cstr = to_cstring!(m_name.clone()); + let (fn_nm_ptr, _fn_nm_len) = (name_cstr.as_ptr(), name_cstr.as_bytes().len()); + + let meta_as_value = unsafe { LLVMMetadataAsValue(module_ctx, compiled_unit) }; + unsafe { LLVMAddNamedMetadataOperand(*module_di, fn_nm_ptr, meta_as_value) }; + } + } + + fn create_compiled_unit( + di_builder: *mut llvm_sys::LLVMOpaqueDIBuilder, + builder_file: *mut LLVMOpaqueMetadata, + producer: String, + ) -> *mut LLVMOpaqueMetadata { + let builder_ref = di_builder; + let cstr = to_cstring!(producer); + let (producer_ptr, producer_len) = (cstr.as_ptr(), cstr.as_bytes().len()); + + let flags = String::new(); + let cstr = to_cstring!(flags); + let (flags_ptr, flags_len) = (cstr.as_ptr(), cstr.as_bytes().len()); + + let slash = "/".to_string(); + let cstr = to_cstring!(slash); + let (slash_ptr, slash_len) = (cstr.as_ptr(), cstr.as_bytes().len()); + + let none = String::new(); + let cstr = to_cstring!(none); + let (none_ptr, none_len) = (cstr.as_ptr(), cstr.as_bytes().len()); + + let compiled_unit: *mut LLVMOpaqueMetadata = unsafe { + LLVMDIBuilderCreateCompileUnit( + builder_ref, + LLVMDWARFSourceLanguageRust, + builder_file, + producer_ptr, + producer_len, + 0, /* is_optimized */ + flags_ptr, + flags_len, + 0, /* runtime_version */ + std::ptr::null(), /* *const i8 */ + 0, /* usize */ + LLVMDWARFEmissionKind::LLVMDWARFEmissionKindFull, + 0, /* u32 */ + 0, /* i32 */ + 0, /* i32 */ + slash_ptr, /* *const i8 */ + slash_len, /* usize */ + none_ptr, /* *const i8 */ + none_len, /* usize */ + ) + }; + compiled_unit + } + + pub fn create_subroutine_type( &self, name: &str, param_types: *mut LLVMMetadataRef, @@ -1025,29 +1364,57 @@ impl<'up> DIBuilder<'up> { &'a self, bc: &'a Bytecode, func_ctx: &'a FunctionContext<'_, '_>, - ) -> Option> { + ) -> PublicInstruction { if let Some(_di_builder_core) = &self.0 { let instr = Instruction::new(bc, func_ctx); instr.debug(); - return Some(PublicInstruction(instr)); + return PublicInstruction(Some(instr)); } - None + PublicInstruction(None) } - pub fn create_load_store( - &self, - instr: Option, - load: *mut LLVMValue, - store: *mut LLVMValue, - mty: &mty::Type, - ) { - if let Some(_di_builder_core) = &self.0 { - if let Some(instruction) = instr { - instruction.0.create_load_store(load, store, mty); - } + pub fn add_name_alias(instr: LLVMValueRef, name: &str) { + let cstr = to_cstring!(name); + let (nm_ptr, nm_len) = (cstr.as_ptr(), cstr.as_bytes().len()); + unsafe { + LLVMSetValueName2(instr, nm_ptr, nm_len); } } + // creates auto variable for a given type mty and name + pub fn create_auto_variable( + &self, + scope: LLVMMetadataRef, + mty: &move_model::ty::Type, + name: &String, + file: LLVMMetadataRef, + line: libc::c_uint, + column: libc::c_uint, + ) -> *mut LLVMOpaqueMetadata { + let di_builder = self.builder_ref().unwrap(); + let ty: *mut llvm_sys::LLVMOpaqueMetadata = self.get_type(mty.clone(), name); + let cstr = to_cstring!(name.as_str()); + let (nm_ptr, nm_len) = (cstr.as_ptr(), cstr.as_bytes().len()); + let x: *mut LLVMOpaqueMetadata; + unsafe { + let lexical_block = + LLVMDIBuilderCreateLexicalBlock(di_builder, scope, file, line, column); + x = LLVMDIBuilderCreateAutoVariable( + di_builder, + lexical_block, /* scope */ + nm_ptr, + nm_len, + file, + line, + ty, + 0, + 0, + 0, + ); + }; + x + } + pub fn finalize(&self) { if let Some(x) = &self.0 { unsafe { LLVMDIBuilderFinalize(x.builder_ref) }; @@ -1069,6 +1436,34 @@ fn loc_display(loc: &move_model::model::Loc, env: &GlobalEnv) -> (String, u32, u } } +fn print_to_str(val: *mut LLVMValue) -> String { + unsafe { + CStr::from_ptr(LLVMPrintValueToString(val)) + .to_str() + .unwrap_or("No Info") + .to_owned() + } +} + +fn print_bb_to_str(bb: LLVMBasicBlockRef) -> String { + unsafe { + let val = LLVMBasicBlockAsValue(bb); + CStr::from_ptr(LLVMPrintValueToString(val)) + .to_str() + .unwrap_or("No Info") + .to_owned() + } +} + +fn print_module_to_str(module: &LLVMModuleRef) -> String { + unsafe { + CStr::from_ptr(LLVMPrintModuleToString(*module)) + .to_str() + .unwrap() + .to_owned() + } +} + fn find_line_column(file_path: &str, find_offset: usize) -> Result<(i32, usize)> { // Open the file let file = File::open(file_path)?; diff --git a/language/solana/move-to-solana/src/stackless/entrypoint.rs b/language/solana/move-to-solana/src/stackless/entrypoint.rs index 97ddf0554a..20cd4dc604 100644 --- a/language/solana/move-to-solana/src/stackless/entrypoint.rs +++ b/language/solana/move-to-solana/src/stackless/entrypoint.rs @@ -320,7 +320,6 @@ impl<'mm, 'up> EntrypointGenerator<'mm, 'up> { .llvm_builder .load(self.retval, self.llvm_cx.int_type(64), "exit_code"); self.llvm_builder.build_return(ret); - self.llvm_module.verify(); if log_enabled!(target: "entry_point", Level::Debug) { self.llvm_module.dump(); diff --git a/language/solana/move-to-solana/src/stackless/llvm.rs b/language/solana/move-to-solana/src/stackless/llvm.rs index 74919dbded..78c8d61a0b 100644 --- a/language/solana/move-to-solana/src/stackless/llvm.rs +++ b/language/solana/move-to-solana/src/stackless/llvm.rs @@ -13,6 +13,7 @@ //! - Hides weirdly mutable array pointers. //! - Provides high-level instruction builders compatible with the stackless bytecode model. +use libc::abort; use llvm_extra_sys::*; use llvm_sys::{core::*, prelude::*, target::*, target_machine::*, LLVMOpcode, LLVMUnnamedAddr}; use log::debug; @@ -39,7 +40,7 @@ pub use llvm_sys::{ use crate::stackless::{ dwarf::{from_raw_slice_to_string, DIBuilder}, - GlobalContext, + GlobalContext, ModuleContext, }; pub fn initialize_sbf() { @@ -107,7 +108,7 @@ impl Context { pub fn create_di_builder<'up>( &'up self, g_ctx: &'up GlobalContext, - module: &mut Module, + module: &Module, source: &str, debug: bool, ) -> DIBuilder { @@ -257,7 +258,7 @@ impl Context { pub struct TargetData(LLVMTargetDataRef); #[derive(Debug)] -pub struct Module(LLVMModuleRef); +pub struct Module(pub LLVMModuleRef); impl Drop for Module { fn drop(&mut self) { @@ -384,11 +385,20 @@ impl Module { pub fn verify(&self) { use llvm_sys::analysis::*; unsafe { - LLVMVerifyModule( + let name = &self.get_module_id(); + let addr = &self.0; + debug!(target: "module", "{name} module verification address {:#?}", addr); + if LLVMVerifyModule( self.0, - LLVMVerifierFailureAction::LLVMAbortProcessAction, + LLVMVerifierFailureAction::LLVMPrintMessageAction, ptr::null_mut(), - ); + ) == 1 + { + println!("\n{} module verification failed\n", &self.get_module_id()); + let module_info = &self.print_to_str(); + debug!(target: "module", "Module content:\n{module_info}\n"); + abort(); + } } } @@ -482,9 +492,17 @@ impl Module { Ok(()) } + + pub fn print_to_str(&self) -> &str { + unsafe { + CStr::from_ptr(LLVMPrintModuleToString(self.0)) + .to_str() + .unwrap() + } + } } -pub struct Builder(LLVMBuilderRef); +pub struct Builder(pub LLVMBuilderRef); impl Drop for Builder { fn drop(&mut self) { @@ -534,9 +552,9 @@ impl Builder { dst: Alloca, ) -> (*mut LLVMValue, *mut LLVMValue) { unsafe { - let tmp_reg = LLVMBuildLoad2(self.0, ty.0, src.0, "load_store_tmp".cstr()); - let store = LLVMBuildStore(self.0, tmp_reg, dst.0); - (tmp_reg, store) + let load = LLVMBuildLoad2(self.0, ty.0, src.0, "load_store_tmp".cstr()); + let store = LLVMBuildStore(self.0, load, dst.0); + (load, store) } } @@ -878,6 +896,7 @@ impl Builder { fnval: Function, args: &[(Type, Alloca)], dst: &[(Type, Alloca)], + instr_dbg: super::dwarf::PublicInstruction<'_>, ) { unsafe { let args = args @@ -888,7 +907,59 @@ impl Builder { AnyValue(LLVMBuildLoad2(self.0, ty.0, val.0, name.cstr())) }) .collect::>(); - self.call_store(fnval, &args, dst) + self.call_store_with_dst(fnval, &args, dst, instr_dbg) + } + } + + fn call_store_with_dst( + &self, + fnval: Function, + args: &[AnyValue], + dst: &[(Type, Alloca)], + instr_dbg: super::dwarf::PublicInstruction<'_>, + ) { + let fnty = fnval.llvm_type(); + + unsafe { + let mut args = args.iter().map(|a| a.0).collect::>(); + let func_name = get_name(fnval.0); + let ret = LLVMBuildCall2( + self.0, + fnty.0, + fnval.0, + args.as_mut_ptr(), + args.len() as libc::c_uint, + (if dst.is_empty() { "" } else { "retval" }).cstr(), + ); + let ret_name = get_name(ret); + instr_dbg.create_call(ret); + debug!(target: "functions", "call_store function {} ret {}", &func_name, &ret_name); + + if dst.is_empty() { + // No return values. + } else if dst.len() == 1 { + // Single return value. + let alloca = dst[0].1; + let alloca_name = alloca.get_name(); + let ret = LLVMBuildStore(self.0, ret, dst[0].1 .0); + let ret_name = get_name(ret); + debug!(target: "functions", "call_store alloca_name {} ret {} alloca {:#?} ", &alloca_name, &ret_name, alloca); + } else { + // Multiple return values-- unwrap the struct. + let extracts = dst + .iter() + .enumerate() + .map(|(i, (_ty, dval))| { + let _name = dval.get_name(); + let name = format!("extract_{i}"); + let ev = LLVMBuildExtractValue(self.0, ret, i as libc::c_uint, name.cstr()); + (ev, dval) + }) + .collect::>(); + for (ev, dval) in extracts { + LLVMBuildStore(self.0, ev, dval.0); + } + } } } @@ -1159,7 +1230,7 @@ impl FunctionType { } #[derive(Debug, Copy, Clone)] -pub struct Function(LLVMValueRef); +pub struct Function(pub LLVMValueRef); impl Function { pub fn as_gv(&self) -> Global { @@ -1218,10 +1289,15 @@ impl Function { unsafe { Type(LLVMGetReturnType(LLVMGlobalGetValueType(self.0))) } } - pub fn verify(&self) { + pub fn verify(&self, module_cx: &ModuleContext<'_, '_>) { use llvm_sys::analysis::*; + let module_info = module_cx.llvm_module.print_to_str(); + debug!(target: "function", "Module content:\n{module_info}\n"); unsafe { - LLVMVerifyFunction(self.0, LLVMVerifierFailureAction::LLVMAbortProcessAction); + if LLVMVerifyFunction(self.0, LLVMVerifierFailureAction::LLVMPrintMessageAction) == 1 { + println!("{} function verifiction failed", &self.get_name()); + abort(); + } } } } diff --git a/language/solana/move-to-solana/src/stackless/module_context.rs b/language/solana/move-to-solana/src/stackless/module_context.rs index 830e8c11bb..241567a452 100644 --- a/language/solana/move-to-solana/src/stackless/module_context.rs +++ b/language/solana/move-to-solana/src/stackless/module_context.rs @@ -75,10 +75,10 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> { self.entrypoint_generator.add_entries(self); } - self.llvm_module.verify(); self.llvm_di_builder .print_log_unresoled_types(UnresolvedPrintLogLevel::Warning); self.llvm_di_builder.finalize(); + self.llvm_module.verify(); } /// Generate LLVM IR struct declarations for all Move structures. diff --git a/language/solana/move-to-solana/src/stackless/rttydesc.rs b/language/solana/move-to-solana/src/stackless/rttydesc.rs index 7e4c716606..37bef9c637 100644 --- a/language/solana/move-to-solana/src/stackless/rttydesc.rs +++ b/language/solana/move-to-solana/src/stackless/rttydesc.rs @@ -92,7 +92,9 @@ impl<'mm, 'up> RttyContext<'mm, 'up> { let tyv_display = &mty.display(ty_display_ctx); debug!(target: "rtty", "get_llvm_type_for_move_vector: {tyv_display}"); } - m_ctx.llvm_di_builder.create_vector(mvec, &ty, llmod, None); + m_ctx + .llvm_di_builder + .create_vector(m_ctx, mvec, &ty, llmod, None); ty } diff --git a/language/solana/move-to-solana/src/stackless/translate.rs b/language/solana/move-to-solana/src/stackless/translate.rs index 61d03b543f..2ad0658550 100644 --- a/language/solana/move-to-solana/src/stackless/translate.rs +++ b/language/solana/move-to-solana/src/stackless/translate.rs @@ -147,11 +147,11 @@ impl<'up> GlobalContext<'up> { let Self { env, llvm_cx, .. } = self; let m_env = env.get_module(id); - let llvm_builder = llvm_cx.create_builder(); let modname = m_env.llvm_module_name(); debug!(target: "dwarf", "Create DWARF for module {:#?} with source {:#?}", modname, source); - let mut module = self.llvm_cx.create_module(&modname); - let llvm_di_builder = llvm_cx.create_di_builder(self, &mut module, source, options.debug); + // DIBuilder does not depend on Builder and can be created first + let llvm_di_builder = llvm_cx.create_di_builder(self, llmod, source, options.debug); + let llvm_builder = llvm_cx.create_builder(); let rtty_cx = RttyContext::new(self.env, &self.llvm_cx, llmod); ModuleContext { env: self.env.get_module(id), @@ -225,10 +225,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { let map_node_to_type: BTreeMap = g_env .get_nodes() .iter() - .map(|nd| { - debug!(target: "nodes", "{:#?} {:#?}", nd, g_env.get_node_loc(*nd)); - (*nd, g_env.get_node_type(*nd)) - }) + .map(|nd| (*nd, g_env.get_node_type(*nd))) .collect(); debug!(target: "nodes", "\n{:#?}", &map_node_to_type); @@ -293,7 +290,6 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { name = format!("local_{}__{}", i, s); } let llval = self.module_cx.llvm_builder.build_alloca(llty, &name); - debug!(target: "functions", "adding {i} local {}:\n {:#?}\n {:#?}\n {:#?}\n", &name, mty, llty, llval); self.locals.push(Local { mty: mty.instantiate(self.type_params), llty, @@ -349,14 +345,17 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { } } + let di_func = self.module_cx.llvm_di_builder.create_function(&self, None); + // Translate instructions for instr in &fn_data.code { self.translate_instruction(instr); } - ll_fn.verify(); - - self.module_cx.llvm_di_builder.create_function(&self, None); + self.module_cx + .llvm_di_builder + .finalize_function(&self, di_func); + ll_fn.verify(self.module_cx); } fn translate_instruction(&mut self, instr: &sbc::Bytecode) { @@ -382,7 +381,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { | mty::PrimitiveType::U256, ) => { let (load, store) = builder.load_store(llty, src_llval, dst_llval); - builder_di.create_load_store(instr_dbg, load, store, mty); + instr_dbg.create_load_store(load, store, mty, llty, src_llval, dst_llval); } mty::Type::Reference(_, _) => { builder.load_store(llty, src_llval, dst_llval); @@ -484,7 +483,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { } } sbc::Bytecode::Call(_, dst, op, src, None) => { - self.translate_call(dst, op, src); + self.translate_call(dst, op, src, instr, instr_dbg); } sbc::Bytecode::Ret(_, vals) => match vals.len() { 0 => { @@ -531,7 +530,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { builder.position_at_end(llbb); } sbc::Bytecode::Abort(_, local) => { - self.emit_rtcall(RtCall::Abort(*local)); + self.emit_rtcall(RtCall::Abort(*local), instr); } sbc::Bytecode::Nop(_) => {} _ => { @@ -1165,6 +1164,8 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { dst: &[mast::TempIndex], op: &sbc::Operation, src: &[mast::TempIndex], + instr: &sbc::Bytecode, + instr_dbg: super::dwarf::PublicInstruction<'_>, ) { use sbc::Operation; let emitter_nop: CheckEmitterFn = (|_, _| (), EmitterFnKind::PreCheck); @@ -1176,7 +1177,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { let fn_name = &self.env.get_name_str(); debug!(target: "dwarf", "translate_call function {fn_name} op {:#?} dst {:#?} src {:#?} types {:#?}", op, dst, src, &types); - self.translate_fun_call(*mod_id, *fun_id, &types, dst, src); + self.translate_fun_call(*mod_id, *fun_id, &types, dst, src, instr, instr_dbg); } Operation::BorrowLoc => { assert_eq!(src.len(), 1); @@ -1284,7 +1285,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { mty::Type::Struct(_, _, _) => ( /* nop */ ), mty::Type::Reference(_, _) => { /* nop */ } mty::Type::Vector(elt_mty) => { - self.emit_rtcall(RtCall::VecDestroy(idx, (**elt_mty).clone())); + self.emit_rtcall(RtCall::VecDestroy(idx, (**elt_mty).clone()), instr); } _ => todo!("{mty:?}"), } @@ -1526,6 +1527,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { types: &[mty::Type], dst: &[mast::TempIndex], src: &[mast::TempIndex], + _instr: &sbc::Bytecode, ) { let types = mty::Type::instantiate_vec(types.to_vec(), self.type_params); let typarams = self.module_cx.get_rttydesc_ptrs(&types); @@ -1599,6 +1601,8 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { types: &[mty::Type], dst: &[mast::TempIndex], src: &[mast::TempIndex], + instr: &sbc::Bytecode, + instr_dbg: super::dwarf::PublicInstruction<'_>, ) { // Handle native function calls specially. { @@ -1606,7 +1610,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { let fn_id = fun_id.qualified(mod_id); let fn_env = global_env.get_function(fn_id); if fn_env.is_native() { - return self.translate_native_fun_call(mod_id, fun_id, types, dst, src); + return self.translate_native_fun_call(mod_id, fun_id, types, dst, src, instr); } } @@ -1658,7 +1662,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { self.module_cx .llvm_builder - .load_call_store(ll_fn, &src, &dst); + .load_call_store(ll_fn, &src, &dst, instr_dbg); } // Optional vec_mty is only used for a vector literal (i.e., Constant)) @@ -1868,7 +1872,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { (res_val.llvm_type(), res_ptr) } - fn emit_rtcall(&self, rtcall: RtCall) { + fn emit_rtcall(&self, rtcall: RtCall, _instr: &sbc::Bytecode) { match &rtcall { RtCall::Abort(local_idx) => { let llfn = ModuleContext::get_runtime_function( @@ -1883,6 +1887,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> { llfn, &[(local_llty, local_llval)], &[], + super::dwarf::PublicInstruction::none(), ); self.module_cx.llvm_builder.build_unreachable(); } diff --git a/language/tools/move-mv-llvm-compiler/src/main.rs b/language/tools/move-mv-llvm-compiler/src/main.rs index 19160fec2b..6c3e0b9be8 100644 --- a/language/tools/move-mv-llvm-compiler/src/main.rs +++ b/language/tools/move-mv-llvm-compiler/src/main.rs @@ -289,7 +289,8 @@ fn main() -> anyhow::Result<()> { Err(err) => eprintln!("Error creating directory: {}", err), } } - if let Some(module_di) = mod_cx.llvm_di_builder.module_di() { + if let Some(_module_di) = mod_cx.llvm_di_builder.module_di() { + let module_di = mod_cx.llvm_module.0; let output_file = format!("{}.debug_info", output_file); llvm_write_to_file(module_di, true, &output_file)?; } diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0x1__signer.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0x1__signer.ll.debug_info.expected index 5493a7f993..5d18124059 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0x1__signer.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0x1__signer.ll.debug_info.expected @@ -1,15 +1,41 @@ -; ModuleID = '0x1__signer.dbg_info' -source_filename = "/language/move-stdlib/sources/signer.move" +; ModuleID = '0x1__signer' +source_filename = "./../../../../../move-stdlib/sources/signer.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +declare i32 @memcmp(ptr, ptr, i64) + +define [32 x i8] @"0000000000000001_signer_address_of_HobbRqPY4HqJJ6"(ptr nonnull readonly %s) !dbg !2 { +entry: + %local_0 = alloca ptr, align 8 + %local_1 = alloca ptr, align 8 + %local_2 = alloca ptr, align 8 + %local_3 = alloca [32 x i8], align 1 + store ptr %s, ptr %local_0, align 8 + %load_store_tmp = load ptr, ptr %local_0, align 8 + store ptr %load_store_tmp, ptr %local_1, align 8 + %loaded_alloca = load ptr, ptr %local_1, align 8 + %retval = call ptr @move_native_signer_borrow_address(ptr %loaded_alloca) + store ptr %retval, ptr %local_2, align 8 + %load_deref_store_tmp1 = load ptr, ptr %local_2, align 8 + %load_deref_store_tmp2 = load [32 x i8], ptr %load_deref_store_tmp1, align 1 + store [32 x i8] %load_deref_store_tmp2, ptr %local_3, align 1 + %retval1 = load [32 x i8], ptr %local_3, align 1 + ret [32 x i8] %retval1 +} + +declare ptr @move_native_signer_borrow_address(ptr) !llvm.dbg.cu = !{!0} -!address_of = !{!2} +!address_of = !{!2, !7, !8, !9} !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "move-mv-llvm-compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, sysroot: "/") !1 = !DIFile(filename: "signer.move", directory: "/language/move-stdlib/sources") -!2 = distinct !DISubprogram(name: "address_of", linkageName: "address_of", scope: !3, file: !1, line: 11, type: !4, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !8) -!3 = !DINamespace(name: "address_of", scope: !1) -!4 = !DISubroutineType(types: !5) -!5 = !{!6} -!6 = !DILocalVariable(name: "s", scope: !3, file: !1, type: !7) -!7 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "unspecified type") -!8 = !{} +!2 = distinct !DISubprogram(name: "address_of", linkageName: "address_of", scope: !1, file: !1, line: 11, type: !3, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !6) +!3 = !DISubroutineType(types: !4) +!4 = !{!5} +!5 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "unspecified type") +!6 = !{} +!7 = distinct !DILexicalBlock(scope: !2, file: !1, line: 10) +!8 = !DINamespace(name: "address_of", scope: !1) +!9 = !DILocation(line: 11, column: 4, scope: !7) diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0xcafe__BasicCoin.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0xcafe__BasicCoin.ll.debug_info.expected index 13c456231d..02c8ee9f57 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0xcafe__BasicCoin.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin-build/0xcafe__BasicCoin.ll.debug_info.expected @@ -1,5 +1,9 @@ -; ModuleID = '0xcafe__BasicCoin.dbg_info' +; ModuleID = '0xcafe__BasicCoin' source_filename = "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/basic-coin.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +declare i32 @memcmp(ptr, ptr, i64) !llvm.dbg.cu = !{!0} diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x101__M.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x101__M.ll.debug_info.expected index 01f06dc358..c1f8eaf8b0 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x101__M.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x101__M.ll.debug_info.expected @@ -1,48 +1,126 @@ -; ModuleID = '0x101__M.dbg_info' +; ModuleID = '0x101__M' source_filename = "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +%struct.M__MyStruct = type { i32, i1, %struct.M__EmptyStruct, i8, %struct.M__Combined } +%struct.M__EmptyStruct = type { i1 } +%struct.M__Combined = type { i1, %struct.M__U64Struct } +%struct.M__U64Struct = type { i64 } + +declare i32 @memcmp(ptr, ptr, i64) + +define %struct.M__MyStruct @"0000000000000101_M_fun_1_AcLtMspYikxikv"(i8 %par_1_u8, i1 %par_2_bool) !dbg !2 { +entry: + %local_0 = alloca i8, align 1 + %local_1 = alloca i1, align 1 + %local_2__field1_u32 = alloca i32, align 4 + %local_3__field2_bool = alloca i1, align 1 + %local_4__dummy_field = alloca i1, align 1 + %local_5__field3_empty = alloca %struct.M__EmptyStruct, align 8 + %local_6__field4_u8 = alloca i8, align 1 + %local_7__field_combined_bool = alloca i1, align 1 + %local_8__field_u64 = alloca i64, align 8 + %local_9__field_combined_u64_struct = alloca %struct.M__U64Struct, align 8 + %local_10__field6_combined = alloca %struct.M__Combined, align 8 + %local_11 = alloca %struct.M__MyStruct, align 8 + store i8 %par_1_u8, ptr %local_0, align 1 + store i1 %par_2_bool, ptr %local_1, align 1 + store i32 15, ptr %local_2__field1_u32, align 4 + %load_store_tmp = load i1, ptr %local_1, align 1, !dbg !38 + store i1 %load_store_tmp, ptr %local_3__field2_bool, align 1, !dbg !38 + call void @llvm.dbg.declare(metadata ptr %local_1, metadata !39, metadata !DIExpression()), !dbg !38 + call void @llvm.dbg.declare(metadata ptr %local_3__field2_bool, metadata !41, metadata !DIExpression()), !dbg !38 + store i1 false, ptr %local_4__dummy_field, align 1 + %fv.0 = load i1, ptr %local_4__dummy_field, align 1 + %insert_0 = insertvalue %struct.M__EmptyStruct undef, i1 %fv.0, 0 + store %struct.M__EmptyStruct %insert_0, ptr %local_5__field3_empty, align 1 + %load_store_tmp1 = load i8, ptr %local_0, align 1, !dbg !43 + store i8 %load_store_tmp1, ptr %local_6__field4_u8, align 1, !dbg !43 + call void @llvm.dbg.declare(metadata ptr %local_0, metadata !44, metadata !DIExpression()), !dbg !43 + call void @llvm.dbg.declare(metadata ptr %local_6__field4_u8, metadata !46, metadata !DIExpression()), !dbg !43 + store i1 false, ptr %local_7__field_combined_bool, align 1 + store i64 1, ptr %local_8__field_u64, align 8 + %fv.02 = load i64, ptr %local_8__field_u64, align 8 + %insert_03 = insertvalue %struct.M__U64Struct undef, i64 %fv.02, 0 + store %struct.M__U64Struct %insert_03, ptr %local_9__field_combined_u64_struct, align 8 + %fv.04 = load i1, ptr %local_7__field_combined_bool, align 1 + %fv.1 = load %struct.M__U64Struct, ptr %local_9__field_combined_u64_struct, align 8 + %insert_05 = insertvalue %struct.M__Combined undef, i1 %fv.04, 0 + %insert_1 = insertvalue %struct.M__Combined %insert_05, %struct.M__U64Struct %fv.1, 1 + store %struct.M__Combined %insert_1, ptr %local_10__field6_combined, align 8 + %fv.06 = load i32, ptr %local_2__field1_u32, align 4 + %fv.17 = load i1, ptr %local_3__field2_bool, align 1 + %fv.2 = load %struct.M__EmptyStruct, ptr %local_5__field3_empty, align 1 + %fv.3 = load i8, ptr %local_6__field4_u8, align 1 + %fv.4 = load %struct.M__Combined, ptr %local_10__field6_combined, align 8 + %insert_08 = insertvalue %struct.M__MyStruct undef, i32 %fv.06, 0 + %insert_19 = insertvalue %struct.M__MyStruct %insert_08, i1 %fv.17, 1 + %insert_2 = insertvalue %struct.M__MyStruct %insert_19, %struct.M__EmptyStruct %fv.2, 2 + %insert_3 = insertvalue %struct.M__MyStruct %insert_2, i8 %fv.3, 3 + %insert_4 = insertvalue %struct.M__MyStruct %insert_3, %struct.M__Combined %fv.4, 4 + store %struct.M__MyStruct %insert_4, ptr %local_11, align 8 + %retval = load %struct.M__MyStruct, ptr %local_11, align 8 + ret %struct.M__MyStruct %retval +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 + +attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } !llvm.dbg.cu = !{!0} -!struct.M__EmptyStruct = !{!2} -!struct.M__U64Struct = !{!8} -!struct.M__Combined = !{!14} -!struct.M__MyStruct = !{!20} -!fun_1 = !{!31} +!fun_1 = !{!2, !8, !9, !10} +!struct.M__EmptyStruct = !{!11} +!struct.M__U64Struct = !{!16} +!struct.M__Combined = !{!22} +!struct.M__MyStruct = !{!28} !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "move-mv-llvm-compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, sysroot: "/") !1 = !DIFile(filename: "dwarf-functions.move", directory: "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests") -!2 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__EmptyStruct__ptr", baseType: !3, size: 64, align: 64, dwarfAddressSpace: 0) -!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !4, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !5) -!4 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) -!5 = !{!6} -!6 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !4, file: !1, line: 27, baseType: !7, size: 1, align: 8) -!7 = !DIBasicType(name: "bool", size: 8) -!8 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__U64Struct__ptr", baseType: !9, size: 64, align: 64, dwarfAddressSpace: 0) -!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !10, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !11) -!10 = !DINamespace(name: "struct.M__U64Struct", scope: !1) -!11 = !{!12} -!12 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !10, file: !1, line: 29, baseType: !13, size: 64, align: 64) -!13 = !DIBasicType(name: "u64", size: 64) -!14 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__Combined__ptr", baseType: !15, size: 64, align: 64, dwarfAddressSpace: 0) -!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !16, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !17) -!16 = !DINamespace(name: "struct.M__Combined", scope: !1) -!17 = !{!18, !19} -!18 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !16, file: !1, line: 31, baseType: !7, size: 1, align: 8) -!19 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !16, file: !1, line: 32, baseType: !9, size: 64, align: 64, offset: 8) -!20 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct__ptr", baseType: !21, size: 64, align: 64, dwarfAddressSpace: 0) -!21 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !22, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !23) -!22 = !DINamespace(name: "struct.M__MyStruct", scope: !1) -!23 = !{!24, !26, !27, !28, !30} -!24 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !22, file: !1, line: 19, baseType: !25, size: 32, align: 32) -!25 = !DIBasicType(name: "u32", size: 32) -!26 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !22, file: !1, line: 20, baseType: !7, size: 1, align: 8, offset: 32) -!27 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !22, file: !1, line: 21, baseType: !3, size: 8, align: 8, offset: 40) -!28 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !22, file: !1, line: 22, baseType: !29, size: 8, align: 8, offset: 48) -!29 = !DIBasicType(name: "u8", size: 8) -!30 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !22, file: !1, line: 23, baseType: !15, size: 128, align: 64, offset: 56) -!31 = distinct !DISubprogram(name: "fun_1", linkageName: "fun_1", scope: !32, file: !1, line: 33, type: !33, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !37) -!32 = !DINamespace(name: "fun_1", scope: !1) -!33 = !DISubroutineType(types: !34) -!34 = !{!35, !36} -!35 = !DILocalVariable(name: "par_1_u8", scope: !32, file: !1, type: !29) -!36 = !DILocalVariable(name: "par_2_bool", arg: 1, scope: !32, file: !1, line: 1, type: !7) -!37 = !{} +!2 = distinct !DISubprogram(name: "fun_1", linkageName: "fun_1", scope: !1, file: !1, line: 33, type: !3, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !7) +!3 = !DISubroutineType(types: !4) +!4 = !{!5, !6} +!5 = !DIBasicType(name: "u8", size: 8) +!6 = !DIBasicType(name: "bool", size: 8) +!7 = !{} +!8 = distinct !DILexicalBlock(scope: !2, file: !1, line: 5) +!9 = !DINamespace(name: "fun_1", scope: !1) +!10 = !DILocation(line: 33, column: 4, scope: !8) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__EmptyStruct__ptr", baseType: !12, size: 64, align: 64, dwarfAddressSpace: 0) +!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !13, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !14) +!13 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !13, file: !1, line: 27, baseType: !6, size: 1, align: 8) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__U64Struct__ptr", baseType: !17, size: 64, align: 64, dwarfAddressSpace: 0) +!17 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !18, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !19) +!18 = !DINamespace(name: "struct.M__U64Struct", scope: !1) +!19 = !{!20} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !18, file: !1, line: 29, baseType: !21, size: 64, align: 64) +!21 = !DIBasicType(name: "u64", size: 64) +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__Combined__ptr", baseType: !23, size: 64, align: 64, dwarfAddressSpace: 0) +!23 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !24, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !25) +!24 = !DINamespace(name: "struct.M__Combined", scope: !1) +!25 = !{!26, !27} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !24, file: !1, line: 31, baseType: !6, size: 1, align: 8) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !24, file: !1, line: 32, baseType: !17, size: 64, align: 64, offset: 8) +!28 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct__ptr", baseType: !29, size: 64, align: 64, dwarfAddressSpace: 0) +!29 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !30, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !31) +!30 = !DINamespace(name: "struct.M__MyStruct", scope: !1) +!31 = !{!32, !34, !35, !36, !37} +!32 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !30, file: !1, line: 19, baseType: !33, size: 32, align: 32) +!33 = !DIBasicType(name: "u32", size: 32) +!34 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !30, file: !1, line: 20, baseType: !6, size: 1, align: 8, offset: 32) +!35 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !30, file: !1, line: 21, baseType: !12, size: 8, align: 8, offset: 40) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !30, file: !1, line: 22, baseType: !5, size: 8, align: 8, offset: 48) +!37 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !30, file: !1, line: 23, baseType: !23, size: 128, align: 64, offset: 56) +!38 = !DILocation(line: 37, column: 26, scope: !2) +!39 = !DILocalVariable(name: "load_store_/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move_37_par_2_bool", scope: !40, file: !1, line: 37, type: !6) +!40 = distinct !DILexicalBlock(scope: !2, file: !1, line: 37, column: 26) +!41 = !DILocalVariable(name: "load_store_/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move_37_par_2_bool", scope: !42, file: !1, line: 37, type: !6) +!42 = distinct !DILexicalBlock(scope: !2, file: !1, line: 37, column: 26) +!43 = !DILocation(line: 39, column: 24, scope: !2) +!44 = !DILocalVariable(name: "load_store_/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move_39_par_1_u8", scope: !45, file: !1, line: 39, type: !5) +!45 = distinct !DILexicalBlock(scope: !2, file: !1, line: 39, column: 24) +!46 = !DILocalVariable(name: "load_store_/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move_39_par_1_u8", scope: !47, file: !1, line: 39, type: !5) +!47 = distinct !DILexicalBlock(scope: !2, file: !1, line: 39, column: 24) diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x201__M.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x201__M.ll.debug_info.expected index 4002c05fd9..fb7bbd57bc 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x201__M.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions-build/0x201__M.ll.debug_info.expected @@ -1,46 +1,98 @@ -; ModuleID = '0x201__M.dbg_info' +; ModuleID = '0x201__M' source_filename = "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +%struct.M__MyStruct_2 = type { i32, %struct.M__MyStruct } +%struct.M__MyStruct = type { i32, i1, %struct.M__EmptyStruct, i8, %struct.M__Combined } +%struct.M__EmptyStruct = type { i1 } +%struct.M__Combined = type { i1, %struct.M__U64Struct } +%struct.M__U64Struct = type { i64 } + +declare i32 @memcmp(ptr, ptr, i64) + +define %struct.M__MyStruct_2 @"0000000000000201_M_fun_2_2AUudfp1Qwf7h7"(i32 %par_1_u32) !dbg !2 { +entry: + %local_0 = alloca i32, align 4 + %local_1__field1_u32 = alloca i32, align 4 + %local_2 = alloca i8, align 1 + %local_3 = alloca i1, align 1 + %local_4__other_my_struct_from_101 = alloca %struct.M__MyStruct, align 8 + %local_5 = alloca %struct.M__MyStruct_2, align 8 + store i32 %par_1_u32, ptr %local_0, align 4 + %load_store_tmp = load i32, ptr %local_0, align 4, !dbg !40 + store i32 %load_store_tmp, ptr %local_1__field1_u32, align 4, !dbg !40 + call void @llvm.dbg.declare(metadata ptr %local_0, metadata !41, metadata !DIExpression()), !dbg !40 + call void @llvm.dbg.declare(metadata ptr %local_1__field1_u32, metadata !43, metadata !DIExpression()), !dbg !40 + store i8 7, ptr %local_2, align 1 + store i1 true, ptr %local_3, align 1 + %call_arg_0 = load i8, ptr %local_2, align 1 + %call_arg_1 = load i1, ptr %local_3, align 1 + %retval = call %struct.M__MyStruct @"0000000000000101_M_fun_1_AcLtMspYikxikv"(i8 %call_arg_0, i1 %call_arg_1), !dbg !45 + store %struct.M__MyStruct %retval, ptr %local_4__other_my_struct_from_101, align 8 + %fv.0 = load i32, ptr %local_1__field1_u32, align 4 + %fv.1 = load %struct.M__MyStruct, ptr %local_4__other_my_struct_from_101, align 8 + %insert_0 = insertvalue %struct.M__MyStruct_2 undef, i32 %fv.0, 0 + %insert_1 = insertvalue %struct.M__MyStruct_2 %insert_0, %struct.M__MyStruct %fv.1, 1 + store %struct.M__MyStruct_2 %insert_1, ptr %local_5, align 8 + %retval1 = load %struct.M__MyStruct_2, ptr %local_5, align 8 + ret %struct.M__MyStruct_2 %retval1 +} + +declare %struct.M__MyStruct @"0000000000000101_M_fun_1_AcLtMspYikxikv"(i8, i1) + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 + +attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } !llvm.dbg.cu = !{!0} -!struct.M__MyStruct_2 = !{!2} -!fun_2 = !{!33} +!fun_2 = !{!2, !7, !8, !9} +!struct.M__MyStruct_2 = !{!10} !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "move-mv-llvm-compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, sysroot: "/") !1 = !DIFile(filename: "dwarf-functions.move", directory: "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests") -!2 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct_2__ptr", baseType: !3, size: 64, align: 64, dwarfAddressSpace: 0) -!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct_2", scope: !4, file: !1, line: 2, size: 256, align: 8, flags: DIFlagObjcClassComplete, elements: !5) -!4 = !DINamespace(name: "struct.M__MyStruct_2", scope: !1) -!5 = !{!6, !8} -!6 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !4, file: !1, line: 2, baseType: !7, size: 32, align: 32) -!7 = !DIBasicType(name: "u32", size: 32) -!8 = !DIDerivedType(tag: DW_TAG_member, name: "other_my_struct_from_101", scope: !4, file: !1, line: 3, baseType: !9, size: 192, align: 64, offset: 32) -!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !10, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !11) -!10 = !DINamespace(name: "struct.M__MyStruct", scope: !1) -!11 = !{!12, !13, !15, !20, !22} -!12 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !10, file: !1, line: 19, baseType: !7, size: 32, align: 32) -!13 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !10, file: !1, line: 20, baseType: !14, size: 1, align: 8, offset: 32) -!14 = !DIBasicType(name: "bool", size: 8) -!15 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !10, file: !1, line: 21, baseType: !16, size: 8, align: 8, offset: 40) -!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !17, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !18) -!17 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) -!18 = !{!19} -!19 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !17, file: !1, line: 27, baseType: !14, size: 1, align: 8) -!20 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !10, file: !1, line: 22, baseType: !21, size: 8, align: 8, offset: 48) -!21 = !DIBasicType(name: "u8", size: 8) -!22 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !10, file: !1, line: 23, baseType: !23, size: 128, align: 64, offset: 56) -!23 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !24, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !25) -!24 = !DINamespace(name: "struct.M__Combined", scope: !1) -!25 = !{!26, !27} -!26 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !24, file: !1, line: 31, baseType: !14, size: 1, align: 8) -!27 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !24, file: !1, line: 32, baseType: !28, size: 64, align: 64, offset: 8) -!28 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !29, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !30) -!29 = !DINamespace(name: "struct.M__U64Struct", scope: !1) -!30 = !{!31} -!31 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !29, file: !1, line: 29, baseType: !32, size: 64, align: 64) -!32 = !DIBasicType(name: "u64", size: 64) -!33 = distinct !DISubprogram(name: "fun_2", linkageName: "fun_2", scope: !34, file: !1, line: 7, type: !35, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !38) -!34 = !DINamespace(name: "fun_2", scope: !1) -!35 = !DISubroutineType(types: !36) -!36 = !{!37} -!37 = !DILocalVariable(name: "par_1_u32", scope: !34, file: !1, type: !7) -!38 = !{} +!2 = distinct !DISubprogram(name: "fun_2", linkageName: "fun_2", scope: !1, file: !1, line: 7, type: !3, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !6) +!3 = !DISubroutineType(types: !4) +!4 = !{!5} +!5 = !DIBasicType(name: "u32", size: 32) +!6 = !{} +!7 = distinct !DILexicalBlock(scope: !2, file: !1, line: 5) +!8 = !DINamespace(name: "fun_2", scope: !1) +!9 = !DILocation(line: 7, column: 4, scope: !7) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct_2__ptr", baseType: !11, size: 64, align: 64, dwarfAddressSpace: 0) +!11 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct_2", scope: !12, file: !1, line: 2, size: 256, align: 8, flags: DIFlagObjcClassComplete, elements: !13) +!12 = !DINamespace(name: "struct.M__MyStruct_2", scope: !1) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !12, file: !1, line: 2, baseType: !5, size: 32, align: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "other_my_struct_from_101", scope: !12, file: !1, line: 3, baseType: !16, size: 192, align: 64, offset: 32) +!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !17, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !18) +!17 = !DINamespace(name: "struct.M__MyStruct", scope: !1) +!18 = !{!19, !20, !22, !27, !29} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !17, file: !1, line: 19, baseType: !5, size: 32, align: 32) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !17, file: !1, line: 20, baseType: !21, size: 1, align: 8, offset: 32) +!21 = !DIBasicType(name: "bool", size: 8) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !17, file: !1, line: 21, baseType: !23, size: 8, align: 8, offset: 40) +!23 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !24, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !25) +!24 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) +!25 = !{!26} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !24, file: !1, line: 27, baseType: !21, size: 1, align: 8) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !17, file: !1, line: 22, baseType: !28, size: 8, align: 8, offset: 48) +!28 = !DIBasicType(name: "u8", size: 8) +!29 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !17, file: !1, line: 23, baseType: !30, size: 128, align: 64, offset: 56) +!30 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !31, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !32) +!31 = !DINamespace(name: "struct.M__Combined", scope: !1) +!32 = !{!33, !34} +!33 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !31, file: !1, line: 31, baseType: !21, size: 1, align: 8) +!34 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !31, file: !1, line: 32, baseType: !35, size: 64, align: 64, offset: 8) +!35 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !36, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !37) +!36 = !DINamespace(name: "struct.M__U64Struct", scope: !1) +!37 = !{!38} +!38 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !36, file: !1, line: 29, baseType: !39, size: 64, align: 64) +!39 = !DIBasicType(name: "u64", size: 64) +!40 = !DILocation(line: 10, column: 25, scope: !2) +!41 = !DILocalVariable(name: "load_store_/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move_10_par_1_u32", scope: !42, file: !1, line: 10, type: !5) +!42 = distinct !DILexicalBlock(scope: !2, file: !1, line: 10, column: 25) +!43 = !DILocalVariable(name: "load_store_/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-functions.move_10_par_1_u32", scope: !44, file: !1, line: 10, type: !5) +!44 = distinct !DILexicalBlock(scope: !2, file: !1, line: 10, column: 25) +!45 = !DILocation(line: 11, column: 39, scope: !2) diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x101__M.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x101__M.ll.debug_info.expected index 0e7c82182c..f098df8bf6 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x101__M.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x101__M.ll.debug_info.expected @@ -1,45 +1,100 @@ -; ModuleID = '0x101__M.dbg_info' +; ModuleID = '0x101__M' source_filename = "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +%struct.M__MyStruct = type { i32, i1, %struct.M__EmptyStruct, i8, %struct.M__Combined } +%struct.M__EmptyStruct = type { i1 } +%struct.M__Combined = type { i1, %struct.M__U64Struct } +%struct.M__U64Struct = type { i64 } + +declare i32 @memcmp(ptr, ptr, i64) + +define %struct.M__MyStruct @"0000000000000101_M_fun_1_AcLtMspYikxikv"() !dbg !2 { +entry: + %local_0__field1_u32 = alloca i32, align 4 + %local_1__field2_bool = alloca i1, align 1 + %local_2__dummy_field = alloca i1, align 1 + %local_3__field3_empty = alloca %struct.M__EmptyStruct, align 8 + %local_4__field4_u8 = alloca i8, align 1 + %local_5__field_combined_bool = alloca i1, align 1 + %local_6__field_u64 = alloca i64, align 8 + %local_7__field_combined_u64_struct = alloca %struct.M__U64Struct, align 8 + %local_8__field6_combined = alloca %struct.M__Combined, align 8 + %local_9 = alloca %struct.M__MyStruct, align 8 + store i32 15, ptr %local_0__field1_u32, align 4 + store i1 true, ptr %local_1__field2_bool, align 1 + store i1 false, ptr %local_2__dummy_field, align 1 + %fv.0 = load i1, ptr %local_2__dummy_field, align 1 + %insert_0 = insertvalue %struct.M__EmptyStruct undef, i1 %fv.0, 0 + store %struct.M__EmptyStruct %insert_0, ptr %local_3__field3_empty, align 1 + store i8 7, ptr %local_4__field4_u8, align 1 + store i1 false, ptr %local_5__field_combined_bool, align 1 + store i64 1, ptr %local_6__field_u64, align 8 + %fv.01 = load i64, ptr %local_6__field_u64, align 8 + %insert_02 = insertvalue %struct.M__U64Struct undef, i64 %fv.01, 0 + store %struct.M__U64Struct %insert_02, ptr %local_7__field_combined_u64_struct, align 8 + %fv.03 = load i1, ptr %local_5__field_combined_bool, align 1 + %fv.1 = load %struct.M__U64Struct, ptr %local_7__field_combined_u64_struct, align 8 + %insert_04 = insertvalue %struct.M__Combined undef, i1 %fv.03, 0 + %insert_1 = insertvalue %struct.M__Combined %insert_04, %struct.M__U64Struct %fv.1, 1 + store %struct.M__Combined %insert_1, ptr %local_8__field6_combined, align 8 + %fv.05 = load i32, ptr %local_0__field1_u32, align 4 + %fv.16 = load i1, ptr %local_1__field2_bool, align 1 + %fv.2 = load %struct.M__EmptyStruct, ptr %local_3__field3_empty, align 1 + %fv.3 = load i8, ptr %local_4__field4_u8, align 1 + %fv.4 = load %struct.M__Combined, ptr %local_8__field6_combined, align 8 + %insert_07 = insertvalue %struct.M__MyStruct undef, i32 %fv.05, 0 + %insert_18 = insertvalue %struct.M__MyStruct %insert_07, i1 %fv.16, 1 + %insert_2 = insertvalue %struct.M__MyStruct %insert_18, %struct.M__EmptyStruct %fv.2, 2 + %insert_3 = insertvalue %struct.M__MyStruct %insert_2, i8 %fv.3, 3 + %insert_4 = insertvalue %struct.M__MyStruct %insert_3, %struct.M__Combined %fv.4, 4 + store %struct.M__MyStruct %insert_4, ptr %local_9, align 8 + %retval = load %struct.M__MyStruct, ptr %local_9, align 8 + ret %struct.M__MyStruct %retval +} !llvm.dbg.cu = !{!0} -!struct.M__EmptyStruct = !{!2} -!struct.M__U64Struct = !{!8} -!struct.M__Combined = !{!14} -!struct.M__MyStruct = !{!20} -!fun_1 = !{!31} +!fun_1 = !{!2, !5, !6, !7} +!struct.M__EmptyStruct = !{!8} +!struct.M__U64Struct = !{!14} +!struct.M__Combined = !{!20} +!struct.M__MyStruct = !{!26} !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "move-mv-llvm-compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, sysroot: "/") !1 = !DIFile(filename: "dwarf-struct-2-modules.move", directory: "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests") -!2 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__EmptyStruct__ptr", baseType: !3, size: 64, align: 64, dwarfAddressSpace: 0) -!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !4, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !5) -!4 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) -!5 = !{!6} -!6 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !4, file: !1, line: 27, baseType: !7, size: 1, align: 8) -!7 = !DIBasicType(name: "bool", size: 8) -!8 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__U64Struct__ptr", baseType: !9, size: 64, align: 64, dwarfAddressSpace: 0) -!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !10, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !11) -!10 = !DINamespace(name: "struct.M__U64Struct", scope: !1) +!2 = distinct !DISubprogram(name: "fun_1", linkageName: "fun_1", scope: !1, file: !1, line: 33, type: !3, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !4) +!3 = !DISubroutineType(types: !4) +!4 = !{} +!5 = distinct !DILexicalBlock(scope: !2, file: !1, line: 5) +!6 = !DINamespace(name: "fun_1", scope: !1) +!7 = !DILocation(line: 33, column: 4, scope: !5) +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__EmptyStruct__ptr", baseType: !9, size: 64, align: 64, dwarfAddressSpace: 0) +!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !10, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !11) +!10 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) !11 = !{!12} -!12 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !10, file: !1, line: 29, baseType: !13, size: 64, align: 64) -!13 = !DIBasicType(name: "u64", size: 64) -!14 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__Combined__ptr", baseType: !15, size: 64, align: 64, dwarfAddressSpace: 0) -!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !16, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !17) -!16 = !DINamespace(name: "struct.M__Combined", scope: !1) -!17 = !{!18, !19} -!18 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !16, file: !1, line: 31, baseType: !7, size: 1, align: 8) -!19 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !16, file: !1, line: 32, baseType: !9, size: 64, align: 64, offset: 8) -!20 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct__ptr", baseType: !21, size: 64, align: 64, dwarfAddressSpace: 0) -!21 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !22, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !23) -!22 = !DINamespace(name: "struct.M__MyStruct", scope: !1) -!23 = !{!24, !26, !27, !28, !30} -!24 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !22, file: !1, line: 19, baseType: !25, size: 32, align: 32) -!25 = !DIBasicType(name: "u32", size: 32) -!26 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !22, file: !1, line: 20, baseType: !7, size: 1, align: 8, offset: 32) -!27 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !22, file: !1, line: 21, baseType: !3, size: 8, align: 8, offset: 40) -!28 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !22, file: !1, line: 22, baseType: !29, size: 8, align: 8, offset: 48) -!29 = !DIBasicType(name: "u8", size: 8) -!30 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !22, file: !1, line: 23, baseType: !15, size: 128, align: 64, offset: 56) -!31 = distinct !DISubprogram(name: "fun_1", linkageName: "fun_1", scope: !32, file: !1, line: 33, type: !33, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !34) -!32 = !DINamespace(name: "fun_1", scope: !1) -!33 = !DISubroutineType(types: !34) -!34 = !{} +!12 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !10, file: !1, line: 27, baseType: !13, size: 1, align: 8) +!13 = !DIBasicType(name: "bool", size: 8) +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__U64Struct__ptr", baseType: !15, size: 64, align: 64, dwarfAddressSpace: 0) +!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !16, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !17) +!16 = !DINamespace(name: "struct.M__U64Struct", scope: !1) +!17 = !{!18} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !16, file: !1, line: 29, baseType: !19, size: 64, align: 64) +!19 = !DIBasicType(name: "u64", size: 64) +!20 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__Combined__ptr", baseType: !21, size: 64, align: 64, dwarfAddressSpace: 0) +!21 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !22, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !23) +!22 = !DINamespace(name: "struct.M__Combined", scope: !1) +!23 = !{!24, !25} +!24 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !22, file: !1, line: 31, baseType: !13, size: 1, align: 8) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !22, file: !1, line: 32, baseType: !15, size: 64, align: 64, offset: 8) +!26 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct__ptr", baseType: !27, size: 64, align: 64, dwarfAddressSpace: 0) +!27 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !28, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !29) +!28 = !DINamespace(name: "struct.M__MyStruct", scope: !1) +!29 = !{!30, !32, !33, !34, !36} +!30 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !28, file: !1, line: 19, baseType: !31, size: 32, align: 32) +!31 = !DIBasicType(name: "u32", size: 32) +!32 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !28, file: !1, line: 20, baseType: !13, size: 1, align: 8, offset: 32) +!33 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !28, file: !1, line: 21, baseType: !9, size: 8, align: 8, offset: 40) +!34 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !28, file: !1, line: 22, baseType: !35, size: 8, align: 8, offset: 48) +!35 = !DIBasicType(name: "u8", size: 8) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !28, file: !1, line: 23, baseType: !21, size: 128, align: 64, offset: 56) diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x201__M.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x201__M.ll.debug_info.expected index c3227e09b9..81f8786646 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x201__M.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules-build/0x201__M.ll.debug_info.expected @@ -1,44 +1,76 @@ -; ModuleID = '0x201__M.dbg_info' +; ModuleID = '0x201__M' source_filename = "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-2-modules.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +%struct.M__MyStruct_2 = type { i32, %struct.M__MyStruct } +%struct.M__MyStruct = type { i32, i1, %struct.M__EmptyStruct, i8, %struct.M__Combined } +%struct.M__EmptyStruct = type { i1 } +%struct.M__Combined = type { i1, %struct.M__U64Struct } +%struct.M__U64Struct = type { i64 } + +declare i32 @memcmp(ptr, ptr, i64) + +define %struct.M__MyStruct_2 @"0000000000000201_M_fun_2_2AUudfp1Qwf7h7"() !dbg !2 { +entry: + %local_0__field1_u32 = alloca i32, align 4 + %local_1__other_my_struct_from_101 = alloca %struct.M__MyStruct, align 8 + %local_2 = alloca %struct.M__MyStruct_2, align 8 + store i32 15, ptr %local_0__field1_u32, align 4 + %retval = call %struct.M__MyStruct @"0000000000000101_M_fun_1_AcLtMspYikxikv"(), !dbg !39 + store %struct.M__MyStruct %retval, ptr %local_1__other_my_struct_from_101, align 8 + %fv.0 = load i32, ptr %local_0__field1_u32, align 4 + %fv.1 = load %struct.M__MyStruct, ptr %local_1__other_my_struct_from_101, align 8 + %insert_0 = insertvalue %struct.M__MyStruct_2 undef, i32 %fv.0, 0 + %insert_1 = insertvalue %struct.M__MyStruct_2 %insert_0, %struct.M__MyStruct %fv.1, 1 + store %struct.M__MyStruct_2 %insert_1, ptr %local_2, align 8 + %retval1 = load %struct.M__MyStruct_2, ptr %local_2, align 8 + ret %struct.M__MyStruct_2 %retval1 +} + +declare %struct.M__MyStruct @"0000000000000101_M_fun_1_AcLtMspYikxikv"() !llvm.dbg.cu = !{!0} -!struct.M__MyStruct_2 = !{!2} -!fun_2 = !{!33} +!fun_2 = !{!2, !5, !6, !7} +!struct.M__MyStruct_2 = !{!8} !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "move-mv-llvm-compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, sysroot: "/") !1 = !DIFile(filename: "dwarf-struct-2-modules.move", directory: "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests") -!2 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct_2__ptr", baseType: !3, size: 64, align: 64, dwarfAddressSpace: 0) -!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct_2", scope: !4, file: !1, line: 2, size: 256, align: 8, flags: DIFlagObjcClassComplete, elements: !5) -!4 = !DINamespace(name: "struct.M__MyStruct_2", scope: !1) -!5 = !{!6, !8} -!6 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !4, file: !1, line: 2, baseType: !7, size: 32, align: 32) -!7 = !DIBasicType(name: "u32", size: 32) -!8 = !DIDerivedType(tag: DW_TAG_member, name: "other_my_struct_from_101", scope: !4, file: !1, line: 3, baseType: !9, size: 192, align: 64, offset: 32) -!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !10, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !11) -!10 = !DINamespace(name: "struct.M__MyStruct", scope: !1) -!11 = !{!12, !13, !15, !20, !22} -!12 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !10, file: !1, line: 19, baseType: !7, size: 32, align: 32) -!13 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !10, file: !1, line: 20, baseType: !14, size: 1, align: 8, offset: 32) -!14 = !DIBasicType(name: "bool", size: 8) -!15 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !10, file: !1, line: 21, baseType: !16, size: 8, align: 8, offset: 40) -!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !17, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !18) -!17 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) -!18 = !{!19} -!19 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !17, file: !1, line: 27, baseType: !14, size: 1, align: 8) -!20 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !10, file: !1, line: 22, baseType: !21, size: 8, align: 8, offset: 48) -!21 = !DIBasicType(name: "u8", size: 8) -!22 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !10, file: !1, line: 23, baseType: !23, size: 128, align: 64, offset: 56) -!23 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !24, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !25) -!24 = !DINamespace(name: "struct.M__Combined", scope: !1) -!25 = !{!26, !27} -!26 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !24, file: !1, line: 31, baseType: !14, size: 1, align: 8) -!27 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !24, file: !1, line: 32, baseType: !28, size: 64, align: 64, offset: 8) -!28 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !29, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !30) -!29 = !DINamespace(name: "struct.M__U64Struct", scope: !1) -!30 = !{!31} -!31 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !29, file: !1, line: 29, baseType: !32, size: 64, align: 64) -!32 = !DIBasicType(name: "u64", size: 64) -!33 = distinct !DISubprogram(name: "fun_2", linkageName: "fun_2", scope: !34, file: !1, line: 7, type: !35, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !36) -!34 = !DINamespace(name: "fun_2", scope: !1) -!35 = !DISubroutineType(types: !36) -!36 = !{} +!2 = distinct !DISubprogram(name: "fun_2", linkageName: "fun_2", scope: !1, file: !1, line: 7, type: !3, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !4) +!3 = !DISubroutineType(types: !4) +!4 = !{} +!5 = distinct !DILexicalBlock(scope: !2, file: !1, line: 5) +!6 = !DINamespace(name: "fun_2", scope: !1) +!7 = !DILocation(line: 7, column: 4, scope: !5) +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct_2__ptr", baseType: !9, size: 64, align: 64, dwarfAddressSpace: 0) +!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct_2", scope: !10, file: !1, line: 2, size: 256, align: 8, flags: DIFlagObjcClassComplete, elements: !11) +!10 = !DINamespace(name: "struct.M__MyStruct_2", scope: !1) +!11 = !{!12, !14} +!12 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !10, file: !1, line: 2, baseType: !13, size: 32, align: 32) +!13 = !DIBasicType(name: "u32", size: 32) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "other_my_struct_from_101", scope: !10, file: !1, line: 3, baseType: !15, size: 192, align: 64, offset: 32) +!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !16, file: !1, line: 19, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !17) +!16 = !DINamespace(name: "struct.M__MyStruct", scope: !1) +!17 = !{!18, !19, !21, !26, !28} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !16, file: !1, line: 19, baseType: !13, size: 32, align: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !16, file: !1, line: 20, baseType: !20, size: 1, align: 8, offset: 32) +!20 = !DIBasicType(name: "bool", size: 8) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !16, file: !1, line: 21, baseType: !22, size: 8, align: 8, offset: 40) +!22 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !23, file: !1, line: 27, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !24) +!23 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) +!24 = !{!25} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !23, file: !1, line: 27, baseType: !20, size: 1, align: 8) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !16, file: !1, line: 22, baseType: !27, size: 8, align: 8, offset: 48) +!27 = !DIBasicType(name: "u8", size: 8) +!28 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !16, file: !1, line: 23, baseType: !29, size: 128, align: 64, offset: 56) +!29 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !30, file: !1, line: 31, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !31) +!30 = !DINamespace(name: "struct.M__Combined", scope: !1) +!31 = !{!32, !33} +!32 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !30, file: !1, line: 31, baseType: !20, size: 1, align: 8) +!33 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !30, file: !1, line: 32, baseType: !34, size: 64, align: 64, offset: 8) +!34 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !35, file: !1, line: 29, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !36) +!35 = !DINamespace(name: "struct.M__U64Struct", scope: !1) +!36 = !{!37} +!37 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !35, file: !1, line: 29, baseType: !38, size: 64, align: 64) +!38 = !DIBasicType(name: "u64", size: 64) +!39 = !DILocation(line: 11, column: 39, scope: !2) diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-build/0x100__M.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-build/0x100__M.ll.debug_info.expected index c38d44d4a4..0239cca6a5 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-build/0x100__M.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct-build/0x100__M.ll.debug_info.expected @@ -1,45 +1,100 @@ -; ModuleID = '0x100__M.dbg_info' +; ModuleID = '0x100__M' source_filename = "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-struct.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +%struct.M__MyStruct = type { i32, i1, %struct.M__EmptyStruct, i8, %struct.M__Combined } +%struct.M__EmptyStruct = type { i1 } +%struct.M__Combined = type { i1, %struct.M__U64Struct } +%struct.M__U64Struct = type { i64 } + +declare i32 @memcmp(ptr, ptr, i64) + +define %struct.M__MyStruct @"0000000000000100_M_fun_1_9t9szYU8mToycs"() !dbg !2 { +entry: + %local_0__field1_u32 = alloca i32, align 4 + %local_1__field2_bool = alloca i1, align 1 + %local_2__dummy_field = alloca i1, align 1 + %local_3__field3_empty = alloca %struct.M__EmptyStruct, align 8 + %local_4__field4_u8 = alloca i8, align 1 + %local_5__field_combined_bool = alloca i1, align 1 + %local_6__field_u64 = alloca i64, align 8 + %local_7__field_combined_u64_struct = alloca %struct.M__U64Struct, align 8 + %local_8__field6_combined = alloca %struct.M__Combined, align 8 + %local_9 = alloca %struct.M__MyStruct, align 8 + store i32 15, ptr %local_0__field1_u32, align 4 + store i1 true, ptr %local_1__field2_bool, align 1 + store i1 false, ptr %local_2__dummy_field, align 1 + %fv.0 = load i1, ptr %local_2__dummy_field, align 1 + %insert_0 = insertvalue %struct.M__EmptyStruct undef, i1 %fv.0, 0 + store %struct.M__EmptyStruct %insert_0, ptr %local_3__field3_empty, align 1 + store i8 7, ptr %local_4__field4_u8, align 1 + store i1 false, ptr %local_5__field_combined_bool, align 1 + store i64 1, ptr %local_6__field_u64, align 8 + %fv.01 = load i64, ptr %local_6__field_u64, align 8 + %insert_02 = insertvalue %struct.M__U64Struct undef, i64 %fv.01, 0 + store %struct.M__U64Struct %insert_02, ptr %local_7__field_combined_u64_struct, align 8 + %fv.03 = load i1, ptr %local_5__field_combined_bool, align 1 + %fv.1 = load %struct.M__U64Struct, ptr %local_7__field_combined_u64_struct, align 8 + %insert_04 = insertvalue %struct.M__Combined undef, i1 %fv.03, 0 + %insert_1 = insertvalue %struct.M__Combined %insert_04, %struct.M__U64Struct %fv.1, 1 + store %struct.M__Combined %insert_1, ptr %local_8__field6_combined, align 8 + %fv.05 = load i32, ptr %local_0__field1_u32, align 4 + %fv.16 = load i1, ptr %local_1__field2_bool, align 1 + %fv.2 = load %struct.M__EmptyStruct, ptr %local_3__field3_empty, align 1 + %fv.3 = load i8, ptr %local_4__field4_u8, align 1 + %fv.4 = load %struct.M__Combined, ptr %local_8__field6_combined, align 8 + %insert_07 = insertvalue %struct.M__MyStruct undef, i32 %fv.05, 0 + %insert_18 = insertvalue %struct.M__MyStruct %insert_07, i1 %fv.16, 1 + %insert_2 = insertvalue %struct.M__MyStruct %insert_18, %struct.M__EmptyStruct %fv.2, 2 + %insert_3 = insertvalue %struct.M__MyStruct %insert_2, i8 %fv.3, 3 + %insert_4 = insertvalue %struct.M__MyStruct %insert_3, %struct.M__Combined %fv.4, 4 + store %struct.M__MyStruct %insert_4, ptr %local_9, align 8 + %retval = load %struct.M__MyStruct, ptr %local_9, align 8 + ret %struct.M__MyStruct %retval +} !llvm.dbg.cu = !{!0} -!struct.M__EmptyStruct = !{!2} -!struct.M__U64Struct = !{!8} -!struct.M__Combined = !{!14} -!struct.M__MyStruct = !{!20} -!fun_1 = !{!31} +!fun_1 = !{!2, !5, !6, !7} +!struct.M__EmptyStruct = !{!8} +!struct.M__U64Struct = !{!14} +!struct.M__Combined = !{!20} +!struct.M__MyStruct = !{!26} !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "move-mv-llvm-compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, sysroot: "/") !1 = !DIFile(filename: "dwarf-struct.move", directory: "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests") -!2 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__EmptyStruct__ptr", baseType: !3, size: 64, align: 64, dwarfAddressSpace: 0) -!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !4, file: !1, line: 10, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !5) -!4 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) -!5 = !{!6} -!6 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !4, file: !1, line: 10, baseType: !7, size: 1, align: 8) -!7 = !DIBasicType(name: "bool", size: 8) -!8 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__U64Struct__ptr", baseType: !9, size: 64, align: 64, dwarfAddressSpace: 0) -!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !10, file: !1, line: 12, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !11) -!10 = !DINamespace(name: "struct.M__U64Struct", scope: !1) +!2 = distinct !DISubprogram(name: "fun_1", linkageName: "fun_1", scope: !1, file: !1, line: 16, type: !3, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !4) +!3 = !DISubroutineType(types: !4) +!4 = !{} +!5 = distinct !DILexicalBlock(scope: !2, file: !1, line: 5) +!6 = !DINamespace(name: "fun_1", scope: !1) +!7 = !DILocation(line: 16, column: 4, scope: !5) +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__EmptyStruct__ptr", baseType: !9, size: 64, align: 64, dwarfAddressSpace: 0) +!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__EmptyStruct", scope: !10, file: !1, line: 10, size: 8, align: 8, flags: DIFlagObjcClassComplete, elements: !11) +!10 = !DINamespace(name: "struct.M__EmptyStruct", scope: !1) !11 = !{!12} -!12 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !10, file: !1, line: 12, baseType: !13, size: 64, align: 64) -!13 = !DIBasicType(name: "u64", size: 64) -!14 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__Combined__ptr", baseType: !15, size: 64, align: 64, dwarfAddressSpace: 0) -!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !16, file: !1, line: 14, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !17) -!16 = !DINamespace(name: "struct.M__Combined", scope: !1) -!17 = !{!18, !19} -!18 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !16, file: !1, line: 14, baseType: !7, size: 1, align: 8) -!19 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !16, file: !1, line: 15, baseType: !9, size: 64, align: 64, offset: 8) -!20 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct__ptr", baseType: !21, size: 64, align: 64, dwarfAddressSpace: 0) -!21 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !22, file: !1, line: 2, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !23) -!22 = !DINamespace(name: "struct.M__MyStruct", scope: !1) -!23 = !{!24, !26, !27, !28, !30} -!24 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !22, file: !1, line: 2, baseType: !25, size: 32, align: 32) -!25 = !DIBasicType(name: "u32", size: 32) -!26 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !22, file: !1, line: 3, baseType: !7, size: 1, align: 8, offset: 32) -!27 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !22, file: !1, line: 4, baseType: !3, size: 8, align: 8, offset: 40) -!28 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !22, file: !1, line: 5, baseType: !29, size: 8, align: 8, offset: 48) -!29 = !DIBasicType(name: "u8", size: 8) -!30 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !22, file: !1, line: 6, baseType: !15, size: 128, align: 64, offset: 56) -!31 = distinct !DISubprogram(name: "fun_1", linkageName: "fun_1", scope: !32, file: !1, line: 16, type: !33, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !34) -!32 = !DINamespace(name: "fun_1", scope: !1) -!33 = !DISubroutineType(types: !34) -!34 = !{} +!12 = !DIDerivedType(tag: DW_TAG_member, name: "dummy_field", scope: !10, file: !1, line: 10, baseType: !13, size: 1, align: 8) +!13 = !DIBasicType(name: "bool", size: 8) +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__U64Struct__ptr", baseType: !15, size: 64, align: 64, dwarfAddressSpace: 0) +!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__U64Struct", scope: !16, file: !1, line: 12, size: 64, align: 8, flags: DIFlagObjcClassComplete, elements: !17) +!16 = !DINamespace(name: "struct.M__U64Struct", scope: !1) +!17 = !{!18} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "field_u64", scope: !16, file: !1, line: 12, baseType: !19, size: 64, align: 64) +!19 = !DIBasicType(name: "u64", size: 64) +!20 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__Combined__ptr", baseType: !21, size: 64, align: 64, dwarfAddressSpace: 0) +!21 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__Combined", scope: !22, file: !1, line: 14, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !23) +!22 = !DINamespace(name: "struct.M__Combined", scope: !1) +!23 = !{!24, !25} +!24 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_bool", scope: !22, file: !1, line: 14, baseType: !13, size: 1, align: 8) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "field_combined_u64_struct", scope: !22, file: !1, line: 15, baseType: !15, size: 64, align: 64, offset: 8) +!26 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.M__MyStruct__ptr", baseType: !27, size: 64, align: 64, dwarfAddressSpace: 0) +!27 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.M__MyStruct", scope: !28, file: !1, line: 2, size: 192, align: 8, flags: DIFlagObjcClassComplete, elements: !29) +!28 = !DINamespace(name: "struct.M__MyStruct", scope: !1) +!29 = !{!30, !32, !33, !34, !36} +!30 = !DIDerivedType(tag: DW_TAG_member, name: "field1_u32", scope: !28, file: !1, line: 2, baseType: !31, size: 32, align: 32) +!31 = !DIBasicType(name: "u32", size: 32) +!32 = !DIDerivedType(tag: DW_TAG_member, name: "field2_bool", scope: !28, file: !1, line: 3, baseType: !13, size: 1, align: 8, offset: 32) +!33 = !DIDerivedType(tag: DW_TAG_member, name: "field3_empty", scope: !28, file: !1, line: 4, baseType: !9, size: 8, align: 8, offset: 40) +!34 = !DIDerivedType(tag: DW_TAG_member, name: "field4_u8", scope: !28, file: !1, line: 5, baseType: !35, size: 8, align: 8, offset: 48) +!35 = !DIBasicType(name: "u8", size: 8) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "field6_combined", scope: !28, file: !1, line: 6, baseType: !21, size: 128, align: 64, offset: 56) diff --git a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-vector-build/0x101__vector.ll.debug_info.expected b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-vector-build/0x101__vector.ll.debug_info.expected index f7cf0b7995..ab55f0893a 100644 --- a/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-vector-build/0x101__vector.ll.debug_info.expected +++ b/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-vector-build/0x101__vector.ll.debug_info.expected @@ -1,41 +1,237 @@ -; ModuleID = '0x101__vector.dbg_info' +; ModuleID = '0x101__vector' source_filename = "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests/dwarf-vector.move" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf-solana-solana" + +%__move_rt_type = type { { ptr, i64 }, i64, ptr } +%struct.vector__Bar = type { %struct.vector__Foo } +%struct.vector__Foo = type { i64, i1 } + +@__move_rttydesc_vector__Foo = private unnamed_addr constant %__move_rt_type { { ptr, i64 } { ptr @__move_rttydesc_vector__Foo_name, i64 77 }, i64 11, ptr @__move_rttydesc_vector__Foo_info } +@__move_rttydesc_vector__Foo_name = private unnamed_addr constant [77 x i8] c"0000000000000000000000000000000000000000000000000000000000000101::vector::Foo" +@__move_rttydesc_u64_name = private unnamed_addr constant [3 x i8] c"u64" +@__move_rttydesc_NOTHING_info = private unnamed_addr constant i8 -1 +@0 = private unnamed_addr constant [1 x i8] c"x" +@__move_rttydesc_bool_name = private unnamed_addr constant [4 x i8] c"bool" +@1 = private unnamed_addr constant [1 x i8] c"y" +@s_fld_array = private unnamed_addr constant [2 x { %__move_rt_type, i64, { ptr, i64 } }] [{ %__move_rt_type, i64, { ptr, i64 } } { %__move_rt_type { { ptr, i64 } { ptr @__move_rttydesc_u64_name, i64 3 }, i64 5, ptr @__move_rttydesc_NOTHING_info }, i64 0, { ptr, i64 } { ptr @0, i64 1 } }, { %__move_rt_type, i64, { ptr, i64 } } { %__move_rt_type { { ptr, i64 } { ptr @__move_rttydesc_bool_name, i64 4 }, i64 1, ptr @__move_rttydesc_NOTHING_info }, i64 8, { ptr, i64 } { ptr @1, i64 1 } }] +@__move_rttydesc_vector__Foo_info = private unnamed_addr constant { ptr, i64, i64, i64 } { ptr @s_fld_array, i64 2, i64 16, i64 8 } +@__move_rttydesc_vector__Bar = private unnamed_addr constant %__move_rt_type { { ptr, i64 } { ptr @__move_rttydesc_vector__Bar_name, i64 77 }, i64 11, ptr @__move_rttydesc_vector__Bar_info } +@__move_rttydesc_vector__Bar_name = private unnamed_addr constant [77 x i8] c"0000000000000000000000000000000000000000000000000000000000000101::vector::Bar" +@2 = private unnamed_addr constant [3 x i8] c"foo" +@s_fld_array.1 = private unnamed_addr constant [1 x { %__move_rt_type, i64, { ptr, i64 } }] [{ %__move_rt_type, i64, { ptr, i64 } } { %__move_rt_type { { ptr, i64 } { ptr @__move_rttydesc_vector__Foo_name, i64 77 }, i64 11, ptr @__move_rttydesc_vector__Foo_info }, i64 0, { ptr, i64 } { ptr @2, i64 3 } }] +@__move_rttydesc_vector__Bar_info = private unnamed_addr constant { ptr, i64, i64, i64 } { ptr @s_fld_array.1, i64 1, i64 16, i64 8 } + +declare i32 @memcmp(ptr, ptr, i64) + +declare ptr @move_native_vector_borrow(ptr, ptr, i64) + +declare { ptr, i64, i64 } @move_native_vector_empty(ptr) + +declare void @move_native_vector_push_back(ptr, ptr, ptr) + +define void @"0000000000000101_vector_test_singleton__J2xbF6jng4dp5e"() !dbg !2 { +entry: + %local_0 = alloca { ptr, i64, i64 }, align 8 + %local_1 = alloca { ptr, i64, i64 }, align 8 + %local_2 = alloca %struct.vector__Bar, align 8 + %local_3 = alloca %struct.vector__Foo, align 8 + %local_4__x = alloca i64, align 8 + %local_5__y = alloca i1, align 1 + %local_6 = alloca %struct.vector__Foo, align 8 + %local_7 = alloca %struct.vector__Foo, align 8 + %local_8 = alloca { ptr, i64, i64 }, align 8 + %local_9 = alloca ptr, align 8 + %local_10 = alloca i64, align 8 + %local_11 = alloca ptr, align 8 + %local_12 = alloca %struct.vector__Foo, align 8 + %local_13 = alloca %struct.vector__Foo, align 8 + %local_14 = alloca i1, align 1 + %local_15 = alloca i64, align 8 + %local_16__foo = alloca %struct.vector__Foo, align 8 + %local_17 = alloca %struct.vector__Bar, align 8 + %local_18 = alloca %struct.vector__Bar, align 8 + %local_19 = alloca { ptr, i64, i64 }, align 8 + %local_20 = alloca ptr, align 8 + %local_21 = alloca i64, align 8 + %local_22 = alloca ptr, align 8 + %local_23 = alloca %struct.vector__Bar, align 8 + %local_24 = alloca %struct.vector__Bar, align 8 + %local_25 = alloca i1, align 1 + %local_26 = alloca i64, align 8 + store i64 0, ptr %local_4__x, align 8 + store i1 false, ptr %local_5__y, align 1 + %fv.0 = load i64, ptr %local_4__x, align 8 + %fv.1 = load i1, ptr %local_5__y, align 1 + %insert_0 = insertvalue %struct.vector__Foo undef, i64 %fv.0, 0 + %insert_1 = insertvalue %struct.vector__Foo %insert_0, i1 %fv.1, 1 + store %struct.vector__Foo %insert_1, ptr %local_6, align 8 + %load_store_tmp = load %struct.vector__Foo, ptr %local_6, align 8 + store %struct.vector__Foo %load_store_tmp, ptr %local_3, align 8 + %load_store_tmp1 = load %struct.vector__Foo, ptr %local_3, align 8 + store %struct.vector__Foo %load_store_tmp1, ptr %local_7, align 8 + %call_arg_0 = load %struct.vector__Foo, ptr %local_7, align 8 + %retval = call { ptr, i64, i64 } @"0000000000000101_vector_singleton_2hb84uZexr9BHm"(%struct.vector__Foo %call_arg_0), !dbg !36 + store { ptr, i64, i64 } %retval, ptr %local_8, align 8 + %load_store_tmp2 = load { ptr, i64, i64 }, ptr %local_8, align 8 + store { ptr, i64, i64 } %load_store_tmp2, ptr %local_0, align 8 + store ptr %local_0, ptr %local_9, align 8 + store i64 0, ptr %local_10, align 8 + %loaded_alloca = load ptr, ptr %local_9, align 8 + %loaded_alloca3 = load i64, ptr %local_10, align 8 + %retval4 = call ptr @move_native_vector_borrow(ptr @__move_rttydesc_vector__Foo, ptr %loaded_alloca, i64 %loaded_alloca3) + store ptr %retval4, ptr %local_11, align 8 + %load_deref_store_tmp1 = load ptr, ptr %local_11, align 8 + %load_deref_store_tmp2 = load %struct.vector__Foo, ptr %load_deref_store_tmp1, align 8 + store %struct.vector__Foo %load_deref_store_tmp2, ptr %local_12, align 8 + %load_store_tmp5 = load %struct.vector__Foo, ptr %local_3, align 8 + store %struct.vector__Foo %load_store_tmp5, ptr %local_13, align 8 + %0 = call i1 @move_rt_struct_cmp_eq(ptr @__move_rttydesc_vector__Foo, ptr %local_12, ptr %local_13) + store i1 %0, ptr %local_14, align 1 + %cnd = load i1, ptr %local_14, align 1 + br i1 %cnd, label %bb_1, label %bb_0 + +bb_1: ; preds = %entry + br label %bb_2 + +bb_0: ; preds = %entry + store i64 0, ptr %local_15, align 8 + %call_arg_06 = load i64, ptr %local_15, align 8 + call void @move_rt_abort(i64 %call_arg_06) + unreachable + +bb_2: ; preds = %bb_1 + %fv.07 = load %struct.vector__Foo, ptr %local_3, align 8 + %insert_08 = insertvalue %struct.vector__Bar undef, %struct.vector__Foo %fv.07, 0 + store %struct.vector__Bar %insert_08, ptr %local_17, align 8 + %load_store_tmp9 = load %struct.vector__Bar, ptr %local_17, align 8 + store %struct.vector__Bar %load_store_tmp9, ptr %local_2, align 8 + %load_store_tmp10 = load %struct.vector__Bar, ptr %local_2, align 8 + store %struct.vector__Bar %load_store_tmp10, ptr %local_18, align 8 + %call_arg_011 = load %struct.vector__Bar, ptr %local_18, align 8 + %retval12 = call { ptr, i64, i64 } @"0000000000000101_vector_singleton_39QxpzcPR6oc9x"(%struct.vector__Bar %call_arg_011), !dbg !37 + store { ptr, i64, i64 } %retval12, ptr %local_19, align 8 + %load_store_tmp13 = load { ptr, i64, i64 }, ptr %local_19, align 8 + store { ptr, i64, i64 } %load_store_tmp13, ptr %local_1, align 8 + store ptr %local_1, ptr %local_20, align 8 + store i64 0, ptr %local_21, align 8 + %loaded_alloca14 = load ptr, ptr %local_20, align 8 + %loaded_alloca15 = load i64, ptr %local_21, align 8 + %retval16 = call ptr @move_native_vector_borrow(ptr @__move_rttydesc_vector__Bar, ptr %loaded_alloca14, i64 %loaded_alloca15) + store ptr %retval16, ptr %local_22, align 8 + %load_deref_store_tmp117 = load ptr, ptr %local_22, align 8 + %load_deref_store_tmp218 = load %struct.vector__Bar, ptr %load_deref_store_tmp117, align 8 + store %struct.vector__Bar %load_deref_store_tmp218, ptr %local_23, align 8 + %1 = call i1 @move_rt_struct_cmp_eq(ptr @__move_rttydesc_vector__Bar, ptr %local_23, ptr %local_2) + store i1 %1, ptr %local_25, align 1 + %cnd19 = load i1, ptr %local_25, align 1 + br i1 %cnd19, label %bb_4, label %bb_3 + +bb_4: ; preds = %bb_2 + br label %bb_5 + +bb_3: ; preds = %bb_2 + store i64 0, ptr %local_26, align 8 + %call_arg_020 = load i64, ptr %local_26, align 8 + call void @move_rt_abort(i64 %call_arg_020) + unreachable + +bb_5: ; preds = %bb_4 + ret void +} + +define private { ptr, i64, i64 } @"0000000000000101_vector_singleton_2hb84uZexr9BHm"(%struct.vector__Foo %e) !dbg !25 { +entry: + %local_0 = alloca %struct.vector__Foo, align 8 + %local_1 = alloca { ptr, i64, i64 }, align 8 + %local_2 = alloca { ptr, i64, i64 }, align 8 + %local_3 = alloca ptr, align 8 + %local_4 = alloca %struct.vector__Foo, align 8 + %local_5 = alloca { ptr, i64, i64 }, align 8 + store %struct.vector__Foo %e, ptr %local_0, align 8 + %retval = call { ptr, i64, i64 } @move_native_vector_empty(ptr @__move_rttydesc_vector__Foo) + store { ptr, i64, i64 } %retval, ptr %local_2, align 8 + %load_store_tmp = load { ptr, i64, i64 }, ptr %local_2, align 8 + store { ptr, i64, i64 } %load_store_tmp, ptr %local_1, align 8 + store ptr %local_1, ptr %local_3, align 8 + %loaded_alloca = load ptr, ptr %local_3, align 8 + call void @move_native_vector_push_back(ptr @__move_rttydesc_vector__Foo, ptr %loaded_alloca, ptr %local_0) + %load_store_tmp1 = load { ptr, i64, i64 }, ptr %local_1, align 8 + store { ptr, i64, i64 } %load_store_tmp1, ptr %local_5, align 8 + %retval2 = load { ptr, i64, i64 }, ptr %local_5, align 8 + ret { ptr, i64, i64 } %retval2 +} + +define private { ptr, i64, i64 } @"0000000000000101_vector_singleton_39QxpzcPR6oc9x"(%struct.vector__Bar %e) !dbg !31 { +entry: + %local_0 = alloca %struct.vector__Bar, align 8 + %local_1 = alloca { ptr, i64, i64 }, align 8 + %local_2 = alloca { ptr, i64, i64 }, align 8 + %local_3 = alloca ptr, align 8 + %local_4 = alloca %struct.vector__Bar, align 8 + %local_5 = alloca { ptr, i64, i64 }, align 8 + store %struct.vector__Bar %e, ptr %local_0, align 8 + %retval = call { ptr, i64, i64 } @move_native_vector_empty(ptr @__move_rttydesc_vector__Bar) + store { ptr, i64, i64 } %retval, ptr %local_2, align 8 + %load_store_tmp = load { ptr, i64, i64 }, ptr %local_2, align 8 + store { ptr, i64, i64 } %load_store_tmp, ptr %local_1, align 8 + store ptr %local_1, ptr %local_3, align 8 + %loaded_alloca = load ptr, ptr %local_3, align 8 + call void @move_native_vector_push_back(ptr @__move_rttydesc_vector__Bar, ptr %loaded_alloca, ptr %local_0) + %load_store_tmp1 = load { ptr, i64, i64 }, ptr %local_1, align 8 + store { ptr, i64, i64 } %load_store_tmp1, ptr %local_5, align 8 + %retval2 = load { ptr, i64, i64 }, ptr %local_5, align 8 + ret { ptr, i64, i64 } %retval2 +} + +declare i1 @move_rt_struct_cmp_eq(ptr nonnull readonly dereferenceable(32), ptr nonnull readonly, ptr nonnull readonly) + +; Function Attrs: cold noreturn +declare void @move_rt_abort(i64) #0 + +attributes #0 = { cold noreturn } !llvm.dbg.cu = !{!0} -!struct.vector__Foo = !{!2, !10, !10, !10} -!struct.vector__Bar = !{!13, !18, !18, !18} -!test_singleton_contains = !{!19} -!singleton = !{!23, !28} +!test_singleton_contains = !{!2, !5, !6, !7} +!struct.vector__Foo = !{!8, !16, !16, !16} +!struct.vector__Bar = !{!19, !24, !24, !24} +!singleton = !{!25, !28, !29, !30, !31, !34, !29, !35} !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "move-mv-llvm-compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, sysroot: "/") !1 = !DIFile(filename: "dwarf-vector.move", directory: "/language/tools/move-mv-llvm-compiler/tests/dwarf-tests") -!2 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.vector__Foo__ptr", baseType: !3, size: 64, align: 64, dwarfAddressSpace: 0) -!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.vector__Foo", scope: !4, file: !1, line: 2, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !5) -!4 = !DINamespace(name: "struct.vector__Foo", scope: !1) -!5 = !{!6, !8} -!6 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !4, file: !1, line: 2, baseType: !7, size: 64, align: 64) -!7 = !DIBasicType(name: "u64", size: 64) -!8 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !4, file: !1, line: 3, baseType: !9, size: 1, align: 8, offset: 64) -!9 = !DIBasicType(name: "bool", size: 8) -!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !3, size: 192, align: 8, flags: DIFlagVector, elements: !11) -!11 = !{!12} -!12 = !DISubrange(count: 1, lowerBound: 0) -!13 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.vector__Bar__ptr", baseType: !14, size: 64, align: 64, dwarfAddressSpace: 0) -!14 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.vector__Bar", scope: !15, file: !1, line: 3, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !16) -!15 = !DINamespace(name: "struct.vector__Bar", scope: !1) -!16 = !{!17} -!17 = !DIDerivedType(tag: DW_TAG_member, name: "foo", scope: !15, file: !1, line: 3, baseType: !3, size: 128, align: 64) -!18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !14, size: 192, align: 8, flags: DIFlagVector, elements: !11) -!19 = distinct !DISubprogram(name: "test_singleton_contains", linkageName: "test_singleton_contains", scope: !20, file: !1, line: 17, type: !21, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !22) -!20 = !DINamespace(name: "test_singleton_contains", scope: !1) -!21 = !DISubroutineType(types: !22) -!22 = !{} -!23 = distinct !DISubprogram(name: "singleton", linkageName: "singleton", scope: !24, file: !1, line: 11, type: !25, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !22) -!24 = !DINamespace(name: "singleton", scope: !1) -!25 = !DISubroutineType(types: !26) -!26 = !{!27} -!27 = !DILocalVariable(name: "e", scope: !24, file: !1, type: !3) -!28 = distinct !DISubprogram(name: "singleton", linkageName: "singleton", scope: !24, file: !1, line: 11, type: !29, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !22) -!29 = !DISubroutineType(types: !30) -!30 = !{!31} -!31 = !DILocalVariable(name: "e", scope: !24, file: !1, type: !14) +!2 = distinct !DISubprogram(name: "test_singleton_contains", linkageName: "test_singleton_contains", scope: !1, file: !1, line: 17, type: !3, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !4) +!3 = !DISubroutineType(types: !4) +!4 = !{} +!5 = distinct !DILexicalBlock(scope: !2, file: !1, line: 23) +!6 = !DINamespace(name: "test_singleton_contains", scope: !1) +!7 = !DILocation(line: 17, column: 4, scope: !5) +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.vector__Foo__ptr", baseType: !9, size: 64, align: 64, dwarfAddressSpace: 0) +!9 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.vector__Foo", scope: !10, file: !1, line: 2, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !11) +!10 = !DINamespace(name: "struct.vector__Foo", scope: !1) +!11 = !{!12, !14} +!12 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !10, file: !1, line: 2, baseType: !13, size: 64, align: 64) +!13 = !DIBasicType(name: "u64", size: 64) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !10, file: !1, line: 3, baseType: !15, size: 1, align: 8, offset: 64) +!15 = !DIBasicType(name: "bool", size: 8) +!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 192, align: 8, flags: DIFlagVector, elements: !17) +!17 = !{!18} +!18 = !DISubrange(count: 1, lowerBound: 0) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "struct.vector__Bar__ptr", baseType: !20, size: 64, align: 64, dwarfAddressSpace: 0) +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "struct.vector__Bar", scope: !21, file: !1, line: 3, size: 128, align: 8, flags: DIFlagObjcClassComplete, elements: !22) +!21 = !DINamespace(name: "struct.vector__Bar", scope: !1) +!22 = !{!23} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "foo", scope: !21, file: !1, line: 3, baseType: !9, size: 128, align: 64) +!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !20, size: 192, align: 8, flags: DIFlagVector, elements: !17) +!25 = distinct !DISubprogram(name: "singleton", linkageName: "singleton", scope: !1, file: !1, line: 11, type: !26, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !4) +!26 = !DISubroutineType(types: !27) +!27 = !{!9} +!28 = distinct !DILexicalBlock(scope: !25, file: !1, line: 9) +!29 = !DINamespace(name: "singleton", scope: !1) +!30 = !DILocation(line: 11, column: 4, scope: !28) +!31 = distinct !DISubprogram(name: "singleton", linkageName: "singleton", scope: !1, file: !1, line: 11, type: !32, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, retainedNodes: !4) +!32 = !DISubroutineType(types: !33) +!33 = !{!20} +!34 = distinct !DILexicalBlock(scope: !31, file: !1, line: 9) +!35 = !DILocation(line: 11, column: 4, scope: !34) +!36 = !DILocation(line: 20, column: 26, scope: !2) +!37 = !DILocation(line: 23, column: 43, scope: !2)