blob: ecbce2c6b6e92542df130425db563f38c6b310c3 [file] [log] [blame]
//===- ExactCheckOpt.cpp -------------------------------------------------- --//
//
// The SAFECode Compiler
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass tries to lower bounds checks and load/store checks to exact
// checks, that is checks whose bounds information can be determined easily,
// say, allocations inside a function or global variables. Therefore SAFECode
// does not need to register stuffs in the meta-data.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "exactcheck-opt"
#include "safecode/OptimizeChecks.h"
#include "safecode/Support/AllocatorInfo.h"
#include "SCUtils.h"
#include "dsa/DSSupport.h"
#include "llvm/ADT/Statistic.h"
NAMESPACE_SC_BEGIN
static RegisterPass<ExactCheckOpt> X ("exactcheck-opt", "Exact check optimization", true);
// Pass Statistics
namespace {
STATISTIC (ExactChecks , "The number of checks lowered to exactcheck");
}
char ExactCheckOpt::ID = 0;
//
// Method: runOnModule()
//
// Description:
// This method is the entry point for the transform pass.
//
// Inputs:
// M - The LLVM module to transform.
//
// Return value:
// true - The module was modified.
// false - The module was not modified.
//
bool
ExactCheckOpt::runOnModule(Module & M) {
ExactChecks = 0;
intrinsic = &getAnalysis<InsertSCIntrinsic>();
ExactCheck2 = intrinsic->getIntrinsic("sc.exactcheck2").F;
InsertSCIntrinsic::intrinsic_const_iterator i = intrinsic->intrinsic_begin();
InsertSCIntrinsic::intrinsic_const_iterator e = intrinsic->intrinsic_end();
for (; i != e; ++i) {
if (i->flag & (InsertSCIntrinsic::SC_INTRINSIC_BOUNDSCHECK
| InsertSCIntrinsic::SC_INTRINSIC_MEMCHECK)) {
checkingIntrinsicsToBeRemoved.clear();
Function * F = i->F;
for (Value::use_iterator UI = F->use_begin(), E = F->use_end();
UI != E;
++UI) {
CallInst * CI = dyn_cast<CallInst>(*UI);
if (CI) {
visitCheckingIntrinsic(CI);
}
}
ExactChecks += checkingIntrinsicsToBeRemoved.size();
//
// Remove checking intrinsics that have been optimized
//
for (std::vector<CallInst*>::const_iterator i = checkingIntrinsicsToBeRemoved.begin(), e = checkingIntrinsicsToBeRemoved.end(); i != e; ++i) {
(*i)->eraseFromParent();
}
}
}
//
// Conservatively assume that we have changed something in the module.
//
return true;
}
//
// Function: visitCheckingIntrinsic()
//
// Description:
// Attempts to rewrite an extensive check into an efficient, accurate array
// bounds check which will not use meta-data information
//
// Inputs:
// CI - A pointer to the instruction that performs a run-time check.
//
// Return value:
// true - Successfully rewrite the check into an exact check.
// false - Cannot perform the optimization.
//
bool
ExactCheckOpt::visitCheckingIntrinsic(CallInst * CI) {
//
// Get the pointer that is checked by this run-time check.
//
Value * CheckPtr = intrinsic->getValuePointer(CI);
//
// Strip off all casts and GEPs to try to find the source of the pointer.
//
Value * BasePtr = intrinsic->findObject (CheckPtr);
if (!BasePtr) return false;
//
// Attempt to get the size of the pointer. If a size is returned, we know
// that the base pointer points to the beginning of an object, and we can do
// a run-time check without a lookup.
//
if (Value * Size = intrinsic->getObjectSize(BasePtr)) {
rewriteToExactCheck(CI, BasePtr, CheckPtr, Size);
return true;
}
//
// We were not able to insert a call to exactcheck().
//
return false;
}
//
// Function: rewriteToExactCheck()
//
// Description:
// Rewrite a check into an exact check
//
// Inputs:
// BasePointer - An LLVM Value representing the base of the object to check.
// Result - An LLVM Value representing the pointer to check.
// Bounds - An LLVM Value representing the bounds of the check.
//
void
ExactCheckOpt::rewriteToExactCheck(CallInst * CI, Value * BasePointer,
Value * ResultPointer, Value * Bounds) {
// The LLVM type for a void *
const Type *VoidPtrType = getVoidPtrType();
const Type * Int32Type = IntegerType::getInt32Ty(getGlobalContext());
//
// For readability, make sure that both the base pointer and the result
// pointer have names.
//
if (!(BasePointer->hasName())) BasePointer->setName("base");
if (!(ResultPointer->hasName())) ResultPointer->setName("result");
//
// Cast the operands to the correct type.
//
if (BasePointer->getType() != VoidPtrType)
BasePointer = castTo (BasePointer, VoidPtrType,
BasePointer->getName()+".ec.casted",
CI);
if (ResultPointer->getType() != VoidPtrType)
ResultPointer = castTo (ResultPointer, VoidPtrType,
ResultPointer->getName()+".ec.casted",
CI);
Value * CastBounds = Bounds;
if (Bounds->getType() != Int32Type)
CastBounds = castTo (Bounds, Int32Type, Bounds->getName()+".ec.casted", CI);
//
// Create the call to exactcheck2().
//
std::vector<Value *> args(1, BasePointer);
args.push_back(ResultPointer);
args.push_back(CastBounds);
CallInst * ExactCheckCI = CallInst::Create (ExactCheck2, args.begin(), args.end(), "", CI);
// boundscheck / exactcheck return an out of bound pointer when REWRITE_OOB is
// enabled. We need to replace all uses to make the optimization correct, but
// we don't need do anything for load / store checks.
//
// We can test the condition above by simply testing the return types of the
// checking functions.
if (ExactCheckCI->getType() == CI->getType()) {
CI->replaceAllUsesWith(ExactCheckCI);
}
checkingIntrinsicsToBeRemoved.push_back(CI);
}
NAMESPACE_SC_END