[llvm] r266193 - Calculate __builtin_object_size when pointer depends on a condition

Petar Jovanovic via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 13 05:25:34 PDT 2016


Author: petarj
Date: Wed Apr 13 07:25:25 2016
New Revision: 266193

URL: http://llvm.org/viewvc/llvm-project?rev=266193&view=rev
Log:
Calculate __builtin_object_size when pointer depends on a condition

This patch fixes calculating of builtin_object_size if it depends on a
condition. Before this patch compiler did not know how to calculate the
object size when it finds a condition that cannot be eliminated.
This patch enables calculating of builtin_object_size even in case when
condition cannot be eliminated by choosing minimum or maximum value as a
result from condition. Choosing minimum or maximum value from condition
is based on the second argument of __builtin_object_size function.

Patch by Strahinja Petrovic.

Differential Revision: http://reviews.llvm.org/D18438

Added:
    llvm/trunk/test/Transforms/CodeGenPrepare/builtin-condition.ll
    llvm/trunk/test/Transforms/InstCombine/builtin-object-size-offset.ll
Modified:
    llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h
    llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
    llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp

Modified: llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h?rev=266193&r1=266192&r2=266193&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h (original)
+++ llvm/trunk/include/llvm/Analysis/MemoryBuiltins.h Wed Apr 13 07:25:25 2016
@@ -32,6 +32,11 @@ class TargetLibraryInfo;
 class Type;
 class Value;
 
+enum class ObjSizeMode {
+  Exact = 0,
+  Min = 1,
+  Max = 2
+};
 
 /// \brief Tests if a value is a call or invoke to a library function that
 /// allocates or reallocates memory (either malloc, calloc, realloc, or strdup
@@ -130,8 +135,11 @@ static inline CallInst *isFreeCall(Value
 /// underlying object pointed to by Ptr.
 /// If RoundToAlign is true, then Size is rounded up to the aligment of allocas,
 /// byval arguments, and global variables.
+/// If Mode is Min or Max the size will be evaluated even if it depends on
+/// a condition and corresponding value will be returned (min or max).
 bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
-                   const TargetLibraryInfo *TLI, bool RoundToAlign = false);
+                   const TargetLibraryInfo *TLI, bool RoundToAlign = false,
+                   ObjSizeMode Mode = ObjSizeMode::Exact);
 
 typedef std::pair<APInt, APInt> SizeOffsetType;
 
@@ -143,6 +151,7 @@ class ObjectSizeOffsetVisitor
   const DataLayout &DL;
   const TargetLibraryInfo *TLI;
   bool RoundToAlign;
+  ObjSizeMode Mode;
   unsigned IntTyBits;
   APInt Zero;
   SmallPtrSet<Instruction *, 8> SeenInsts;
@@ -155,7 +164,8 @@ class ObjectSizeOffsetVisitor
 
 public:
   ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI,
-                          LLVMContext &Context, bool RoundToAlign = false);
+                          LLVMContext &Context, bool RoundToAlign = false,
+                          ObjSizeMode Mode = ObjSizeMode::Exact);
 
   SizeOffsetType compute(Value *V);
 

Modified: llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryBuiltins.cpp?rev=266193&r1=266192&r2=266193&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/MemoryBuiltins.cpp (original)
+++ llvm/trunk/lib/Analysis/MemoryBuiltins.cpp Wed Apr 13 07:25:25 2016
@@ -367,29 +367,29 @@ const CallInst *llvm::isFreeCall(const V
 //===----------------------------------------------------------------------===//
 //  Utility functions to compute size of objects.
 //
-
+static APInt getSizeWithOverflow(const SizeOffsetType &Data) {
+  if (Data.second.isNegative() || Data.first.ult(Data.second))
+    return APInt(Data.first.getBitWidth(), 0);
+  return Data.first - Data.second;
+}
 
 /// \brief Compute the size of the object pointed by Ptr. Returns true and the
 /// object size in Size if successful, and false otherwise.
 /// If RoundToAlign is true, then Size is rounded up to the aligment of allocas,
 /// byval arguments, and global variables.
 bool llvm::getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
-                         const TargetLibraryInfo *TLI, bool RoundToAlign) {
-  ObjectSizeOffsetVisitor Visitor(DL, TLI, Ptr->getContext(), RoundToAlign);
+                         const TargetLibraryInfo *TLI, bool RoundToAlign,
+                         llvm::ObjSizeMode Mode) {
+  ObjectSizeOffsetVisitor Visitor(DL, TLI, Ptr->getContext(),
+                                  RoundToAlign, Mode);
   SizeOffsetType Data = Visitor.compute(const_cast<Value*>(Ptr));
   if (!Visitor.bothKnown(Data))
     return false;
 
-  APInt ObjSize = Data.first, Offset = Data.second;
-  // check for overflow
-  if (Offset.slt(0) || ObjSize.ult(Offset))
-    Size = 0;
-  else
-    Size = (ObjSize - Offset).getZExtValue();
+  Size = getSizeWithOverflow(Data).getZExtValue();
   return true;
 }
 
-
 STATISTIC(ObjectVisitorArgument,
           "Number of arguments with unsolved size and offset");
 STATISTIC(ObjectVisitorLoad,
@@ -405,8 +405,9 @@ APInt ObjectSizeOffsetVisitor::align(API
 ObjectSizeOffsetVisitor::ObjectSizeOffsetVisitor(const DataLayout &DL,
                                                  const TargetLibraryInfo *TLI,
                                                  LLVMContext &Context,
-                                                 bool RoundToAlign)
-    : DL(DL), TLI(TLI), RoundToAlign(RoundToAlign) {
+                                                 bool RoundToAlign,
+                                                 ObjSizeMode Mode)
+    : DL(DL), TLI(TLI), RoundToAlign(RoundToAlign), Mode(Mode) {
   // Pointer size must be rechecked for each object visited since it could have
   // a different address space.
 }
@@ -606,8 +607,28 @@ SizeOffsetType ObjectSizeOffsetVisitor::
 SizeOffsetType ObjectSizeOffsetVisitor::visitSelectInst(SelectInst &I) {
   SizeOffsetType TrueSide  = compute(I.getTrueValue());
   SizeOffsetType FalseSide = compute(I.getFalseValue());
-  if (bothKnown(TrueSide) && bothKnown(FalseSide) && TrueSide == FalseSide)
-    return TrueSide;
+  if (bothKnown(TrueSide) && bothKnown(FalseSide)) {
+    if (TrueSide == FalseSide) {
+        return TrueSide;
+    }
+
+    APInt TrueResult = getSizeWithOverflow(TrueSide);
+    APInt FalseResult = getSizeWithOverflow(FalseSide);
+
+    if (TrueResult == FalseResult) {
+      return TrueSide;
+    }
+    if (Mode == ObjSizeMode::Min) {
+      if (TrueResult.slt(FalseResult))
+        return TrueSide;
+      return FalseSide;
+    }
+    if (Mode == ObjSizeMode::Max) {
+      if (TrueResult.sgt(FalseResult))
+        return TrueSide;
+      return FalseSide;
+    }
+  }
   return unknown();
 }
 

Modified: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp?rev=266193&r1=266192&r2=266193&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp Wed Apr 13 07:25:25 2016
@@ -22,6 +22,7 @@
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Analysis/MemoryBuiltins.h"
 #include "llvm/IR/CallSite.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
@@ -1807,10 +1808,18 @@ bool CodeGenPrepare::optimizeCallInst(Ca
     default: break;
     case Intrinsic::objectsize: {
       // Lower all uses of llvm.objectsize.*
-      bool Min = (cast<ConstantInt>(II->getArgOperand(1))->getZExtValue() == 1);
+      uint64_t Size;
       Type *ReturnTy = CI->getType();
-      Constant *RetVal = ConstantInt::get(ReturnTy, Min ? 0 : -1ULL);
-
+      Constant *RetVal = nullptr;
+      ConstantInt *Op1 = cast<ConstantInt>(II->getArgOperand(1));
+      ObjSizeMode Mode = Op1->isZero() ? ObjSizeMode::Max : ObjSizeMode::Min;
+      if (getObjectSize(II->getArgOperand(0),
+                        Size, *DL, TLInfo, false, Mode)) {
+        RetVal = ConstantInt::get(ReturnTy, Size);
+      } else {
+        RetVal = ConstantInt::get(ReturnTy,
+                                  Mode == ObjSizeMode::Min ? 0 : -1ULL);
+      }
       // Substituting this can cause recursive simplifications, which can
       // invalidate our iterator.  Use a WeakVH to hold onto it in case this
       // happens.

Added: llvm/trunk/test/Transforms/CodeGenPrepare/builtin-condition.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/CodeGenPrepare/builtin-condition.ll?rev=266193&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/CodeGenPrepare/builtin-condition.ll (added)
+++ llvm/trunk/test/Transforms/CodeGenPrepare/builtin-condition.ll Wed Apr 13 07:25:25 2016
@@ -0,0 +1,90 @@
+; RUN: opt -codegenprepare -S  < %s | FileCheck %s
+
+; #include<stdlib.h>
+; #define STATIC_BUF_SIZE 10
+; #define LARGER_BUF_SIZE 30
+;
+; size_t foo1(int flag) {
+;   char *cptr;
+;   char chararray[LARGER_BUF_SIZE];
+;   char chararray2[STATIC_BUF_SIZE];
+;   if(flag)
+;     cptr = chararray2;
+;    else
+;     cptr = chararray;
+;
+;   return  __builtin_object_size(cptr, 2);
+; }
+;
+; size_t foo2(int n) {
+;   char Small[10];
+;   char Large[20];
+;   char *Ptr = n ? Small : Large + 19;
+;   return __builtin_object_size(Ptr, 0);
+; }
+;
+; void foo() {
+;   size_t ret;
+;   size_t ret1;
+;   ret = foo1(0);
+;   ret1 = foo2(0);
+;   printf("\n%d %d\n", ret, ret1);
+; }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at .str = private unnamed_addr constant [8 x i8] c"\0A%d %d\0A\00", align 1
+
+define i64 @foo1(i32 %flag) {
+entry:
+  %chararray = alloca [30 x i8], align 16
+  %chararray2 = alloca [10 x i8], align 1
+  %0 = getelementptr inbounds [30 x i8], [30 x i8]* %chararray, i64 0, i64 0
+  call void @llvm.lifetime.start(i64 30, i8* %0)
+  %1 = getelementptr inbounds [10 x i8], [10 x i8]* %chararray2, i64 0, i64 0
+  call void @llvm.lifetime.start(i64 10, i8* %1)
+  %tobool = icmp eq i32 %flag, 0
+  %cptr.0 = select i1 %tobool, i8* %0, i8* %1
+  %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %cptr.0, i1 true)
+  call void @llvm.lifetime.end(i64 10, i8* %1)
+  call void @llvm.lifetime.end(i64 30, i8* %0)
+  ret i64 %2
+; CHECK-LABEL: foo1
+; CHECK:  ret i64 10
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture)
+
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1)
+
+declare void @llvm.lifetime.end(i64, i8* nocapture)
+
+define i64 @foo2(i32 %n) {
+entry:
+  %Small = alloca [10 x i8], align 1
+  %Large = alloca [20 x i8], align 16
+  %0 = getelementptr inbounds [10 x i8], [10 x i8]* %Small, i64 0, i64 0
+  call void @llvm.lifetime.start(i64 10, i8* %0)
+  %1 = getelementptr inbounds [20 x i8], [20 x i8]* %Large, i64 0, i64 0
+  call void @llvm.lifetime.start(i64 20, i8* %1)
+  %tobool = icmp ne i32 %n, 0
+  %add.ptr = getelementptr inbounds [20 x i8], [20 x i8]* %Large, i64 0, i64 19
+  %cond = select i1 %tobool, i8* %0, i8* %add.ptr
+  %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %cond, i1 false)
+  call void @llvm.lifetime.end(i64 20, i8* %1)
+  call void @llvm.lifetime.end(i64 10, i8* %0)
+  ret i64 %2
+; CHECK-LABEL: foo2
+; CHECK:  ret i64 10
+}
+
+define void @foo() {
+entry:
+  %call = tail call i64 @foo1(i32 0)
+  %call1 = tail call i64 @foo2(i32 0)
+  %call2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str, i64 0, i64 0), i64 %call, i64 %call1)
+  ret void
+}
+
+declare i32 @printf(i8* nocapture readonly, ...)
\ No newline at end of file

Added: llvm/trunk/test/Transforms/InstCombine/builtin-object-size-offset.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/builtin-object-size-offset.ll?rev=266193&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/builtin-object-size-offset.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/builtin-object-size-offset.ll Wed Apr 13 07:25:25 2016
@@ -0,0 +1,58 @@
+; RUN: opt -instcombine -S < %s | FileCheck %s
+
+; #include <stdlib.h>
+; #include <stdio.h>
+;
+; int foo1(int N) {
+;   char Big[20];
+;   char Small[10];
+;   char *Ptr = N ? Big + 10 : Small;
+;   return __builtin_object_size(Ptr, 0);
+; }
+;
+; void foo() {
+;   size_t ret;
+;   ret = foo1(0);
+;   printf("\n %d", ret);
+; }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at .str = private unnamed_addr constant [5 x i8] c"\0A %d\00", align 1
+
+define i32 @foo1(i32 %N) {
+entry:
+  %Big = alloca [20 x i8], align 16
+  %Small = alloca [10 x i8], align 1
+  %0 = getelementptr inbounds [20 x i8], [20 x i8]* %Big, i64 0, i64 0
+  call void @llvm.lifetime.start(i64 20, i8* %0)
+  %1 = getelementptr inbounds [10 x i8], [10 x i8]* %Small, i64 0, i64 0
+  call void @llvm.lifetime.start(i64 10, i8* %1)
+  %tobool = icmp ne i32 %N, 0
+  %add.ptr = getelementptr inbounds [20 x i8], [20 x i8]* %Big, i64 0, i64 10
+  %cond = select i1 %tobool, i8* %add.ptr, i8* %1
+  %2 = call i64 @llvm.objectsize.i64.p0i8(i8* %cond, i1 false)
+  %conv = trunc i64 %2 to i32
+  call void @llvm.lifetime.end(i64 10, i8* %1)
+  call void @llvm.lifetime.end(i64 20, i8* %0)
+  ret i32 %conv
+; CHECK: ret i32 10 
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture)
+
+declare i64 @llvm.objectsize.i64.p0i8(i8*, i1)
+
+declare void @llvm.lifetime.end(i64, i8* nocapture)
+
+define void @foo() {
+entry:
+  %call = tail call i32 @foo1(i32 0)
+  %conv = sext i32 %call to i64
+  %call1 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i64 %conv)
+  ret void
+}
+
+declare i32 @printf(i8* nocapture readonly, ...)
+




More information about the llvm-commits mailing list