Skip to content

Commit 445ef91

Browse files
authored
Support debug info of 128-bit enum members (#15770)
On the LLVM 21 development branch, the `LLVMDIBuilderCreateEnumeratorOfArbitraryPrecision` function (which I submitted to LLVM) supports enumerators larger than the 64 bits that `LLVMDIBuilderCreateEnumerator` can handle. The underlying C++ implementation can be backported all the way back to LLVM 13, but if we added it to `llvm_ext.cc`, this would create an awkward situation where version 18 to 20 would miss out for no apparent reason. Thus, this PR requires LLVM 21 or above.
1 parent 7a24a48 commit 445ef91

File tree

5 files changed

+31
-11
lines changed

5 files changed

+31
-11
lines changed

spec/compiler/codegen/debug_spec.cr

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,16 @@ describe "Code gen: debug" do
301301
y.bar
302302
), debug: Crystal::Debug::All).to_i.should eq(123)
303303
end
304+
305+
{% unless LibLLVM::IS_LT_210 %}
306+
it "supports 128-bit enumerators" do
307+
codegen(<<-CRYSTAL, debug: Crystal::Debug::All).to_s.should contain(%(!DIEnumerator(name: "X", value: 1002003004005006007008009)))
308+
enum Foo : Int128
309+
X = 1002003004005006007008009_i128
310+
end
311+
312+
x = Foo::X
313+
CRYSTAL
314+
end
315+
{% end %}
304316
end

src/compiler/crystal/codegen/debug.cr

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,8 @@ module Crystal
128128

129129
def create_debug_type(type : EnumType, original_type : Type)
130130
elements = type.types.map do |name, item|
131-
str_value = item.as?(Const).try &.value.as?(NumberLiteral).try &.value
132-
133-
value =
134-
if type.base_type.kind.unsigned_int?
135-
str_value.try(&.to_u64?) || 0_u64
136-
else
137-
str_value.try(&.to_i64?) || 0_i64
138-
end
139-
140-
di_builder.create_enumerator(name, value)
131+
value = item.as?(Const).try &.value.as?(NumberLiteral).try &.integer_value
132+
di_builder.create_enumerator(name, value || 0)
141133
end
142134

143135
size_in_bits = type.base_type.kind.bytesize

src/llvm/di_builder.cr

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,18 @@ struct LLVM::DIBuilder
108108
end
109109

110110
def create_enumerator(name, value)
111+
is_unsigned = value.is_a?(Int::Unsigned) ? 1 : 0
112+
113+
{% unless LibLLVM::IS_LT_210 %}
114+
if value.is_a?(Int128) || value.is_a?(UInt128)
115+
encoded_value = UInt64[value & UInt64::MAX, (value >> 64) & UInt64::MAX]
116+
return LibLLVM.di_builder_create_enumerator_of_arbitrary_precision(
117+
self, name, name.bytesize, encoded_value.size * 64, encoded_value, is_unsigned)
118+
end
119+
{% end %}
120+
111121
{{ LibLLVM::IS_LT_90 ? LibLLVMExt : LibLLVM }}.di_builder_create_enumerator(
112-
self, name, name.bytesize, value.to_i64!, value.is_a?(Int::Unsigned) ? 1 : 0)
122+
self, name, name.bytesize, value.to_i64!, is_unsigned)
113123
end
114124

115125
def create_enumeration_type(scope, name, file, line_number, size_in_bits, align_in_bits, elements, underlying_type)

src/llvm/lib_llvm.cr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
IS_LT_180 = {{compare_versions(LibLLVM::VERSION, "18.0.0") < 0}}
7474
IS_LT_190 = {{compare_versions(LibLLVM::VERSION, "19.0.0") < 0}}
7575
IS_LT_200 = {{compare_versions(LibLLVM::VERSION, "20.0.0") < 0}}
76+
IS_LT_210 = {{compare_versions(LibLLVM::VERSION, "21.0.0") < 0}}
7677
end
7778
{% end %}
7879

src/llvm/lib_llvm/debug_info.cr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ lib LibLLVM
6060
builder : DIBuilderRef, name : Char*, name_len : SizeT, value : Int64, is_unsigned : Bool,
6161
) : MetadataRef
6262
{% end %}
63+
{% unless LibLLVM::IS_LT_210 %}
64+
fun di_builder_create_enumerator_of_arbitrary_precision = LLVMDIBuilderCreateEnumeratorOfArbitraryPrecision(
65+
builder : DIBuilderRef, name : Char*, name_len : SizeT, size_in_bits : UInt64, words : UInt64*, is_unsigned : Bool,
66+
) : MetadataRef
67+
{% end %}
6368
fun di_builder_create_enumeration_type = LLVMDIBuilderCreateEnumerationType(
6469
builder : DIBuilderRef, scope : MetadataRef, name : Char*, name_len : SizeT, file : MetadataRef,
6570
line_number : UInt, size_in_bits : UInt64, align_in_bits : UInt32,

0 commit comments

Comments
 (0)