diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index a7e2e05b931..49bb713bb6e 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -138,6 +138,7 @@ namespace { (void) llvm::createGEPSplitterPass(); (void) llvm::createSCCVNPass(); (void) llvm::createABCDPass(); + (void) llvm::createObjectSizeLoweringPass(); (void)new llvm::IntervalPartition(); (void)new llvm::FindUsedTypes(); diff --git a/include/llvm/Support/StandardPasses.h b/include/llvm/Support/StandardPasses.h index f233c18de3b..6de1b3aeb73 100644 --- a/include/llvm/Support/StandardPasses.h +++ b/include/llvm/Support/StandardPasses.h @@ -118,8 +118,6 @@ namespace llvm { // Start of function pass. PM->add(createScalarReplAggregatesPass()); // Break up aggregate allocas - if (SimplifyLibCalls) - PM->add(createSimplifyLibCallsPass()); // Library Call Optimizations PM->add(createInstructionCombiningPass()); // Cleanup for scalarrepl. PM->add(createJumpThreadingPass()); // Thread jumps. PM->add(createCFGSimplificationPass()); // Merge & remove BBs @@ -128,6 +126,9 @@ namespace llvm { PM->add(createTailCallEliminationPass()); // Eliminate tail calls PM->add(createCFGSimplificationPass()); // Merge & remove BBs PM->add(createReassociatePass()); // Reassociate expressions + PM->add(createObjectSizeLoweringPass()); // Lower Intrinsic::objsize + if (SimplifyLibCalls) + PM->add(createSimplifyLibCallsPass()); // Library Call Optimizations PM->add(createLoopRotatePass()); // Rotate Loop PM->add(createLICMPass()); // Hoist loop invariants PM->add(createLoopUnswitchPass(OptimizeSize || OptimizationLevel < 3)); diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 7159f86e1e1..c24a12d0cf8 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -336,6 +336,12 @@ FunctionPass *createSCCVNPass(); // FunctionPass *createABCDPass(); +//===----------------------------------------------------------------------===// +// +// ObjSizeLowering - Lower Intrinsic::objsize +// +FunctionPass *createObjectSizeLoweringPass(); + } // End llvm namespace #endif diff --git a/lib/Transforms/Scalar/ObjectSizeLowering.cpp b/lib/Transforms/Scalar/ObjectSizeLowering.cpp new file mode 100644 index 00000000000..9660e796c55 --- /dev/null +++ b/lib/Transforms/Scalar/ObjectSizeLowering.cpp @@ -0,0 +1,114 @@ +//===-- ObjectSizeLowering.cpp - Loop unroller pass -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass lowers Intrinsic::objectsize using SCEV to determine minimum or +// maximum space left in an allocated object. +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "objsize-lower" +#include "llvm/Constants.h" +#include "llvm/Module.h" +#include "llvm/Value.h" +#include "llvm/Target/TargetData.h" +#include "llvm/IntrinsicInst.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/ScalarEvolutionExpander.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + class ObjSizeLower : public FunctionPass { + ScalarEvolution *SE; + TargetData *TD; + public: + static char ID; // Pass identification, replacement for typeid + ObjSizeLower() : FunctionPass(&ID) {} + + bool runOnFunction(Function &F); + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + AU.addRequired(); + AU.addPreserved(); + } + private: + bool LowerCall(IntrinsicInst *); + void ReplaceAllUsesWithUnknown(IntrinsicInst *, bool); + }; +} + +char ObjSizeLower::ID = 0; +static RegisterPass X("objsize-lower", + "Object Size Lowering"); + +// Public interface to the Object Size Lowering pass +FunctionPass *llvm::createObjectSizeLoweringPass() { + return new ObjSizeLower(); +} + +/// runOnFunction - Top level algorithm - Loop over each object size intrinsic +/// and use Scalar Evolutions to get the maximum or minimum size left in the +/// allocated object at any point. +bool ObjSizeLower::runOnFunction(Function &F) { + SE = &getAnalysis(); + TD = getAnalysisIfAvailable(); + + // We really need TargetData for size calculations. + if (!TD) return false; + + bool Changed = false; + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { + for (BasicBlock::iterator I = BB->begin(), L = BB->end(); I != L; ) { + CallInst *CI = dyn_cast(I++); + if (!CI) continue; + + // The only thing we care about are Intrinsic::objectsize calls + IntrinsicInst *II = dyn_cast(CI); + if (!II || II->getIntrinsicID() != Intrinsic::objectsize) continue; + + Changed |= LowerCall(II); + } + } + return Changed; +} + +// Unknown for llvm.objsize is -1 for maximum size, and 0 for minimum size. +void ObjSizeLower::ReplaceAllUsesWithUnknown(IntrinsicInst *II, bool min) { + const Type *ReturnTy = II->getCalledFunction()->getReturnType(); + II->replaceAllUsesWith(ConstantInt::get(ReturnTy, min ? 0 : -1ULL)); + II->eraseFromParent(); +} + +bool ObjSizeLower::LowerCall(IntrinsicInst *II) { + ConstantInt *CI = cast(II->getOperand(2)); + bool minimum = (CI->getZExtValue() == 1); + Value *Op = II->getOperand(1); + const Type *ReturnTy = II->getCalledFunction()->getReturnType(); + + // Grab the SCEV for our access. + const SCEV *thisEV = SE->getSCEV(Op); + + if (const SCEVUnknown *SU = dyn_cast(thisEV)) { + if (GlobalVariable *GV = dyn_cast(SU->getValue())) { + if (GV->hasDefinitiveInitializer()) { + Constant *C = GV->getInitializer(); + size_t globalSize = TD->getTypeAllocSize(C->getType()); + II->replaceAllUsesWith(ConstantInt::get(ReturnTy, globalSize)); + II->eraseFromParent(); + return true; + } + } + } + + ReplaceAllUsesWithUnknown(II, minimum); + return true; +} diff --git a/test/Transforms/InstCombine/objsize.ll b/test/Transforms/ObjSizeLower/objsize.ll similarity index 88% rename from test/Transforms/InstCombine/objsize.ll rename to test/Transforms/ObjSizeLower/objsize.ll index 41d071517df..bcc1f835df5 100644 --- a/test/Transforms/InstCombine/objsize.ll +++ b/test/Transforms/ObjSizeLower/objsize.ll @@ -1,6 +1,5 @@ ; Test a pile of objectsize bounds checking. -; RUN: opt < %s -instcombine -S | FileCheck %s -; XFAIL: * +; RUN: opt < %s -objsize-lower -S | FileCheck %s ; We need target data to get the sizes of the arrays and structures. target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" @@ -19,8 +18,8 @@ define i8* @bar() nounwind { entry: %retval = alloca i8* %0 = call i32 @llvm.objectsize.i32(i8* getelementptr inbounds ([60 x i8]* @a, i32 0, i32 0), i1 false) +; CHECK: %cmp = icmp ne i32 60, -1 %cmp = icmp ne i32 %0, -1 -; CHECK: br i1 true br i1 %cmp, label %cond.true, label %cond.false cond.true: @@ -32,9 +31,10 @@ cond.false: ret i8* %2; } +; FIXME: This should return 0. define i32 @f() nounwind { ; CHECK: @f -; CHECK-NEXT: ret i32 0 +; CHECK-NEXT: ret i32 -1 %1 = call i32 @llvm.objectsize.i32(i8* getelementptr ([60 x i8]* @a, i32 1, i32 0), i1 false) ret i32 %1 } @@ -43,7 +43,7 @@ define i32 @f() nounwind { define i1 @baz() nounwind { ; CHECK: @baz -; CHECK-NEXT: llvm.objectsize.i32 +; CHECK-NEXT: icmp eq i32 -1, -1 %1 = tail call i32 @llvm.objectsize.i32(i8* getelementptr inbounds ([0 x i8]* @window, i32 0, i32 0), i1 false) %2 = icmp eq i32 %1, -1 ret i1 %2