//===- GEPChecks.cpp - Insert GEP run-time checks ------------------------- --//
// 
//                     The LLVM Compiler Infrastructure
//
// 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 instruments GEPs with run-time checks to ensure safe array and
// structure indexing.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "safecode"

#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "safecode/GEPChecks.h"
#include "safecode/Utility.h"

namespace llvm {

char InsertGEPChecks::ID = 0;

static RegisterPass<InsertGEPChecks>
X ("gepchecks", "Insert GEP run-time checks");

//
// Command Line Options
//

// Disable checks on pure structure indexing
cl::opt<bool> DisableStructChecks ("disable-structgepchecks", cl::Hidden,
                                   cl::init(false),
                                   cl::desc("Disable Struct GEP Checks"));

// Pass Statistics
namespace {
  STATISTIC (GEPChecks, "Bounds Checks Added");
  STATISTIC (SafeGEP,   "GEPs proven safe by SAFECode");
}

//
// Method: visitGetElementPtrInst()
//
// Description:
//  This method checks to see if the specified GEP is safe.  If it cannot prove
//  it safe, it then adds a run-time check for it.
//
void
InsertGEPChecks::visitGetElementPtrInst (GetElementPtrInst & GEP) {
  //
  // Don't insert a check if GEP only indexes into a structure and the
  // user doesn't want to do structure index checking.
  //
  if (DisableStructChecks && indexesStructsOnly (&GEP)) {
    return;
  }

  //
  // Get the function in which the GEP instruction lives.
  //
  Value * PH = ConstantPointerNull::get (getVoidPtrType(GEP.getContext()));
  BasicBlock::iterator InsertPt = &GEP;
  ++InsertPt;
  Instruction * ResultPtr = castTo (&GEP,
                                    getVoidPtrType(GEP.getContext()),
                                    GEP.getName() + ".cast",
                                    InsertPt);

  //
  // Make this an actual cast instruction; it will make it easier to update
  // DSA.
  //
  Value * SrcPtr = castTo (GEP.getPointerOperand(),
                           getVoidPtrType(GEP.getContext()),
                           GEP.getName()+".cast",
                           InsertPt);

  //
  // Create the call to the run-time check.
  //
  std::vector<Value *> args(1, PH);
  args.push_back (SrcPtr);
  args.push_back (ResultPtr);
  CallInst * CI = CallInst::Create (PoolCheckArrayUI, args, "", InsertPt);

  //
  // Add debugging info metadata to the run-time check.
  //
  if (MDNode * MD = GEP.getMetadata ("dbg"))
    CI->setMetadata ("dbg", MD);

  //
  // Update the statistics.
  //
  ++GEPChecks;
  return;
}

//
// Method: doInitialization()
//
// Description:
//  Perform module-level initialization before the pass is run.  For this
//  pass, we need to create a function prototype for the GEP check function.
//
// Inputs:
//  M - A reference to the LLVM module to modify.
//
// Return value:
//  true - This LLVM module has been modified.
//
bool
InsertGEPChecks::doInitialization (Module & M) {
  //
  // Create a function prototype for the function that performs incomplete
  // pointer arithmetic (GEP) checks.
  //
  Type * VoidPtrTy = getVoidPtrType (M.getContext());
  Constant * F = M.getOrInsertFunction ("boundscheckui",
                                        VoidPtrTy,
                                        VoidPtrTy,
                                        VoidPtrTy,
                                        VoidPtrTy,
                                        NULL);

  //
  // Mark the function as readonly; that will enable it to be hoisted out of
  // loops by the standard loop optimization passes.
  //
  (cast<Function>(F))->addFnAttr (Attribute::ReadOnly);
  return true;
}

bool
InsertGEPChecks::runOnFunction (Function & F) {
  //
  // Get pointers to required analysis passes.
  //
  TD      = &getAnalysis<DataLayout>();
  abcPass = &getAnalysis<ArrayBoundsCheckLocal>();

  //
  // Get a pointer to the run-time check function.
  //
  PoolCheckArrayUI = F.getParent()->getFunction ("boundscheckui");

  //
  // Visit all of the instructions in the function.
  //
  visit (F);
  return true;
}

}

