[llvm] r370168 - Annotate return values of allocation functions with dereferenceable_or_null

David Bolvansky via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 28 01:28:20 PDT 2019


Author: xbolva00
Date: Wed Aug 28 01:28:20 2019
New Revision: 370168

URL: http://llvm.org/viewvc/llvm-project?rev=370168&view=rev
Log:
Annotate return values of allocation functions with dereferenceable_or_null

Summary:
Example
define dso_local noalias i8* @_Z6maixxnv() local_unnamed_addr #0 {
entry:
  %call = tail call noalias dereferenceable_or_null(64) i8* @malloc(i64 64) #6
  ret i8* %call
}


Reviewers: jdoerfert

Reviewed By: jdoerfert

Subscribers: aaron.ballman, llvm-commits

Tags: #llvm

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

Modified:
    llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h
    llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll
    llvm/trunk/test/Transforms/InstCombine/deref-alloc-fns.ll
    llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll
    llvm/trunk/test/Transforms/InstCombine/objsize.ll
    llvm/trunk/test/Transforms/InstCombine/realloc.ll

Modified: llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h (original)
+++ llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h Wed Aug 28 01:28:20 2019
@@ -93,6 +93,11 @@ bool isReallocLikeFn(const Value *V, con
 /// reallocates memory (e.g., realloc).
 bool isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI);
 
+/// Tests if a value is a call or invoke to a library function that
+/// allocates memory and throws if an allocation failed (e.g., new).
+bool isOpNewLikeFn(const Value *V, const TargetLibraryInfo *TLI,
+                     bool LookThroughBitCast = false);
+
 //===----------------------------------------------------------------------===//
 //  malloc Call Utility Functions.
 //

Modified: llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryBuiltins.cpp?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/MemoryBuiltins.cpp (original)
+++ llvm/trunk/lib/Analysis/MemoryBuiltins.cpp Wed Aug 28 01:28:20 2019
@@ -276,6 +276,13 @@ bool llvm::isReallocLikeFn(const Functio
   return getAllocationDataForFunction(F, ReallocLike, TLI).hasValue();
 }
 
+/// Tests if a value is a call or invoke to a library function that
+/// allocates memory and throws if an allocation failed (e.g., new).
+bool llvm::isOpNewLikeFn(const Value *V, const TargetLibraryInfo *TLI,
+                     bool LookThroughBitCast) {
+  return getAllocationData(V, OpNewLike, TLI, LookThroughBitCast).hasValue();
+}
+
 /// extractMallocCall - Returns the corresponding CallInst if the instruction
 /// is a malloc call.  Since CallInst::CreateMalloc() only creates calls, we
 /// ignore InvokeInst here.

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp Wed Aug 28 01:28:20 2019
@@ -4178,8 +4178,41 @@ static IntrinsicInst *findInitTrampoline
   return nullptr;
 }
 
+static void annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI) {
+  ConstantInt *Op0C = dyn_cast<ConstantInt>(Call.getOperand(0));
+  ConstantInt *Op1C = (Call.getNumArgOperands() == 1)
+                          ? nullptr
+                          : dyn_cast<ConstantInt>(Call.getOperand(1));
+  if ((Op0C && Op0C->isNullValue()) || (Op1C && Op1C->isNullValue()))
+    return;
+  if (isMallocLikeFn(&Call, TLI) && Op0C) {
+    Call.addAttribute(AttributeList::ReturnIndex,
+                      Attribute::getWithDereferenceableOrNullBytes(
+                          Call.getContext(), Op0C->getZExtValue()));
+  } else if (isOpNewLikeFn(&Call, TLI) && Op0C) {
+    Call.addAttribute(AttributeList::ReturnIndex,
+                      Attribute::getWithDereferenceableBytes(
+                          Call.getContext(), Op0C->getZExtValue()));
+  } else if (isReallocLikeFn(&Call, TLI) && Op1C) {
+    Call.addAttribute(AttributeList::ReturnIndex,
+                      Attribute::getWithDereferenceableOrNullBytes(
+                          Call.getContext(), Op1C->getZExtValue()));
+  } else if (isCallocLikeFn(&Call, TLI) && Op0C && Op1C) {
+    bool Overflow;
+    const APInt &N = Op0C->getValue();
+    APInt Size = N.umul_ov(Op1C->getValue(), Overflow);
+    if (!Overflow)
+      Call.addAttribute(AttributeList::ReturnIndex,
+                        Attribute::getWithDereferenceableOrNullBytes(
+                            Call.getContext(), Size.getZExtValue()));
+  }
+}
+
 /// Improvements for call, callbr and invoke instructions.
 Instruction *InstCombiner::visitCallBase(CallBase &Call) {
+  if (isAllocationFn(&Call, &TLI))
+    annotateAnyAllocSite(Call, &TLI);
+
   if (isAllocLikeFn(&Call, &TLI))
     return visitAllocSite(Call);
 

Modified: llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/compare-unescaped.ll Wed Aug 28 01:28:20 2019
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -instcombine -S < %s | FileCheck %s
 
 @gp = global i32* null, align 8
@@ -5,23 +6,25 @@
 declare i8* @malloc(i64) #1
 
 define i1 @compare_global_trivialeq() {
+; CHECK-LABEL: @compare_global_trivialeq(
+; CHECK-NEXT:    ret i1 false
+;
   %m = call i8* @malloc(i64 4)
   %bc = bitcast i8* %m to i32*
   %lgp = load i32*, i32** @gp, align 8
   %cmp = icmp eq i32* %bc, %lgp
   ret i1 %cmp
-; CHECK-LABEL: compare_global_trivialeq
-; CHECK: ret i1 false
 }
 
 define i1 @compare_global_trivialne() {
+; CHECK-LABEL: @compare_global_trivialne(
+; CHECK-NEXT:    ret i1 true
+;
   %m = call i8* @malloc(i64 4)
   %bc = bitcast i8* %m to i32*
   %lgp = load i32*, i32** @gp, align 8
   %cmp = icmp ne i32* %bc, %lgp
   ret i1 %cmp
-; CHECK-LABEL: compare_global_trivialne
-; CHECK: ret i1 true
 }
 
 
@@ -30,45 +33,68 @@ define i1 @compare_global_trivialne() {
 ; The comparison should fold to false irrespective of whether the call to malloc can be elided or not
 declare void @f()
 define i1 @compare_and_call_with_deopt() {
-; CHECK-LABEL: compare_and_call_with_deopt
+; CHECK-LABEL: @compare_and_call_with_deopt(
+; CHECK-NEXT:    [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
+; CHECK-NEXT:    tail call void @f() [ "deopt"(i8* [[M]]) ]
+; CHECK-NEXT:    ret i1 false
+;
   %m = call i8* @malloc(i64 24)
   %bc = bitcast i8* %m to i32*
   %lgp = load i32*, i32** @gp, align 8, !nonnull !0
   %cmp = icmp eq i32* %lgp, %bc
   tail call void @f() [ "deopt"(i8* %m) ]
   ret i1 %cmp
-; CHECK: ret i1 false
 }
 
 ; Same functon as above with deopt operand in function f, but comparison is NE
 define i1 @compare_ne_and_call_with_deopt() {
-; CHECK-LABEL: compare_ne_and_call_with_deopt
+; CHECK-LABEL: @compare_ne_and_call_with_deopt(
+; CHECK-NEXT:    [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
+; CHECK-NEXT:    tail call void @f() [ "deopt"(i8* [[M]]) ]
+; CHECK-NEXT:    ret i1 true
+;
   %m = call i8* @malloc(i64 24)
   %bc = bitcast i8* %m to i32*
   %lgp = load i32*, i32** @gp, align 8, !nonnull !0
   %cmp = icmp ne i32* %lgp, %bc
   tail call void @f() [ "deopt"(i8* %m) ]
   ret i1 %cmp
-; CHECK: ret i1 true
 }
 
 ; Same function as above, but global not marked nonnull, and we cannot fold the comparison
 define i1 @compare_ne_global_maybe_null() {
-; CHECK-LABEL: compare_ne_global_maybe_null
+; CHECK-LABEL: @compare_ne_global_maybe_null(
+; CHECK-NEXT:    [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
+; CHECK-NEXT:    [[BC:%.*]] = bitcast i8* [[M]] to i32*
+; CHECK-NEXT:    [[LGP:%.*]] = load i32*, i32** @gp, align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32* [[LGP]], [[BC]]
+; CHECK-NEXT:    tail call void @f() [ "deopt"(i8* [[M]]) ]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
   %m = call i8* @malloc(i64 24)
   %bc = bitcast i8* %m to i32*
   %lgp = load i32*, i32** @gp
   %cmp = icmp ne i32* %lgp, %bc
   tail call void @f() [ "deopt"(i8* %m) ]
   ret i1 %cmp
-; CHECK: ret i1 %cmp
 }
 
 ; FIXME: The comparison should fold to false since %m escapes (call to function escape)
 ; after the comparison.
 declare void @escape(i8*)
 define i1 @compare_and_call_after() {
-; CHECK-LABEL: compare_and_call_after
+; CHECK-LABEL: @compare_and_call_after(
+; CHECK-NEXT:    [[M:%.*]] = call dereferenceable_or_null(24) i8* @malloc(i64 24)
+; CHECK-NEXT:    [[BC:%.*]] = bitcast i8* [[M]] to i32*
+; CHECK-NEXT:    [[LGP:%.*]] = load i32*, i32** @gp, align 8, !nonnull !0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32* [[LGP]], [[BC]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[ESCAPE_CALL:%.*]], label [[JUST_RETURN:%.*]]
+; CHECK:       escape_call:
+; CHECK-NEXT:    call void @escape(i8* [[M]])
+; CHECK-NEXT:    ret i1 true
+; CHECK:       just_return:
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
   %m = call i8* @malloc(i64 24)
   %bc = bitcast i8* %m to i32*
   %lgp = load i32*, i32** @gp, align 8, !nonnull !0
@@ -76,56 +102,74 @@ define i1 @compare_and_call_after() {
   br i1 %cmp, label %escape_call, label %just_return
 
 escape_call:
- call void @escape(i8* %m)
- ret i1 true
+  call void @escape(i8* %m)
+  ret i1 true
 
 just_return:
- ret i1 %cmp
+  ret i1 %cmp
 }
 
 define i1 @compare_distinct_mallocs() {
+; CHECK-LABEL: @compare_distinct_mallocs(
+; CHECK-NEXT:    ret i1 false
+;
   %m = call i8* @malloc(i64 4)
   %n = call i8* @malloc(i64 4)
   %cmp = icmp eq i8* %m, %n
   ret i1 %cmp
-  ; CHECK-LABEL: compare_distinct_mallocs
-  ; CHECK: ret i1 false
 }
 
-; the compare is folded to true since the folding compare looks through bitcasts. 
-; call to malloc and the bitcast instructions are elided after that since there are no uses of the malloc 
+; the compare is folded to true since the folding compare looks through bitcasts.
+; call to malloc and the bitcast instructions are elided after that since there are no uses of the malloc
 define i1 @compare_samepointer_under_bitcast() {
+; CHECK-LABEL: @compare_samepointer_under_bitcast(
+; CHECK-NEXT:    ret i1 true
+;
   %m = call i8* @malloc(i64 4)
   %bc = bitcast i8* %m to i32*
   %bcback = bitcast i32* %bc to i8*
   %cmp = icmp eq i8* %m, %bcback
   ret i1 %cmp
-; CHECK-LABEL: compare_samepointer_under_bitcast
-; CHECK: ret i1 true 
 }
 
-; the compare is folded to true since the folding compare looks through bitcasts. 
+; the compare is folded to true since the folding compare looks through bitcasts.
 ; The malloc call for %m cannot be elided since it is used in the call to function f.
 define i1 @compare_samepointer_escaped() {
+; CHECK-LABEL: @compare_samepointer_escaped(
+; CHECK-NEXT:    [[M:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
+; CHECK-NEXT:    call void @f() [ "deopt"(i8* [[M]]) ]
+; CHECK-NEXT:    ret i1 true
+;
   %m = call i8* @malloc(i64 4)
   %bc = bitcast i8* %m to i32*
   %bcback = bitcast i32* %bc to i8*
   %cmp = icmp eq i8* %m, %bcback
   call void @f() [ "deopt"(i8* %m) ]
   ret i1 %cmp
-; CHECK-LABEL: compare_samepointer_escaped
-; CHECK-NEXT: %m = call i8* @malloc(i64 4)
-; CHECK-NEXT: call void @f() [ "deopt"(i8* %m) ]
-; CHECK: ret i1 true 
 }
 
 ; Technically, we can fold the %cmp2 comparison, even though %m escapes through
 ; the ret statement since `ret` terminates the function and we cannot reach from
-; the ret to cmp. 
+; the ret to cmp.
 ; FIXME: Folding this %cmp2 when %m escapes through ret could be an issue with
 ; cross-threading data dependencies since we do not make the distinction between
 ; atomic and non-atomic loads in capture tracking.
 define i8* @compare_ret_escape(i8* %c) {
+; CHECK-LABEL: @compare_ret_escape(
+; CHECK-NEXT:    [[M:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
+; CHECK-NEXT:    [[N:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8* [[N]], [[C:%.*]]
+; CHECK-NEXT:    br i1 [[CMP]], label [[RETST:%.*]], label [[CHK:%.*]]
+; CHECK:       retst:
+; CHECK-NEXT:    ret i8* [[M]]
+; CHECK:       chk:
+; CHECK-NEXT:    [[BC:%.*]] = bitcast i8* [[M]] to i32*
+; CHECK-NEXT:    [[LGP:%.*]] = load i32*, i32** @gp, align 8, !nonnull !0
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32* [[LGP]], [[BC]]
+; CHECK-NEXT:    br i1 [[CMP2]], label [[RETST]], label [[CHK2:%.*]]
+; CHECK:       chk2:
+; CHECK-NEXT:    ret i8* [[N]]
+;
   %m = call i8* @malloc(i64 4)
   %n = call i8* @malloc(i64 4)
   %cmp = icmp eq i8* %n, %c
@@ -142,23 +186,21 @@ chk:
 
 chk2:
   ret i8* %n
-; CHECK-LABEL: compare_ret_escape
-; CHECK: %cmp = icmp eq i8* %n, %c
-; CHECK: %cmp2 = icmp eq i32* %lgp, %bc
 }
 
 ; The malloc call for %m cannot be elided since it is used in the call to function f.
 ; However, the cmp can be folded to true as %n doesnt escape and %m, %n are distinct allocations
 define i1 @compare_distinct_pointer_escape() {
+; CHECK-LABEL: @compare_distinct_pointer_escape(
+; CHECK-NEXT:    [[M:%.*]] = call dereferenceable_or_null(4) i8* @malloc(i64 4)
+; CHECK-NEXT:    tail call void @f() [ "deopt"(i8* [[M]]) ]
+; CHECK-NEXT:    ret i1 true
+;
   %m = call i8* @malloc(i64 4)
   %n = call i8* @malloc(i64 4)
   tail call void @f() [ "deopt"(i8* %m) ]
   %cmp = icmp ne i8* %m, %n
   ret i1 %cmp
-; CHECK-LABEL: compare_distinct_pointer_escape
-; CHECK-NEXT: %m = call i8* @malloc(i64 4)
-; CHECK-NEXT: tail call void @f() [ "deopt"(i8* %m) ]
-; CHECK-NEXT: ret i1 true
 }
 
 !0 = !{}

Modified: llvm/trunk/test/Transforms/InstCombine/deref-alloc-fns.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/deref-alloc-fns.ll?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/deref-alloc-fns.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/deref-alloc-fns.ll Wed Aug 28 01:28:20 2019
@@ -17,7 +17,7 @@ define noalias i8* @malloc_nonconstant_s
 
 define noalias i8* @malloc_constant_size() {
 ; CHECK-LABEL: @malloc_constant_size(
-; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @malloc(i64 40)
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias dereferenceable_or_null(40) i8* @malloc(i64 40)
 ; CHECK-NEXT:    ret i8* [[CALL]]
 ;
   %call = tail call noalias i8* @malloc(i64 40)
@@ -35,7 +35,7 @@ define noalias i8* @malloc_constant_size
 
 define noalias i8* @malloc_constant_size3() {
 ; CHECK-LABEL: @malloc_constant_size3(
-; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias dereferenceable(80) i8* @malloc(i64 40)
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias dereferenceable(80) dereferenceable_or_null(40) i8* @malloc(i64 40)
 ; CHECK-NEXT:    ret i8* [[CALL]]
 ;
   %call = tail call noalias dereferenceable(80) i8* @malloc(i64 40)
@@ -72,7 +72,7 @@ define noalias i8* @realloc_constant_zer
 
 define noalias i8* @realloc_constant_size(i8* %p) {
 ; CHECK-LABEL: @realloc_constant_size(
-; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @realloc(i8* [[P:%.*]], i64 40)
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias dereferenceable_or_null(40) i8* @realloc(i8* [[P:%.*]], i64 40)
 ; CHECK-NEXT:    ret i8* [[CALL]]
 ;
   %call = tail call noalias i8* @realloc(i8* %p, i64 40)
@@ -136,7 +136,7 @@ define noalias i8* @calloc_constant_zero
 
 define noalias i8* @calloc_constant_size() {
 ; CHECK-LABEL: @calloc_constant_size(
-; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @calloc(i64 16, i64 8)
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias dereferenceable_or_null(128) i8* @calloc(i64 16, i64 8)
 ; CHECK-NEXT:    ret i8* [[CALL]]
 ;
   %call = tail call noalias i8* @calloc(i64 16, i64 8)
@@ -152,7 +152,6 @@ define noalias i8* @calloc_constant_size
   ret i8* %call
 }
 
-
 define noalias i8* @op_new_nonconstant_size(i64 %n) {
 ; CHECK-LABEL: @op_new_nonconstant_size(
 ; CHECK-NEXT:    [[CALL:%.*]] = tail call i8* @_Znam(i64 [[N:%.*]])
@@ -162,17 +161,17 @@ define noalias i8* @op_new_nonconstant_s
   ret i8* %call
 }
 
-define noalias i8* @op_new_constant_zero_size() {
-; CHECK-LABEL: @op_new_constant_zero_size(
-; CHECK-NEXT:    [[CALL:%.*]] = tail call i8* @_Znam(i64 40)
+define noalias i8* @op_new_constant_size() {
+; CHECK-LABEL: @op_new_constant_size(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call dereferenceable_or_null(40) i8* @_Znam(i64 40)
 ; CHECK-NEXT:    ret i8* [[CALL]]
 ;
   %call = tail call i8* @_Znam(i64 40)
   ret i8* %call
 }
 
-define noalias i8* @op_new_constant_size() {
-; CHECK-LABEL: @op_new_constant_size(
+define noalias i8* @op_new_constant_zero_size() {
+; CHECK-LABEL: @op_new_constant_zero_size(
 ; CHECK-NEXT:    [[CALL:%.*]] = tail call i8* @_Znam(i64 0)
 ; CHECK-NEXT:    ret i8* [[CALL]]
 ;

Modified: llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/malloc-free-delete.ll Wed Aug 28 01:28:20 2019
@@ -1,14 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -instcombine -S | FileCheck %s
 ; PR1201
 define i32 @main(i32 %argc, i8** %argv) {
 ; CHECK-LABEL: @main(
-    %c_19 = alloca i8*
-    %malloc_206 = tail call i8* @malloc(i32 mul (i32 ptrtoint (i8* getelementptr (i8, i8* null, i32 1) to i32), i32 10))
-    store i8* %malloc_206, i8** %c_19
-    %tmp_207 = load i8*, i8** %c_19
-    tail call void @free(i8* %tmp_207)
-    ret i32 0
-; CHECK-NEXT: ret i32 0
+; CHECK-NEXT:    ret i32 0
+;
+  %c_19 = alloca i8*
+  %malloc_206 = tail call i8* @malloc(i32 mul (i32 ptrtoint (i8* getelementptr (i8, i8* null, i32 1) to i32), i32 10))
+  store i8* %malloc_206, i8** %c_19
+  %tmp_207 = load i8*, i8** %c_19
+  tail call void @free(i8* %tmp_207)
+  ret i32 0
 }
 
 declare noalias i8* @calloc(i32, i32) nounwind
@@ -17,7 +19,8 @@ declare void @free(i8*)
 
 define i1 @foo() {
 ; CHECK-LABEL: @foo(
-; CHECK-NEXT: ret i1 false
+; CHECK-NEXT:    ret i1 false
+;
   %m = call i8* @malloc(i32 1)
   %z = icmp eq i8* %m, null
   call void @free(i8* %m)
@@ -33,7 +36,8 @@ declare void @llvm.memset.p0i8.i32(i8*,
 
 define void @test3(i8* %src) {
 ; CHECK-LABEL: @test3(
-; CHECK-NEXT: ret void
+; CHECK-NEXT:    ret void
+;
   %a = call noalias i8* @malloc(i32 10)
   call void @llvm.lifetime.start.p0i8(i64 10, i8* %a)
   call void @llvm.lifetime.end.p0i8(i64 10, i8* %a)
@@ -50,7 +54,8 @@ define void @test3(i8* %src) {
 ;; This used to crash.
 define void @test4() {
 ; CHECK-LABEL: @test4(
-; CHECK-NEXT: ret void
+; CHECK-NEXT:    ret void
+;
   %A = call i8* @malloc(i32 16000)
   %B = bitcast i8* %A to double*
   %C = bitcast double* %B to i8*
@@ -58,23 +63,24 @@ define void @test4() {
   ret void
 }
 
-; CHECK-LABEL: @test5(
 define void @test5(i8* %ptr, i8** %esc) {
-; CHECK-NEXT: call i8* @malloc
-; CHECK-NEXT: call i8* @malloc
-; CHECK-NEXT: call i8* @malloc
-; CHECK-NEXT: call i8* @malloc
-; CHECK-NEXT: call i8* @malloc
-; CHECK-NEXT: call i8* @malloc
-; CHECK-NEXT: call i8* @malloc
-; CHECK-NEXT: call void @llvm.memcpy
-; CHECK-NEXT: call void @llvm.memmove
-; CHECK-NEXT: store
-; CHECK-NEXT: call void @llvm.memcpy
-; CHECK-NEXT: call void @llvm.memmove
-; CHECK-NEXT: call void @llvm.memset
-; CHECK-NEXT: store volatile
-; CHECK-NEXT: ret
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[A:%.*]] = call dereferenceable_or_null(700) i8* @malloc(i32 700)
+; CHECK-NEXT:    [[B:%.*]] = call dereferenceable_or_null(700) i8* @malloc(i32 700)
+; CHECK-NEXT:    [[C:%.*]] = call dereferenceable_or_null(700) i8* @malloc(i32 700)
+; CHECK-NEXT:    [[D:%.*]] = call dereferenceable_or_null(700) i8* @malloc(i32 700)
+; CHECK-NEXT:    [[E:%.*]] = call dereferenceable_or_null(700) i8* @malloc(i32 700)
+; CHECK-NEXT:    [[F:%.*]] = call dereferenceable_or_null(700) i8* @malloc(i32 700)
+; CHECK-NEXT:    [[G:%.*]] = call dereferenceable_or_null(700) i8* @malloc(i32 700)
+; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 dereferenceable(32) [[PTR:%.*]], i8* align 1 dereferenceable(32) [[A]], i32 32, i1 false)
+; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i32(i8* align 1 dereferenceable(32) [[PTR]], i8* align 1 dereferenceable(32) [[B]], i32 32, i1 false)
+; CHECK-NEXT:    store i8* [[C]], i8** [[ESC:%.*]], align 8
+; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[D]], i8* [[PTR]], i32 32, i1 true)
+; CHECK-NEXT:    call void @llvm.memmove.p0i8.p0i8.i32(i8* [[E]], i8* [[PTR]], i32 32, i1 true)
+; CHECK-NEXT:    call void @llvm.memset.p0i8.i32(i8* [[F]], i8 5, i32 32, i1 true)
+; CHECK-NEXT:    store volatile i8 4, i8* [[G]], align 1
+; CHECK-NEXT:    ret void
+;
   %a = call i8* @malloc(i32 700)
   %b = call i8* @malloc(i32 700)
   %c = call i8* @malloc(i32 700)
@@ -98,17 +104,19 @@ define void @test5(i8* %ptr, i8** %esc)
 ;; Using simplifycfg will remove the empty basic block and the branch operation
 ;; Then, performing a dead elimination will remove the comparison.
 ;; This is what happens with -O1 and upper.
-; CHECK-LABEL: @test6(
 define void @test6(i8* %foo) minsize {
-; CHECK:  %tobool = icmp eq i8* %foo, null
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i8* [[FOO:%.*]], null
+; CHECK-NEXT:    tail call void @free(i8* [[FOO]])
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    ret void
+;
 ;; Call to free moved
-; CHECK-NEXT: tail call void @free(i8* %foo)
-; CHECK-NEXT: br i1 %tobool, label %if.end, label %if.then
-; CHECK: if.then:
 ;; Block is now empty and may be simplified by simplifycfg
-; CHECK-NEXT:   br label %if.end
-; CHECK: if.end:
-; CHECK-NEXT:  ret void
 entry:
   %tobool = icmp eq i8* %foo, null
   br i1 %tobool, label %if.end, label %if.then
@@ -126,27 +134,40 @@ declare void @_ZdlPvRKSt9nothrow_t(i8*,
 declare i32 @__gxx_personality_v0(...)
 declare void @_ZN1AC2Ev(i8* %this)
 
-; CHECK-LABEL: @test7(
 define void @test7() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    invoke void @_ZN1AC2Ev(i8* undef)
+; CHECK-NEXT:    to label [[DOTNOEXC_I:%.*]] unwind label [[LPAD_I:%.*]]
+; CHECK:       .noexc.i:
+; CHECK-NEXT:    unreachable
+; CHECK:       lpad.i:
+; CHECK-NEXT:    [[TMP0:%.*]] = landingpad { i8*, i32 }
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    resume { i8*, i32 } [[TMP0]]
+;
 entry:
   %nt = alloca i8
-  ; CHECK-NOT: call {{.*}}@_ZnwmRKSt9nothrow_t(
   %call.i = tail call i8* @_ZnwmRKSt9nothrow_t(i64 1, i8* %nt) builtin nounwind
   invoke void @_ZN1AC2Ev(i8* undef)
-          to label %.noexc.i unwind label %lpad.i
+  to label %.noexc.i unwind label %lpad.i
 
 .noexc.i:                                         ; preds = %entry
   unreachable
 
 lpad.i:                                           ; preds = %entry
   %0 = landingpad { i8*, i32 } cleanup
-  ; CHECK-NOT: call {{.*}}@_ZdlPvRKSt9nothrow_t(
   call void @_ZdlPvRKSt9nothrow_t(i8* %call.i, i8* %nt) builtin nounwind
   resume { i8*, i32 } %0
 }
 
 declare i8* @_Znwm(i64) nobuiltin
 define i8* @_Znwj(i32 %n) nobuiltin {
+; CHECK-LABEL: @_Znwj(
+; CHECK-NEXT:    [[Z:%.*]] = zext i32 [[N:%.*]] to i64
+; CHECK-NEXT:    [[M:%.*]] = call i8* @_Znwm(i64 [[Z]])
+; CHECK-NEXT:    ret i8* [[M]]
+;
   %z = zext i32 %n to i64
   %m = call i8* @_Znwm(i64 %z)
   ret i8* %m
@@ -157,18 +178,34 @@ declare void @_ZdlPv(i8*) nobuiltin
 declare void @_ZdaPv(i8*) nobuiltin
 
 define linkonce void @_ZdlPvm(i8* %p, i64) nobuiltin {
+; CHECK-LABEL: @_ZdlPvm(
+; CHECK-NEXT:    call void @_ZdlPv(i8* [[P:%.*]])
+; CHECK-NEXT:    ret void
+;
   call void @_ZdlPv(i8* %p)
   ret void
 }
 define linkonce void @_ZdlPvj(i8* %p, i32) nobuiltin {
+; CHECK-LABEL: @_ZdlPvj(
+; CHECK-NEXT:    call void @_ZdlPv(i8* [[P:%.*]])
+; CHECK-NEXT:    ret void
+;
   call void @_ZdlPv(i8* %p)
   ret void
 }
 define linkonce void @_ZdaPvm(i8* %p, i64) nobuiltin {
+; CHECK-LABEL: @_ZdaPvm(
+; CHECK-NEXT:    call void @_ZdaPv(i8* [[P:%.*]])
+; CHECK-NEXT:    ret void
+;
   call void @_ZdaPv(i8* %p)
   ret void
 }
 define linkonce void @_ZdaPvj(i8* %p, i32) nobuiltin {
+; CHECK-LABEL: @_ZdaPvj(
+; CHECK-NEXT:    call void @_ZdaPv(i8* [[P:%.*]])
+; CHECK-NEXT:    ret void
+;
   call void @_ZdaPv(i8* %p)
   ret void
 }
@@ -196,9 +233,10 @@ declare void @_ZdlPvSt11align_val_tRKSt9
 declare void @_ZdaPvSt11align_val_tRKSt9nothrow_t(i8*, i64, i8*) nobuiltin
 
 
-; CHECK-LABEL: @test8(
 define void @test8() {
-  ; CHECK-NOT: call
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    ret void
+;
   %nt = alloca i8
   %nw = call i8* @_Znwm(i64 32) builtin
   call void @_ZdlPv(i8* %nw) builtin
@@ -234,25 +272,30 @@ define void @test8() {
 declare noalias i8* @"\01??2 at YAPEAX_K@Z"(i64) nobuiltin
 declare void @"\01??3 at YAXPEAX@Z"(i8*) nobuiltin
 
-; CHECK-LABEL: @test9(
 define void @test9() {
-  ; CHECK-NOT: call
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    ret void
+;
   %new_long_long = call noalias i8* @"\01??2 at YAPEAX_K@Z"(i64 32) builtin
   call void @"\01??3 at YAXPEAX@Z"(i8* %new_long_long) builtin
   ret void
 }
 
 define void @test10()  {
-; CHECK-LABEL: @test10
-; CHECK: call void @_ZdlPv
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:    call void @_ZdlPv(i8* null)
+; CHECK-NEXT:    ret void
+;
   call void @_ZdlPv(i8* null)
   ret void
 }
 
 define void @test11() {
-; CHECK-LABEL: @test11
-; CHECK: call i8* @_Znwm
-; CHECK: call void @_ZdlPv
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(8) i8* @_Znwm(i64 8) #5
+; CHECK-NEXT:    call void @_ZdlPv(i8* [[CALL]])
+; CHECK-NEXT:    ret void
+;
   %call = call i8* @_Znwm(i64 8) builtin
   call void @_ZdlPv(i8* %call)
   ret void
@@ -260,19 +303,21 @@ define void @test11() {
 
 ;; Check that the optimization that moves a call to free in its predecessor
 ;; block (see test6) also happens when noop casts are involved.
-; CHECK-LABEL: @test12(
 define void @test12(i32* %foo) minsize {
-; CHECK:  %tobool = icmp eq i32* %foo, null
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i32* [[FOO:%.*]], null
+; CHECK-NEXT:    [[BITCAST:%.*]] = bitcast i32* [[FOO]] to i8*
+; CHECK-NEXT:    tail call void @free(i8* [[BITCAST]])
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    ret void
+;
 ;; Everything before the call to free should have been moved as well.
-; CHECK-NEXT:   %bitcast = bitcast i32* %foo to i8*
 ;; Call to free moved
-; CHECK-NEXT: tail call void @free(i8* %bitcast)
-; CHECK-NEXT: br i1 %tobool, label %if.end, label %if.then
-; CHECK: if.then:
 ;; Block is now empty and may be simplified by simplifycfg
-; CHECK-NEXT:   br label %if.end
-; CHECK: if.end:
-; CHECK-NEXT:  ret void
 entry:
   %tobool = icmp eq i32* %foo, null
   br i1 %tobool, label %if.end, label %if.then

Modified: llvm/trunk/test/Transforms/InstCombine/objsize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/objsize.ll?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/objsize.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/objsize.ll Wed Aug 28 01:28:20 2019
@@ -161,7 +161,7 @@ entry:
 define i8* @test5(i32 %n) nounwind ssp {
 ; CHECK-LABEL: @test5(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = tail call noalias i8* @malloc(i32 20) #0
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call noalias dereferenceable_or_null(20) i8* @malloc(i32 20) #0
 ; CHECK-NEXT:    [[TMP1:%.*]] = load i8*, i8** @s, align 8
 ; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 dereferenceable(10) [[TMP0]], i8* align 1 dereferenceable(10) [[TMP1]], i32 10, i1 false)
 ; CHECK-NEXT:    ret i8* [[TMP0]]
@@ -177,7 +177,7 @@ entry:
 define void @test6(i32 %n) nounwind ssp {
 ; CHECK-LABEL: @test6(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = tail call noalias i8* @malloc(i32 20) #0
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call noalias dereferenceable_or_null(20) i8* @malloc(i32 20) #0
 ; CHECK-NEXT:    [[TMP1:%.*]] = load i8*, i8** @s, align 8
 ; CHECK-NEXT:    [[TMP2:%.*]] = tail call i8* @__memcpy_chk(i8* [[TMP0]], i8* [[TMP1]], i32 30, i32 20) #0
 ; CHECK-NEXT:    ret void
@@ -196,7 +196,7 @@ declare noalias i8* @malloc(i32) nounwin
 
 define i32 @test7(i8** %esc) {
 ; CHECK-LABEL: @test7(
-; CHECK-NEXT:    [[ALLOC:%.*]] = call noalias i8* @malloc(i32 48) #0
+; CHECK-NEXT:    [[ALLOC:%.*]] = call noalias dereferenceable_or_null(48) i8* @malloc(i32 48) #0
 ; CHECK-NEXT:    store i8* [[ALLOC]], i8** [[ESC:%.*]], align 4
 ; CHECK-NEXT:    ret i32 32
 ;
@@ -211,7 +211,7 @@ declare noalias i8* @calloc(i32, i32) no
 
 define i32 @test8(i8** %esc) {
 ; CHECK-LABEL: @test8(
-; CHECK-NEXT:    [[ALLOC:%.*]] = call noalias i8* @calloc(i32 5, i32 7) #0
+; CHECK-NEXT:    [[ALLOC:%.*]] = call noalias dereferenceable_or_null(35) i8* @calloc(i32 5, i32 7) #0
 ; CHECK-NEXT:    store i8* [[ALLOC]], i8** [[ESC:%.*]], align 4
 ; CHECK-NEXT:    ret i32 30
 ;

Modified: llvm/trunk/test/Transforms/InstCombine/realloc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/realloc.ll?rev=370168&r1=370167&r2=370168&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/realloc.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/realloc.ll Wed Aug 28 01:28:20 2019
@@ -7,7 +7,7 @@ declare noalias i8* @malloc(i64) #1
 
 define i8* @realloc_null_ptr() #0 {
 ; CHECK-LABEL: @realloc_null_ptr(
-; CHECK-NEXT:    [[MALLOC:%.*]] = call i8* @malloc(i64 100)
+; CHECK-NEXT:    [[MALLOC:%.*]] = call dereferenceable_or_null(100) i8* @malloc(i64 100)
 ; CHECK-NEXT:    ret i8* [[MALLOC]]
 ;
   %call = call i8* @realloc(i8* null, i64 100) #2
@@ -16,7 +16,7 @@ define i8* @realloc_null_ptr() #0 {
 
 define i8* @realloc_unknown_ptr(i8* %ptr) #0 {
 ; CHECK-LABEL: @realloc_unknown_ptr(
-; CHECK-NEXT:    [[CALL:%.*]] = call i8* @realloc(i8* [[PTR:%.*]], i64 100)
+; CHECK-NEXT:    [[CALL:%.*]] = call dereferenceable_or_null(100) i8* @realloc(i8* [[PTR:%.*]], i64 100)
 ; CHECK-NEXT:    ret i8* [[CALL]]
 ;
   %call = call i8* @realloc(i8* %ptr, i64 100) #2




More information about the llvm-commits mailing list