Skip to content

Commit

Permalink
Support debug information for 64-bit or unsigned enums (#14081)
Browse files Browse the repository at this point in the history
  • Loading branch information
HertzDevil authored Dec 13, 2023
1 parent a3be0f5 commit 8942394
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 33 deletions.
15 changes: 15 additions & 0 deletions spec/debug/large_enums.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
enum SignedEnum : Int64
X = 0x0123_4567_89ab_cdef_i64
end

enum UnsignedEnum : UInt64
Y = 0xfedc_ba98_7654_3210_u64
end

x = SignedEnum::X
y = UnsignedEnum::Y
# print: x
# lldb-check: (SignedEnum) $0 = X
# print: y
# lldb-check: (UnsignedEnum) $1 = Y
debugger
1 change: 1 addition & 0 deletions spec/debug/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ $driver $SCRIPT_ROOT/top_level.cr $debugger
$driver $SCRIPT_ROOT/strings.cr $debugger
$driver $SCRIPT_ROOT/arrays.cr $debugger
$driver $SCRIPT_ROOT/blocks.cr $debugger
$driver $SCRIPT_ROOT/large_enums.cr $debugger
29 changes: 15 additions & 14 deletions src/compiler/crystal/codegen/debug.cr
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,21 @@ module Crystal

def create_debug_type(type : EnumType, original_type : Type)
elements = type.types.map do |name, item|
value = if item.is_a?(Const) && (value2 = item.value).is_a?(NumberLiteral)
value2.value.to_i64 rescue value2.value.to_u64
else
0
end
str_value = item.as?(Const).try &.value.as?(NumberLiteral).try &.value

value =
if type.base_type.kind.unsigned_int?
str_value.try(&.to_u64?) || 0_u64
else
str_value.try(&.to_i64?) || 0_i64
end

di_builder.create_enumerator(name, value)
end
di_builder.create_enumeration_type(nil, original_type.to_s, nil, 1, 32, 32, elements, get_debug_type(type.base_type))

size_in_bits = type.base_type.kind.bytesize
align_in_bits = align_of(type.base_type)
di_builder.create_enumeration_type(nil, original_type.to_s, nil, 1, size_in_bits, align_in_bits, elements, get_debug_type(type.base_type))
end

def create_debug_type(type : InstanceVarContainer, original_type : Type)
Expand Down Expand Up @@ -202,7 +209,7 @@ module Crystal
if ivar_debug_type = get_debug_type(ivar_type)
embedded_type = llvm_type(ivar_type)
size = @program.target_machine.data_layout.size_in_bits(embedded_type)
align = llvm_typer.align_of(embedded_type) * 8u64
align = align_of(ivar_type)
member = di_builder.create_member_type(nil, ivar_type.to_s, nil, 1, size, align, 0, LLVM::DIFlags::Zero, ivar_debug_type)
element_types << member
end
Expand Down Expand Up @@ -342,13 +349,7 @@ module Crystal
end

private def align_of(type)
case type
when CharType then 32
when IntegerType then type.bits
when FloatType then type.bytes * 8
when BoolType then 8
else 0 # unsupported
end
@program.target_machine.data_layout.abi_alignment(llvm_type(type)) * 8
end

private def declare_local(type, alloca, location, basic_block : LLVM::BasicBlock? = nil, &)
Expand Down
7 changes: 2 additions & 5 deletions src/llvm/di_builder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,8 @@ struct LLVM::DIBuilder
end

def create_enumerator(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 %}
{{ LibLLVM::IS_LT_90 ? LibLLVMExt : LibLLVM }}.di_builder_create_enumerator(
self, name, name.bytesize, value.to_i64!, value.is_a?(Int::Unsigned) ? 1 : 0)
end

def create_enumeration_type(scope, name, file, line_number, size_in_bits, align_in_bits, elements, underlying_type)
Expand Down
10 changes: 6 additions & 4 deletions src/llvm/ext/llvm_ext.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ using namespace llvm;
extern "C" {

#if !LLVM_VERSION_GE(9, 0)
LLVMMetadataRef LLVMExtDIBuilderCreateEnumerator(
LLVMDIBuilderRef Dref, const char *Name, int64_t Value) {
DIEnumerator *e = unwrap(Dref)->createEnumerator(Name, Value);
return wrap(e);
LLVMMetadataRef LLVMExtDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder,
const char *Name, size_t NameLen,
int64_t Value,
LLVMBool IsUnsigned) {
return wrap(unwrap(Builder)->createEnumerator({Name, NameLen}, Value,
IsUnsigned != 0));
}

void LLVMExtClearCurrentDebugLocation(LLVMBuilderRef B) {
Expand Down
18 changes: 9 additions & 9 deletions src/llvm/lib_llvm/debug_info.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ lib LibLLVM
{% if LibLLVM::IS_LT_110 %}
fun di_builder_create_compile_unit = LLVMDIBuilderCreateCompileUnit(
builder : DIBuilderRef, lang : LLVM::DwarfSourceLanguage, file_ref : MetadataRef, producer : Char*,
producer_len : SizeT, is_optimized : Int, flags : Char*, flags_len : SizeT, runtime_ver : UInt,
producer_len : SizeT, is_optimized : Bool, flags : Char*, flags_len : SizeT, runtime_ver : UInt,
split_name : Char*, split_name_len : SizeT, kind : DWARFEmissionKind, dwo_id : UInt,
split_debug_inlining : Int, debug_info_for_profiling : Int
split_debug_inlining : Bool, debug_info_for_profiling : Bool
) : MetadataRef
{% else %}
fun di_builder_create_compile_unit = LLVMDIBuilderCreateCompileUnit(
builder : DIBuilderRef, lang : LLVM::DwarfSourceLanguage, file_ref : MetadataRef, producer : Char*,
producer_len : SizeT, is_optimized : Int, flags : Char*, flags_len : SizeT, runtime_ver : UInt,
producer_len : SizeT, is_optimized : Bool, flags : Char*, flags_len : SizeT, runtime_ver : UInt,
split_name : Char*, split_name_len : SizeT, kind : DWARFEmissionKind, dwo_id : UInt,
split_debug_inlining : Int, debug_info_for_profiling : Int, sys_root : Char*,
split_debug_inlining : Bool, debug_info_for_profiling : Bool, sys_root : Char*,
sys_root_len : SizeT, sdk : Char*, sdk_len : SizeT
) : MetadataRef
{% end %}
Expand All @@ -34,8 +34,8 @@ lib LibLLVM
fun di_builder_create_function = LLVMDIBuilderCreateFunction(
builder : DIBuilderRef, scope : MetadataRef, name : Char*, name_len : SizeT,
linkage_name : Char*, linkage_name_len : SizeT, file : MetadataRef, line_no : UInt,
ty : MetadataRef, is_local_to_unit : Int, is_definition : Int, scope_line : UInt,
flags : LLVM::DIFlags, is_optimized : Int
ty : MetadataRef, is_local_to_unit : Bool, is_definition : Bool, scope_line : UInt,
flags : LLVM::DIFlags, is_optimized : Bool
) : MetadataRef

fun di_builder_create_lexical_block = LLVMDIBuilderCreateLexicalBlock(
Expand All @@ -57,7 +57,7 @@ lib LibLLVM
) : MetadataRef
{% unless LibLLVM::IS_LT_90 %}
fun di_builder_create_enumerator = LLVMDIBuilderCreateEnumerator(
builder : DIBuilderRef, name : Char*, name_len : SizeT, value : Int64, is_unsigned : Int
builder : DIBuilderRef, name : Char*, name_len : SizeT, value : Int64, is_unsigned : Bool
) : MetadataRef
{% end %}
fun di_builder_create_enumeration_type = LLVMDIBuilderCreateEnumerationType(
Expand Down Expand Up @@ -118,11 +118,11 @@ lib LibLLVM

fun di_builder_create_auto_variable = LLVMDIBuilderCreateAutoVariable(
builder : DIBuilderRef, scope : MetadataRef, name : Char*, name_len : SizeT, file : MetadataRef,
line_no : UInt, ty : MetadataRef, always_preserve : Int, flags : LLVM::DIFlags, align_in_bits : UInt32
line_no : UInt, ty : MetadataRef, always_preserve : Bool, flags : LLVM::DIFlags, align_in_bits : UInt32
) : MetadataRef
fun di_builder_create_parameter_variable = LLVMDIBuilderCreateParameterVariable(
builder : DIBuilderRef, scope : MetadataRef, name : Char*, name_len : SizeT, arg_no : UInt,
file : MetadataRef, line_no : UInt, ty : MetadataRef, always_preserve : Int, flags : LLVM::DIFlags
file : MetadataRef, line_no : UInt, ty : MetadataRef, always_preserve : Bool, flags : LLVM::DIFlags
) : MetadataRef

fun set_subprogram = LLVMSetSubprogram(func : ValueRef, sp : MetadataRef)
Expand Down
4 changes: 3 additions & 1 deletion src/llvm/lib_llvm_ext.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ lib LibLLVMExt
alias Int = LibC::Int
alias UInt = LibC::UInt

alias SizeT = LibC::SizeT

type OperandBundleDefRef = Void*

{% if LibLLVM::IS_LT_90 %}
fun di_builder_create_enumerator = LLVMExtDIBuilderCreateEnumerator(builder : LibLLVM::DIBuilderRef, name : Char*, value : Int64) : LibLLVM::MetadataRef
fun di_builder_create_enumerator = LLVMExtDIBuilderCreateEnumerator(builder : LibLLVM::DIBuilderRef, name : Char*, name_len : SizeT, value : Int64, is_unsigned : LibLLVM::Bool) : LibLLVM::MetadataRef
fun clear_current_debug_location = LLVMExtClearCurrentDebugLocation(b : LibLLVM::BuilderRef)
{% end %}

Expand Down

0 comments on commit 8942394

Please sign in to comment.