[llvm] r332990 - [InstCombine] Calloc-ed strings optimizations

David Bolvansky via llvm-commits llvm-commits at lists.llvm.org
Tue May 22 08:41:23 PDT 2018


Author: xbolva00
Date: Tue May 22 08:41:23 2018
New Revision: 332990

URL: http://llvm.org/viewvc/llvm-project?rev=332990&view=rev
Log:
[InstCombine] Calloc-ed strings optimizations

Summary:
Example cases:
strlen(calloc(...)) -> 0

Reviewers: efriedma, bkramer

Reviewed By: bkramer

Subscribers: llvm-commits

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

Added:
    llvm/trunk/test/Transforms/InstCombine/zero-string.ll
Modified:
    llvm/trunk/include/llvm/Analysis/ValueTracking.h
    llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
    llvm/trunk/lib/Analysis/ValueTracking.cpp
    llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp

Modified: llvm/trunk/include/llvm/Analysis/ValueTracking.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ValueTracking.h?rev=332990&r1=332989&r2=332990&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/ValueTracking.h (original)
+++ llvm/trunk/include/llvm/Analysis/ValueTracking.h Tue May 22 08:41:23 2018
@@ -274,7 +274,7 @@ class Value;
 
   /// If we can compute the length of the string pointed to by the specified
   /// pointer, return 'len+1'.  If we can't, return 0.
-  uint64_t GetStringLength(const Value *V, unsigned CharSize = 8);
+  uint64_t GetStringLength(const Value *V, const TargetLibraryInfo *TLI, unsigned CharSize = 8);
 
   /// This method strips off any GEP address adjustments and pointer casts from
   /// the specified value, returning the original object being addressed. Note

Modified: llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryBuiltins.cpp?rev=332990&r1=332989&r2=332990&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/MemoryBuiltins.cpp (original)
+++ llvm/trunk/lib/Analysis/MemoryBuiltins.cpp Tue May 22 08:41:23 2018
@@ -589,7 +589,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::
 
   // Handle strdup-like functions separately.
   if (FnData->AllocTy == StrDupLike) {
-    APInt Size(IntTyBits, GetStringLength(CS.getArgument(0)));
+    APInt Size(IntTyBits, GetStringLength(CS.getArgument(0), TLI));
     if (!Size)
       return unknown();
 

Modified: llvm/trunk/lib/Analysis/ValueTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ValueTracking.cpp?rev=332990&r1=332989&r2=332990&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ValueTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/ValueTracking.cpp Tue May 22 08:41:23 2018
@@ -3372,10 +3372,39 @@ static uint64_t GetStringLengthH(const V
   return NullIndex + 1;
 }
 
+static bool isStringFromCalloc(const Value *Str, const TargetLibraryInfo *TLI) {
+  const CallInst *Calloc = dyn_cast<CallInst>(Str);
+  if (!Calloc)
+    return false;
+
+  const Function *InnerCallee = Calloc->getCalledFunction();
+  if (!InnerCallee)
+    return false;
+
+  LibFunc Func;
+  if (!TLI->getLibFunc(*InnerCallee, Func) || !TLI->has(Func) ||
+      Func != LibFunc_calloc)
+    return false;
+
+  const ConstantInt *N = dyn_cast<ConstantInt>(Calloc->getOperand(0));
+  const ConstantInt *Size = dyn_cast<ConstantInt>(Calloc->getOperand(1));
+
+  if (!N || !Size)
+    return false;
+
+  if (N->isNullValue() || Size->isNullValue())
+    return false;
+
+  return true;
+}
+
 /// If we can compute the length of the string pointed to by
 /// the specified pointer, return 'len+1'.  If we can't, return 0.
-uint64_t llvm::GetStringLength(const Value *V, unsigned CharSize) {
-  if (!V->getType()->isPointerTy()) return 0;
+uint64_t llvm::GetStringLength(const Value *V, const TargetLibraryInfo *TLI, unsigned CharSize) {
+  if (!V->getType()->isPointerTy())
+    return 0;
+  if (isStringFromCalloc(V, TLI))
+    return 1;
 
   SmallPtrSet<const PHINode*, 32> PHIs;
   uint64_t Len = GetStringLengthH(V, PHIs, CharSize);

Modified: llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp?rev=332990&r1=332989&r2=332990&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp Tue May 22 08:41:23 2018
@@ -160,7 +160,7 @@ Value *LibCallSimplifier::optimizeStrCat
   Value *Src = CI->getArgOperand(1);
 
   // See if we can get the length of the input string.
-  uint64_t Len = GetStringLength(Src);
+  uint64_t Len = GetStringLength(Src, TLI);
   if (Len == 0)
     return nullptr;
   --Len; // Unbias length.
@@ -205,7 +205,7 @@ Value *LibCallSimplifier::optimizeStrNCa
     return nullptr;
 
   // See if we can get the length of the input string.
-  uint64_t SrcLen = GetStringLength(Src);
+  uint64_t SrcLen = GetStringLength(Src, TLI);
   if (SrcLen == 0)
     return nullptr;
   --SrcLen; // Unbias length.
@@ -234,7 +234,7 @@ Value *LibCallSimplifier::optimizeStrChr
   // of the input string and turn this into memchr.
   ConstantInt *CharC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
   if (!CharC) {
-    uint64_t Len = GetStringLength(SrcStr);
+    uint64_t Len = GetStringLength(SrcStr, TLI);
     if (Len == 0 || !FT->getParamType(1)->isIntegerTy(32)) // memchr needs i32.
       return nullptr;
 
@@ -313,8 +313,8 @@ Value *LibCallSimplifier::optimizeStrCmp
     return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType());
 
   // strcmp(P, "x") -> memcmp(P, "x", 2)
-  uint64_t Len1 = GetStringLength(Str1P);
-  uint64_t Len2 = GetStringLength(Str2P);
+  uint64_t Len1 = GetStringLength(Str1P, TLI);
+  uint64_t Len2 = GetStringLength(Str2P, TLI);
   if (Len1 && Len2) {
     return emitMemCmp(Str1P, Str2P,
                       ConstantInt::get(DL.getIntPtrType(CI->getContext()),
@@ -370,7 +370,7 @@ Value *LibCallSimplifier::optimizeStrCpy
     return Src;
 
   // See if we can get the length of the input string.
-  uint64_t Len = GetStringLength(Src);
+  uint64_t Len = GetStringLength(Src, TLI);
   if (Len == 0)
     return nullptr;
 
@@ -390,7 +390,7 @@ Value *LibCallSimplifier::optimizeStpCpy
   }
 
   // See if we can get the length of the input string.
-  uint64_t Len = GetStringLength(Src);
+  uint64_t Len = GetStringLength(Src, TLI);
   if (Len == 0)
     return nullptr;
 
@@ -412,7 +412,7 @@ Value *LibCallSimplifier::optimizeStrNCp
   Value *LenOp = CI->getArgOperand(2);
 
   // See if we can get the length of the input string.
-  uint64_t SrcLen = GetStringLength(Src);
+  uint64_t SrcLen = GetStringLength(Src, TLI);
   if (SrcLen == 0)
     return nullptr;
   --SrcLen;
@@ -448,7 +448,7 @@ Value *LibCallSimplifier::optimizeString
   Value *Src = CI->getArgOperand(0);
 
   // Constant folding: strlen("xyz") -> 3
-  if (uint64_t Len = GetStringLength(Src, CharSize))
+  if (uint64_t Len = GetStringLength(Src, TLI, CharSize))
     return ConstantInt::get(CI->getType(), Len - 1);
 
   // If s is a constant pointer pointing to a string literal, we can fold
@@ -512,8 +512,8 @@ Value *LibCallSimplifier::optimizeString
 
   // strlen(x?"foo":"bars") --> x ? 3 : 4
   if (SelectInst *SI = dyn_cast<SelectInst>(Src)) {
-    uint64_t LenTrue = GetStringLength(SI->getTrueValue(), CharSize);
-    uint64_t LenFalse = GetStringLength(SI->getFalseValue(), CharSize);
+    uint64_t LenTrue = GetStringLength(SI->getTrueValue(), TLI, CharSize);
+    uint64_t LenFalse = GetStringLength(SI->getFalseValue(), TLI, CharSize);
     if (LenTrue && LenFalse) {
       ORE.emit([&]() {
         return OptimizationRemark("instcombine", "simplify-libcalls", CI)
@@ -2142,7 +2142,7 @@ Value *LibCallSimplifier::optimizeFPuts(
   }
 
   // fputs(s,F) --> fwrite(s,1,strlen(s),F)
-  uint64_t Len = GetStringLength(CI->getArgOperand(0));
+  uint64_t Len = GetStringLength(CI->getArgOperand(0), TLI);
   if (!Len)
     return nullptr;
 
@@ -2565,7 +2565,7 @@ bool FortifiedLibCallSimplifier::isForti
     if (OnlyLowerUnknownSize)
       return false;
     if (isString) {
-      uint64_t Len = GetStringLength(CI->getArgOperand(SizeOp));
+      uint64_t Len = GetStringLength(CI->getArgOperand(SizeOp), TLI);
       // If the length is 0 we don't know how long it is and so we can't
       // remove the check.
       if (Len == 0)
@@ -2637,7 +2637,7 @@ Value *FortifiedLibCallSimplifier::optim
     return nullptr;
 
   // Maybe we can stil fold __st[rp]cpy_chk to __memcpy_chk.
-  uint64_t Len = GetStringLength(Src);
+  uint64_t Len = GetStringLength(Src, TLI);
   if (Len == 0)
     return nullptr;
 
@@ -2716,4 +2716,4 @@ Value *FortifiedLibCallSimplifier::optim
 
 FortifiedLibCallSimplifier::FortifiedLibCallSimplifier(
     const TargetLibraryInfo *TLI, bool OnlyLowerUnknownSize)
-    : TLI(TLI), OnlyLowerUnknownSize(OnlyLowerUnknownSize) {}
+    : TLI(TLI), OnlyLowerUnknownSize(OnlyLowerUnknownSize) {}
\ No newline at end of file

Added: llvm/trunk/test/Transforms/InstCombine/zero-string.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/zero-string.ll?rev=332990&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/zero-string.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/zero-string.ll Tue May 22 08:41:23 2018
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instcombine  -S | FileCheck %s
+
+declare i32 @strlen(i8* nocapture)
+declare noalias i8* @calloc(i32, i32)
+declare noalias i8* @malloc(i32)
+
+define i32 @calloc_strlen() {
+; CHECK-LABEL: @calloc_strlen(
+; CHECK-NEXT:    ret i32 0
+;
+  %call = tail call noalias i8* @calloc(i32 10, i32 1)
+  %call1 = tail call i32 @strlen(i8* %call)
+  ret i32 %call1
+}
+
+define i32 @calloc_strlen_not_const_nmemb(i32 %n) {
+; CHECK-LABEL: @calloc_strlen_not_const_nmemb(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @calloc(i32 [[N:%.*]], i32 10)
+; CHECK-NEXT:    [[CALL1:%.*]] = tail call i32 @strlen(i8* [[CALL]])
+; CHECK-NEXT:    ret i32 [[CALL1]]
+;
+  %call = tail call noalias i8* @calloc(i32 %n, i32 10)
+  %call1 = tail call i32 @strlen(i8* %call) #4
+  ret i32 %call1
+}
+
+
+define i32 @calloc_strlen_not_const_size(i32 %size) {
+; CHECK-LABEL: @calloc_strlen_not_const_size(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @calloc(i32 1, i32 [[SIZE:%.*]])
+; CHECK-NEXT:    [[CALL1:%.*]] = tail call i32 @strlen(i8* [[CALL]])
+; CHECK-NEXT:    ret i32 [[CALL1]]
+;
+  %call = tail call noalias i8* @calloc(i32 1, i32 %size)
+  %call1 = tail call i32 @strlen(i8* %call) #4
+  ret i32 %call1
+}
+
+
+define i32 @calloc_strlen_not_const_args(i32 %n, i32 %size) {
+; CHECK-LABEL: @calloc_strlen_not_const_args(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @calloc(i32 [[N:%.*]], i32 [[SIZE:%.*]])
+; CHECK-NEXT:    [[CALL1:%.*]] = tail call i32 @strlen(i8* [[CALL]])
+; CHECK-NEXT:    ret i32 [[CALL1]]
+;
+  %call = tail call noalias i8* @calloc(i32 %n, i32 %size)
+  %call1 = tail call i32 @strlen(i8* %call) #4
+  ret i32 %call1
+}
+
+
+define i32 @malloc_strlen() {
+; CHECK-LABEL: @malloc_strlen(
+; CHECK-NEXT:    [[CALL:%.*]] = tail call noalias i8* @malloc(i32 10)
+; CHECK-NEXT:    [[CALL1:%.*]] = tail call i32 @strlen(i8* [[CALL]])
+; CHECK-NEXT:    ret i32 [[CALL1]]
+;
+  %call = tail call noalias i8* @malloc(i32 10)
+  %call1 = tail call i32 @strlen(i8* %call)
+  ret i32 %call1
+




More information about the llvm-commits mailing list