Skip to content

Commit

Permalink
compiler: mark FFI functions as ModRef=Ref using TBAA metadata.
Browse files Browse the repository at this point in the history
Fascinatingly, the fact that you can mark call instructions with
!tbaa metadata is completely undocumented. Regardless, it is true:
a !tbaa metadata for an "immutable" type will cause
AliasAnalysis::getModRefBehavior to return OnlyReadsMemory for that
call site.

Don't bother marking loads with TBAA yet since we already place
!load.invariant on them (which is as good as the TBAA "immutable"
flag) and after that we're limited by lack of !nonnull anyway.

Also, add TBAA analysis passes in our pipeline to actually engage it.
whitequark committed Mar 28, 2016
1 parent 418f0a5 commit 1d8b0d4
Showing 2 changed files with 22 additions and 4 deletions.
4 changes: 4 additions & 0 deletions artiq/compiler/targets.py
Original file line number Diff line number Diff line change
@@ -89,6 +89,10 @@ def optimize(self, llmodule):
llpassmgr = llvm.create_module_pass_manager()
self.target_machine().target_data.add_pass(llpassmgr)

# Register our alias analysis passes.
llpassmgr.add_basic_alias_analysis_pass()
llpassmgr.add_type_based_alias_analysis_pass()

# Start by cleaning up after our codegen and exposing as much
# information to LLVM as possible.
llpassmgr.add_constant_merge_pass()
22 changes: 18 additions & 4 deletions artiq/compiler/transforms/llvm_ir_generator.py
Original file line number Diff line number Diff line change
@@ -181,6 +181,14 @@ def __init__(self, engine, module_name, target, function_map, object_map, type_m
self.phis = []
self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
self.empty_metadata = self.llmodule.add_metadata([])
self.tbaa_tree = self.llmodule.add_metadata([
ll.MetaDataString(self.llmodule, "ARTIQ TBAA")
])
self.tbaa_noalias_call = self.llmodule.add_metadata([
ll.MetaDataString(self.llmodule, "non-aliasing function call"),
self.tbaa_tree,
ll.Constant(lli64, 1)
])

def needs_sret(self, lltyp, may_be_large=True):
if isinstance(lltyp, ll.VoidType):
@@ -1252,17 +1260,18 @@ def ret_error_handler(typ):
return llret

def process_Call(self, insn):
if types.is_rpc_function(insn.target_function().type):
functiontyp = insn.target_function().type
if types.is_rpc_function(functiontyp):
return self._build_rpc(insn.target_function().loc,
insn.target_function().type,
functiontyp,
insn.arguments(),
llnormalblock=None, llunwindblock=None)
elif types.is_c_function(insn.target_function().type):
elif types.is_c_function(functiontyp):
llfun, llargs = self._prepare_ffi_call(insn)
else:
llfun, llargs = self._prepare_closure_call(insn)

if self.has_sret(insn.target_function().type):
if self.has_sret(functiontyp):
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])

llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
@@ -1276,6 +1285,11 @@ def process_Call(self, insn):
if insn.is_cold:
llcall.cconv = 'coldcc'

if types.is_c_function(functiontyp):
# All our global state is confined to our compilation unit,
# so by definition no FFI call can mutate it.
llcall.metadata['tbaa'] = self.tbaa_noalias_call

return llresult

def process_Invoke(self, insn):

0 comments on commit 1d8b0d4

Please sign in to comment.