Skip to content

Commit

Permalink
Remove most LLVM::DIBuilder functions from llvm_ext.cc (#13448)
Browse files Browse the repository at this point in the history
  • Loading branch information
HertzDevil authored May 10, 2023
1 parent cfc1e0e commit 0d2471c
Show file tree
Hide file tree
Showing 7 changed files with 388 additions and 390 deletions.
8 changes: 8 additions & 0 deletions src/compiler/crystal/codegen/crystal_llvm_builder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ module Crystal
@builder.build_operand_bundle_def(name, values)
end

def current_debug_location_metadata
{% if LibLLVM::IS_LT_90 %}
LibLLVM.value_as_metadata LibLLVM.get_current_debug_location(@builder)
{% else %}
LibLLVM.get_current_debug_location2(@builder)
{% end %}
end

def to_unsafe
@builder.to_unsafe
end
Expand Down
46 changes: 25 additions & 21 deletions src/compiler/crystal/codegen/debug.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ require "./codegen"

module Crystal
class CodeGenVisitor
CRYSTAL_LANG_DEBUG_IDENTIFIER = 0x28_u32
#
# We have to use it because LLDB has builtin type system support for C++/clang that we can use for now for free.
# Later on we can implement LLDB Crystal type system so we can get official Language ID
#
CPP_LANG_DEBUG_IDENTIFIER = 0x0004_u32
# workaround for `LLVM::Builder` not being GC'ed (#13250)
private class DIBuilder
def initialize(mod : LLVM::Module)
@builder = LLVM::DIBuilder.new(mod)
end

def finalize
@builder.dispose
end

forward_missing_to @builder
end

record FunMetadata, filename : String, metadata : LibLLVM::MetadataRef

Expand All @@ -20,13 +26,14 @@ module Crystal
@debug_types_per_module = {} of LLVM::Module => Hash(Type, LibLLVM::MetadataRef?)

def di_builder(llvm_module = @llvm_mod || @main_mod)
di_builders = @di_builders ||= {} of LLVM::Module => LLVM::DIBuilder
di_builders[llvm_module] ||= LLVM::DIBuilder.new(llvm_module).tap do |di_builder|
di_builders = @di_builders ||= {} of LLVM::Module => DIBuilder
di_builders[llvm_module] ||= DIBuilder.new(llvm_module).tap do |di_builder|
file, dir = file_and_dir(llvm_module.name == "" ? "main" : llvm_module.name)
# @debug.variables? is set to true if parameter --debug is set in command line.
# This flag affects only debug variables generation. It sets Optimized parameter to false.
is_optimised = !@debug.variables?
di_builder.create_compile_unit(CPP_LANG_DEBUG_IDENTIFIER, file, dir, "Crystal", is_optimised, "", 0_u32)
# TODO: switch to Crystal's language code for LLVM 16+ (#13174)
di_builder.create_compile_unit(LLVM::DwarfSourceLanguage::C_plus_plus, file, dir, "Crystal", is_optimised, "", 0_u32)
end
end

Expand Down Expand Up @@ -66,8 +73,7 @@ module Crystal
int = di_builder.create_basic_type("int", 32, 32, LLVM::DwarfTypeEncoding::Signed)
debug_types << int
end
debug_types_array = di_builder.get_or_create_type_array(debug_types)
di_builder.create_subroutine_type(nil, debug_types_array)
di_builder.create_subroutine_type(nil, debug_types)
end

def debug_type_cache
Expand Down Expand Up @@ -141,7 +147,6 @@ module Crystal
end
di_builder.create_enumerator(name, value)
end
elements = di_builder.get_or_create_array(elements)
di_builder.create_enumeration_type(nil, original_type.to_s, nil, 1, 32, 32, elements, get_debug_type(type.base_type))
end

Expand All @@ -165,11 +170,10 @@ module Crystal
end

size = @program.target_machine.data_layout.size_in_bits(struct_type)
elements = di_builder.get_or_create_type_array(element_types)
if type.extern_union?
debug_type = di_builder.create_union_type(nil, original_type.to_s, current_debug_file, 1, size, size, LLVM::DIFlags::Zero, elements)
debug_type = di_builder.create_union_type(nil, original_type.to_s, current_debug_file, 1, size, size, LLVM::DIFlags::Zero, element_types)
else
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, size, size, LLVM::DIFlags::Zero, nil, elements)
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, size, size, LLVM::DIFlags::Zero, nil, element_types)
unless type.struct?
debug_type = di_builder.create_pointer_type(debug_type, 8u64 * llvm_typer.pointer_size, 8u64 * llvm_typer.pointer_size, original_type.to_s)
end
Expand Down Expand Up @@ -206,12 +210,12 @@ module Crystal

size = @program.target_machine.data_layout.size_in_bits(struct_type.struct_element_types[is_struct ? 0 : 1])
offset = @program.target_machine.data_layout.offset_of_element(struct_type, 1) * 8u64
debug_type = di_builder.create_union_type(nil, nil, current_debug_file, 1, size, size, LLVM::DIFlags::Zero, di_builder.get_or_create_type_array(element_types))
debug_type = di_builder.create_union_type(nil, "", current_debug_file, 1, size, size, LLVM::DIFlags::Zero, element_types)
unless is_struct
element_types.clear
element_types << di_builder.create_member_type(nil, "type_id", nil, 1, 32, 32, 0, LLVM::DIFlags::Zero, get_debug_type(@program.uint32))
element_types << di_builder.create_member_type(nil, "union", nil, 1, size, size, offset, LLVM::DIFlags::Zero, debug_type)
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, struct_type_size, struct_type_size, LLVM::DIFlags::Zero, nil, di_builder.get_or_create_type_array(element_types))
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, struct_type_size, struct_type_size, LLVM::DIFlags::Zero, nil, element_types)
end
di_builder.replace_temporary(tmp_debug_type, debug_type)
debug_type
Expand All @@ -234,7 +238,7 @@ module Crystal
end

size = @program.target_machine.data_layout.size_in_bits(struct_type)
debug_type = di_builder.create_union_type(nil, original_type.to_s, current_debug_file, 1, size, size, LLVM::DIFlags::Zero, di_builder.get_or_create_type_array(element_types))
debug_type = di_builder.create_union_type(nil, original_type.to_s, current_debug_file, 1, size, size, LLVM::DIFlags::Zero, element_types)
di_builder.replace_temporary(tmp_debug_type, debug_type)
debug_type
end
Expand Down Expand Up @@ -274,7 +278,7 @@ module Crystal
end

size = @program.target_machine.data_layout.size_in_bits(struct_type)
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, size, size, LLVM::DIFlags::Zero, nil, di_builder.get_or_create_type_array(element_types))
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, size, size, LLVM::DIFlags::Zero, nil, element_types)
unless type.struct?
debug_type = di_builder.create_pointer_type(debug_type, 8u64 * llvm_typer.pointer_size, 8u64 * llvm_typer.pointer_size, original_type.to_s)
end
Expand Down Expand Up @@ -302,7 +306,7 @@ module Crystal
end

size = @program.target_machine.data_layout.size_in_bits(struct_type)
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, size, size, LLVM::DIFlags::Zero, nil, di_builder.get_or_create_type_array(element_types))
debug_type = di_builder.create_struct_type(nil, original_type.to_s, nil, 1, size, size, LLVM::DIFlags::Zero, nil, element_types)
unless type.struct?
debug_type = di_builder.create_pointer_type(debug_type, 8u64 * llvm_typer.pointer_size, 8u64 * llvm_typer.pointer_size, original_type.to_s)
end
Expand Down Expand Up @@ -370,7 +374,7 @@ module Crystal
old_debug_location = @current_debug_location
set_current_debug_location location
if builder.current_debug_location != llvm_nil && (ptr = alloca)
di_builder.insert_declare_at_end(ptr, var, expr, builder.current_debug_location, block)
di_builder.insert_declare_at_end(ptr, var, expr, builder.current_debug_location_metadata, block)
set_current_debug_location old_debug_location
true
else
Expand Down
154 changes: 116 additions & 38 deletions src/llvm/di_builder.cr
Original file line number Diff line number Diff line change
@@ -1,122 +1,200 @@
require "./lib_llvm"

struct LLVM::DIBuilder
def initialize(@llvm_module : Module)
@unwrap = LibLLVMExt.create_di_builder(llvm_module)
private DW_TAG_structure_type = 19

private def initialize(@unwrap : LibLLVM::DIBuilderRef, @llvm_module : Module)
end

def self.new(mod : LLVM::Module)
new(LibLLVM.create_di_builder(mod), mod)
end

def dispose
LibLLVM.dispose_di_builder(self)
end

def create_compile_unit(lang : DwarfSourceLanguage, file, dir, producer, optimized, flags, runtime_version)
file = create_file(file, dir)
{% if LibLLVM::IS_LT_110 %}
LibLLVM.di_builder_create_compile_unit(self,
lang, file, producer, producer.bytesize, optimized ? 1 : 0, flags, flags.bytesize, runtime_version,
split_name: nil, split_name_len: 0, kind: LibLLVM::DWARFEmissionKind::Full, dwo_id: 0,
split_debug_inlining: 1, debug_info_for_profiling: 0,
)
{% else %}
LibLLVM.di_builder_create_compile_unit(self,
lang, file, producer, producer.bytesize, optimized ? 1 : 0, flags, flags.bytesize, runtime_version,
split_name: nil, split_name_len: 0, kind: LibLLVM::DWARFEmissionKind::Full, dwo_id: 0,
split_debug_inlining: 1, debug_info_for_profiling: 0, sys_root: nil, sys_root_len: 0, sdk: nil, sdk_len: 0,
)
{% end %}
end

def create_compile_unit(lang, file, dir, producer, optimized, flags, runtime_version)
LibLLVMExt.di_builder_create_compile_unit(self, lang, file, dir, producer, optimized ? 1 : 0, flags, runtime_version)
@[Deprecated("Pass an `LLVM::DwarfSourceLanguage` for `lang` instead")]
def create_compile_unit(lang cpp_lang_code, file, dir, producer, optimized, flags, runtime_version)
# map the c++ values from `llvm::dwarf::SourceLanguage` to the c values from `LLVMDWARFSourceLanguage`
c_lang_code =
case cpp_lang_code
when 0x8001; DwarfSourceLanguage::Mips_Assembler
when 0x8e57; DwarfSourceLanguage::GOOGLE_RenderScript
when 0xb000; DwarfSourceLanguage::BORLAND_Delphi
else DwarfSourceLanguage.new(lang - 1)
end

create_compile_unit(c_lang_code, file, dir, producer, optimized, flags, runtime_version)
end

def create_basic_type(name, size_in_bits, align_in_bits, encoding)
LibLLVMExt.di_builder_create_basic_type(self, name, size_in_bits, align_in_bits, encoding.value)
LibLLVM.di_builder_create_basic_type(self, name, name.bytesize, size_in_bits, encoding.value, DIFlags::Zero)
end

def get_or_create_type_array(types : Array(LibLLVM::MetadataRef))
LibLLVMExt.di_builder_get_or_create_type_array(self, types, types.size)
LibLLVM.di_builder_get_or_create_type_array(self, types, types.size)
end

def create_subroutine_type(file, parameter_types)
LibLLVMExt.di_builder_create_subroutine_type(self, file, parameter_types)
LibLLVM.di_builder_create_subroutine_type(self, file, parameter_types, parameter_types.size, DIFlags::Zero)
end

def create_file(file, dir)
LibLLVMExt.di_builder_create_file(self, file, dir)
LibLLVM.di_builder_create_file(self, file, file.bytesize, dir, dir.bytesize)
end

def create_lexical_block(scope, file_scope, line, column)
LibLLVMExt.di_builder_create_lexical_block(self, scope, file_scope, line, column)
LibLLVM.di_builder_create_lexical_block(self, scope, file_scope, line, column)
end

def create_lexical_block_file(scope, file_scope, discriminator = 0)
LibLLVMExt.di_builder_create_lexical_block_file(self, scope, file_scope, discriminator)
LibLLVM.di_builder_create_lexical_block_file(self, scope, file_scope, discriminator)
end

def create_function(scope, name, linkage_name, file, line, composite_type, is_local_to_unit, is_definition,
scope_line, flags, is_optimized, func)
LibLLVMExt.di_builder_create_function(self, scope, name, linkage_name, file, line, composite_type,
is_local_to_unit, is_definition, scope_line, flags, is_optimized, func)
sub = LibLLVM.di_builder_create_function(self, scope, name, name.bytesize,
linkage_name, linkage_name.bytesize, file, line, composite_type, is_local_to_unit ? 1 : 0,
is_definition ? 1 : 0, scope_line, flags, is_optimized ? 1 : 0)
LibLLVM.set_subprogram(func, sub)
sub
end

def create_auto_variable(scope, name, file, line, type, align_in_bits, flags = DIFlags::Zero)
LibLLVMExt.di_builder_create_auto_variable(self, scope, name, file, line, type, 1, flags, align_in_bits)
LibLLVM.di_builder_create_auto_variable(self, scope, name, name.bytesize, file, line, type, 1, flags, align_in_bits)
end

def create_parameter_variable(scope, name, argno, file, line, type, flags = DIFlags::Zero)
LibLLVMExt.di_builder_create_parameter_variable(self, scope, name, argno, file, line, type, 1, flags)
LibLLVM.di_builder_create_parameter_variable(self, scope, name, name.bytesize, argno, file, line, type, 1, flags)
end

def create_expression(addr, length)
LibLLVMExt.di_builder_create_expression(self, addr, length)
LibLLVM.di_builder_create_expression(self, addr, length)
end

def insert_declare_at_end(storage, var_info, expr, dl, block)
LibLLVMExt.di_builder_insert_declare_at_end(self, storage, var_info, expr, dl, block)
def insert_declare_at_end(storage, var_info, expr, dl : LibLLVM::MetadataRef, block)
LibLLVM.di_builder_insert_declare_at_end(self, storage, var_info, expr, dl, block)
end

def get_or_create_array(elements : Array(LibLLVM::MetadataRef))
LibLLVMExt.di_builder_get_or_create_array(self, elements, elements.size)
LibLLVM.di_builder_get_or_create_array(self, elements, elements.size)
end

def create_enumerator(name, value)
LibLLVMExt.di_builder_create_enumerator(self, name, value)
{% if LibLLVM::IS_LT_90 %}
LibLLVMExt.di_builder_create_enumerator(self, name, value)
{% else %}
LibLLVM.di_builder_create_enumerator(self, name, name.bytesize, value, 0)
{% end %}
end

def create_enumeration_type(scope, name, file, line_number, size_in_bits, align_in_bits, elements, underlying_type)
LibLLVMExt.di_builder_create_enumeration_type(self, scope, name, file, line_number, size_in_bits,
align_in_bits, elements, underlying_type)
LibLLVM.di_builder_create_enumeration_type(self, scope, name, name.bytesize, file, line_number,
size_in_bits, align_in_bits, elements, elements.size, underlying_type)
end

def create_struct_type(scope, name, file, line, size_in_bits, align_in_bits, flags, derived_from, element_types)
LibLLVMExt.di_builder_create_struct_type(self, scope, name, file, line, size_in_bits, align_in_bits,
flags, derived_from, element_types)
LibLLVM.di_builder_create_struct_type(self, scope, name, name.bytesize, file, line,
size_in_bits, align_in_bits, flags, derived_from, element_types, element_types.size, 0, nil, nil, 0)
end

def create_union_type(scope, name, file, line, size_in_bits, align_in_bits, flags, element_types)
LibLLVMExt.di_builder_create_union_type(self, scope, name, file, line, size_in_bits, align_in_bits,
flags, element_types)
LibLLVM.di_builder_create_union_type(self, scope, name, name.bytesize, file, line,
size_in_bits, align_in_bits, flags, element_types, element_types.size, 0, nil, 0)
end

def create_array_type(size_in_bits, align_in_bits, type, subs)
elements = self.get_or_create_array(subs)
LibLLVMExt.di_builder_create_array_type(self, size_in_bits, align_in_bits, type, elements)
LibLLVM.di_builder_create_array_type(self, size_in_bits, align_in_bits, type, subs, subs.size)
end

def create_member_type(scope, name, file, line, size_in_bits, align_in_bits, offset_in_bits, flags, ty)
LibLLVMExt.di_builder_create_member_type(self, scope, name, file, line, size_in_bits, align_in_bits,
LibLLVM.di_builder_create_member_type(self, scope, name, name.bytesize, file, line, size_in_bits, align_in_bits,
offset_in_bits, flags, ty)
end

def create_pointer_type(pointee, size_in_bits, align_in_bits, name)
LibLLVMExt.di_builder_create_pointer_type(self, pointee, size_in_bits, align_in_bits, name)
LibLLVM.di_builder_create_pointer_type(self, pointee, size_in_bits, align_in_bits, 0, name, name.bytesize)
end

def create_replaceable_composite_type(scope, name, file, line)
LibLLVMExt.di_builder_create_replaceable_composite_type(self, scope, name, file, line)
LibLLVM.di_builder_create_replaceable_composite_type(self, DW_TAG_structure_type, name, name.bytesize,
scope, file, line, 0, 0, 0, DIFlags::FwdDecl, nil, 0)
end

def replace_temporary(from, to)
LibLLVMExt.di_builder_replace_temporary(self, from, to)
LibLLVM.metadata_replace_all_uses_with(from, to)
end

def create_unspecified_type(name : String)
LibLLVMExt.di_builder_create_unspecified_type(self, name, name.size)
LibLLVM.di_builder_create_unspecified_type(self, name, name.bytesize)
end

def get_or_create_array_subrange(lo, count)
LibLLVMExt.di_builder_get_or_create_array_subrange(self, lo, count)
end

def create_reference_type(debug_type)
LibLLVM.di_builder_create_reference_type(self, 16, debug_type) # 16 is the code for DW_TAG_reference_type
LibLLVM.di_builder_get_or_create_subrange(self, lo, count)
end

def end
LibLLVMExt.di_builder_finalize(self)
LibLLVM.di_builder_finalize(self)
end

def to_unsafe
@unwrap
end

@[Deprecated("Use a `LibLLVM::MetadataRef` for `dl` instead")]
def insert_declare_at_end(storage, var_info, expr, dl : LibLLVM::ValueRef | LLVM::Value, block)
dl = dl.to_unsafe unless dl.is_a?(LibLLVM::ValueRef)
insert_declare_at_end(storage, var_info, expr, LibLLVM.value_as_metadata(dl), block)
end

@[Deprecated("Pass an array for `parameter_types` directly")]
def create_subroutine_type(file, parameter_types : LibLLVM::MetadataRef)
create_subroutine_type(file, extract_metadata_array(parameter_types))
end

@[Deprecated("Pass an array for `elements` directly")]
def create_enumeration_type(scope, name, file, line_number, size_in_bits, align_in_bits, elements : LibLLVM::MetadataRef, underlying_type)
create_enumeration_type(scope, name, file, line_number, size_in_bits, align_in_bits, extract_metadata_array(elements), underlying_type)
end

@[Deprecated("Pass an array for `element_types` directly")]
def create_struct_type(scope, name, file, line, size_in_bits, align_in_bits, flags, derived_from, element_types : LibLLVM::MetadataRef)
create_struct_type(scope, name, file, line, size_in_bits, align_in_bits, flags, derived_from, extract_metadata_array(element_types))
end

@[Deprecated("Pass an array for `element_types` directly")]
def create_union_type(scope, name, file, line, size_in_bits, align_in_bits, flags, element_types : LibLLVM::MetadataRef)
create_union_type(scope, name, file, line, size_in_bits, align_in_bits, flags, extract_metadata_array(element_types))
end

@[Deprecated("Pass an array for `subs` directly")]
def create_array_type(size_in_bits, align_in_bits, type, subs : LibLLVM::MetadataRef)
create_array_type(size_in_bits, align_in_bits, type, extract_metadata_array(subs))
end

private def extract_metadata_array(metadata : LibLLVM::MetadataRef)
metadata_as_value = LibLLVM.metadata_as_value(@llvm_module.context, metadata)
operand_count = LibLLVM.get_md_node_num_operands(metadata_as_value).to_i
operands = Pointer(LibLLVM::ValueRef).malloc(operand_count)
LibLLVM.get_md_node_operands(metadata_as_value, operands)
Slice.new(operand_count) { |i| LibLLVM.value_as_metadata(operands[i]) }
end
end
Loading

0 comments on commit 0d2471c

Please sign in to comment.