diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr index c6b4b3d7bca7..c22f368cb590 100644 --- a/src/compiler/crystal/codegen/codegen.cr +++ b/src/compiler/crystal/codegen/codegen.cr @@ -427,9 +427,34 @@ module Crystal end def define_slice_constant(info : Program::ConstSliceInfo) + initializer = const_slice_data_array(info) + global = @llvm_mod.globals.add(initializer.type, info.name) + if @llvm_mod != @main_mod + global.linkage = LLVM::Linkage::External + elsif @single_module + global.linkage = LLVM::Linkage::Internal + end + global.global_constant = true + global.initializer = initializer + end + + private def const_slice_data_array(info : Program::ConstSliceInfo) args = info.args.to_unsafe kind = info.element_type llvm_element_type = llvm_type(@program.type_from_literal_kind(kind)) + + {% unless LibLLVM::IS_LT_210 %} + case kind + when .u8?, .u16?, .u32?, .u64?, .i8?, .i16?, .i32?, .i64?, .f32?, .f64? + return llvm_element_type.const_data_array(info.to_bytes) + end + {% end %} + + case kind + when .u8?, .i8? + return llvm_context.const_bytes(info.to_bytes) + end + llvm_elements = Array.new(info.args.size) do |i| num = args[i].as(NumberLiteral) case kind @@ -447,15 +472,7 @@ module Crystal in .f64? then llvm_element_type.const_double(num.value) end end - - global = @llvm_mod.globals.add(llvm_element_type.array(info.args.size), info.name) - if @llvm_mod != @main_mod - global.linkage = LLVM::Linkage::External - elsif @single_module - global.linkage = LLVM::Linkage::Internal - end - global.global_constant = true - global.initializer = llvm_element_type.const_array(llvm_elements) + llvm_element_type.const_array(llvm_elements) end class CodegenWellKnownFunctions < Visitor diff --git a/src/compiler/crystal/interpreter/context.cr b/src/compiler/crystal/interpreter/context.cr index 3fee5dd16f02..b5f6a219a4ab 100644 --- a/src/compiler/crystal/interpreter/context.cr +++ b/src/compiler/crystal/interpreter/context.cr @@ -293,33 +293,7 @@ class Crystal::Repl::Context end def const_slice_buffer(info : Program::ConstSliceInfo) : UInt8* - @const_slice_buffers.put_if_absent(info.name) do - kind = info.element_type - element_size = kind.bytesize // 8 - buffer = Pointer(UInt8).malloc(info.args.size * element_size) - ptr = buffer - - info.args.each do |arg| - num = arg.as(NumberLiteral) - case kind - in .i8? then ptr.as(Int8*).value = num.value.to_i8 - in .i16? then ptr.as(Int16*).value = num.value.to_i16 - in .i32? then ptr.as(Int32*).value = num.value.to_i32 - in .i64? then ptr.as(Int64*).value = num.value.to_i64 - in .i128? then ptr.as(Int128*).value = num.value.to_i128 - in .u8? then ptr.as(UInt8*).value = num.value.to_u8 - in .u16? then ptr.as(UInt16*).value = num.value.to_u16 - in .u32? then ptr.as(UInt32*).value = num.value.to_u32 - in .u64? then ptr.as(UInt64*).value = num.value.to_u64 - in .u128? then ptr.as(UInt128*).value = num.value.to_u128 - in .f32? then ptr.as(Float32*).value = num.value.to_f32 - in .f64? then ptr.as(Float64*).value = num.value.to_f64 - end - ptr += element_size - end - - buffer - end + @const_slice_buffers.put_if_absent(info.name) { info.to_bytes.to_unsafe } end def aligned_sizeof_type(node : ASTNode) : Int32 diff --git a/src/compiler/crystal/program.cr b/src/compiler/crystal/program.cr index 0c71a287b519..f5f926dc870f 100644 --- a/src/compiler/crystal/program.cr +++ b/src/compiler/crystal/program.cr @@ -84,10 +84,35 @@ module Crystal # This pool is passed to the parser, macro expander, etc. getter string_pool = StringPool.new - record ConstSliceInfo, - name : String, - element_type : NumberKind, - args : Array(ASTNode) + record ConstSliceInfo, name : String, element_type : NumberKind, args : Array(ASTNode) do + def to_bytes : Bytes + element_size = element_type.bytesize // 8 + bytesize = args.size * element_size + buffer = Pointer(UInt8).malloc(bytesize) + ptr = buffer + + args.each do |arg| + num = arg.as(NumberLiteral) + case element_type + in .i8? then ptr.as(Int8*).value = num.value.to_i8 + in .i16? then ptr.as(Int16*).value = num.value.to_i16 + in .i32? then ptr.as(Int32*).value = num.value.to_i32 + in .i64? then ptr.as(Int64*).value = num.value.to_i64 + in .i128? then ptr.as(Int128*).value = num.value.to_i128 + in .u8? then ptr.as(UInt8*).value = num.value.to_u8 + in .u16? then ptr.as(UInt16*).value = num.value.to_u16 + in .u32? then ptr.as(UInt32*).value = num.value.to_u32 + in .u64? then ptr.as(UInt64*).value = num.value.to_u64 + in .u128? then ptr.as(UInt128*).value = num.value.to_u128 + in .f32? then ptr.as(Float32*).value = num.value.to_f32 + in .f64? then ptr.as(Float64*).value = num.value.to_f64 + end + ptr += element_size + end + + buffer.to_slice(bytesize) + end + end # All constant slices constructed via the `Slice.literal` compiler built-in, # indexed by their buffers' internal names (e.g. `$Slice:0`). diff --git a/src/llvm/context.cr b/src/llvm/context.cr index 84c96610a96f..76b6036d04d9 100644 --- a/src/llvm/context.cr +++ b/src/llvm/context.cr @@ -108,10 +108,14 @@ class LLVM::Context end def const_string(string : String) : Value + const_bytes(string.unsafe_byte_slice(0, string.bytesize + 1)) + end + + def const_bytes(bytes : Bytes) : Value {% if LibLLVM::IS_LT_190 %} - Value.new LibLLVM.const_string_in_context(self, string, string.bytesize, 0) + Value.new LibLLVM.const_string_in_context(self, bytes, bytes.size, 1) {% else %} - Value.new LibLLVM.const_string_in_context2(self, string, string.bytesize, 0) + Value.new LibLLVM.const_string_in_context2(self, bytes, bytes.size, 1) {% end %} end diff --git a/src/llvm/lib_llvm/core.cr b/src/llvm/lib_llvm/core.cr index 9f7d4217e357..def2ca7f7bc3 100644 --- a/src/llvm/lib_llvm/core.cr +++ b/src/llvm/lib_llvm/core.cr @@ -136,6 +136,9 @@ lib LibLLVM {% end %} fun const_struct_in_context = LLVMConstStructInContext(c : ContextRef, constant_vals : ValueRef*, count : UInt, packed : Bool) : ValueRef fun const_array = LLVMConstArray(element_ty : TypeRef, constant_vals : ValueRef*, length : UInt) : ValueRef + {% unless LibLLVM::IS_LT_210 %} + fun const_data_array = LLVMConstDataArray(element_ty : TypeRef, data : Char*, size_in_bytes : SizeT) : ValueRef + {% end %} fun align_of = LLVMAlignOf(ty : TypeRef) : ValueRef fun size_of = LLVMSizeOf(ty : TypeRef) : ValueRef diff --git a/src/llvm/type.cr b/src/llvm/type.cr index 7d0582a9f736..fb7667a8af5e 100644 --- a/src/llvm/type.cr +++ b/src/llvm/type.cr @@ -173,6 +173,14 @@ struct LLVM::Type Value.new LibLLVM.const_array(self, (values.to_unsafe.as(LibLLVM::ValueRef*)), values.size) end + def const_data_array(buffer : Bytes) : Value + {% if LibLLVM::IS_LT_210 %} + raise NotImplementedError.new("LLVM::Type#const_data_array") + {% else %} + Value.new LibLLVM.const_data_array(self, buffer, buffer.bytesize) + {% end %} + end + def inline_asm(asm_string, constraints, has_side_effects = false, is_align_stack = false, can_throw = false, dialect : InlineAsmDialect = InlineAsmDialect::ATT) value = {% if LibLLVM::IS_LT_130 %}