Skip to content

Commit f1998de

Browse files
author
Ary Borenszweig
committedMar 3, 2017
Codegen: use malloc_atomic whenever possible. Fixes #4081
1 parent dc0d365 commit f1998de

File tree

3 files changed

+92
-8
lines changed

3 files changed

+92
-8
lines changed
 

‎src/compiler/crystal/codegen/codegen.cr

+44-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Crystal
99
MAIN_NAME = "__crystal_main"
1010
RAISE_NAME = "__crystal_raise"
1111
MALLOC_NAME = "__crystal_malloc"
12+
MALLOC_ATOMIC_NAME = "__crystal_malloc_atomic"
1213
REALLOC_NAME = "__crystal_realloc"
1314
PERSONALITY_NAME = "__crystal_personality"
1415
GET_EXCEPTION_NAME = "__crystal_get_exception"
@@ -129,6 +130,7 @@ module Crystal
129130
@empty_md_list : LLVM::Value
130131
@rescue_block : LLVM::BasicBlock?
131132
@malloc_fun : LLVM::Function?
133+
@malloc_atomic_fun : LLVM::Function?
132134
@sret_value : LLVM::Value?
133135
@cant_pass_closure_to_c_exception_call : Call?
134136
@realloc_fun : LLVM::Function?
@@ -1746,7 +1748,12 @@ module Crystal
17461748
if type.passed_by_value?
17471749
@last = alloca struct_type
17481750
else
1749-
@last = malloc struct_type
1751+
if type.is_a?(InstanceVarContainer) && !type.struct? &&
1752+
type.all_instance_vars.each_value.any? &.type.has_inner_pointers?
1753+
@last = malloc struct_type
1754+
else
1755+
@last = malloc_atomic struct_type
1756+
end
17501757
end
17511758
memset @last, int8(0), struct_type.size
17521759
type_ptr = @last
@@ -1806,9 +1813,15 @@ module Crystal
18061813
end
18071814

18081815
def malloc(type)
1809-
@malloc_fun ||= @main_mod.functions[MALLOC_NAME]?
1810-
if malloc_fun = @malloc_fun
1811-
malloc_fun = check_main_fun MALLOC_NAME, malloc_fun
1816+
generic_malloc(type) { malloc_fun }
1817+
end
1818+
1819+
def malloc_atomic(type)
1820+
generic_malloc(type) { malloc_atomic_fun }
1821+
end
1822+
1823+
def generic_malloc(type)
1824+
if malloc_fun = yield
18121825
size = trunc(type.size, llvm_context.int32)
18131826
pointer = call malloc_fun, size
18141827
bit_cast pointer, type.pointer
@@ -1818,12 +1831,18 @@ module Crystal
18181831
end
18191832

18201833
def array_malloc(type, count)
1821-
@malloc_fun ||= @main_mod.functions[MALLOC_NAME]?
1834+
generic_array_malloc(type, count) { malloc_fun }
1835+
end
1836+
1837+
def array_malloc_atomic(type, count)
1838+
generic_array_malloc(type, count) { malloc_atomic_fun }
1839+
end
1840+
1841+
def generic_array_malloc(type, count)
18221842
size = trunc(type.size, llvm_context.int32)
18231843
count = trunc(count, llvm_context.int32)
18241844
size = builder.mul size, count
1825-
if malloc_fun = @malloc_fun
1826-
malloc_fun = check_main_fun MALLOC_NAME, malloc_fun
1845+
if malloc_fun = yield
18271846
pointer = call malloc_fun, size
18281847
memset pointer, int8(0), size
18291848
bit_cast pointer, type.pointer
@@ -1835,6 +1854,24 @@ module Crystal
18351854
end
18361855
end
18371856

1857+
def malloc_fun
1858+
@malloc_fun ||= @main_mod.functions[MALLOC_NAME]?
1859+
if malloc_fun = @malloc_fun
1860+
check_main_fun MALLOC_NAME, malloc_fun
1861+
else
1862+
nil
1863+
end
1864+
end
1865+
1866+
def malloc_atomic_fun
1867+
@malloc_atomic_fun ||= @main_mod.functions[MALLOC_ATOMIC_NAME]?
1868+
if malloc_fun = @malloc_atomic_fun
1869+
check_main_fun MALLOC_ATOMIC_NAME, malloc_fun
1870+
else
1871+
nil
1872+
end
1873+
end
1874+
18381875
def memset(pointer, value, size)
18391876
pointer = cast_to_void_pointer pointer
18401877
call @program.memset(@llvm_mod, llvm_context), [pointer, value, trunc(size, llvm_context.int32), int32(4), int1(0)]

‎src/compiler/crystal/codegen/primitives.cr

+5-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,11 @@ class Crystal::CodeGenVisitor
423423
def codegen_primitive_pointer_malloc(node, target_def, call_args)
424424
type = node.type.as(PointerInstanceType)
425425
llvm_type = llvm_embedded_type(type.element_type)
426-
last = array_malloc(llvm_type, call_args[1])
426+
if type.element_type.has_inner_pointers?
427+
last = array_malloc(llvm_type, call_args[1])
428+
else
429+
last = array_malloc_atomic(llvm_type, call_args[1])
430+
end
427431
last
428432
end
429433

‎src/compiler/crystal/codegen/types.cr

+43
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,49 @@ module Crystal
3939
end
4040
end
4141

42+
# Returns `true` if the type has inner pointers.
43+
# This is useful to know because if a type doesn't have
44+
# inner pointers we can use `malloc_atomic` instead of
45+
# `malloc` in `Pointer.malloc` for a tiny performance boost.
46+
def has_inner_pointers?
47+
case self
48+
when void?
Has conversations. Original line has conversations.
49+
# We consider Void to have pointers, so doing
50+
# Pointer(Void).malloc(...).as(ReferenceType)
51+
# will consider potential inner pointers as such.
52+
true
53+
when PointerInstanceType
54+
true
55+
when ProcInstanceType
56+
# A proc can have closure data which might have pointers
57+
true
58+
when StaticArrayInstanceType
59+
self.element_type.has_inner_pointers?
60+
when TupleInstanceType
61+
self.tuple_types.any? &.has_inner_pointers?
62+
when NamedTupleInstanceType
63+
self.entries.any? &.type.has_inner_pointers?
64+
when PrimitiveType
65+
false
66+
when EnumType
67+
false
68+
when UnionType
69+
self.union_types.any? &.has_inner_pointers?
70+
when AliasType
71+
self.aliased_type.has_inner_pointers?
72+
when TypeDefType
73+
self.typedef.has_inner_pointers?
74+
when InstanceVarContainer
75+
if struct?
76+
all_instance_vars.each_value.any? &.type.has_inner_pointers?
77+
else
78+
true
79+
end
80+
else
81+
true
82+
end
83+
end
84+
4285
def llvm_name
4386
String.build do |io|
4487
llvm_name io

0 commit comments

Comments
 (0)
Please sign in to comment.