Skip to content

Commit

Permalink
Add Program#size_t and Target#size_bit_width (#14442)
Browse files Browse the repository at this point in the history
Co-authored-by: Johannes Müller <straightshoota@gmail.com>
  • Loading branch information
ysbaddaden and straight-shoota committed Apr 15, 2024
1 parent 5d91d6b commit a4ca7cc
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 46 deletions.
9 changes: 3 additions & 6 deletions src/compiler/crystal/codegen/call.cr
Expand Up @@ -239,9 +239,8 @@ class Crystal::CodeGenVisitor
final_value_casted = cast_to_void_pointer final_value
gep_call_arg = cast_to_void_pointer gep(llvm_type(call_arg_type), call_arg, 0, 0)
size = @abi.size(abi_arg_type.type)
size = @program.bits64? ? int64(size) : int32(size)
align = @abi.align(abi_arg_type.type)
memcpy(final_value_casted, gep_call_arg, size, align, int1(0))
memcpy(final_value_casted, gep_call_arg, size_t(size), align, int1(0))
call_arg = load cast, final_value
else
# Keep same call arg
Expand All @@ -256,9 +255,8 @@ class Crystal::CodeGenVisitor
final_value_casted = cast_to_void_pointer final_value
call_arg_casted = cast_to_void_pointer call_arg
size = @abi.size(abi_arg_type.type)
size = @program.bits64? ? int64(size) : int32(size)
align = @abi.align(abi_arg_type.type)
memcpy(final_value_casted, call_arg_casted, size, align, int1(0))
memcpy(final_value_casted, call_arg_casted, size_t(size), align, int1(0))
final_value
end

Expand Down Expand Up @@ -532,9 +530,8 @@ class Crystal::CodeGenVisitor
final_value = alloca abi_return.type
final_value_casted = cast_to_void_pointer final_value
size = @abi.size(abi_return.type)
size = @program.@program.bits64? ? int64(size) : int32(size)
align = @abi.align(abi_return.type)
memcpy(final_value_casted, cast2, size, align, int1(0))
memcpy(final_value_casted, cast2, size_t(size), align, int1(0))
@last = final_value
end
in .indirect?
Expand Down
60 changes: 27 additions & 33 deletions src/compiler/crystal/codegen/codegen.cr
Expand Up @@ -2079,7 +2079,7 @@ module Crystal
end

def pre_initialize_aggregate(type, struct_type, ptr)
memset ptr, int8(0), struct_type.size
memset ptr, int8(0), size_t(struct_type.size)
run_instance_vars_initializers(type, type, ptr)

unless type.struct?
Expand Down Expand Up @@ -2148,7 +2148,7 @@ module Crystal
if malloc_fun = yield
pointer = call malloc_fun, size
else
pointer = call_c_malloc size
pointer = call c_malloc_fun, size_t(size)
end

pointer_cast pointer, type.pointer
Expand All @@ -2168,10 +2168,10 @@ module Crystal
if malloc_fun = yield
pointer = call malloc_fun, size
else
pointer = call_c_malloc size
pointer = call c_malloc_fun, size_t(size)
end

memset pointer, int8(0), size
memset pointer, int8(0), size_t(size)
pointer_cast pointer, type.pointer
end

Expand Down Expand Up @@ -2211,43 +2211,39 @@ module Crystal
end
end

# We only use C's malloc in tests that don't require the prelude,
# so they don't require the GC. Outside tests these are not used,
# and __crystal_* functions are invoked instead.

def call_c_malloc(size)
size = trunc(size, llvm_context.int32) unless @program.bits64?
call c_malloc_fun, size
end
# Fallbacks to libc malloc and realloc when the expected __crystal_*
# functions aren't defined (e.g. empty prelude). We only use them in tests
# that don't require the prelude, so they don't require the GC.
#
# Outside tests the __crystal_* functions should have been defined and will
# be invoked instead.

def c_malloc_fun
malloc_fun = @c_malloc_fun = fetch_typed_fun(@main_mod, "malloc") do
size = @program.bits64? ? @main_llvm_context.int64 : @main_llvm_context.int32
LLVM::Type.function([size], @main_llvm_context.void_pointer)
LLVM::Type.function([main_llvm_context_size_t], @main_llvm_context.void_pointer)
end

check_main_fun "malloc", malloc_fun
end

def call_c_realloc(buffer, size)
size = trunc(size, llvm_context.int32) unless @program.bits64?
call c_realloc_fun, [buffer, size]
end

def c_realloc_fun
realloc_fun = @c_realloc_fun = fetch_typed_fun(@main_mod, "realloc") do
size = @program.bits64? ? @main_llvm_context.int64 : @main_llvm_context.int32
LLVM::Type.function([@main_llvm_context.void_pointer, size], @main_llvm_context.void_pointer)
LLVM::Type.function([@main_llvm_context.void_pointer, main_llvm_context_size_t], @main_llvm_context.void_pointer)
end

check_main_fun "realloc", realloc_fun
end

def memset(pointer, value, size)
len_arg = @program.bits64? ? size : trunc(size, llvm_context.int32)
# can't use `#size_t` because it targets @llvm_context instead of
# @main_llvm_context which confuses LLVM that considers them as distinct
# types despite the dumped LLVM IR looking identical
private def main_llvm_context_size_t
@main_llvm_context.int(@program.size_bit_width)
end

def memset(pointer, value, size)
pointer = cast_to_void_pointer pointer
res = call c_memset_fun, [pointer, value, len_arg, int1(0)]
res = call c_memset_fun, [pointer, value, size, int1(0)]
LibLLVM.set_instr_param_alignment(res, 1, 4)

res
Expand All @@ -2266,7 +2262,7 @@ module Crystal
if realloc_fun = crystal_realloc_fun
call realloc_fun, [buffer, size]
else
call_c_realloc buffer, size
call c_realloc_fun, [buffer, size_t(size)]
end
end

Expand All @@ -2278,28 +2274,26 @@ module Crystal

private def c_memset_fun
name = {% if LibLLVM::IS_LT_150 %}
@program.bits64? ? "llvm.memset.p0i8.i64" : "llvm.memset.p0i8.i32"
"llvm.memset.p0i8.i#{@program.size_bit_width}"
{% else %}
@program.bits64? ? "llvm.memset.p0.i64" : "llvm.memset.p0.i32"
"llvm.memset.p0.i#{@program.size_bit_width}"
{% end %}

fetch_typed_fun(@llvm_mod, name) do
len_type = @program.bits64? ? @llvm_context.int64 : @llvm_context.int32
arg_types = [@llvm_context.void_pointer, @llvm_context.int8, len_type, @llvm_context.int1]
arg_types = [@llvm_context.void_pointer, @llvm_context.int8, size_t, @llvm_context.int1]
LLVM::Type.function(arg_types, @llvm_context.void)
end
end

private def c_memcpy_fun
name = {% if LibLLVM::IS_LT_150 %}
@program.bits64? ? "llvm.memcpy.p0i8.p0i8.i64" : "llvm.memcpy.p0i8.p0i8.i32"
"llvm.memcpy.p0i8.p0i8.i#{@program.size_bit_width}"
{% else %}
@program.bits64? ? "llvm.memcpy.p0.p0.i64" : "llvm.memcpy.p0.p0.i32"
"llvm.memcpy.p0.p0.i#{@program.size_bit_width}"
{% end %}

fetch_typed_fun(@llvm_mod, name) do
len_type = @program.bits64? ? @llvm_context.int64 : @llvm_context.int32
arg_types = [@llvm_context.void_pointer, @llvm_context.void_pointer, len_type, @llvm_context.int1]
arg_types = [@llvm_context.void_pointer, @llvm_context.void_pointer, size_t, @llvm_context.int1]
LLVM::Type.function(arg_types, @llvm_context.void)
end
end
Expand Down
19 changes: 19 additions & 0 deletions src/compiler/crystal/codegen/llvm_builder_helper.cr
Expand Up @@ -30,6 +30,25 @@ module Crystal
int32(n)
end

def size_t
llvm_context.int(@program.size_bit_width)
end

def size_t(n)
size_t.const_int(n)
end

def size_t(value : LLVM::Value)
case value.type.int_width <=> @program.size_bit_width
when .zero?
value
when .positive?
builder.trunc(value, size_t)
else
builder.zext(value, size_t)
end
end

def int(n, type)
llvm_type(type).const_int(n)
end
Expand Down
6 changes: 1 addition & 5 deletions src/compiler/crystal/codegen/llvm_typer.cr
Expand Up @@ -586,11 +586,7 @@ module Crystal
end

def size_t
if @program.bits64?
@llvm_context.int64
else
@llvm_context.int32
end
@llvm_context.int(@program.size_bit_width)
end

@pointer_size : UInt64?
Expand Down
11 changes: 11 additions & 0 deletions src/compiler/crystal/codegen/target.cr
Expand Up @@ -58,6 +58,17 @@ class Crystal::Codegen::Target
end
end

def size_bit_width
case @architecture
when "aarch64", "x86_64"
64
when "arm", "i386", "wasm32"
32
else
raise "BUG: unknown Target#size_bit_width for #{@architecture} target architecture"
end
end

def os_name
case self
when .macos?
Expand Down
3 changes: 1 addition & 2 deletions src/compiler/crystal/codegen/unions.cr
Expand Up @@ -122,11 +122,10 @@ module Crystal
@llvm_typer.size_of(from_value_type),
@llvm_typer.size_of(to_value_type),
}.min
size = @program.bits64? ? int64(size) : int32(size)
memcpy(
cast_to_void_pointer(union_value(to_llvm_type, union_pointer)),
cast_to_void_pointer(union_value(from_llvm_type, value)),
size,
size_t(size),
align: @llvm_typer.align_of(to_value_type),
src_align: @llvm_typer.align_of(from_value_type),
volatile: int1(0),
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/crystal/semantic/flags.cr
Expand Up @@ -25,6 +25,10 @@ class Crystal::Program
codegen_target.pointer_bit_width == 64
end

def size_bit_width
codegen_target.size_bit_width
end

private def flags_for_target(target)
flags = Set(String).new

Expand Down

0 comments on commit a4ca7cc

Please sign in to comment.