From 1d8b0d46bc6d0b63723764e463d482975a135917 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 28 Mar 2016 02:52:15 +0000 Subject: [PATCH] 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. --- artiq/compiler/targets.py | 4 ++++ .../compiler/transforms/llvm_ir_generator.py | 22 +++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 42f5551b0..34f85d85f 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -89,6 +89,10 @@ class Target: 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() diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index fcb3b5d85..5ae0c3faa 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -181,6 +181,14 @@ class LLVMIRGenerator: 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 @@ class LLVMIRGenerator: 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 @@ class LLVMIRGenerator: 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):