//===- BreakConstantStrings.cpp - Make global string constants non-constant - //
// 
//                          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 removes the constant attribute from all global strings.  This is
// done so that the native system linker does not link the strings into the
// same global string.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "break-conststrings"

#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/InstIterator.h"

#include "safecode/BreakConstantStrings.h"

#include <iostream>
#include <map>
#include <utility>

namespace llvm {

// Identifier variable for the pass
char BreakConstantStrings::ID = 0;

// Statistics
STATISTIC (GVChanges,   "Number of Strings Made Non-Constant");

// Register the pass
static RegisterPass<BreakConstantStrings> P ("break-conststrings",
                                             "Make strings non-constant");

//
// Method: runOnModule()
//
// Description:
//  Entry point for this LLVM pass.
//
// Return value:
//  true  - The module was modified.
//  false - The module was not modified.
//
bool
BreakConstantStrings::runOnModule (Module & M) {
  bool modified = false;
  const Type * Int8Type  = IntegerType::getInt8Ty(getGlobalContext());

  //
  // Scan through all the global variables in the module.  Mark a variable as
  // non-constant if:
  //  o) The variable is constant
  //  o) The variable is an array of characters (Int8Ty).
  //  o) The variable is not in a special section (e.g. debug info section).
  //     This ensures that we don't mess up debug information or other special
  //     strings within the code.
  //
  Module::global_iterator i,e;
  for (i = M.global_begin(), e = M.global_end(); i != e; ++i) {
    GlobalVariable * GV = i;

    //
    // All global variables are pointer types.  Find the type of what the
    // global variable pointer is pointing at.
    //
    if (GV->isConstant() && (!GV->hasSection())) {
      const PointerType * PT = dyn_cast<PointerType>(GV->getType());
      if (const ArrayType * AT = dyn_cast<ArrayType>(PT->getElementType())) {
        if (AT->getElementType() == Int8Type) {
          modified = true;
          ++GVChanges;
          GV->setConstant (false);
        }
      }
    }
  }

  return modified;
}

}

