Skip to content

Commit 1ee4de3

Browse files
committed
NativeCompiler computes the link-dependencies of the functions provided to it.
1 parent 9954544 commit 1ee4de3

File tree

6 files changed

+62
-29
lines changed

6 files changed

+62
-29
lines changed

typed_python/compiler/native_compiler/binary_shared_object.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(self, binarySharedObject, diskPath, functionPointers, globalVariabl
3636
class BinarySharedObject:
3737
"""Models a shared object library (.so) loadable on linux systems."""
3838

39-
def __init__(self, binaryForm, functionTypes, globalVariableDefinitions):
39+
def __init__(self, binaryForm, functionTypes, globalVariableDefinitions, usedExternalFunctions):
4040
"""
4141
Args:
4242
binaryForm - a bytes object containing the actual compiled code for the module
@@ -47,21 +47,27 @@ def __init__(self, binaryForm, functionTypes, globalVariableDefinitions):
4747
self.binaryForm = binaryForm
4848
self.functionTypes = functionTypes
4949
self.globalVariableDefinitions = globalVariableDefinitions
50+
self.usedExternalFunctions = usedExternalFunctions
5051
self.hash = sha_hash(binaryForm)
5152

5253
@property
5354
def definedSymbols(self):
5455
return self.functionTypes.keys()
5556

5657
@staticmethod
57-
def fromDisk(path, globalVariableDefinitions, functionNameToType):
58+
def fromDisk(path, globalVariableDefinitions, functionNameToType, usedExternalFunctions):
5859
with open(path, "rb") as f:
5960
binaryForm = f.read()
6061

61-
return BinarySharedObject(binaryForm, functionNameToType, globalVariableDefinitions)
62+
return BinarySharedObject(
63+
binaryForm,
64+
functionNameToType,
65+
globalVariableDefinitions,
66+
usedExternalFunctions
67+
)
6268

6369
@staticmethod
64-
def fromModule(module, globalVariableDefinitions, functionNameToType):
70+
def fromModule(module, globalVariableDefinitions, functionNameToType, usedExternalFunctions):
6571
target_triple = llvm.get_process_triple()
6672
target = llvm.Target.from_triple(target_triple)
6773
target_machine_shared_object = target.create_target_machine(reloc='pic', codemodel='default')
@@ -82,7 +88,12 @@ def fromModule(module, globalVariableDefinitions, functionNameToType):
8288
)
8389

8490
with open(os.path.join(tf, "module.so"), "rb") as so_file:
85-
return BinarySharedObject(so_file.read(), functionNameToType, globalVariableDefinitions)
91+
return BinarySharedObject(
92+
so_file.read(),
93+
functionNameToType,
94+
globalVariableDefinitions,
95+
usedExternalFunctions
96+
)
8697

8798
def load(self, storageDir):
8899
"""Instantiate this .so in temporary storage and return a dict from symbol -> integer function pointer"""

typed_python/compiler/native_compiler/compiler_cache.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ def loadModuleByHash(self, moduleHash, nameToTypedCallTarget, nameToNativeFuncti
137137

138138
with open(os.path.join(targetDir, "submodules.dat"), "rb") as f:
139139
submodules = SerializationContext().deserialize(f.read(), ListOf(str))
140+
141+
with open(os.path.join(targetDir, "linkDependencies.dat"), "rb") as f:
142+
linkDependencies = SerializationContext().deserialize(f.read(), ListOf(str))
143+
140144
except Exception:
141145
self.markModuleHashInvalid(moduleHash)
142146
return False
@@ -159,7 +163,8 @@ def loadModuleByHash(self, moduleHash, nameToTypedCallTarget, nameToNativeFuncti
159163
loaded = BinarySharedObject.fromDisk(
160164
modulePath,
161165
globalVarDefs,
162-
functionNameToNativeType
166+
functionNameToNativeType,
167+
linkDependencies
163168
).loadFromPath(modulePath)
164169

165170
self.loadedModules[moduleHash] = loaded
@@ -173,7 +178,7 @@ def loadModuleByHash(self, moduleHash, nameToTypedCallTarget, nameToNativeFuncti
173178

174179
return True
175180

176-
def addModule(self, binarySharedObject, nameToTypedCallTarget, linkDependencies):
181+
def addModule(self, binarySharedObject, nameToTypedCallTarget):
177182
"""Add new code to the compiler cache.
178183
179184
Args:
@@ -185,10 +190,14 @@ def addModule(self, binarySharedObject, nameToTypedCallTarget, linkDependencies)
185190
"""
186191
dependentHashes = set()
187192

188-
for name in linkDependencies:
193+
for name in binarySharedObject.usedExternalFunctions:
189194
dependentHashes.add(self.symbolToLoadedModuleHash[name])
190195

191-
path, hashToUse = self.writeModuleToDisk(binarySharedObject, nameToTypedCallTarget, dependentHashes)
196+
path, hashToUse = self.writeModuleToDisk(
197+
binarySharedObject,
198+
nameToTypedCallTarget,
199+
dependentHashes
200+
)
192201

193202
self.loadedModules[hashToUse] = (
194203
binarySharedObject.loadFromPath(os.path.join(path, "module.so"))
@@ -291,6 +300,14 @@ def writeModuleToDisk(self, binarySharedObject, nameToTypedCallTarget, submodule
291300
with open(os.path.join(tempTargetDir, "submodules.dat"), "wb") as f:
292301
f.write(SerializationContext().serialize(ListOf(str)(submodules), ListOf(str)))
293302

303+
with open(os.path.join(tempTargetDir, "linkDependencies.dat"), "wb") as f:
304+
f.write(
305+
SerializationContext().serialize(
306+
ListOf(str)(binarySharedObject.usedExternalFunctions),
307+
ListOf(str)
308+
)
309+
)
310+
294311
try:
295312
os.rename(tempTargetDir, targetDir)
296313
except IOError:

typed_python/compiler/native_compiler/module_definition.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,20 @@ class ModuleDefinition:
2222
moduleText - a string containing the llvm IR for the module
2323
functionList - a list of the names of exported functions
2424
globalDefinitions - a dict from name to a GlobalDefinition
25+
usedExternalFunctions - a set of symbols of functions that were compiled
26+
in different modules that we depend on. These will all be in some module.
2527
"""
2628
GET_GLOBAL_VARIABLES_NAME = ".get_global_variables"
2729

28-
def __init__(self, moduleText, functionNameToType, globalVariableDefinitions):
30+
def __init__(
31+
self,
32+
moduleText,
33+
functionNameToType,
34+
globalVariableDefinitions,
35+
usedExternalFunctions
36+
):
2937
self.moduleText = moduleText
3038
self.functionNameToType = functionNameToType
3139
self.globalVariableDefinitions = globalVariableDefinitions
3240
self.hash = sha_hash(moduleText)
41+
self.usedExternalFunctions = usedExternalFunctions

typed_python/compiler/native_compiler/native_ast_to_llvm.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,8 @@ def __init__(self,
568568
builder,
569569
arg_assignments,
570570
output_type,
571-
external_function_references
571+
external_function_references,
572+
usedExternalFunctions
572573
):
573574
self.function = function
574575

@@ -582,6 +583,7 @@ def __init__(self,
582583
self.arg_assignments = arg_assignments
583584
self.output_type = output_type
584585
self.external_function_references = external_function_references
586+
self.usedExternalFunctions = usedExternalFunctions
585587
self.tags_initialized = {}
586588
self.stack_slots = {}
587589

@@ -712,7 +714,9 @@ def namedCallTargetToLLVM(self, target):
712714
func = self.external_function_references[target.name]
713715
elif target.name in self.converter._externallyDefinedFunctionTypes:
714716
# this function is defined in a shared object that we've loaded from a prior
715-
# invocation
717+
# invocation. We don't have the code available locally, so we can't inline it.
718+
self.usedExternalFunctions.add(target.name)
719+
716720
if target.name not in self.external_function_references:
717721
func_type = llvmlite.ir.FunctionType(
718722
type_to_llvm_type(target.output_type),
@@ -1683,6 +1687,7 @@ def add_functions(self, names_to_definitions):
16831687

16841688
globalDefinitions = {}
16851689
globalDefinitionsLlvmValues = {}
1690+
usedExternalFunctions = set()
16861691

16871692
while names_to_definitions:
16881693
for name in sorted(names_to_definitions):
@@ -1712,7 +1717,8 @@ def add_functions(self, names_to_definitions):
17121717
builder,
17131718
arg_assignments,
17141719
definition.output_type,
1715-
external_function_references
1720+
external_function_references,
1721+
usedExternalFunctions
17161722
)
17171723

17181724
func_converter.setup()
@@ -1759,7 +1765,8 @@ def add_functions(self, names_to_definitions):
17591765
return ModuleDefinition(
17601766
str(module),
17611767
functionTypes,
1762-
globalDefinitions
1768+
globalDefinitions,
1769+
usedExternalFunctions
17631770
)
17641771

17651772
def defineGlobalMetadataAccessor(self, module, globalDefinitions, globalDefinitionsLlvmValues):

typed_python/compiler/native_compiler/native_compiler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ def addFunctions(
114114
# map from str to native_ast.Function
115115
functionDefinitions,
116116
# map from str to the TypedCallTarget for any function that's actually typed
117-
typedCallTargets,
118-
externallyUsed
117+
typedCallTargets
119118
):
120119
"""Add a collection of functions to the compiler.
121120
@@ -131,10 +130,10 @@ def addFunctions(
131130
loadedModule.linkGlobalVariables()
132131
else:
133132
binary = self._buildSharedObject(functionDefinitions)
133+
134134
self.compilerCache.addModule(
135135
binary,
136136
typedCallTargets,
137-
externallyUsed
138137
)
139138

140139
def functionPointerByName(self, linkName) -> NativeFunctionPointer:
@@ -206,6 +205,7 @@ def _buildSharedObject(self, functions):
206205
mod,
207206
module.globalVariableDefinitions,
208207
module.functionNameToType,
208+
module.usedExternalFunctions
209209
)
210210

211211
def _buildModule(self, functions):

typed_python/compiler/python_to_native_converter.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,20 +108,9 @@ def buildAndLinkNewModule(self):
108108
return
109109

110110
# get a set of function names that we depend on
111-
externallyUsed = set()
112-
113-
for funcName in targets:
114-
ident = self._identity_for_link_name.get(funcName)
115-
if ident is not None:
116-
for dep in self._dependencies.getNamesDependedOn(ident):
117-
depLN = self._link_name_for_identity.get(dep)
118-
if depLN not in targets:
119-
externallyUsed.add(depLN)
120-
121111
self.nativeCompiler.addFunctions(
122112
targets,
123-
{name: self._targets[name] for name in targets if name in self._targets},
124-
externallyUsed
113+
{name: self._targets[name] for name in targets if name in self._targets}
125114
)
126115

127116
def extract_new_function_definitions(self):

0 commit comments

Comments
 (0)