From: Nuno Lopes Date: Fri, 20 Jul 2012 22:39:33 +0000 (+0000) Subject: move the bounds checking pass to the instrumentation folder, where it belongs. I... X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=78435f6bb7574d3d26f8c5151e2c140c525b7994;p=oota-llvm.git move the bounds checking pass to the instrumentation folder, where it belongs. I dunno why in the world I dropped it in the Scalar folder in the first place. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160587 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index bbf3a69d246..4b0c448acfc 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -38,6 +38,13 @@ ModulePass *createAddressSanitizerPass(); // Insert ThreadSanitizer (race detection) instrumentation FunctionPass *createThreadSanitizerPass(); + +// BoundsChecking - This pass instruments the code to perform run-time bounds +// checking on loads, stores, and other memory intrinsics. +// Penalty is the maximum run-time that is acceptable for the user. +// +FunctionPass *createBoundsCheckingPass(unsigned Penalty = 5); + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 67f2e377f72..3dce6fe37fd 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -328,14 +328,6 @@ Pass *createLowerAtomicPass(); // Pass *createCorrelatedValuePropagationPass(); -//===----------------------------------------------------------------------===// -// -// BoundsChecking - This pass instruments the code to perform run-time bounds -// checking on loads, stores, and other memory intrinsics. -// Penalty is the maximum run-time that is acceptable for the user. -// -FunctionPass *createBoundsCheckingPass(unsigned Penalty = 5); - //===----------------------------------------------------------------------===// // // ObjCARCAPElim - ObjC ARC autorelease pool elimination. diff --git a/lib/Transforms/Instrumentation/BoundsChecking.cpp b/lib/Transforms/Instrumentation/BoundsChecking.cpp new file mode 100644 index 00000000000..09e0f144512 --- /dev/null +++ b/lib/Transforms/Instrumentation/BoundsChecking.cpp @@ -0,0 +1,209 @@ +//===- BoundsChecking.cpp - Instrumentation for run-time bounds checking --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a pass that instruments the code to perform run-time +// bounds checking on loads, stores, and other memory intrinsics. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "bounds-checking" +#include "llvm/IRBuilder.h" +#include "llvm/Intrinsics.h" +#include "llvm/Pass.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/InstIterator.h" +#include "llvm/Support/TargetFolder.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Transforms/Instrumentation.h" +using namespace llvm; + +static cl::opt 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"); + +typedef IRBuilder BuilderTy; + +namespace { + struct BoundsChecking : public FunctionPass { + static char ID; + + BoundsChecking(unsigned _Penalty = 5) : FunctionPass(ID), Penalty(_Penalty){ + initializeBoundsCheckingPass(*PassRegistry::getPassRegistry()); + } + + virtual bool runOnFunction(Function &F); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + } + + private: + const TargetData *TD; + ObjectSizeOffsetEvaluator *ObjSizeEval; + BuilderTy *Builder; + Instruction *Inst; + BasicBlock *TrapBB; + unsigned Penalty; + + BasicBlock *getTrapBB(); + void emitBranchToTrap(Value *Cmp = 0); + bool computeAllocSize(Value *Ptr, APInt &Offset, Value* &OffsetValue, + APInt &Size, Value* &SizeValue); + bool instrument(Value *Ptr, Value *Val); + }; +} + +char BoundsChecking::ID = 0; +INITIALIZE_PASS(BoundsChecking, "bounds-checking", "Run-time bounds checking", + false, false) + + +/// 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 && SingleTrapBB) + return TrapBB; + + Function *Fn = Inst->getParent()->getParent(); + BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint(); + TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); + Builder->SetInsertPoint(TrapBB); + + llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap); + CallInst *TrapCall = Builder->CreateCall(F); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + TrapCall->setDebugLoc(Inst->getDebugLoc()); + Builder->CreateUnreachable(); + + Builder->SetInsertPoint(PrevInsertPoint); + return TrapBB; +} + + +/// 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(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); + OldBB->getTerminator()->eraseFromParent(); + + if (Cmp) + BranchInst::Create(getTrapBB(), Cont, Cmp, OldBB); + else + BranchInst::Create(getTrapBB(), OldBB); +} + + +/// 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 +/// size of memory block that is touched. +/// Returns true if any change was made to the IR, false otherwise. +bool BoundsChecking::instrument(Value *Ptr, Value *InstVal) { + uint64_t NeededSize = TD->getTypeStoreSize(InstVal->getType()); + DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize) + << " bytes\n"); + + SizeOffsetEvalType SizeOffset = ObjSizeEval->compute(Ptr); + + if (!ObjSizeEval->bothKnown(SizeOffset)) { + ++ChecksUnable; + return false; + } + + Value *Size = SizeOffset.first; + Value *Offset = SizeOffset.second; + ConstantInt *SizeCI = dyn_cast(Size); + + IntegerType *IntTy = TD->getIntPtrType(Inst->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) + // + // optimization: if Size >= 0 (signed), skip 1st check + // FIXME: add NSW/NUW here? -- we dont care if the subtraction overflows + Value *ObjSize = Builder->CreateSub(Size, Offset); + Value *Cmp2 = Builder->CreateICmpULT(Size, Offset); + Value *Cmp3 = Builder->CreateICmpULT(ObjSize, NeededSizeVal); + Value *Or = Builder->CreateOr(Cmp2, Cmp3); + if (!SizeCI || SizeCI->getValue().slt(0)) { + Value *Cmp1 = Builder->CreateICmpSLT(Offset, ConstantInt::get(IntTy, 0)); + Or = Builder->CreateOr(Cmp1, Or); + } + emitBranchToTrap(Or); + + ++ChecksAdded; + return true; +} + +bool BoundsChecking::runOnFunction(Function &F) { + TD = &getAnalysis(); + + TrapBB = 0; + 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 + std::vector WorkList; + for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { + Instruction *I = &*i; + if (isa(I) || isa(I) || isa(I) || + isa(I)) + WorkList.push_back(I); + } + + bool MadeChange = false; + for (std::vector::iterator i = WorkList.begin(), + e = WorkList.end(); i != e; ++i) { + Inst = *i; + + Builder->SetInsertPoint(Inst); + if (LoadInst *LI = dyn_cast(Inst)) { + MadeChange |= instrument(LI->getPointerOperand(), LI); + } else if (StoreInst *SI = dyn_cast(Inst)) { + MadeChange |= instrument(SI->getPointerOperand(), SI->getValueOperand()); + } else if (AtomicCmpXchgInst *AI = dyn_cast(Inst)) { + MadeChange |= instrument(AI->getPointerOperand(),AI->getCompareOperand()); + } else if (AtomicRMWInst *AI = dyn_cast(Inst)) { + MadeChange |= instrument(AI->getPointerOperand(), AI->getValOperand()); + } else { + llvm_unreachable("unknown Instruction type"); + } + } + return MadeChange; +} + +FunctionPass *llvm::createBoundsCheckingPass(unsigned Penalty) { + return new BoundsChecking(Penalty); +} diff --git a/lib/Transforms/Instrumentation/CMakeLists.txt b/lib/Transforms/Instrumentation/CMakeLists.txt index eaa3a4000f8..00de882f171 100644 --- a/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/lib/Transforms/Instrumentation/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_library(LLVMInstrumentation AddressSanitizer.cpp + BoundsChecking.cpp EdgeProfiling.cpp FunctionBlackList.cpp GCOVProfiling.cpp diff --git a/lib/Transforms/Scalar/BoundsChecking.cpp b/lib/Transforms/Scalar/BoundsChecking.cpp deleted file mode 100644 index ef2f39d8583..00000000000 --- a/lib/Transforms/Scalar/BoundsChecking.cpp +++ /dev/null @@ -1,209 +0,0 @@ -//===- BoundsChecking.cpp - Instrumentation for run-time bounds checking --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements a pass that instruments the code to perform run-time -// bounds checking on loads, stores, and other memory intrinsics. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "bounds-checking" -#include "llvm/Transforms/Scalar.h" -#include "llvm/IRBuilder.h" -#include "llvm/Intrinsics.h" -#include "llvm/Pass.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/MemoryBuiltins.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/TargetFolder.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetData.h" -using namespace llvm; - -static cl::opt 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"); - -typedef IRBuilder BuilderTy; - -namespace { - struct BoundsChecking : public FunctionPass { - static char ID; - - BoundsChecking(unsigned _Penalty = 5) : FunctionPass(ID), Penalty(_Penalty){ - initializeBoundsCheckingPass(*PassRegistry::getPassRegistry()); - } - - virtual bool runOnFunction(Function &F); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - } - - private: - const TargetData *TD; - ObjectSizeOffsetEvaluator *ObjSizeEval; - BuilderTy *Builder; - Instruction *Inst; - BasicBlock *TrapBB; - unsigned Penalty; - - BasicBlock *getTrapBB(); - void emitBranchToTrap(Value *Cmp = 0); - bool computeAllocSize(Value *Ptr, APInt &Offset, Value* &OffsetValue, - APInt &Size, Value* &SizeValue); - bool instrument(Value *Ptr, Value *Val); - }; -} - -char BoundsChecking::ID = 0; -INITIALIZE_PASS(BoundsChecking, "bounds-checking", "Run-time bounds checking", - false, false) - - -/// 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 && SingleTrapBB) - return TrapBB; - - Function *Fn = Inst->getParent()->getParent(); - BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint(); - TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn); - Builder->SetInsertPoint(TrapBB); - - llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap); - CallInst *TrapCall = Builder->CreateCall(F); - TrapCall->setDoesNotReturn(); - TrapCall->setDoesNotThrow(); - TrapCall->setDebugLoc(Inst->getDebugLoc()); - Builder->CreateUnreachable(); - - Builder->SetInsertPoint(PrevInsertPoint); - return TrapBB; -} - - -/// 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(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); - OldBB->getTerminator()->eraseFromParent(); - - if (Cmp) - BranchInst::Create(getTrapBB(), Cont, Cmp, OldBB); - else - BranchInst::Create(getTrapBB(), OldBB); -} - - -/// 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 -/// size of memory block that is touched. -/// Returns true if any change was made to the IR, false otherwise. -bool BoundsChecking::instrument(Value *Ptr, Value *InstVal) { - uint64_t NeededSize = TD->getTypeStoreSize(InstVal->getType()); - DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize) - << " bytes\n"); - - SizeOffsetEvalType SizeOffset = ObjSizeEval->compute(Ptr); - - if (!ObjSizeEval->bothKnown(SizeOffset)) { - ++ChecksUnable; - return false; - } - - Value *Size = SizeOffset.first; - Value *Offset = SizeOffset.second; - ConstantInt *SizeCI = dyn_cast(Size); - - IntegerType *IntTy = TD->getIntPtrType(Inst->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) - // - // optimization: if Size >= 0 (signed), skip 1st check - // FIXME: add NSW/NUW here? -- we dont care if the subtraction overflows - Value *ObjSize = Builder->CreateSub(Size, Offset); - Value *Cmp2 = Builder->CreateICmpULT(Size, Offset); - Value *Cmp3 = Builder->CreateICmpULT(ObjSize, NeededSizeVal); - Value *Or = Builder->CreateOr(Cmp2, Cmp3); - if (!SizeCI || SizeCI->getValue().slt(0)) { - Value *Cmp1 = Builder->CreateICmpSLT(Offset, ConstantInt::get(IntTy, 0)); - Or = Builder->CreateOr(Cmp1, Or); - } - emitBranchToTrap(Or); - - ++ChecksAdded; - return true; -} - -bool BoundsChecking::runOnFunction(Function &F) { - TD = &getAnalysis(); - - TrapBB = 0; - 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 - std::vector WorkList; - for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { - Instruction *I = &*i; - if (isa(I) || isa(I) || isa(I) || - isa(I)) - WorkList.push_back(I); - } - - bool MadeChange = false; - for (std::vector::iterator i = WorkList.begin(), - e = WorkList.end(); i != e; ++i) { - Inst = *i; - - Builder->SetInsertPoint(Inst); - if (LoadInst *LI = dyn_cast(Inst)) { - MadeChange |= instrument(LI->getPointerOperand(), LI); - } else if (StoreInst *SI = dyn_cast(Inst)) { - MadeChange |= instrument(SI->getPointerOperand(), SI->getValueOperand()); - } else if (AtomicCmpXchgInst *AI = dyn_cast(Inst)) { - MadeChange |= instrument(AI->getPointerOperand(),AI->getCompareOperand()); - } else if (AtomicRMWInst *AI = dyn_cast(Inst)) { - MadeChange |= instrument(AI->getPointerOperand(), AI->getValOperand()); - } else { - llvm_unreachable("unknown Instruction type"); - } - } - return MadeChange; -} - -FunctionPass *llvm::createBoundsCheckingPass(unsigned Penalty) { - return new BoundsChecking(Penalty); -} diff --git a/lib/Transforms/Scalar/CMakeLists.txt b/lib/Transforms/Scalar/CMakeLists.txt index bf9cc66392a..a01e0661b1f 100644 --- a/lib/Transforms/Scalar/CMakeLists.txt +++ b/lib/Transforms/Scalar/CMakeLists.txt @@ -1,7 +1,6 @@ add_llvm_library(LLVMScalarOpts ADCE.cpp BasicBlockPlacement.cpp - BoundsChecking.cpp CodeGenPrepare.cpp ConstantProp.cpp CorrelatedValuePropagation.cpp diff --git a/test/Instrumentation/BoundsChecking/lit.local.cfg b/test/Instrumentation/BoundsChecking/lit.local.cfg new file mode 100644 index 00000000000..19eebc0ac7a --- /dev/null +++ b/test/Instrumentation/BoundsChecking/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Instrumentation/BoundsChecking/many-trap.ll b/test/Instrumentation/BoundsChecking/many-trap.ll new file mode 100644 index 00000000000..0bbb9592b05 --- /dev/null +++ b/test/Instrumentation/BoundsChecking/many-trap.ll @@ -0,0 +1,16 @@ +; 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 +define void @f1(i64 %x) nounwind { + %1 = alloca i128, i64 %x + %2 = load i128* %1, align 4 + %3 = load i128* %1, align 4 + ret void +; 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() +} diff --git a/test/Instrumentation/BoundsChecking/phi.ll b/test/Instrumentation/BoundsChecking/phi.ll new file mode 100644 index 00000000000..86b59222707 --- /dev/null +++ b/test/Instrumentation/BoundsChecking/phi.ll @@ -0,0 +1,52 @@ +; 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" + +@global = private unnamed_addr constant [10 x i8] c"ola\00mundo\00", align 1 + +; CHECK: f1 +; no checks are possible here +; CHECK-NOT: trap +define void @f1(i8* nocapture %c) { +entry: + %0 = load i8* %c, align 1 + %tobool1 = icmp eq i8 %0, 0 + br i1 %tobool1, label %while.end, label %while.body + +while.body: + %c.addr.02 = phi i8* [ %incdec.ptr, %while.body ], [ %c, %entry ] + %incdec.ptr = getelementptr inbounds i8* %c.addr.02, i64 -1 + store i8 100, i8* %c.addr.02, align 1 + %1 = load i8* %incdec.ptr, align 1 + %tobool = icmp eq i8 %1, 0 + br i1 %tobool, label %while.end, label %while.body + +while.end: + ret void +} + + +; CHECK: f2 +define void @f2() { +while.body.i.preheader: + %addr = getelementptr inbounds [10 x i8]* @global, i64 0, i64 9 + br label %while.body.i + +while.body.i: +; CHECK: phi +; CHECK-NEXT: phi +; CHECK-NOT: phi + %c.addr.02.i = phi i8* [ %incdec.ptr.i, %while.body.i ], [ %addr, %while.body.i.preheader ] + %incdec.ptr.i = getelementptr inbounds i8* %c.addr.02.i, i64 -1 +; CHECK: sub i64 10, %0 +; CHECK-NEXT: icmp ult i64 10, %0 +; CHECK-NEXT: icmp ult i64 {{.*}}, 1 +; CHECK-NEXT: or i1 +; CHECK-NEXT: br {{.*}}, label %trap + store i8 100, i8* %c.addr.02.i, align 1 + %0 = load i8* %incdec.ptr.i, align 1 + %tobool.i = icmp eq i8 %0, 0 + br i1 %tobool.i, label %fn.exit, label %while.body.i + +fn.exit: + ret void +} diff --git a/test/Instrumentation/BoundsChecking/simple.ll b/test/Instrumentation/BoundsChecking/simple.ll new file mode 100644 index 00000000000..3d532c3cf3b --- /dev/null +++ b/test/Instrumentation/BoundsChecking/simple.ll @@ -0,0 +1,118 @@ +; 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" + +@.str = private constant [8 x i8] c"abcdefg\00" ; <[8 x i8]*> + +declare noalias i8* @malloc(i64) nounwind +declare noalias i8* @calloc(i64, i64) nounwind +declare noalias i8* @realloc(i8* nocapture, i64) nounwind + +; CHECK: @f1 +define void @f1() nounwind { + %1 = tail call i8* @malloc(i64 32) + %2 = bitcast i8* %1 to i32* + %idx = getelementptr inbounds i32* %2, i64 2 +; CHECK-NOT: trap + store i32 3, i32* %idx, align 4 + ret void +} + +; CHECK: @f2 +define void @f2() nounwind { + %1 = tail call i8* @malloc(i64 32) + %2 = bitcast i8* %1 to i32* + %idx = getelementptr inbounds i32* %2, i64 8 +; CHECK: trap + store i32 3, i32* %idx, align 4 + ret void +} + +; CHECK: @f3 +define void @f3(i64 %x) nounwind { + %1 = tail call i8* @calloc(i64 4, i64 %x) + %2 = bitcast i8* %1 to i32* + %idx = getelementptr inbounds i32* %2, i64 8 +; CHECK: mul i64 4, % +; CHECK: sub i64 {{.*}}, 32 +; CHECK-NEXT: icmp ult i64 {{.*}}, 32 +; CHECK-NEXT: icmp ult i64 {{.*}}, 4 +; CHECK-NEXT: or i1 +; CHECK: trap + store i32 3, i32* %idx, align 4 + ret void +} + +; CHECK: @f4 +define void @f4(i64 %x) nounwind { + %1 = tail call i8* @realloc(i8* null, i64 %x) nounwind + %2 = bitcast i8* %1 to i32* + %idx = getelementptr inbounds i32* %2, i64 8 +; CHECK: trap + %3 = load i32* %idx, align 4 + ret void +} + +; CHECK: @f5 +define void @f5(i64 %x) nounwind { + %idx = getelementptr inbounds [8 x i8]* @.str, i64 0, i64 %x +; CHECK: trap + %1 = load i8* %idx, align 4 + ret void +} + +; CHECK: @f6 +define void @f6(i64 %x) nounwind { + %1 = alloca i128 +; CHECK-NOT: trap + %2 = load i128* %1, align 4 + ret void +} + +; CHECK: @f7 +define void @f7(i64 %x) nounwind { + %1 = alloca i128, i64 %x +; CHECK: mul i64 16, +; CHECK: trap + %2 = load i128* %1, align 4 + ret void +} + +; CHECK: @f8 +define void @f8() nounwind { + %1 = alloca i128 + %2 = alloca i128 + %3 = select i1 undef, i128* %1, i128* %2 +; CHECK-NOT: trap + %4 = load i128* %3, align 4 + ret void +} + +; CHECK: @f9 +define void @f9(i128* %arg) nounwind { + %1 = alloca i128 + %2 = select i1 undef, i128* %arg, i128* %1 +; CHECK-NOT: trap + %3 = load i128* %2, align 4 + ret void +} + +; CHECK: @f10 +define void @f10(i64 %x, i64 %y) nounwind { + %1 = alloca i128, i64 %x + %2 = alloca i128, i64 %y + %3 = select i1 undef, i128* %1, i128* %2 +; CHECK: select +; CHECK: select +; CHECK: trap + %4 = load i128* %3, align 4 + ret void +} + +; CHECK: @f11 +define void @f11(i128* byval %x) nounwind { + %1 = bitcast i128* %x to i8* + %2 = getelementptr inbounds i8* %1, i64 16 +; CHECK: br label + %3 = load i8* %2, align 4 + ret void +} diff --git a/test/Transforms/BoundsChecking/lit.local.cfg b/test/Transforms/BoundsChecking/lit.local.cfg deleted file mode 100644 index 19eebc0ac7a..00000000000 --- a/test/Transforms/BoundsChecking/lit.local.cfg +++ /dev/null @@ -1 +0,0 @@ -config.suffixes = ['.ll', '.c', '.cpp'] diff --git a/test/Transforms/BoundsChecking/many-trap.ll b/test/Transforms/BoundsChecking/many-trap.ll deleted file mode 100644 index 0bbb9592b05..00000000000 --- a/test/Transforms/BoundsChecking/many-trap.ll +++ /dev/null @@ -1,16 +0,0 @@ -; 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 -define void @f1(i64 %x) nounwind { - %1 = alloca i128, i64 %x - %2 = load i128* %1, align 4 - %3 = load i128* %1, align 4 - ret void -; 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() -} diff --git a/test/Transforms/BoundsChecking/phi.ll b/test/Transforms/BoundsChecking/phi.ll deleted file mode 100644 index 86b59222707..00000000000 --- a/test/Transforms/BoundsChecking/phi.ll +++ /dev/null @@ -1,52 +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" - -@global = private unnamed_addr constant [10 x i8] c"ola\00mundo\00", align 1 - -; CHECK: f1 -; no checks are possible here -; CHECK-NOT: trap -define void @f1(i8* nocapture %c) { -entry: - %0 = load i8* %c, align 1 - %tobool1 = icmp eq i8 %0, 0 - br i1 %tobool1, label %while.end, label %while.body - -while.body: - %c.addr.02 = phi i8* [ %incdec.ptr, %while.body ], [ %c, %entry ] - %incdec.ptr = getelementptr inbounds i8* %c.addr.02, i64 -1 - store i8 100, i8* %c.addr.02, align 1 - %1 = load i8* %incdec.ptr, align 1 - %tobool = icmp eq i8 %1, 0 - br i1 %tobool, label %while.end, label %while.body - -while.end: - ret void -} - - -; CHECK: f2 -define void @f2() { -while.body.i.preheader: - %addr = getelementptr inbounds [10 x i8]* @global, i64 0, i64 9 - br label %while.body.i - -while.body.i: -; CHECK: phi -; CHECK-NEXT: phi -; CHECK-NOT: phi - %c.addr.02.i = phi i8* [ %incdec.ptr.i, %while.body.i ], [ %addr, %while.body.i.preheader ] - %incdec.ptr.i = getelementptr inbounds i8* %c.addr.02.i, i64 -1 -; CHECK: sub i64 10, %0 -; CHECK-NEXT: icmp ult i64 10, %0 -; CHECK-NEXT: icmp ult i64 {{.*}}, 1 -; CHECK-NEXT: or i1 -; CHECK-NEXT: br {{.*}}, label %trap - store i8 100, i8* %c.addr.02.i, align 1 - %0 = load i8* %incdec.ptr.i, align 1 - %tobool.i = icmp eq i8 %0, 0 - br i1 %tobool.i, label %fn.exit, label %while.body.i - -fn.exit: - ret void -} diff --git a/test/Transforms/BoundsChecking/simple.ll b/test/Transforms/BoundsChecking/simple.ll deleted file mode 100644 index 3d532c3cf3b..00000000000 --- a/test/Transforms/BoundsChecking/simple.ll +++ /dev/null @@ -1,118 +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" - -@.str = private constant [8 x i8] c"abcdefg\00" ; <[8 x i8]*> - -declare noalias i8* @malloc(i64) nounwind -declare noalias i8* @calloc(i64, i64) nounwind -declare noalias i8* @realloc(i8* nocapture, i64) nounwind - -; CHECK: @f1 -define void @f1() nounwind { - %1 = tail call i8* @malloc(i64 32) - %2 = bitcast i8* %1 to i32* - %idx = getelementptr inbounds i32* %2, i64 2 -; CHECK-NOT: trap - store i32 3, i32* %idx, align 4 - ret void -} - -; CHECK: @f2 -define void @f2() nounwind { - %1 = tail call i8* @malloc(i64 32) - %2 = bitcast i8* %1 to i32* - %idx = getelementptr inbounds i32* %2, i64 8 -; CHECK: trap - store i32 3, i32* %idx, align 4 - ret void -} - -; CHECK: @f3 -define void @f3(i64 %x) nounwind { - %1 = tail call i8* @calloc(i64 4, i64 %x) - %2 = bitcast i8* %1 to i32* - %idx = getelementptr inbounds i32* %2, i64 8 -; CHECK: mul i64 4, % -; CHECK: sub i64 {{.*}}, 32 -; CHECK-NEXT: icmp ult i64 {{.*}}, 32 -; CHECK-NEXT: icmp ult i64 {{.*}}, 4 -; CHECK-NEXT: or i1 -; CHECK: trap - store i32 3, i32* %idx, align 4 - ret void -} - -; CHECK: @f4 -define void @f4(i64 %x) nounwind { - %1 = tail call i8* @realloc(i8* null, i64 %x) nounwind - %2 = bitcast i8* %1 to i32* - %idx = getelementptr inbounds i32* %2, i64 8 -; CHECK: trap - %3 = load i32* %idx, align 4 - ret void -} - -; CHECK: @f5 -define void @f5(i64 %x) nounwind { - %idx = getelementptr inbounds [8 x i8]* @.str, i64 0, i64 %x -; CHECK: trap - %1 = load i8* %idx, align 4 - ret void -} - -; CHECK: @f6 -define void @f6(i64 %x) nounwind { - %1 = alloca i128 -; CHECK-NOT: trap - %2 = load i128* %1, align 4 - ret void -} - -; CHECK: @f7 -define void @f7(i64 %x) nounwind { - %1 = alloca i128, i64 %x -; CHECK: mul i64 16, -; CHECK: trap - %2 = load i128* %1, align 4 - ret void -} - -; CHECK: @f8 -define void @f8() nounwind { - %1 = alloca i128 - %2 = alloca i128 - %3 = select i1 undef, i128* %1, i128* %2 -; CHECK-NOT: trap - %4 = load i128* %3, align 4 - ret void -} - -; CHECK: @f9 -define void @f9(i128* %arg) nounwind { - %1 = alloca i128 - %2 = select i1 undef, i128* %arg, i128* %1 -; CHECK-NOT: trap - %3 = load i128* %2, align 4 - ret void -} - -; CHECK: @f10 -define void @f10(i64 %x, i64 %y) nounwind { - %1 = alloca i128, i64 %x - %2 = alloca i128, i64 %y - %3 = select i1 undef, i128* %1, i128* %2 -; CHECK: select -; CHECK: select -; CHECK: trap - %4 = load i128* %3, align 4 - ret void -} - -; CHECK: @f11 -define void @f11(i128* byval %x) nounwind { - %1 = bitcast i128* %x to i8* - %2 = getelementptr inbounds i8* %1, i64 16 -; CHECK: br label - %3 = load i8* %2, align 4 - ret void -}