[llvm-commits] [llvm] r158920 - in /llvm/trunk: lib/Transforms/Scalar/BoundsChecking.cpp test/Transforms/BoundsChecking/alloc_size.ll test/Transforms/BoundsChecking/many-trap.ll

Nuno Lopes nunoplopes at sapo.pt
Thu Jun 21 08:59:53 PDT 2012


Author: nlopes
Date: Thu Jun 21 10:59:53 2012
New Revision: 158920

URL: http://llvm.org/viewvc/llvm-project?rev=158920&view=rev
Log:
port the BoundsChecking patch to the new MemoryBuiltin API (i.e., remove most of the code from here).
Remove the alloc_size.ll test until we settle on a metadata format that makes everyone happy..

Removed:
    llvm/trunk/test/Transforms/BoundsChecking/alloc_size.ll
Modified:
    llvm/trunk/lib/Transforms/Scalar/BoundsChecking.cpp
    llvm/trunk/test/Transforms/BoundsChecking/many-trap.ll

Modified: llvm/trunk/lib/Transforms/Scalar/BoundsChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/BoundsChecking.cpp?rev=158920&r1=158919&r2=158920&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/BoundsChecking.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/BoundsChecking.cpp Thu Jun 21 10:59:53 2012
@@ -14,12 +14,8 @@
 
 #define DEBUG_TYPE "bounds-checking"
 #include "llvm/Transforms/Scalar.h"
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/LoopInfo.h"
-#include "llvm/Analysis/ScalarEvolution.h"
-#include "llvm/Analysis/ScalarEvolutionExpander.h"
-#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/Analysis/MemoryBuiltins.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/InstIterator.h"
@@ -27,42 +23,20 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/TargetFolder.h"
 #include "llvm/Target/TargetData.h"
-#include "llvm/Transforms/Utils/Local.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Instructions.h"
 #include "llvm/Intrinsics.h"
-#include "llvm/Metadata.h"
-#include "llvm/Operator.h"
 #include "llvm/Pass.h"
 using namespace llvm;
 
-static cl::opt<bool> ManyTrapBB("bounds-checking-multiple-traps",
-                                cl::desc("Use one trap block per assertion"));
+static cl::opt<bool> SingleTrapBB("bounds-checking-single-trap",
+                                  cl::desc("Use one trap block per function"));
 
 STATISTIC(ChecksAdded, "Bounds checks added");
 STATISTIC(ChecksSkipped, "Bounds checks skipped");
 STATISTIC(ChecksUnable, "Bounds checks unable to add");
-STATISTIC(ChecksUnableInterproc, "Bounds checks unable to add (interprocedural)");
-STATISTIC(ChecksUnableLoad, "Bounds checks unable to add (LoadInst)");
 
 typedef IRBuilder<true, TargetFolder> BuilderTy;
 
 namespace {
-  // FIXME: can use unions here to save space
-  struct CacheData {
-    APInt Offset;
-    Value *OffsetValue;
-    APInt Size;
-    Value *SizeValue;
-    bool ReturnVal;
-    CacheData() {}
-    CacheData(APInt Off, Value *OffVal, APInt Sz, Value *SzVal, bool Ret) :
-      Offset(Off), OffsetValue(OffVal), Size(Sz), SizeValue(SzVal),
-      ReturnVal(Ret) {}
-  };
-  typedef DenseMap<Value*, CacheData> CacheMapTy;
-  typedef SmallPtrSet<Value*, 8> PtrSetTy;
-
   struct BoundsChecking : public FunctionPass {
     static char ID;
 
@@ -74,20 +48,15 @@
 
     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
       AU.addRequired<TargetData>();
-      AU.addRequired<LoopInfo>();
-      AU.addRequired<ScalarEvolution>();
     }
 
   private:
     const TargetData *TD;
-    LoopInfo *LI;
-    ScalarEvolution *SE;
+    ObjectSizeOffsetEvaluator *ObjSizeEval;
     BuilderTy *Builder;
     Function *Fn;
     BasicBlock *TrapBB;
     unsigned Penalty;
-    CacheMapTy CacheMap;
-    PtrSetTy SeenPtrs;
 
     BasicBlock *getTrapBB();
     void emitBranchToTrap(Value *Cmp = 0);
@@ -108,7 +77,7 @@
 /// getTrapBB - create a basic block that traps. All overflowing conditions
 /// branch to this block. There's only one trap block per function.
 BasicBlock *BoundsChecking::getTrapBB() {
-  if (TrapBB && !ManyTrapBB)
+  if (TrapBB && SingleTrapBB)
     return TrapBB;
 
   BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint();
@@ -129,6 +98,16 @@
 /// emitBranchToTrap - emit a branch instruction to a trap block.
 /// If Cmp is non-null, perform a jump only if its value evaluates to true.
 void BoundsChecking::emitBranchToTrap(Value *Cmp) {
+  // check if the comparison is always false
+  ConstantInt *C = dyn_cast_or_null<ConstantInt>(Cmp);
+  if (C) {
+    ++ChecksSkipped;
+    if (!C->getZExtValue())
+      return;
+    else
+      Cmp = 0; // unconditional branch
+  }
+
   Instruction *Inst = Builder->GetInsertPoint();
   BasicBlock *OldBB = Inst->getParent();
   BasicBlock *Cont = OldBB->splitBasicBlock(Inst);
@@ -141,310 +120,6 @@
 }
 
 
-#define GET_VALUE(Val, Int) \
-  if (!Val) \
-    Val = ConstantInt::get(IntTy, Int)
-
-#define RETURN(Val) \
-  do { ReturnVal = Val; goto cache_and_return; } while (0)
-
-/// computeAllocSize - compute the object size and the offset within the object
-/// pointed by Ptr. OffsetValue/SizeValue will be null if they are constant, and
-/// therefore the result is given in Offset/Size variables instead.
-/// Returns true if the offset and size could be computed within the given
-/// maximum run-time penalty.
-bool BoundsChecking::computeAllocSize(Value *Ptr, APInt &Offset,
-                                      Value* &OffsetValue, APInt &Size,
-                                      Value* &SizeValue) {
-  Ptr = Ptr->stripPointerCasts();
-
-  // lookup to see if we've seen the Ptr before
-  CacheMapTy::iterator CacheIt = CacheMap.find(Ptr);
-  if (CacheIt != CacheMap.end()) {
-    CacheData &Cache = CacheIt->second;
-    Offset = Cache.Offset;
-    OffsetValue = Cache.OffsetValue;
-    Size = Cache.Size;
-    SizeValue = Cache.SizeValue;
-    return Cache.ReturnVal;
-  }
-
-  // record the pointers that were handled in this run, so that they can be
-  // cleaned later if something fails
-  SeenPtrs.insert(Ptr);
-
-  IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
-  unsigned IntTyBits = IntTy->getBitWidth();
-  bool ReturnVal;
-
-  // always generate code immediately before the instruction being processed, so
-  // that the generated code dominates the same BBs
-  Instruction *PrevInsertPoint = Builder->GetInsertPoint();
-  if (Instruction *I = dyn_cast<Instruction>(Ptr))
-    Builder->SetInsertPoint(I);
-
-  // initalize with "don't know" state: offset=0 and size=uintmax
-  Offset = 0;
-  Size = APInt::getMaxValue(TD->getTypeSizeInBits(IntTy));
-  OffsetValue = SizeValue = 0;
-
-  if (GEPOperator *GEP = dyn_cast<GEPOperator>(Ptr)) {
-    APInt PtrOffset(IntTyBits, 0);
-    Value *PtrOffsetValue = 0;
-    if (!computeAllocSize(GEP->getPointerOperand(), PtrOffset, PtrOffsetValue,
-                          Size, SizeValue))
-      RETURN(false);
-
-    if (GEP->hasAllConstantIndices()) {
-      SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
-      Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
-      // if PtrOffset is constant, return immediately
-      if (!PtrOffsetValue) {
-        Offset += PtrOffset;
-        RETURN(true);
-      }
-      OffsetValue = ConstantInt::get(IntTy, Offset);
-    } else if (Penalty > 1) {
-      OffsetValue = EmitGEPOffset(Builder, *TD, GEP);
-      GET_VALUE(PtrOffsetValue, PtrOffset);
-    } else
-      RETURN(false);
-
-    OffsetValue = Builder->CreateAdd(PtrOffsetValue, OffsetValue);
-    RETURN(true);
-
-  // global variable with definitive size
-  } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
-    if (GV->hasDefinitiveInitializer()) {
-      Constant *C = GV->getInitializer();
-      Size = TD->getTypeAllocSize(C->getType());
-      RETURN(true);
-    }
-    RETURN(false);
-
-  // stack allocation
-  } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Ptr)) {
-    if (!AI->getAllocatedType()->isSized())
-      RETURN(false);
-
-    Size = TD->getTypeAllocSize(AI->getAllocatedType());
-    if (!AI->isArrayAllocation())
-      RETURN(true); // we are done
-
-    Value *ArraySize = AI->getArraySize();
-    if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
-      Size *= C->getValue();
-      RETURN(true);
-    }
-
-    if (Penalty < 2)
-      RETURN(false);
-
-    // VLA: compute size dynamically
-    SizeValue = ConstantInt::get(ArraySize->getType(), Size);
-    SizeValue = Builder->CreateMul(SizeValue, ArraySize);
-    RETURN(true);
-
-  // function arguments
-  } else if (Argument *A = dyn_cast<Argument>(Ptr)) {
-    // right now we only support byval arguments, so that no interprocedural
-    // analysis is necessary
-    if (!A->hasByValAttr()) {
-      ++ChecksUnableInterproc;
-      RETURN(false);
-    }
-
-    PointerType *PT = cast<PointerType>(A->getType());
-    Size = TD->getTypeAllocSize(PT->getElementType());
-    RETURN(true);
-
-  // ptr = select(ptr1, ptr2)
-  } else if (SelectInst *SI = dyn_cast<SelectInst>(Ptr)) {
-    APInt OffsetTrue(IntTyBits, 0), OffsetFalse(IntTyBits, 0);
-    APInt SizeTrue(IntTyBits, 0), SizeFalse(IntTyBits, 0);
-    Value *OffsetValueTrue = 0, *OffsetValueFalse = 0;
-    Value *SizeValueTrue = 0, *SizeValueFalse = 0;
-
-    bool TrueAlloc = computeAllocSize(SI->getTrueValue(), OffsetTrue,
-                                      OffsetValueTrue, SizeTrue, SizeValueTrue);
-    bool FalseAlloc = computeAllocSize(SI->getFalseValue(), OffsetFalse,
-                                       OffsetValueFalse, SizeFalse,
-                                       SizeValueFalse);
-    if (!TrueAlloc || !FalseAlloc)
-      RETURN(false);
-
-    // fold constant sizes & offsets if they are equal
-    if (!OffsetValueTrue && !OffsetValueFalse && OffsetTrue == OffsetFalse)
-      Offset = OffsetTrue;
-    else if (Penalty > 1) {
-      GET_VALUE(OffsetValueTrue, OffsetTrue);
-      GET_VALUE(OffsetValueFalse, OffsetFalse);
-      OffsetValue = Builder->CreateSelect(SI->getCondition(), OffsetValueTrue,
-                                          OffsetValueFalse);
-    } else
-      RETURN(false);
-
-    if (!SizeValueTrue && !SizeValueFalse && SizeTrue == SizeFalse)
-      Size = SizeTrue;
-    else if (Penalty > 1) {
-      GET_VALUE(SizeValueTrue, SizeTrue);
-      GET_VALUE(SizeValueFalse, SizeFalse);
-      SizeValue = Builder->CreateSelect(SI->getCondition(), SizeValueTrue,
-                                        SizeValueFalse);
-    } else
-      RETURN(false);
-    RETURN(true);
-
-  // call allocation function
-  } else if (CallInst *CI = dyn_cast<CallInst>(Ptr)) {
-    SmallVector<unsigned, 4> Args;
-
-    if (MDNode *MD = CI->getMetadata("alloc_size")) {
-      for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i)
-        Args.push_back(cast<ConstantInt>(MD->getOperand(i))->getZExtValue());
-
-    } else if (Function *Callee = CI->getCalledFunction()) {
-      FunctionType *FTy = Callee->getFunctionType();
-
-      // alloc(size)
-      if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy()) {
-        if ((Callee->getName() == "malloc" ||
-             Callee->getName() == "valloc" ||
-             Callee->getName() == "_Znwj"  || // operator new(unsigned int)
-             Callee->getName() == "_Znwm"  || // operator new(unsigned long)
-             Callee->getName() == "_Znaj"  || // operator new[](unsigned int)
-             Callee->getName() == "_Znam")) {
-          Args.push_back(0);
-        }
-      } else if (FTy->getNumParams() == 2) {
-        // alloc(_, x)
-        if (FTy->getParamType(1)->isIntegerTy() &&
-            ((Callee->getName() == "realloc" ||
-              Callee->getName() == "reallocf"))) {
-          Args.push_back(1);
-
-        // alloc(x, y)
-        } else if (FTy->getParamType(0)->isIntegerTy() &&
-                   FTy->getParamType(1)->isIntegerTy() &&
-                   Callee->getName() == "calloc") {
-          Args.push_back(0);
-          Args.push_back(1);
-        }
-      } else if (FTy->getNumParams() == 3) {
-        // alloc(_, _, x)
-        if (FTy->getParamType(2)->isIntegerTy() &&
-            Callee->getName() == "posix_memalign") {
-          Args.push_back(2);
-        }
-      }
-    }
-
-    if (Args.empty())
-      RETURN(false);
-
-    // check if all arguments are constant. if so, the object size is also const
-    bool AllConst = true;
-    for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
-         I != E; ++I) {
-      if (!isa<ConstantInt>(CI->getArgOperand(*I))) {
-        AllConst = false;
-        break;
-      }
-    }
-
-    if (AllConst) {
-      Size = 1;
-      for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
-           I != E; ++I) {
-        ConstantInt *Arg = cast<ConstantInt>(CI->getArgOperand(*I));
-        Size *= Arg->getValue().zextOrSelf(IntTyBits);
-      }
-      RETURN(true);
-    }
-
-    if (Penalty < 2)
-      RETURN(false);
-
-    // not all arguments are constant, so create a sequence of multiplications
-    for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
-         I != E; ++I) {
-      Value *Arg = Builder->CreateZExt(CI->getArgOperand(*I), IntTy);
-      if (!SizeValue) {
-        SizeValue = Arg;
-        continue;
-      }
-      SizeValue = Builder->CreateMul(SizeValue, Arg);
-    }
-    RETURN(true);
-
-    // TODO: handle more standard functions (+ wchar cousins):
-    // - strdup / strndup
-    // - strcpy / strncpy
-    // - strcat / strncat
-    // - memcpy / memmove
-    // - strcat / strncat
-    // - memset
-
-  } else if (PHINode *PHI = dyn_cast<PHINode>(Ptr)) {
-    // create 2 PHIs: one for offset and another for size
-    PHINode *OffsetPHI = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
-    PHINode *SizePHI   = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
-
-    // insert right away in the cache to handle recursive PHIs
-    CacheMap[Ptr] = CacheData(APInt(), OffsetPHI, APInt(), SizePHI, true);
-
-    // compute offset/size for each PHI incoming pointer
-    for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) {
-      Builder->SetInsertPoint(PHI->getIncomingBlock(i)->getFirstInsertionPt());
-
-      APInt PhiOffset(IntTyBits, 0), PhiSize(IntTyBits, 0);
-      Value *PhiOffsetValue = 0, *PhiSizeValue = 0;
-
-      if (!computeAllocSize(PHI->getIncomingValue(i), PhiOffset, PhiOffsetValue,
-                            PhiSize, PhiSizeValue)) {
-        OffsetPHI->replaceAllUsesWith(UndefValue::get(IntTy));
-        OffsetPHI->eraseFromParent();
-        SizePHI->replaceAllUsesWith(UndefValue::get(IntTy));
-        SizePHI->eraseFromParent();
-        RETURN(false);
-      }
-
-      GET_VALUE(PhiOffsetValue, PhiOffset);
-      GET_VALUE(PhiSizeValue, PhiSize);
-
-      OffsetPHI->addIncoming(PhiOffsetValue, PHI->getIncomingBlock(i));
-      SizePHI->addIncoming(PhiSizeValue, PHI->getIncomingBlock(i));
-    }
-
-    OffsetValue = OffsetPHI;
-    SizeValue = SizePHI;
-    RETURN(true);    
-
-  } else if (isa<UndefValue>(Ptr) || isa<ConstantPointerNull>(Ptr)) {
-    Size = 0;
-    RETURN(true);
-
-  } else if (isa<LoadInst>(Ptr)) {
-    ++ChecksUnableLoad;
-    RETURN(false);
-  }
-
-  DEBUG(dbgs() << "computeAllocSize unhandled value:\n" << *Ptr << "\n");
-  RETURN(false);
-
-cache_and_return:
-  // cache the result and return
-  CacheMap[Ptr] = CacheData(Offset, OffsetValue, Size, SizeValue, ReturnVal);
-
-  // non-computable results can be safely cached
-  if (!ReturnVal)
-    SeenPtrs.erase(Ptr);
-
-  Builder->SetInsertPoint(PrevInsertPoint);
-  return ReturnVal;
-}
-
-
 /// instrument - adds run-time bounds checks to memory accessing instructions.
 /// Ptr is the pointer that will be read/written, and InstVal is either the
 /// result from the load or the value being stored. It is used to determine the
@@ -455,67 +130,29 @@
   DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize)
               << " bytes\n");
 
-  IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
-  unsigned IntTyBits = IntTy->getBitWidth();
-
-  APInt Offset(IntTyBits, 0), Size(IntTyBits, 0);
-  Value *OffsetValue = 0, *SizeValue = 0;
-
-  if (!computeAllocSize(Ptr, Offset, OffsetValue, Size, SizeValue)) {
-    DEBUG(dbgs() << "computeAllocSize failed:\n" << *Ptr << "\n");
-
-    // erase everything that was computed in this iteration from the cache, so
-    // that no dangling references are left behind. We could be a bit smarter if
-    // we kept a dependency graph. It's probably not worth the complexity,
-    // though.
-    for (PtrSetTy::iterator I=SeenPtrs.begin(), E=SeenPtrs.end(); I != E; ++I)
-      CacheMap.erase(*I);
-    SeenPtrs.clear();
+  SizeOffsetEvalType SizeOffset = ObjSizeEval->compute(Ptr);
 
+  if (!ObjSizeEval->bothKnown(SizeOffset)) {
     ++ChecksUnable;
     return false;
   }
 
+  Value *Size   = SizeOffset.first;
+  Value *Offset = SizeOffset.second;
+
+  IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
+  Value *NeededSizeVal = ConstantInt::get(IntTy, NeededSize);
+
   // three checks are required to ensure safety:
   // . Offset >= 0  (since the offset is given from the base ptr)
   // . Size >= Offset  (unsigned)
   // . Size - Offset >= NeededSize  (unsigned)
-  if (!OffsetValue && !SizeValue) {
-    if (Offset.slt(0) || Size.ult(Offset) || (Size - Offset).ult(NeededSize)) {
-      // Out of bounds
-      emitBranchToTrap();
-      ++ChecksAdded;
-      return true;
-    }
-    // in bounds
-    ++ChecksSkipped;
-    return false;
-  }
-
-  // emit check for offset < 0
-  Value *CmpOffset = 0;
-  if (OffsetValue)
-    CmpOffset = Builder->CreateICmpSLT(OffsetValue, ConstantInt::get(IntTy, 0));
-  else if (Offset.slt(0)) {
-    // offset proved to be negative
-    emitBranchToTrap();
-    ++ChecksAdded;
-    return true;
-  }
-
-  // we couldn't determine statically if the memory access is safe; emit a
-  // run-time check
-  GET_VALUE(OffsetValue, Offset);
-  GET_VALUE(SizeValue, Size);
-
-  Value *NeededSizeVal = ConstantInt::get(IntTy, NeededSize);
   // FIXME: add NSW/NUW here?  -- we dont care if the subtraction overflows
-  Value *ObjSize = Builder->CreateSub(SizeValue, OffsetValue);
-  Value *Cmp1 = Builder->CreateICmpULT(SizeValue, OffsetValue);
-  Value *Cmp2 = Builder->CreateICmpULT(ObjSize, NeededSizeVal);
-  Value *Or = Builder->CreateOr(Cmp1, Cmp2);
-  if (CmpOffset)
-    Or = Builder->CreateOr(CmpOffset, Or);
+  Value *ObjSize = Builder->CreateSub(Size, Offset);
+  Value *Cmp1 = Builder->CreateICmpSLT(Offset, ConstantInt::get(IntTy, 0));
+  Value *Cmp2 = Builder->CreateICmpULT(Size, Offset);
+  Value *Cmp3 = Builder->CreateICmpULT(ObjSize, NeededSizeVal);
+  Value *Or = Builder->CreateOr(Cmp1, Builder->CreateOr(Cmp2, Cmp3));
   emitBranchToTrap(Or);
 
   ++ChecksAdded;
@@ -524,13 +161,13 @@
 
 bool BoundsChecking::runOnFunction(Function &F) {
   TD = &getAnalysis<TargetData>();
-  LI = &getAnalysis<LoopInfo>();
-  SE = &getAnalysis<ScalarEvolution>();
 
   TrapBB = 0;
   Fn = &F;
   BuilderTy TheBuilder(F.getContext(), TargetFolder(TD));
   Builder = &TheBuilder;
+  ObjectSizeOffsetEvaluator TheObjSizeEval(TD, F.getContext());
+  ObjSizeEval = &TheObjSizeEval;
 
   // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory
   // touching instructions

Removed: llvm/trunk/test/Transforms/BoundsChecking/alloc_size.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BoundsChecking/alloc_size.ll?rev=158919&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/BoundsChecking/alloc_size.ll (original)
+++ llvm/trunk/test/Transforms/BoundsChecking/alloc_size.ll (removed)
@@ -1,43 +0,0 @@
-; RUN: opt < %s -bounds-checking -S | FileCheck %s
-target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
-
-declare i64* @alloc(i32, i8, i32)
-declare i32* @alloc2(i32, i32)
-
-; CHECK: @f1
-define void @f1(i32 %x) {
-  %call = tail call i32* @alloc2(i32 %x, i32 4) nounwind, !alloc_size !0
-; CHECK: trap
-  store i32 3, i32* %call, align 4
-  ret void
-}
-
-; CHECK: @f2
-define void @f2() {
-  %call1 = tail call i32* @alloc2(i32 2, i32 4) nounwind, !alloc_size !0
-  %arrayidx = getelementptr i32* %call1, i64 2
-; CHECK: br label
-  store i32 3, i32* %arrayidx, align 4
-  ret void
-}
-
-; CHECK: @f3
-define void @f3(i32 %x, i8 %y) {
-  %call = tail call i64* @alloc(i32 %x, i8 %y, i32 7) nounwind, !alloc_size !1
-; CHECK: trap
-  store i64 27, i64* %call, align 4
-  ret void
-}
-
-; CHECK: @f4
-define void @f4() {
-  %call1 = tail call i32* @alloc2(i32 2, i32 4) nounwind, !alloc_size !0
-  %arrayidx = getelementptr i32* %call1, i64 1
-; CHECK-NOT: trap
-  store i32 3, i32* %arrayidx, align 4
-; CHECK: ret
-  ret void
-}
-
-!0 = metadata !{i32 0, i32 1}
-!1 = metadata !{i32 2}

Modified: llvm/trunk/test/Transforms/BoundsChecking/many-trap.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/BoundsChecking/many-trap.ll?rev=158920&r1=158919&r2=158920&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/BoundsChecking/many-trap.ll (original)
+++ llvm/trunk/test/Transforms/BoundsChecking/many-trap.ll Thu Jun 21 10:59:53 2012
@@ -1,4 +1,5 @@
-; RUN: opt < %s -bounds-checking -bounds-checking-multiple-traps -S | FileCheck %s
+; RUN: opt < %s -bounds-checking -S | FileCheck %s
+; RUN: opt < %s -bounds-checking -bounds-checking-single-trap -S | FileCheck -check-prefix=SINGLE %s
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
 
 ; CHECK: @f1
@@ -7,6 +8,9 @@
   %2 = load i128* %1, align 4
   %3 = load i128* %1, align 4
   ret void
-; CHECK: llvm.trap
-; CHECK: llvm.trap
+; CHECK: call void @llvm.trap()
+; CHECK: call void @llvm.trap()
+; CHECK-NOT: call void @llvm.trap()
+; SINGLE: call void @llvm.trap()
+; SINGLE-NOT: call void @llvm.trap()
 }





More information about the llvm-commits mailing list