forked from M-Labs/artiq
compiler: mark FFI functions as ModRef=Ref using TBAA metadata.
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.
This commit is contained in:
parent
0e0f81b509
commit
c6b21652ba
|
@ -89,6 +89,10 @@ class Target:
|
||||||
llpassmgr = llvm.create_module_pass_manager()
|
llpassmgr = llvm.create_module_pass_manager()
|
||||||
self.target_machine().target_data.add_pass(llpassmgr)
|
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
|
# Start by cleaning up after our codegen and exposing as much
|
||||||
# information to LLVM as possible.
|
# information to LLVM as possible.
|
||||||
llpassmgr.add_constant_merge_pass()
|
llpassmgr.add_constant_merge_pass()
|
||||||
|
|
|
@ -181,6 +181,14 @@ class LLVMIRGenerator:
|
||||||
self.phis = []
|
self.phis = []
|
||||||
self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
|
self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
|
||||||
self.empty_metadata = self.llmodule.add_metadata([])
|
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):
|
def needs_sret(self, lltyp, may_be_large=True):
|
||||||
if isinstance(lltyp, ll.VoidType):
|
if isinstance(lltyp, ll.VoidType):
|
||||||
|
@ -1252,17 +1260,18 @@ class LLVMIRGenerator:
|
||||||
return llret
|
return llret
|
||||||
|
|
||||||
def process_Call(self, insn):
|
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,
|
return self._build_rpc(insn.target_function().loc,
|
||||||
insn.target_function().type,
|
functiontyp,
|
||||||
insn.arguments(),
|
insn.arguments(),
|
||||||
llnormalblock=None, llunwindblock=None)
|
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)
|
llfun, llargs = self._prepare_ffi_call(insn)
|
||||||
else:
|
else:
|
||||||
llfun, llargs = self._prepare_closure_call(insn)
|
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"), [])
|
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
||||||
|
|
||||||
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
||||||
|
@ -1276,6 +1285,11 @@ class LLVMIRGenerator:
|
||||||
if insn.is_cold:
|
if insn.is_cold:
|
||||||
llcall.cconv = 'coldcc'
|
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
|
return llresult
|
||||||
|
|
||||||
def process_Invoke(self, insn):
|
def process_Invoke(self, insn):
|
||||||
|
|
Loading…
Reference in New Issue