[llvm] r365924 - [Attributor] Deduce "nofree" function attribute

Hideto Ueno via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 12 10:38:51 PDT 2019


Author: uenoku
Date: Fri Jul 12 10:38:51 2019
New Revision: 365924

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

Summary: Deduce "nofree" function attribute. A more concise description of "nofree" is on D49165.

Reviewers: jdoerfert

Reviewed By: jdoerfert

Subscribers: homerdin, hfinkel, lebedev.ri, hiraditya, llvm-commits

Tags: #llvm

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

Modified:
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp
    llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll
    llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nofree-attributor.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll
    llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=365924&r1=365923&r2=365924&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Fri Jul 12 10:38:51 2019
@@ -50,6 +50,7 @@ STATISTIC(NumFnKnownReturns, "Number of
 STATISTIC(NumFnArgumentReturned,
           "Number of function arguments marked returned");
 STATISTIC(NumFnNoSync, "Number of functions marked nosync");
+STATISTIC(NumFnNoFree, "Number of functions marked nofree");
 
 // TODO: Determine a good default value.
 //
@@ -104,6 +105,9 @@ static void bookkeeping(AbstractAttribut
   case Attribute::NoSync:
     NumFnNoSync++;
     break;
+  case Attribute::NoFree:
+    NumFnNoFree++;
+    break;
   default:
     return;
   }
@@ -909,6 +913,69 @@ ChangeStatus AANoSyncFunction::updateImp
   return ChangeStatus::UNCHANGED;
 }
 
+/// ------------------------ No-Free Attributes ----------------------------
+
+struct AANoFreeFunction : AbstractAttribute, BooleanState {
+
+  /// See AbstractAttribute::AbstractAttribute(...).
+  AANoFreeFunction(Function &F, InformationCache &InfoCache)
+      : AbstractAttribute(F, InfoCache) {}
+
+  /// See AbstractAttribute::getState()
+  ///{
+  AbstractState &getState() override { return *this; }
+  const AbstractState &getState() const override { return *this; }
+  ///}
+
+  /// See AbstractAttribute::getManifestPosition().
+  ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
+
+  /// See AbstractAttribute::getAsStr().
+  const std::string getAsStr() const override {
+    return getAssumed() ? "nofree" : "may-free";
+  }
+
+  /// See AbstractAttribute::updateImpl(...).
+  ChangeStatus updateImpl(Attributor &A) override;
+
+  /// See AbstractAttribute::getAttrKind().
+  Attribute::AttrKind getAttrKind() const override { return ID; }
+
+  /// Return true if "nofree" is assumed.
+  bool isAssumedNoFree() const { return getAssumed(); }
+
+  /// Return true if "nofree" is known.
+  bool isKnownNoFree() const { return getKnown(); }
+
+  /// The identifier used by the Attributor for this class of attributes.
+  static constexpr Attribute::AttrKind ID = Attribute::NoFree;
+};
+
+ChangeStatus AANoFreeFunction::updateImpl(Attributor &A) {
+  Function &F = getAnchorScope();
+
+  // The map from instruction opcodes to those instructions in the function.
+  auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
+
+  for (unsigned Opcode :
+       {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
+        (unsigned)Instruction::Call}) {
+    for (Instruction *I : OpcodeInstMap[Opcode]) {
+
+      auto ICS = ImmutableCallSite(I);
+      auto *NoFreeAA = A.getAAFor<AANoFreeFunction>(*this, *I);
+
+      if ((!NoFreeAA || !NoFreeAA->isValidState() ||
+           !NoFreeAA->isAssumedNoFree()) &&
+          !ICS.hasFnAttr(Attribute::NoFree)) {
+        indicatePessimisticFixpoint();
+        return ChangeStatus::CHANGED;
+      }
+    }
+  }
+  return ChangeStatus::UNCHANGED;
+}
+
 /// ----------------------------------------------------------------------------
 ///                               Attributor
 /// ----------------------------------------------------------------------------
@@ -1057,6 +1124,9 @@ void Attributor::identifyDefaultAbstract
   // Every function might be marked "nosync"
   registerAA(*new AANoSyncFunction(F, InfoCache));
 
+  // Every function might be "no-free".
+  registerAA(*new AANoFreeFunction(F, InfoCache));
+
   // Return attributes are only appropriate if the return type is non void.
   Type *ReturnType = F.getReturnType();
   if (!ReturnType->isVoidTy()) {

Modified: llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll?rev=365924&r1=365923&r2=365924&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/arg_returned.ll Fri Jul 12 10:38:51 2019
@@ -8,13 +8,13 @@
 
 ; TEST SCC test returning an integer value argument
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @sink_r0(i32 returned %r)
-; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
-; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
-; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
 ;
 ; FNATTR: define i32 @sink_r0(i32 returned %r)
@@ -159,22 +159,22 @@ return:
 
 ; TEST SCC test returning a pointer value argument
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @ptr_sink_r0(double* readnone returned %r)
-; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @ptr_scc_r1(double* %a, double* readnone returned %r, double* nocapture readnone %b)
-; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone returned %r)
 ;
 ; FNATTR: define double* @ptr_sink_r0(double* readnone returned %r)
 ; FNATTR: define double* @ptr_scc_r1(double* %a, double* readnone %r, double* nocapture readnone %b)
 ; FNATTR: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r)
 ;
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* returned %r)
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* %a, double* returned %r, double* %b)
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* %a, double* %b, double* returned %r)
 ;
 ; double* ptr_scc_r1(double* a, double* b, double* r);
@@ -261,7 +261,7 @@ return:
 ;
 ; FIXME: no-return missing
 ; FNATTR:  define i32* @rt0(i32* readonly %a)
-; BOTH: Function Attrs: noinline nosync nounwind readonly uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readonly uwtable
 ; BOTH-NEXT:    define i32* @rt0(i32* readonly returned %a)
 define i32* @rt0(i32* %a) #0 {
 entry:
@@ -280,7 +280,7 @@ entry:
 ;
 ; FIXME: no-return missing
 ; FNATTR:  define noalias i32* @rt1(i32* nocapture readonly %a)
-; BOTH: Function Attrs: noinline nosync nounwind readonly uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readonly uwtable
 ; BOTH-NEXT:    define noalias i32* @rt1(i32* nocapture readonly %a)
 define i32* @rt1(i32* %a) #0 {
 entry:
@@ -441,11 +441,11 @@ entry:
 ;   return b == 0? b : x;
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double @select_and_phi(double returned %b)
 ;
 ; FNATTR:     define double @select_and_phi(double %b)
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double @select_and_phi(double returned %b)
 define double @select_and_phi(double %b) #0 {
 entry:
@@ -472,12 +472,12 @@ if.end:
 ;   return b == 0? b : x;
 ; }
 ;
-; BOTH: Function Attrs: noinline nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
 ;
 ; FNATTR:     define double @recursion_select_and_phi(i32 %a, double %b)
 ;
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
 define double @recursion_select_and_phi(i32 %a, double %b) #0 {
 entry:
@@ -503,12 +503,12 @@ if.end:
 ;   return (double*)b;
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @bitcast(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @bitcast(i32* readnone %b)
 ;
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double* @bitcast(i32* returned %b)
 define double* @bitcast(i32* %b) #0 {
 entry:
@@ -526,12 +526,12 @@ entry:
 ;   return b != 0 ? b : x;
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT: define double* @bitcasts_select_and_phi(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @bitcasts_select_and_phi(i32* readnone %b)
 ;
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* returned %b)
 define double* @bitcasts_select_and_phi(i32* %b) #0 {
 entry:
@@ -564,12 +564,12 @@ if.end:
 ;   /* return undef */
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @ret_arg_arg_undef(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @ret_arg_arg_undef(i32* readnone %b)
 ;
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* returned %b)
 define double* @ret_arg_arg_undef(i32* %b) #0 {
 entry:
@@ -602,12 +602,12 @@ ret_undef:
 ;   /* return undef */
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @ret_undef_arg_arg(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @ret_undef_arg_arg(i32* readnone %b)
 ;
-; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* returned %b)
 define double* @ret_undef_arg_arg(i32* %b) #0 {
 entry:
@@ -640,7 +640,7 @@ ret_arg1:
 ;   /* return undef */
 ; }
 ;
-; BOTH: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; BOTH-NEXT:  define double* @ret_undef_arg_undef(i32* readnone returned %b)
 ;
 ; FNATTR:     define double* @ret_undef_arg_undef(i32* readnone %b)
@@ -744,8 +744,8 @@ unreachableblock2:
 attributes #0 = { noinline nounwind uwtable }
 
 ; BOTH-NOT: attributes #
-; BOTH-DAG: attributes #{{[0-9]*}} = { noinline norecurse nosync nounwind readnone uwtable }
-; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nosync nounwind readnone uwtable }
-; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nosync nounwind readonly uwtable }
+; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline norecurse nosync nounwind readnone uwtable }
+; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable }
+; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readonly uwtable }
 ; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable }
 ; BOTH-NOT: attributes #

Modified: llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll?rev=365924&r1=365923&r2=365924&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/fn_noreturn.ll Fri Jul 12 10:38:51 2019
@@ -20,7 +20,7 @@ target datalayout = "e-m:e-i64:64-f80:12
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; CHECK: define void @srec0()
 ;
 define void @srec0() #0 {
@@ -37,7 +37,7 @@ entry:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; CHECK: define i32 @srec16(i32 %a)
 ;
 define i32 @srec16(i32 %a) #0 {
@@ -69,7 +69,7 @@ entry:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; CHECK: define i32 @endless_loop(i32 %a)
 ;
 define i32 @endless_loop(i32 %a) #0 {
@@ -89,7 +89,7 @@ while.body:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline norecurse nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
 ; CHECK: define i32 @dead_return(i32 returned %a)
 ;
 define i32 @dead_return(i32 %a) #0 {
@@ -111,7 +111,7 @@ return:
 ; }
 ;
 ; FIXME: no-return missing
-; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable
+; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable
 ; CHECK: define i32 @multiple_noreturn_calls(i32 %a)
 ;
 define i32 @multiple_noreturn_calls(i32 %a) #0 {

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nofree-attributor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nofree-attributor.ll?rev=365924&r1=365923&r2=365924&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nofree-attributor.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nofree-attributor.ll Fri Jul 12 10:38:51 2019
@@ -1,4 +1,6 @@
-; RUN: opt -functionattrs --disable-nofree-inference=false -S < %s | FileCheck %s
+; RUN: opt -functionattrs --disable-nofree-inference=false -S < %s | FileCheck %s --check-prefix=FNATTR
+; 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 the "nofree" function attribute.
@@ -11,29 +13,33 @@ declare void @_ZdaPv(i8*) local_unnamed_
 
 
 ; TEST 1 (positive case)
-; FIXME: missing "nofree"
-; CHECK: Function Attrs: noinline norecurse nounwind readnone uwtable
-; CHECK: define void @only_return() 
+; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
+; FNATTR-NEXT: define void @only_return()
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @only_return()
 define void @only_return() #0 {
     ret void
 }
 
 
-; TEST 2 (nagative case)
+; TEST 2 (negative case)
 ; Only free
 ; void only_free(char* p) {
 ;    free(p);
 ; }
 
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK: define void @only_free(i8* nocapture) local_unnamed_addr 
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @only_free(i8* nocapture) local_unnamed_addr
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @only_free(i8* nocapture) local_unnamed_addr #1
 define void @only_free(i8* nocapture) local_unnamed_addr #0 {
     tail call void @free(i8* %0) #1
     ret void
 }
 
 
-; TEST 3 (nagative case)
+; TEST 3 (negative case)
 ; Free occurs in same scc.
 ; void free_in_scc1(char*p){
 ;    free_in_scc2(p);
@@ -44,17 +50,23 @@ define void @only_free(i8* nocapture) lo
 ; }
 
 
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK: define void @free_in_scc1(i8* nocapture) local_unnamed_addr 
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @free_in_scc1(i8* nocapture) local_unnamed_addr
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT :define void @free_in_scc1(i8* nocapture) local_unnamed_addr
 define void @free_in_scc1(i8* nocapture) local_unnamed_addr #0 {
   tail call void @free_in_scc2(i8* %0) #1
   ret void
 }
 
 
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK: define void @free_in_scc2(i8* nocapture) local_unnamed_addr 
-define void @free_in_scc2(i8*) local_unnamed_addr #0 {
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @free_in_scc2(i8* nocapture) local_unnamed_addr
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR: define void @free_in_scc2(i8* nocapture) local_unnamed_addr
+define void @free_in_scc2(i8* nocapture) local_unnamed_addr #0 {
   tail call void @free_in_scc1(i8* %0)
   tail call void @free(i8* %0) #1
   ret void
@@ -71,17 +83,19 @@ define void @free_in_scc2(i8*) local_unn
 ; }
 
 
-; FIXME: missing "nofree"
-; CHECK: Function Attrs: noinline nounwind readnone uwtable
-; CHECK: define void @mutual_recursion1() 
+; FNATTR: Function Attrs: noinline nounwind readnone uwtable
+; FNATTR-NEXT: define void @mutual_recursion1()
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
 define void @mutual_recursion1() #0 {
   call void @mutual_recursion2()
   ret void
 }
 
-; FIXME: missing "nofree"
-; CHECK: Function Attrs: noinline nounwind readnone uwtable
-; CHECK: define void @mutual_recursion2() 
+; FNATTR: Function Attrs: noinline nounwind readnone uwtable
+; FNATTR-NEXT: define void @mutual_recursion2()
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
 define void @mutual_recursion2() #0 {
   call void @mutual_recursion1()
   ret void
@@ -89,13 +103,16 @@ define void @mutual_recursion2() #0 {
 
 
 ; TEST 5
-; C++ delete operation (nagative case)
+; C++ delete operation (negative case)
 ; void delete_op (char p[]){
 ;     delete [] p;
 ; }
 
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK: define void @_Z9delete_opPc(i8*) local_unnamed_addr 
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @_Z9delete_opPc(i8*) local_unnamed_addr
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @_Z9delete_opPc(i8*) local_unnamed_addr #1
 define void @_Z9delete_opPc(i8*) local_unnamed_addr #0 {
   %2 = icmp eq i8* %0, null
   br i1 %2, label %4, label %3
@@ -111,9 +128,12 @@ define void @_Z9delete_opPc(i8*) local_u
 
 ; TEST 6 (negative case)
 ; Call realloc
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK: define noalias i8* @call_realloc(i8* nocapture, i64) local_unnamed_addr 
-define noalias i8* @call_realloc(i8*nocapture, i64) local_unnamed_addr #0 {
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define noalias i8* @call_realloc(i8* nocapture, i64) local_unnamed_addr
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define noalias i8* @call_realloc(i8* nocapture, i64) local_unnamed_addr
+define noalias i8* @call_realloc(i8* nocapture, i64) local_unnamed_addr #0 {
     %ret = tail call i8* @realloc(i8* %0, i64 %1) #2
     ret i8* %ret
 }
@@ -122,41 +142,97 @@ define noalias i8* @call_realloc(i8*noca
 ; TEST 7 (positive case)
 ; Call function declaration with "nofree"
 
+
+; FNATTR: Function Attrs: nofree noinline nounwind readnone uwtable
+; FNATTR-NEXT: declare void @nofree_function()
+; ATTRIBUTOR: Function Attrs:  nofree noinline nounwind readnone uwtable 
+; ATTRIBUTOR-NEXT: declare void @nofree_function()
 declare void @nofree_function() nofree readnone #0
 
-; FIXME: missing "nofree"
-; Function Attrs: noinline nounwind readnone uwtable
-; CHECK: define void @call_nofree_function() 
+; FNATTR: Function Attrs: noinline nounwind readnone uwtable
+; FNATTR-NEXT: define void @call_nofree_function()
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @call_nofree_function()
 define void @call_nofree_function() #0 {
     tail call void @nofree_function()
     ret void
 }
 
-; TEST 8 (nagative case)
+; TEST 8 (negative case)
 ; Call function declaration without "nofree"
 
+
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NEXT: declare void @maybe_free()
 declare void @maybe_free() #0
 
 
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK: define void @call_maybe_free() 
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR: define void @call_maybe_free()
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @call_maybe_free()
 define void @call_maybe_free() #0 {
     tail call void @maybe_free()
     ret void
 }
 
 
-; TEST 9 (nagative case)
+; TEST 9 (negative case)
 ; Call both of above functions
 
-; CHECK: Function Attrs: noinline nounwind uwtable
-; CHECK: define void @call_both() 
+; FNATTR: Function Attrs: noinline nounwind uwtable
+; FNATTR-NEXT: define void @call_both()
+; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR-NOT: nofree
+; ATTRIBUTOR-NEXT: define void @call_both()
 define void @call_both() #0 {
     tail call void @maybe_free()
     tail call void @nofree_function()
     ret void
 }
 
+
+; TEST 10 (positive case)
+; Call intrinsic function
+; FNATTRS: Function Attrs: noinline readnone speculatable
+; FNATTRS-NEXT: declare float @llvm.floor.f32(float)
+; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
+; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
+declare float @llvm.floor.f32(float)
+
+; FNATTRS: Function Attrs: noinline nounwind uwtable
+; FNATTRS-NEXT: define void @call_floor(float %a)
+; FIXME: missing nofree
+; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
+
+define void @call_floor(float %a) #0 {
+    tail call float @llvm.floor.f32(float %a)
+    ret void
+}
+
+; TEST 11 (positive case)
+; Check propagation.
+
+; FNATTRS: Function Attrs: noinline nounwind uwtable
+; FNATTRS-NEXT: define void @f1()
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @f1()
+define void @f1() #0 {
+    tail call void @nofree_function()
+    ret void
+}
+
+; FNATTRS: Function Attrs: noinline nounwind uwtable
+; FNATTRS-NEXT: define void @f2()
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
+; ATTRIBUTOR-NEXT: define void @f2()
+define void @f2() #0 {
+    tail call void @f1()
+    ret void
+}
+
 
 attributes #0 = { nounwind uwtable noinline }
 attributes #1 = { nounwind }

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll?rev=365924&r1=365923&r2=365924&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nosync.ll Fri Jul 12 10:38:51 2019
@@ -27,7 +27,7 @@ target datalayout = "e-m:e-i64:64-f80:12
 
 ; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable
 ; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s)
-; ATTRIBUTOR: Function Attrs: nosync nounwind optsize readnone ssp uwtable
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable
 ; ATTRIBUTOR-NEXT: define i32* @foo(%struct.ST* %s)
 define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
 entry:
@@ -44,7 +44,7 @@ entry:
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define i32 @load_monotonic(i32* nocapture readonly)
-; ATTRIBUTOR: Function Attrs: norecurse nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture readonly)
 define i32 @load_monotonic(i32* nocapture readonly) norecurse nounwind uwtable {
   %2 = load atomic i32, i32* %0 monotonic, align 4
@@ -60,7 +60,7 @@ define i32 @load_monotonic(i32* nocaptur
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define void @store_monotonic(i32* nocapture)
-; ATTRIBUTOR: Function Attrs: norecurse nosync nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
 ; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture)
 define void @store_monotonic(i32* nocapture) norecurse nounwind uwtable {
   store atomic i32 10, i32* %0 monotonic, align 4
@@ -76,7 +76,7 @@ define void @store_monotonic(i32* nocapt
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define i32 @load_acquire(i32* nocapture readonly)
-; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
 ; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture readonly)
 define i32 @load_acquire(i32* nocapture readonly) norecurse nounwind uwtable {
@@ -92,7 +92,7 @@ define i32 @load_acquire(i32* nocapture
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define void @load_release(i32* nocapture)
-; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
 ; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture)
 define void @load_release(i32* nocapture) norecurse nounwind uwtable {
@@ -104,7 +104,7 @@ define void @load_release(i32* nocapture
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define void @load_volatile_release(i32* nocapture)
-; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
 ; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture)
 define void @load_volatile_release(i32* nocapture) norecurse nounwind uwtable {
@@ -120,7 +120,7 @@ define void @load_volatile_release(i32*
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define void @volatile_store(i32*)
-; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
 ; ATTRIBUTOR-NEXT: define void @volatile_store(i32*)
 define void @volatile_store(i32*) norecurse nounwind uwtable {
@@ -137,7 +137,7 @@ define void @volatile_store(i32*) norecu
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
 ; FNATTR-NEXT: define i32 @volatile_load(i32*)
-; ATTRIBUTOR: Function Attrs: norecurse nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
 ; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32*)
 define i32 @volatile_load(i32*) norecurse nounwind uwtable {
@@ -185,7 +185,7 @@ define void @call_might_sync() nounwind
 
 ; FNATTR: Function Attrs: nofree noinline nounwind uwtable
 ; FNATTR-NEXT: define i32 @scc1(i32*)
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
 ; ATTRIBUTOR-NEXT: define i32 @scc1(i32*)
 define i32 @scc1(i32*) noinline nounwind uwtable {
@@ -196,7 +196,7 @@ define i32 @scc1(i32*) noinline nounwind
 
 ; FNATTR: Function Attrs: nofree noinline nounwind uwtable
 ; FNATTR-NEXT: define void @scc2(i32*)
-; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nounwind uwtable
 ; ATTRIBUTOR-NOT: nosync
 ; ATTRIBUTOR-NEXT: define void @scc2(i32*)
 define void @scc2(i32*) noinline nounwind uwtable {
@@ -257,7 +257,7 @@ define void @bar(i32 *, %"struct.std::at
 ; TEST 13 - Fence syncscope("singlethread") seq_cst
 ; FNATTR: Function Attrs: nofree norecurse nounwind
 ; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture, %"struct.std::atomic"* nocapture)
-; ATTRIBUTOR: Function Attrs: nosync
+; ATTRIBUTOR: Function Attrs: nofree nosync
 ; ATTRIBUTOR: define void @foo1_singlethread(i32*, %"struct.std::atomic"*)
 define void @foo1_singlethread(i32*, %"struct.std::atomic"*) {
   store i32 100, i32* %0, align 4
@@ -269,7 +269,7 @@ define void @foo1_singlethread(i32*, %"s
 
 ; FNATTR: Function Attrs: nofree norecurse nounwind
 ; FNATTR-NEXT: define void @bar_singlethread(i32* nocapture readnone, %"struct.std::atomic"* nocapture readonly)
-; ATTRIBUTOR: Function Attrs: nosync
+; ATTRIBUTOR: Function Attrs: nofree nosync
 ; ATTRIBUTOR: define void @bar_singlethread(i32*, %"struct.std::atomic"*)
 define void @bar_singlethread(i32 *, %"struct.std::atomic"*) {
   %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0

Modified: llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll?rev=365924&r1=365923&r2=365924&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/nounwind.ll Fri Jul 12 10:38:51 2019
@@ -4,7 +4,7 @@
 ; TEST 1
 ; CHECK: Function Attrs: norecurse nounwind readnone
 ; CHECK-NEXT: define i32 @foo1()
-; ATTRIBUTOR: Function Attrs: nosync nounwind
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
 ; ATTRIBUTOR-NEXT: define i32 @foo1()
 define i32 @foo1() {
   ret i32 1
@@ -13,7 +13,7 @@ define i32 @foo1() {
 ; TEST 2
 ; CHECK: Function Attrs: nounwind readnone
 ; CHECK-NEXT: define i32 @scc1_foo()
-; ATTRIBUTOR: Function Attrs: nosync nounwind
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
 ; ATTRIBUTOR-NEXT: define i32 @scc1_foo()
 define i32 @scc1_foo() {
   %1 = call i32 @scc1_bar()
@@ -24,7 +24,7 @@ define i32 @scc1_foo() {
 ; TEST 3
 ; CHECK: Function Attrs: nounwind readnone
 ; CHECK-NEXT: define i32 @scc1_bar()
-; ATTRIBUTOR: Function Attrs: nosync nounwind
+; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
 ; ATTRIBUTOR-NEXT: define i32 @scc1_bar()
 define i32 @scc1_bar() {
   %1 = call i32 @scc1_foo()




More information about the llvm-commits mailing list