[llvm] r367187 - [Attributor] Deduce "align" attribute

Hideto Ueno via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 28 00:04:01 PDT 2019


Author: uenoku
Date: Sun Jul 28 00:04:01 2019
New Revision: 367187

URL: http://llvm.org/viewvc/llvm-project?rev=367187&view=rev
Log:
[Attributor] Deduce "align" attribute

Summary:
Deduce "align" attribute in attributor.

Reviewers: jdoerfert, sstefan1

Reviewed By: jdoerfert

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D64152

Added:
    llvm/trunk/test/Transforms/FunctionAttrs/align.ll
Modified:
    llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp
    llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll
    llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll

Modified: llvm/trunk/include/llvm/Transforms/IPO/Attributor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/Attributor.h?rev=367187&r1=367186&r2=367187&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/Attributor.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/Attributor.h Sun Jul 28 00:04:01 2019
@@ -905,6 +905,31 @@ struct AADereferenceable : public Abstra
   static constexpr Attribute::AttrKind ID = Attribute::Dereferenceable;
 };
 
+/// An abstract interface for all align attributes.
+struct AAAlign : public AbstractAttribute {
+
+  /// See AbstractAttribute::AbstractAttribute(...).
+  AAAlign(Value &V, InformationCache &InfoCache)
+      : AbstractAttribute(V, InfoCache) {}
+
+  /// See AbstractAttribute::AbstractAttribute(...).
+  AAAlign(Value *AssociatedVal, Value &AnchoredValue,
+          InformationCache &InfoCache)
+      : AbstractAttribute(AssociatedVal, AnchoredValue, InfoCache) {}
+
+  /// See AbastractState::getAttrKind().
+  Attribute::AttrKind getAttrKind() const override { return ID; }
+
+  /// Return assumed alignment.
+  virtual unsigned getAssumedAlign() const = 0;
+
+  /// Return known alignemnt.
+  virtual unsigned getKnownAlign() const = 0;
+
+  /// The identifier used by the Attributor for this class of attributes.
+  static constexpr Attribute::AttrKind ID = Attribute::Alignment;
+};
+
 } // end namespace llvm
 
 #endif // LLVM_TRANSFORMS_IPO_FUNCTIONATTRS_H

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=367187&r1=367186&r2=367187&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Sun Jul 28 00:04:01 2019
@@ -72,6 +72,9 @@ STATISTIC(NumFnArgumentDereferenceable,
           "Number of function arguments marked dereferenceable");
 STATISTIC(NumCSArgumentDereferenceable,
           "Number of call site arguments marked dereferenceable");
+STATISTIC(NumFnReturnedAlign, "Number of function return values marked align");
+STATISTIC(NumFnArgumentAlign, "Number of function arguments marked align");
+STATISTIC(NumCSArgumentAlign, "Number of call site arguments marked align");
 
 // TODO: Determine a good default value.
 //
@@ -115,6 +118,21 @@ static void bookkeeping(AbstractAttribut
     return;
 
   switch (Attr.getKindAsEnum()) {
+  case Attribute::Alignment:
+    switch (MP) {
+    case AbstractAttribute::MP_RETURNED:
+      NumFnReturnedAlign++;
+      break;
+    case AbstractAttribute::MP_ARGUMENT:
+      NumFnArgumentAlign++;
+      break;
+    case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
+      NumCSArgumentAlign++;
+      break;
+    default:
+      break;
+    }
+    break;
   case Attribute::Dereferenceable:
     switch (MP) {
     case AbstractAttribute::MP_RETURNED:
@@ -1974,6 +1992,212 @@ ChangeStatus AADereferenceableCallSiteAr
                                                        : ChangeStatus::CHANGED;
 }
 
+// ------------------------ Align Argument Attribute ------------------------
+
+struct AAAlignImpl : AAAlign, IntegerState {
+
+  // Max alignemnt value allowed in IR
+  static const unsigned MAX_ALIGN = 1U << 29;
+
+  AAAlignImpl(Value *AssociatedVal, Value &AnchoredValue,
+              InformationCache &InfoCache)
+      : AAAlign(AssociatedVal, AnchoredValue, InfoCache),
+        IntegerState(MAX_ALIGN) {}
+
+  AAAlignImpl(Value &V, InformationCache &InfoCache)
+      : AAAlignImpl(&V, V, InfoCache) {}
+
+  /// See AbstractAttribute::getState()
+  /// {
+  AbstractState &getState() override { return *this; }
+  const AbstractState &getState() const override { return *this; }
+  /// }
+
+  virtual const std::string getAsStr() const override {
+    return getAssumedAlign() ? ("align<" + std::to_string(getKnownAlign()) +
+                                "-" + std::to_string(getAssumedAlign()) + ">")
+                             : "unknown-align";
+  }
+
+  /// See AAAlign::getAssumedAlign().
+  unsigned getAssumedAlign() const override { return getAssumed(); }
+
+  /// See AAAlign::getKnownAlign().
+  unsigned getKnownAlign() const override { return getKnown(); }
+
+  /// See AbstractAttriubute::initialize(...).
+  void initialize(Attributor &A) override {
+    Function &F = getAnchorScope();
+
+    unsigned AttrIdx =
+        getAttrIndex(getManifestPosition(), getArgNo(getAnchoredValue()));
+
+    // Already the function has align attribute on return value or argument.
+    if (F.getAttributes().hasAttribute(AttrIdx, ID))
+      addKnownBits(F.getAttribute(AttrIdx, ID).getAlignment());
+  }
+
+  /// See AbstractAttribute::getDeducedAttributes
+  virtual void
+  getDeducedAttributes(SmallVectorImpl<Attribute> &Attrs) const override {
+    LLVMContext &Ctx = AnchoredVal.getContext();
+
+    Attrs.emplace_back(Attribute::getWithAlignment(Ctx, getAssumedAlign()));
+  }
+};
+
+/// Align attribute for function return value.
+struct AAAlignReturned : AAAlignImpl {
+
+  AAAlignReturned(Function &F, InformationCache &InfoCache)
+      : AAAlignImpl(F, InfoCache) {}
+
+  /// See AbstractAttribute::getManifestPosition().
+  virtual ManifestPosition getManifestPosition() const override {
+    return MP_RETURNED;
+  }
+
+  /// See AbstractAttribute::updateImpl(...).
+  virtual ChangeStatus updateImpl(Attributor &A) override;
+};
+
+ChangeStatus AAAlignReturned::updateImpl(Attributor &A) {
+  Function &F = getAnchorScope();
+  auto *AARetValImpl = A.getAAFor<AAReturnedValuesImpl>(*this, F);
+  if (!AARetValImpl) {
+    indicatePessimisticFixpoint();
+    return ChangeStatus::CHANGED;
+  }
+
+  // Currently, align<n> is deduced if alignments in return values are assumed
+  // as greater than n. We reach pessimistic fixpoint if any of the return value
+  // wouldn't have align. If no assumed state was used for reasoning, an
+  // optimistic fixpoint is reached earlier.
+
+  base_t BeforeState = getAssumed();
+  std::function<bool(Value &)> Pred = [&](Value &RV) -> bool {
+    auto *AlignAA = A.getAAFor<AAAlign>(*this, RV);
+
+    if (AlignAA)
+      takeAssumedMinimum(AlignAA->getAssumedAlign());
+    else
+      // Use IR information.
+      takeAssumedMinimum(RV.getPointerAlignment(
+          getAnchorScope().getParent()->getDataLayout()));
+
+    return isValidState();
+  };
+
+  if (!AARetValImpl->checkForallReturnedValues(Pred)) {
+    indicatePessimisticFixpoint();
+    return ChangeStatus::CHANGED;
+  }
+
+  return (getAssumed() != BeforeState) ? ChangeStatus::CHANGED
+                                       : ChangeStatus::UNCHANGED;
+}
+
+/// Align attribute for function argument.
+struct AAAlignArgument : AAAlignImpl {
+
+  AAAlignArgument(Argument &A, InformationCache &InfoCache)
+      : AAAlignImpl(A, InfoCache) {}
+
+  /// See AbstractAttribute::getManifestPosition().
+  virtual ManifestPosition getManifestPosition() const override {
+    return MP_ARGUMENT;
+  }
+
+  /// See AbstractAttribute::updateImpl(...).
+  virtual ChangeStatus updateImpl(Attributor &A) override;
+};
+
+ChangeStatus AAAlignArgument::updateImpl(Attributor &A) {
+
+  Function &F = getAnchorScope();
+  Argument &Arg = cast<Argument>(getAnchoredValue());
+
+  unsigned ArgNo = Arg.getArgNo();
+  const DataLayout &DL = F.getParent()->getDataLayout();
+
+  auto BeforeState = getAssumed();
+
+  // Callback function
+  std::function<bool(CallSite)> CallSiteCheck = [&](CallSite CS) {
+    assert(CS && "Sanity check: Call site was not initialized properly!");
+
+    auto *AlignAA = A.getAAFor<AAAlign>(*this, *CS.getInstruction(), ArgNo);
+
+    // Check that AlignAA is AAAlignCallSiteArgument.
+    if (AlignAA) {
+      ImmutableCallSite ICS(&AlignAA->getAnchoredValue());
+      if (ICS && CS.getInstruction() == ICS.getInstruction()) {
+        takeAssumedMinimum(AlignAA->getAssumedAlign());
+        return isValidState();
+      }
+    }
+
+    Value *V = CS.getArgOperand(ArgNo);
+    takeAssumedMinimum(V->getPointerAlignment(DL));
+    return isValidState();
+  };
+
+  if (!A.checkForAllCallSites(F, CallSiteCheck, true))
+    indicatePessimisticFixpoint();
+
+  return BeforeState == getAssumed() ? ChangeStatus::UNCHANGED
+                                     : ChangeStatus ::CHANGED;
+}
+
+struct AAAlignCallSiteArgument : AAAlignImpl {
+
+  /// See AANonNullImpl::AANonNullImpl(...).
+  AAAlignCallSiteArgument(CallSite CS, unsigned ArgNo,
+                          InformationCache &InfoCache)
+      : AAAlignImpl(CS.getArgOperand(ArgNo), *CS.getInstruction(), InfoCache),
+        ArgNo(ArgNo) {}
+
+  /// See AbstractAttribute::initialize(...).
+  void initialize(Attributor &A) override {
+    CallSite CS(&getAnchoredValue());
+    takeKnownMaximum(getAssociatedValue()->getPointerAlignment(
+        getAnchorScope().getParent()->getDataLayout()));
+  }
+
+  /// See AbstractAttribute::updateImpl(Attributor &A).
+  ChangeStatus updateImpl(Attributor &A) override;
+
+  /// See AbstractAttribute::getManifestPosition().
+  ManifestPosition getManifestPosition() const override {
+    return MP_CALL_SITE_ARGUMENT;
+  };
+
+  // Return argument index of associated value.
+  int getArgNo() const { return ArgNo; }
+
+private:
+  unsigned ArgNo;
+};
+
+ChangeStatus AAAlignCallSiteArgument::updateImpl(Attributor &A) {
+  // NOTE: Never look at the argument of the callee in this method.
+  //       If we do this, "align" is always deduced because of the assumption.
+
+  auto BeforeState = getAssumed();
+
+  Value &V = *getAssociatedValue();
+
+  auto *AlignAA = A.getAAFor<AAAlign>(*this, V);
+
+  if (AlignAA)
+    takeAssumedMinimum(AlignAA->getAssumedAlign());
+  else
+    indicatePessimisticFixpoint();
+
+  return BeforeState == getAssumed() ? ChangeStatus::UNCHANGED
+                                     : ChangeStatus::CHANGED;
+}
+
 /// ----------------------------------------------------------------------------
 ///                               Attributor
 /// ----------------------------------------------------------------------------
@@ -2171,6 +2395,10 @@ void Attributor::identifyDefaultAbstract
       registerAA(*new AAReturnedValuesImpl(F, InfoCache));
 
     if (ReturnType->isPointerTy()) {
+      // Every function with pointer return type might be marked align.
+      if (!Whitelist || Whitelist->count(AAAlignReturned::ID))
+        registerAA(*new AAAlignReturned(F, InfoCache));
+
       // Every function with pointer return type might be marked nonnull.
       if (!Whitelist || Whitelist->count(AANonNullReturned::ID))
         registerAA(*new AANonNullReturned(F, InfoCache));
@@ -2196,6 +2424,10 @@ void Attributor::identifyDefaultAbstract
       // Every argument with pointer type might be marked dereferenceable.
       if (!Whitelist || Whitelist->count(AADereferenceableArgument::ID))
         registerAA(*new AADereferenceableArgument(Arg, InfoCache));
+
+      // Every argument with pointer type might be marked align.
+      if (!Whitelist || Whitelist->count(AAAlignArgument::ID))
+        registerAA(*new AAAlignArgument(Arg, InfoCache));
     }
   }
 
@@ -2254,6 +2486,10 @@ void Attributor::identifyDefaultAbstract
             Whitelist->count(AADereferenceableCallSiteArgument::ID))
           registerAA(*new AADereferenceableCallSiteArgument(CS, i, InfoCache),
                      i);
+
+        // Call site argument attribute "align".
+        if (!Whitelist || Whitelist->count(AAAlignCallSiteArgument::ID))
+          registerAA(*new AAAlignCallSiteArgument(CS, i, InfoCache), i);
       }
     }
   }

Added: llvm/trunk/test/Transforms/FunctionAttrs/align.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/align.ll?rev=367187&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/align.ll (added)
+++ llvm/trunk/test/Transforms/FunctionAttrs/align.ll Sun Jul 28 00:04:01 2019
@@ -0,0 +1,168 @@
+; RUN: opt -attributor -attributor-disable=false -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; Test cases specifically designed for "align" attribute.
+; We use FIXME's to indicate problems and missing attributes.
+
+
+; TEST 1
+; ATTRIBUTOR: define align 8 i32* @test1(i32* returned align 8)
+define i32* @test1(i32* align 8) #0 {
+  ret i32* %0
+}
+
+; TEST 2
+; ATTRIBUTOR: define i32* @test2(i32* returned)
+define i32* @test2(i32*) #0 {
+  ret i32* %0
+}
+
+; TEST 3
+; ATTRIBUTOR: define align 4 i32* @test3(i32* align 8, i32* align 4, i1)
+define i32* @test3(i32* align 8, i32* align 4, i1) #0 {
+  %ret = select i1 %2, i32* %0, i32* %1
+  ret i32* %ret
+}
+
+; TEST 4
+; ATTRIBUTOR: define align 32 i32* @test4(i32* align 32, i32* align 32, i1)
+define i32* @test4(i32* align 32, i32* align 32, i1) #0 {
+  %ret = select i1 %2, i32* %0, i32* %1
+  ret i32* %ret
+}
+
+; TEST 5
+declare i32* @unknown()
+declare align 8 i32* @align8()
+
+
+; ATTRIBUTOR: define align 8 i32* @test5_1()
+define i32* @test5_1() {
+  %ret = tail call align 8 i32* @unknown()
+  ret i32* %ret
+}
+
+; ATTRIBUTOR: define align 8 i32* @test5_2()
+define i32* @test5_2() {
+  %ret = tail call i32* @align8()
+  ret i32* %ret
+}
+
+; TEST 6
+; SCC
+; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_1()
+define i32* @test6_1() #0 {
+  %ret = tail call i32* @test6_2()
+  ret i32* %ret
+}
+
+; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_2()
+define i32* @test6_2() #0 {
+  %ret = tail call i32* @test6_1()
+  ret i32* %ret
+}
+
+
+; char a1 __attribute__((aligned(8)));
+; char a2 __attribute__((aligned(16)));
+;
+; char* f1(char* a ){
+;     return a?a:f2(&a1);
+; }
+; char* f2(char* a){
+;     return a?f1(a):f3(&a2);
+; }
+;
+; char* f3(char* a){
+;     return a?&a1: f1(&a2);
+; }
+
+ at a1 = common global i8 0, align 8
+ at a2 = common global i8 0, align 16
+
+; Function Attrs: nounwind readnone ssp uwtable
+define internal i8* @f1(i8* readnone) local_unnamed_addr #0 {
+; ATTRIBUTOR: define internal nonnull align 8 i8* @f1(i8* nonnull readnone align 8)
+  %2 = icmp eq i8* %0, null
+  br i1 %2, label %3, label %5
+
+; <label>:3:                                      ; preds = %1
+; ATTRIBUTOR: %4 = tail call i8* @f2(i8* nonnull align 8 @a1)
+  %4 = tail call i8* @f2(i8* nonnull @a1)
+  br label %5
+
+; <label>:5:                                      ; preds = %1, %3
+  %6 = phi i8* [ %4, %3 ], [ %0, %1 ]
+  ret i8* %6
+}
+
+; Function Attrs: nounwind readnone ssp uwtable
+define internal i8* @f2(i8* readnone) local_unnamed_addr #0 {
+; ATTRIBUTOR: define internal nonnull align 8 i8* @f2(i8* nonnull readnone align 8)
+  %2 = icmp eq i8* %0, null
+  br i1 %2, label %5, label %3
+
+; <label>:3:                                      ; preds = %1
+
+; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 8 %0)
+  %4 = tail call i8* @f1(i8* nonnull %0)
+  br label %7
+
+; <label>:5:                                      ; preds = %1
+; ATTRIBUTOR: %6 = tail call i8* @f3(i8* nonnull align 16 @a2)
+  %6 = tail call i8* @f3(i8* nonnull @a2)
+  br label %7
+
+; <label>:7:                                      ; preds = %5, %3
+  %8 = phi i8* [ %4, %3 ], [ %6, %5 ]
+  ret i8* %8
+}
+
+; Function Attrs: nounwind readnone ssp uwtable
+define internal i8* @f3(i8* readnone) local_unnamed_addr #0 {
+; ATTRIBUTOR: define internal nonnull align 8 i8* @f3(i8* nonnull readnone align 16)
+  %2 = icmp eq i8* %0, null
+  br i1 %2, label %3, label %5
+
+; <label>:3:                                      ; preds = %1
+; ATTRIBUTOR: %4 = tail call i8* @f1(i8* nonnull align 16 @a2)
+  %4 = tail call i8* @f1(i8* nonnull @a2)
+  br label %5
+
+; <label>:5:                                      ; preds = %1, %3
+  %6 = phi i8* [ %4, %3 ], [ @a1, %1 ]
+  ret i8* %6
+}
+
+; TEST 7
+; Better than IR information
+; ATTRIBUTOR: define align 32 i32* @test7(i32* returned align 32 %p)
+define align 4 i32* @test7(i32* align 32 %p) #0 {
+  ret i32* %p
+}
+
+
+; TEST 8
+define void @test8_helper() {
+  %ptr0 = tail call i32* @unknown()
+  %ptr1 = tail call align 4 i32* @unknown()
+  %ptr2 = tail call align 8 i32* @unknown()
+
+  tail call void @test8(i32* %ptr1, i32* %ptr1, i32* %ptr0)
+; ATTRIBUTOR: tail call void @test8(i32* align 4 %ptr1, i32* align 4 %ptr1, i32* %ptr0)
+  tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
+; ATTRIBUTOR: tail call void @test8(i32* align 8 %ptr2, i32* align 4 %ptr1, i32* align 4 %ptr1)
+  tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
+; ATTRIBUTOR: tail call void @test8(i32* align 8 %ptr2, i32* align 4 %ptr1, i32* align 4 %ptr1)
+  ret void
+}
+
+define internal void @test8(i32* %a, i32* %b, i32* %c) {
+; ATTRIBUTOR: define internal void @test8(i32* align 4 %a, i32* align 4 %b, i32* %c)
+  ret void
+}
+
+
+attributes #0 = { nounwind uwtable noinline }
+attributes #1 = { uwtable noinline }

Modified: llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll?rev=367187&r1=367186&r2=367187&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_nocapture.ll Sun Jul 28 00:04:01 2019
@@ -88,7 +88,7 @@ entry:
 ; Other arguments are possible here due to the no-return behavior.
 ;
 ; FIXME: no-return missing
-; CHECK: define noalias nonnull dereferenceable(4294967295) i32* @srec16(i32* nocapture readnone %a)
+; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @srec16(i32* nocapture readnone %a)
 define i32* @srec16(i32* %a) #0 {
 entry:
   %call = call i32* @srec16(i32* %a)

Modified: llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll?rev=367187&r1=367186&r2=367187&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/noalias_returned.ll Sun Jul 28 00:04:01 2019
@@ -79,13 +79,13 @@ declare i8* @baz(...) nounwind uwtable
 ; TEST 5
 
 ; Returning global pointer. Should not be noalias.
-; CHECK: define nonnull dereferenceable(8) i8** @getter()
+; CHECK: define nonnull align 8 dereferenceable(8) i8** @getter()
 define i8** @getter() {
   ret i8** @G
 }
 
 ; Returning global pointer. Should not be noalias.
-; CHECK: define nonnull dereferenceable(8) i8** @calle1()
+; CHECK: define nonnull align 8 dereferenceable(8) i8** @calle1()
 define i8** @calle1(){
   %1 = call i8** @getter()
   ret i8** %1

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll?rev=367187&r1=367186&r2=367187&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nonnull.ll Sun Jul 28 00:04:01 2019
@@ -40,14 +40,14 @@ define i8* @test3() {
 ; just never return period.)
 define i8* @test4_helper() {
 ; FNATTR: define noalias nonnull i8* @test4_helper
-; ATTRIBUTOR: define noalias nonnull dereferenceable(4294967295) i8* @test4_helper
+; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4_helper
   %ret = call i8* @test4()
   ret i8* %ret
 }
 
 define i8* @test4() {
 ; FNATTR: define noalias nonnull i8* @test4
-; ATTRIBUTOR: define noalias nonnull dereferenceable(4294967295) i8* @test4
+; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4
   %ret = call i8* @test4_helper()
   ret i8* %ret
 }




More information about the llvm-commits mailing list