From 1573170bf531b4676447c4781cd1c1f327b00b86 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 9 Jan 2018 23:33:52 +0000 Subject: [PATCH 1/2] Base changes for fine-grained alias analysis --- src/librustc_llvm/ffi.rs | 8 ++++++++ src/librustc_trans/builder.rs | 34 ++++++++++++++++++++++++++++++- src/librustc_trans/mir/operand.rs | 6 +++++- src/librustc_trans/mir/place.rs | 13 +++++++++--- src/librustc_trans/type_of.rs | 2 +- src/rustllvm/RustWrapper.cpp | 23 +++++++++++++++++++++ src/rustllvm/rustllvm.h | 1 + 7 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 2cfb151ae85da..112bf3c99e83e 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -608,6 +608,14 @@ extern "C" { pub fn LLVMMDStringInContext(C: ContextRef, Str: *const c_char, SLen: c_uint) -> ValueRef; pub fn LLVMMDNodeInContext(C: ContextRef, Vals: *const ValueRef, Count: c_uint) -> ValueRef; pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, Name: *const c_char, Val: ValueRef); + pub fn LLVMRustCreateAnonymousAliasScopeDomain(C: ContextRef) -> MetadataRef; + pub fn LLVMRustCreateAnonymousAliasScope(C: ContextRef, + Domain: MetadataRef) + -> MetadataRef; + pub fn LLVMRustCreateAliasScopeList(C: ContextRef, + AliasScopes: *const MetadataRef, + AliasScopesCount: c_uint) + -> MetadataRef; // Operations on scalar constants pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef; diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 4a0b1381a4008..29e7349e27e3a 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -13,7 +13,7 @@ use llvm; use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef}; -use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; +use llvm::{ValueRef, MetadataRef, BasicBlockRef, BuilderRef, ModuleRef}; use common::*; use type_::Type; use value::Value; @@ -571,6 +571,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + pub fn anonymous_alias_scope_domain(&self) -> MetadataRef { + unsafe { + llvm::LLVMRustCreateAnonymousAliasScopeDomain(self.ccx.llcx()) + } + } + + pub fn anonymous_alias_scope(&self, alias_scope_domain: MetadataRef) -> MetadataRef { + unsafe { + llvm::LLVMRustCreateAnonymousAliasScope(self.ccx.llcx(), alias_scope_domain) + } + } + + pub fn alias_scope_list(&self, alias_scopes: Vec) -> MetadataRef { + unsafe { + llvm::LLVMRustCreateAliasScopeList(self.ccx.llcx(), + alias_scopes.as_ptr(), + alias_scopes.len() as c_uint) + } + } + + pub fn alias_scope_metadata(&self, load: ValueRef, alias_scope_list: MetadataRef) { + unsafe { + llvm::LLVMSetMetadata(load, llvm::MD_alias_scope as c_uint, llvm::LLVMRustMetadataAsValue(self.ccx.llcx(), alias_scope_list)); + } + } + + pub fn noalias_metadata(&self, load: ValueRef, alias_scope_list: MetadataRef) { + unsafe { + llvm::LLVMSetMetadata(load, llvm::MD_noalias as c_uint, llvm::LLVMRustMetadataAsValue(self.ccx.llcx(), alias_scope_list)); + } + } + pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); assert!(!self.llbuilder.is_null()); diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 05af48761a167..4f8a366e291a1 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -10,7 +10,7 @@ use llvm::ValueRef; use rustc::ty; -use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; @@ -108,11 +108,15 @@ impl<'a, 'tcx> OperandRef<'tcx> { OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) }; let layout = ccx.layout_of(projected_ty); + let kind = if let Some(pointee) = self.layout.pointee_info_at(ccx, Size::from_bytes(0)) { + pointee.safe + } else { None }; PlaceRef { llval: llptr, llextra, layout, align: layout.align, + kind, } } diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index b556b6a132312..727dabff8b8c1 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -18,7 +18,7 @@ use base; use builder::Builder; use common::{CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big}; use consts; -use type_of::LayoutLlvmExt; +use type_of::{LayoutLlvmExt, PointerKind}; use type_::Type; use value::Value; use glue; @@ -41,6 +41,9 @@ pub struct PlaceRef<'tcx> { /// What alignment we know for this place pub align: Align, + + /// The pointer restrictions associated with the place this reference was dereferenced from + pub kind: Option, } impl<'a, 'tcx> PlaceRef<'tcx> { @@ -52,7 +55,8 @@ impl<'a, 'tcx> PlaceRef<'tcx> { llval, llextra: ptr::null_mut(), layout, - align + align, + kind: None, } } @@ -185,6 +189,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { }, layout: field, align, + kind: None, } }; @@ -258,6 +263,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { llextra: self.llextra, layout: field, align, + kind: None, } } @@ -374,7 +380,8 @@ impl<'a, 'tcx> PlaceRef<'tcx> { llval: bcx.inbounds_gep(self.llval, &[C_usize(bcx.ccx, 0), llindex]), llextra: ptr::null_mut(), layout: self.layout.field(bcx.ccx, 0), - align: self.align + align: self.align, + kind: None, } } diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 8d9bc07fe5630..8cbdf877ce0aa 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -172,7 +172,7 @@ impl<'a, 'tcx> CrateContext<'a, 'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PointerKind { /// Most general case, we know no restrictions to tell LLVM. Shared, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 95130d596e165..87f043d398570 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1406,3 +1406,26 @@ LLVMRustModuleCost(LLVMModuleRef M) { auto f = unwrap(M)->functions(); return std::distance(std::begin(f), std::end(f)); } + +extern "C" LLVMMetadataRef +LLVMRustCreateAnonymousAliasScopeDomain(LLVMContextRef C) { + MDBuilder builder(*unwrap(C)); + return wrap(builder.createAnonymousAliasScopeDomain()); +} + +extern "C" LLVMMetadataRef +LLVMRustCreateAnonymousAliasScope(LLVMContextRef C, LLVMMetadataRef Domain) { + MDBuilder builder(*unwrap(C)); + return wrap(builder.createAnonymousAliasScope(cast(unwrap(Domain)))); +} + +extern "C" LLVMMetadataRef +LLVMRustCreateAliasScopeList(LLVMContextRef C, + LLVMMetadataRef *AliasScopes, + unsigned AliasScopesCount) { + SmallVector Elements; + for (unsigned i = 0; i < AliasScopesCount; ++i) { + Elements.push_back(unwrap(AliasScopes[i])); + } + return wrap(MDTuple::get(*unwrap(C), Elements)); +} diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index f4bd78147f631..575b5a05f6a97 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -70,6 +70,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/Linker/Linker.h" +#include "llvm/IR/MDBuilder.h" extern "C" void LLVMRustSetLastError(const char *); From ba85119e93db2a20a39bd962eede765aeaf032b3 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 10 Jan 2018 17:42:45 +0000 Subject: [PATCH 2/2] Noalias function calls with frozen pointers --- src/librustc_trans/builder.rs | 62 +++++++++++++++++++++++++++-- src/librustc_trans/mir/block.rs | 14 ++++--- src/librustc_trans/mir/mod.rs | 9 ++++- src/librustc_trans/mir/operand.rs | 23 ++++++++++- src/librustc_trans/mir/place.rs | 21 +++++++++- src/librustc_trans/mir/rvalue.rs | 12 +++++- src/librustc_trans/mir/statement.rs | 20 +++++++++- 7 files changed, 144 insertions(+), 17 deletions(-) diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 29e7349e27e3a..b26d6e7ac3568 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -27,6 +27,7 @@ use std::ffi::CString; use std::ops::Range; use std::ptr; use syntax_pos::Span; +use std::collections::HashMap; // All Builders must have an llfn associated with them #[must_use] @@ -922,8 +923,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn call(&self, llfn: ValueRef, args: &[ValueRef], - bundle: Option<&OperandBundleDef>) -> ValueRef { + pub fn call(&self, + llfn: ValueRef, + args: &[ValueRef], + bundle: Option<&OperandBundleDef>) + -> ValueRef { + self.call_vrf(llfn, args, bundle, None) + } + + pub fn call_vrf(&self, + llfn: ValueRef, + args: &[ValueRef], + bundle: Option<&OperandBundleDef>, + alias_scoper: Option<&AliasScoper>) + -> ValueRef { self.count_insn("call"); debug!("Call {:?} with args ({})", @@ -937,8 +950,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut()); unsafe { - llvm::LLVMRustBuildCall(self.llbuilder, llfn, args.as_ptr(), - args.len() as c_uint, bundle, noname()) + let call = llvm::LLVMRustBuildCall(self.llbuilder, llfn, args.as_ptr(), + args.len() as c_uint, bundle, noname()); + if let Some(alias_scoper) = alias_scoper { + if let Some(call_scope) = alias_scoper.call_scope(&self) { + self.noalias_metadata(call, call_scope); + } + } + call } } @@ -1292,3 +1311,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.call(lifetime_intrinsic, &[C_u64(self.ccx, size), ptr], None); } } + +#[derive(Debug)] +pub struct AliasScoper { + pub scope_domain: MetadataRef, + pub scopes: HashMap, +} + +impl AliasScoper { + pub fn alias_scope(&mut self, bcx: &Builder, index: usize) -> MetadataRef { + let scope_domain = self.scope_domain; + let new_alias_scope_list = || { + bcx.anonymous_alias_scope(scope_domain) + }; + *self.scopes.entry(index).or_insert_with(new_alias_scope_list) + } + + pub fn call_scope(&self, bcx: &Builder) -> Option { + let alias_scopes: Vec<_> = self.scopes.values().cloned().collect(); + if !alias_scopes.is_empty() { + Some(bcx.alias_scope_list(alias_scopes)) + } else { None } + } +} + +#[derive(Debug)] +pub struct Vrf<'a> { + pub index: usize, + pub alias_scoper: &'a mut AliasScoper, +} + +impl<'a> Vrf<'a> { + pub fn alias_scope(&mut self, bcx: &Builder) -> MetadataRef { + self.alias_scoper.alias_scope(bcx, self.index) + } +} diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 8c9fb03954583..5a6e5d987afe8 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -19,6 +19,7 @@ use abi::{Abi, FnType, ArgType, PassMode}; use base; use callee; use builder::Builder; +use builder::{AliasScoper}; use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_undef}; use consts; use meth; @@ -36,23 +37,24 @@ use super::operand::OperandRef; use super::operand::OperandValue::{Pair, Ref, Immediate}; impl<'a, 'tcx> MirContext<'a, 'tcx> { - pub fn trans_block(&mut self, bb: mir::BasicBlock) { + pub fn trans_block(&mut self, bb: mir::BasicBlock, alias_scoper: &mut AliasScoper) { let mut bcx = self.get_builder(bb); let data = &self.mir[bb]; debug!("trans_block({:?}={:?})", bb, data); for statement in &data.statements { - bcx = self.trans_statement(bcx, statement); + bcx = self.trans_statement(bcx, statement, alias_scoper); } - self.trans_terminator(bcx, bb, data.terminator()); + self.trans_terminator_vrf(bcx, bb, data.terminator(), Some(alias_scoper)); } - fn trans_terminator(&mut self, + fn trans_terminator_vrf(&mut self, mut bcx: Builder<'a, 'tcx>, bb: mir::BasicBlock, - terminator: &mir::Terminator<'tcx>) + terminator: &mir::Terminator<'tcx>, + alias_scoper: Option<&AliasScoper>) { debug!("trans_terminator: {:?}", terminator); @@ -138,7 +140,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { this.store_return(&ret_bcx, ret_dest, &fn_ty.ret, invokeret); } } else { - let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle); + let llret = bcx.call_vrf(fn_ptr, &llargs, cleanup_bundle, alias_scoper); fn_ty.apply_attrs_callsite(llret); if this.mir[bb].is_cleanup { // Cleanup is always the cold path. Don't inline diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 917ff87a674b6..001964d53e81b 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -19,6 +19,7 @@ use rustc::infer::TransNormalize; use rustc::session::config::FullDebugInfo; use base; use builder::Builder; +use builder::{AliasScoper}; use common::{CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::Instance; @@ -28,6 +29,7 @@ use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; use syntax::symbol::keywords; use std::iter; +use std::collections::HashMap; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -313,10 +315,15 @@ pub fn trans_mir<'a, 'tcx: 'a>( let rpo = traversal::reverse_postorder(&mir); let mut visited = BitVector::new(mir.basic_blocks().len()); + let mut alias_scoper = AliasScoper { + scope_domain: bcx.anonymous_alias_scope_domain(), + scopes: HashMap::new() + }; + // Translate the body of each block using reverse postorder for (bb, _) in rpo { visited.insert(bb.index()); - mircx.trans_block(bb); + mircx.trans_block(bb, &mut alias_scoper); } // Remove blocks that haven't been visited, or have no diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 4f8a366e291a1..6074d0fd40c9d 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -17,6 +17,7 @@ use rustc_data_structures::indexed_vec::Idx; use base; use common::{self, CrateContext, C_undef, C_usize}; use builder::Builder; +use builder::{Vrf}; use value::Value; use type_of::LayoutLlvmExt; use type_::Type; @@ -298,6 +299,15 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx: &Builder<'a, 'tcx>, place: &mir::Place<'tcx>) -> OperandRef<'tcx> + { + self.trans_consume_vrf(bcx, place, None) + } + + pub fn trans_consume_vrf(&mut self, + bcx: &Builder<'a, 'tcx>, + place: &mir::Place<'tcx>, + vrf: Option<&mut Vrf>) + -> OperandRef<'tcx> { debug!("trans_consume(place={:?})", place); @@ -315,20 +325,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // for most places, to consume them we just load them // out from their home - self.trans_place(bcx, place).load(bcx) + self.trans_place(bcx, place).load_with_vrf(bcx, vrf) } pub fn trans_operand(&mut self, bcx: &Builder<'a, 'tcx>, operand: &mir::Operand<'tcx>) -> OperandRef<'tcx> + { + self.trans_operand_vrf(bcx, operand, None) + } + + pub fn trans_operand_vrf(&mut self, + bcx: &Builder<'a, 'tcx>, + operand: &mir::Operand<'tcx>, + vrf: Option<&mut Vrf>) + -> OperandRef<'tcx> { debug!("trans_operand(operand={:?})", operand); match *operand { mir::Operand::Copy(ref place) | mir::Operand::Move(ref place) => { - self.trans_consume(bcx, place) + self.trans_consume_vrf(bcx, place, vrf) } mir::Operand::Constant(ref constant) => { diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index 727dabff8b8c1..035021d70fe80 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -16,6 +16,7 @@ use rustc::mir::tcx::PlaceTy; use rustc_data_structures::indexed_vec::Idx; use base; use builder::Builder; +use builder::{Vrf}; use common::{CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big}; use consts; use type_of::{LayoutLlvmExt, PointerKind}; @@ -86,7 +87,11 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } pub fn load(&self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> { - debug!("PlaceRef::load: {:?}", self); + self.load_with_vrf(bcx, None) + } + + pub fn load_with_vrf(&self, bcx: &Builder<'a, 'tcx>, vrf: Option<&mut Vrf>) -> OperandRef<'tcx> { + debug!("PlaceRef::load: {:?} {:?}", self, vrf); assert!(!self.has_extra()); @@ -135,6 +140,20 @@ impl<'a, 'tcx> PlaceRef<'tcx> { if let layout::Abi::Scalar(ref scalar) = self.layout.abi { scalar_load_metadata(load, scalar); } + if let Some(kind) = self.kind { + let no_alias = match kind { + PointerKind::Shared => false, + PointerKind::UniqueOwned | + PointerKind::Frozen | + PointerKind::UniqueBorrowed => true + }; + if no_alias { + if let Some(vrf) = vrf { + debug!("vrf-alias index {:?}", vrf.index); + bcx.alias_scope_metadata(load, vrf.alias_scope(bcx)); + } + } + } load }; OperandValue::Immediate(base::to_immediate(bcx, llval, self.layout)) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 56309f20dc12e..20c044fca13c8 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -20,6 +20,7 @@ use std::{u128, i128}; use base; use builder::Builder; +use builder::{Vrf}; use callee; use common::{self, val_ty}; use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_uint_big}; @@ -182,6 +183,15 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx: Builder<'a, 'tcx>, rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) + { + self.trans_rvalue_operand_vrf(bcx, rvalue, None) + } + + pub fn trans_rvalue_operand_vrf(&mut self, + bcx: Builder<'a, 'tcx>, + rvalue: &mir::Rvalue<'tcx>, + vrf: Option<&mut Vrf>) + -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); @@ -470,7 +480,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { (bcx, operand) } mir::Rvalue::Use(ref operand) => { - let operand = self.trans_operand(&bcx, operand); + let operand = self.trans_operand_vrf(&bcx, operand, vrf); (bcx, operand) } mir::Rvalue::Repeat(..) | diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index e0ca5dcc9d082..d51995d643033 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -16,10 +16,14 @@ use builder::Builder; use super::MirContext; use super::LocalRef; +use rustc_data_structures::indexed_vec::Idx; +use builder::{AliasScoper, Vrf}; + impl<'a, 'tcx> MirContext<'a, 'tcx> { pub fn trans_statement(&mut self, bcx: Builder<'a, 'tcx>, - statement: &mir::Statement<'tcx>) + statement: &mir::Statement<'tcx>, + alias_scoper: &mut AliasScoper) -> Builder<'a, 'tcx> { debug!("trans_statement(statement={:?})", statement); @@ -32,7 +36,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { self.trans_rvalue(bcx, tr_dest, rvalue) } LocalRef::Operand(None) => { - let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue); + let mut vrf_index = index.index(); + if let mir::Rvalue::Use(ref operand) = *rvalue { + if let mir::Operand::Copy(ref place) = *operand { + if let mir::Place::Projection(ref proj) = *place { + if let mir::Place::Local(index) = proj.base { + vrf_index = index.index(); + } + } + } + } + let vrf = &mut Vrf { index: vrf_index, alias_scoper }; + let (bcx, operand) = + self.trans_rvalue_operand_vrf(bcx, rvalue, Some(vrf)); self.locals[index] = LocalRef::Operand(Some(operand)); bcx }