diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 5ff48d68891..443892b761c 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -282,6 +282,11 @@ public: AttributeSet removeAttributes(LLVMContext &C, unsigned Index, AttributeSet Attrs) const; + /// \brief Add the dereferenceable attribute to the attribute set at the given + /// index. Since attribute sets are immutable, this returns a new set. + AttributeSet addDereferenceableAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const; + //===--------------------------------------------------------------------===// // AttributeSet Accessors //===--------------------------------------------------------------------===// diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 77b77f5b427..398998ae596 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -239,6 +239,9 @@ public: /// @brief removes the attributes from the list of attributes. void removeAttributes(unsigned i, AttributeSet attr); + /// @brief adds the dereferenceable attribute to the list of attributes. + void addDereferenceableAttr(unsigned i, uint64_t Bytes); + /// @brief Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { return AttributeSets.getParamAlignment(i); diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 045e51eb1ba..ac9ef35f319 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -1375,6 +1375,9 @@ public: /// removeAttribute - removes the attribute from the list of attributes. void removeAttribute(unsigned i, Attribute attr); + /// \brief adds the dereferenceable attribute to the list of attributes. + void addDereferenceableAttr(unsigned i, uint64_t Bytes); + /// \brief Determine whether this call has the given attribute. bool hasFnAttr(Attribute::AttrKind A) const { assert(A != Attribute::NoBuiltin && @@ -3056,6 +3059,9 @@ public: /// removeAttribute - removes the attribute from the list of attributes. void removeAttribute(unsigned i, Attribute attr); + /// \brief removes the dereferenceable attribute to the list of attributes. + void addDereferenceableAttr(unsigned i, uint64_t Bytes); + /// \brief Determine whether this call has the given attribute. bool hasFnAttr(Attribute::AttrKind A) const { assert(A != Attribute::NoBuiltin && diff --git a/lib/IR/Attributes.cpp b/lib/IR/Attributes.cpp index 04545ea919a..daac6b5f639 100644 --- a/lib/IR/Attributes.cpp +++ b/lib/IR/Attributes.cpp @@ -835,6 +835,13 @@ AttributeSet AttributeSet::removeAttributes(LLVMContext &C, unsigned Index, return get(C, AttrSet); } +AttributeSet AttributeSet::addDereferenceableAttr(LLVMContext &C, unsigned Index, + uint64_t Bytes) const { + llvm::AttrBuilder B; + B.addDereferenceableAttr(Bytes); + return addAttributes(C, Index, AttributeSet::get(C, Index, B)); +} + //===----------------------------------------------------------------------===// // AttributeSet Accessor Methods //===----------------------------------------------------------------------===// diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp index fe44f17d686..33e15262524 100644 --- a/lib/IR/Function.cpp +++ b/lib/IR/Function.cpp @@ -343,6 +343,12 @@ void Function::removeAttributes(unsigned i, AttributeSet attrs) { setAttributes(PAL); } +void Function::addDereferenceableAttr(unsigned i, uint64_t Bytes) { + AttributeSet PAL = getAttributes(); + PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + // Maintain the GC name for each function in an on-the-side table. This saves // allocating an additional word in Function for programs which do not use GC // (i.e., most programs) at the cost of increased overhead for clients which do diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp index 132800efeeb..8c4eeafdf84 100644 --- a/lib/IR/Instructions.cpp +++ b/lib/IR/Instructions.cpp @@ -346,6 +346,12 @@ void CallInst::removeAttribute(unsigned i, Attribute attr) { setAttributes(PAL); } +void CallInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) { + AttributeSet PAL = getAttributes(); + PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + bool CallInst::hasFnAttrImpl(Attribute::AttrKind A) const { if (AttributeList.hasAttribute(AttributeSet::FunctionIndex, A)) return true; @@ -605,6 +611,12 @@ void InvokeInst::removeAttribute(unsigned i, Attribute attr) { setAttributes(PAL); } +void InvokeInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) { + AttributeSet PAL = getAttributes(); + PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes); + setAttributes(PAL); +} + LandingPadInst *InvokeInst::getLandingPadInst() const { return cast(getUnwindDest()->getFirstNonPHI()); } diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 87dc8621a95..53a90d05af7 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1127,11 +1127,17 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { if (isKnownNonNull(DerivedPtr)) II->addAttribute(AttributeSet::ReturnIndex, Attribute::NonNull); - // TODO: dereferenceable -> deref attribute + // isDereferenceablePointer -> deref attribute + if (DerivedPtr->isDereferenceablePointer(DL)) { + if (Argument *A = dyn_cast(DerivedPtr)) { + uint64_t Bytes = A->getDereferenceableBytes(); + II->addDereferenceableAttr(AttributeSet::ReturnIndex, Bytes); + } + } // TODO: bitcast(relocate(p)) -> relocate(bitcast(p)) // Canonicalize on the type from the uses to the defs - + // TODO: relocate((gep p, C, C2, ...)) -> gep(relocate(p), C, C2, ...) } } diff --git a/test/Transforms/InstCombine/gc.relocate.ll b/test/Transforms/InstCombine/gc.relocate.ll new file mode 100644 index 00000000000..d10ef5fcfa2 --- /dev/null +++ b/test/Transforms/InstCombine/gc.relocate.ll @@ -0,0 +1,20 @@ +; RUN: opt < %s -datalayout -instcombine -S | FileCheck %s + +; Uses InstCombine with DataLayout to propagate dereferenceable +; attribute via gc.relocate: if the derived ptr is dereferenceable(N), +; then the return attribute of gc.relocate is dereferenceable(N). + +declare zeroext i1 @return_i1() +declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()*, i32, i32, ...) +declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32, i32, i32) + +define i32 addrspace(1)* @deref(i32 addrspace(1)* dereferenceable(8) %dparam) { +; Checks that a dereferenceabler pointer +; CHECK-LABEL: @deref +; CHECK: call dereferenceable(8) +entry: + %load = load i32 addrspace(1)* %dparam + %tok = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 addrspace(1)* %dparam) + %relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %tok, i32 4, i32 4) + ret i32 addrspace(1)* %relocate +} \ No newline at end of file