//===- 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 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); for (Value::use_iterator CallIter = OldIntrinsic->use_begin(), E = OldIntrinsic->use_end(); CallIter != E; ) { CallInst *Call = dyn_cast(*CallIter++); if (!Call) { report_fatal_error("CanonicalizeMemIntrinsics: Taking the address of an " "intrinsic is not allowed: " + OldName); } // 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(); }