1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
//===- 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);
for (Value::use_iterator CallIter = OldIntrinsic->use_begin(),
E = OldIntrinsic->use_end(); CallIter != E; ) {
CallInst *Call = dyn_cast<CallInst>(*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();
}
|