Skip to content

Commit 65b622c

Browse files
Augustus LonerganWilliam Grant
authored andcommitted
Limit compiler cache interface to getTarget and addModule
Current implementation of the interface, used via _loadFromCompilerCache, runs loadForSymbol for a given link name and then returns two dicts representing everything the cache touched during this load process. Maintaining this interface makes the partial-load refactor difficult, and muddies the converter layers/cache relationship. Here we alter the API so that we can ask the cache for a TypedCallTarget, and add modules, and that's it. This means getting rid of _loadFromCompilerCache, and associated registers for tracking what's being converted. Also means passing the cache down to the native_ast_to_llvm layer.
1 parent 6b010c1 commit 65b622c

File tree

5 files changed

+108
-120
lines changed

5 files changed

+108
-120
lines changed

typed_python/compiler/compiler_cache.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,28 @@ def __init__(self, cacheDir):
6262
if len(moduleHash) == 40:
6363
self.loadNameManifestFromStoredModuleByHash(moduleHash)
6464

65+
self.targetsLoaded = {}
66+
6567
def hasSymbol(self, linkName):
6668
return linkName in self.nameToModuleHash
6769

70+
def getTarget(self, linkName):
71+
assert self.hasSymbol(linkName)
72+
73+
self.loadForSymbol(linkName)
74+
75+
return self.targetsLoaded[linkName]
76+
6877
def markModuleHashInvalid(self, hashstr):
6978
with open(os.path.join(self.cacheDir, hashstr, "marked_invalid"), "w"):
7079
pass
7180

7281
def loadForSymbol(self, linkName):
7382
moduleHash = self.nameToModuleHash[linkName]
7483

75-
nameToTypedCallTarget = {}
76-
nameToNativeFunctionType = {}
77-
78-
if not self.loadModuleByHash(moduleHash, nameToTypedCallTarget, nameToNativeFunctionType):
79-
return None
80-
81-
return nameToTypedCallTarget, nameToNativeFunctionType
84+
self.loadModuleByHash(moduleHash)
8285

83-
def loadModuleByHash(self, moduleHash, nameToTypedCallTarget, nameToNativeFunctionType):
86+
def loadModuleByHash(self, moduleHash):
8487
"""Load a module by name.
8588
8689
As we load, place all the newly imported typed call targets into
@@ -114,11 +117,7 @@ def loadModuleByHash(self, moduleHash, nameToTypedCallTarget, nameToNativeFuncti
114117

115118
# load the submodules first
116119
for submodule in submodules:
117-
if not self.loadModuleByHash(
118-
submodule,
119-
nameToTypedCallTarget,
120-
nameToNativeFunctionType
121-
):
120+
if not self.loadModuleByHash(submodule):
122121
return False
123122

124123
modulePath = os.path.join(targetDir, "module.so")
@@ -131,8 +130,7 @@ def loadModuleByHash(self, moduleHash, nameToTypedCallTarget, nameToNativeFuncti
131130

132131
self.loadedModules[moduleHash] = loaded
133132

134-
nameToTypedCallTarget.update(callTargets)
135-
nameToNativeFunctionType.update(functionNameToNativeType)
133+
self.targetsLoaded.update(callTargets)
136134

137135
return True
138136

typed_python/compiler/llvm_compiler.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,14 @@ def create_execution_engine(inlineThreshold):
8484

8585

8686
class Compiler:
87-
def __init__(self, inlineThreshold):
87+
def __init__(self, inlineThreshold, compilerCache):
8888
self.engine, self.module_pass_manager = create_execution_engine(inlineThreshold)
89-
self.converter = native_ast_to_llvm.Converter()
89+
self.converter = native_ast_to_llvm.Converter(compilerCache)
9090
self.functions_by_name = {}
9191
self.inlineThreshold = inlineThreshold
9292
self.verbose = False
9393
self.optimize = True
9494

95-
def markExternal(self, functionNameToType):
96-
"""Provide type signatures for a set of external functions."""
97-
self.converter.markExternal(functionNameToType)
98-
9995
def mark_converter_verbose(self):
10096
self.converter.verbose = True
10197

typed_python/compiler/native_ast_to_llvm.py

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -501,14 +501,13 @@ def __init__(self,
501501
module,
502502
globalDefinitions,
503503
globalDefinitionLlvmValues,
504-
function,
505504
converter,
506505
builder,
507506
arg_assignments,
508507
output_type,
509-
external_function_references
508+
external_function_references,
509+
compilerCache,
510510
):
511-
self.function = function
512511

513512
# dict from name to GlobalVariableDefinition
514513
self.globalDefinitions = globalDefinitions
@@ -522,6 +521,7 @@ def __init__(self,
522521
self.external_function_references = external_function_references
523522
self.tags_initialized = {}
524523
self.stack_slots = {}
524+
self.compilerCache = compilerCache
525525

526526
def tags_as(self, new_tags):
527527
class scoper():
@@ -648,7 +648,24 @@ def namedCallTargetToLLVM(self, target):
648648
llvmlite.ir.Function(self.module, func_type, target.name)
649649

650650
func = self.external_function_references[target.name]
651-
elif target.name in self.converter._externallyDefinedFunctionTypes:
651+
elif target.name in self.converter._function_definitions:
652+
func = self.converter._functions_by_name[target.name]
653+
654+
if func.module is not self.module:
655+
# first, see if we'd like to inline this module
656+
if (
657+
self.converter.totalFunctionComplexity(target.name) < CROSS_MODULE_INLINE_COMPLEXITY
658+
):
659+
func = self.converter.repeatFunctionInModule(target.name, self.module)
660+
else:
661+
if target.name not in self.external_function_references:
662+
self.external_function_references[target.name] = \
663+
llvmlite.ir.Function(self.module, func.function_type, func.name)
664+
665+
func = self.external_function_references[target.name]
666+
else:
667+
# TODO: decide whether to inline based on something in the compiler cache
668+
assert self.compilerCache is not None and self.compilerCache.hasSymbol(target.name)
652669
# this function is defined in a shared object that we've loaded from a prior
653670
# invocation
654671
if target.name not in self.external_function_references:
@@ -665,22 +682,6 @@ def namedCallTargetToLLVM(self, target):
665682
)
666683

667684
func = self.external_function_references[target.name]
668-
else:
669-
func = self.converter._functions_by_name[target.name]
670-
671-
if func.module is not self.module:
672-
# first, see if we'd like to inline this module
673-
if (
674-
self.converter.totalFunctionComplexity(target.name) < CROSS_MODULE_INLINE_COMPLEXITY
675-
and self.converter.canBeInlined(target.name)
676-
):
677-
func = self.converter.repeatFunctionInModule(target.name, self.module)
678-
else:
679-
if target.name not in self.external_function_references:
680-
self.external_function_references[target.name] = \
681-
llvmlite.ir.Function(self.module, func.function_type, func.name)
682-
683-
func = self.external_function_references[target.name]
684685

685686
return TypedLLVMValue(
686687
func,
@@ -1484,16 +1485,12 @@ def define(fname, output, inputs, vararg=False):
14841485

14851486

14861487
class Converter:
1487-
def __init__(self):
1488+
def __init__(self, compilerCache):
14881489
object.__init__(self)
14891490
self._modules = {}
14901491
self._functions_by_name = {}
14911492
self._function_definitions = {}
14921493

1493-
# a map from function name to function type for functions that
1494-
# are defined in external shared objects and linked in to this one.
1495-
self._externallyDefinedFunctionTypes = {}
1496-
14971494
# total number of instructions in each function, by name
14981495
self._function_complexity = {}
14991496

@@ -1502,12 +1499,7 @@ def __init__(self):
15021499
self._printAllNativeCalls = os.getenv("TP_COMPILER_LOG_NATIVE_CALLS")
15031500
self.verbose = False
15041501

1505-
def markExternal(self, functionNameToType):
1506-
"""Provide type signatures for a set of external functions."""
1507-
self._externallyDefinedFunctionTypes.update(functionNameToType)
1508-
1509-
def canBeInlined(self, name):
1510-
return name not in self._externallyDefinedFunctionTypes
1502+
self.compilerCache = compilerCache
15111503

15121504
def totalFunctionComplexity(self, name):
15131505
"""Return the total number of instructions contained in a function.
@@ -1621,19 +1613,19 @@ def add_functions(self, names_to_definitions):
16211613
TypedLLVMValue(func.args[i], definition.args[i][1])
16221614

16231615
block = func.append_basic_block('entry')
1624-
builder = llvmlite.ir.IRBuilder(block)
1616+
builder = llvmlite.ir.IRBuilder(block) # this shares state with func
16251617

16261618
try:
16271619
func_converter = FunctionConverter(
16281620
module,
16291621
globalDefinitions,
16301622
globalDefinitionsLlvmValues,
1631-
func,
16321623
self,
16331624
builder,
16341625
arg_assignments,
16351626
definition.output_type,
1636-
external_function_references
1627+
external_function_references,
1628+
self.compilerCache,
16371629
)
16381630

16391631
func_converter.setup()

0 commit comments

Comments
 (0)