blob: 1acde98d322a3f50d44c35ecd75492a4498a0e1b [file] [log] [blame] [edit]
//===- CanonicalizeMemIntrinsics.cpp - Make memcpy's "len" arg consistent--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass canonicalizes uses of the llvm.memset, llvm.memcpy and
// llvm.memmove intrinsics so that the variants with 64-bit "len"
// arguments aren't used, and the 32-bit variants are used instead.
//
// This means the PNaCl translator won't need to handle two versions
// of each of these intrinsics, and it won't need to do any implicit
// truncations from 64-bit to 32-bit.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"
using namespace llvm;
namespace {
// This is a ModulePass because that makes it easier to find all
// uses of intrinsics efficiently.
class CanonicalizeMemIntrinsics : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
CanonicalizeMemIntrinsics() : ModulePass(ID) {
initializeCanonicalizeMemIntrinsicsPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnModule(Module &M);
};
}
char CanonicalizeMemIntrinsics::ID = 0;
INITIALIZE_PASS(CanonicalizeMemIntrinsics, "canonicalize-mem-intrinsics",
"Make memcpy() et al's \"len\" argument consistent",
false, false)
static bool expandIntrinsic(Module *M, Intrinsic::ID ID) {
SmallVector<Type *, 3> Types;
Types.push_back(Type::getInt8PtrTy(M->getContext()));
if (ID != Intrinsic::memset)
Types.push_back(Type::getInt8PtrTy(M->getContext()));
unsigned LengthTypePos = Types.size();
Types.push_back(Type::getInt64Ty(M->getContext()));
std::string OldName = Intrinsic::getName(ID, Types);
Function *OldIntrinsic = M->getFunction(OldName);
if (!OldIntrinsic)
return false;
Types[LengthTypePos] = Type::getInt32Ty(M->getContext());
Function *NewIntrinsic = Intrinsic::getDeclaration(M, ID, Types);
SmallVector<CallInst *, 64> Calls;
for (User *U : OldIntrinsic->users()) {
if (CallInst *Call = dyn_cast<CallInst>(U))
Calls.push_back(Call);
else
report_fatal_error("CanonicalizeMemIntrinsics: Taking the address of an "
"intrinsic is not allowed: " +
OldName);
}
for (CallInst *Call : Calls) {
// This temporarily leaves Call non-well-typed.
Call->setCalledFunction(NewIntrinsic);
// Truncate the "len" argument. No overflow check.
IRBuilder<> Builder(Call);
Value *Length = Builder.CreateTrunc(Call->getArgOperand(2),
Type::getInt32Ty(M->getContext()),
"mem_len_truncate");
Call->setArgOperand(2, Length);
}
OldIntrinsic->eraseFromParent();
return true;
}
bool CanonicalizeMemIntrinsics::runOnModule(Module &M) {
bool Changed = false;
Changed |= expandIntrinsic(&M, Intrinsic::memset);
Changed |= expandIntrinsic(&M, Intrinsic::memcpy);
Changed |= expandIntrinsic(&M, Intrinsic::memmove);
return Changed;
}
ModulePass *llvm::createCanonicalizeMemIntrinsicsPass() {
return new CanonicalizeMemIntrinsics();
}