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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
//===-- CPPTargetMachine.h - TargetMachine for the C++ backend --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <OptPasses.h>
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Function.h"
// XXX
#include "llvm/Support/FormattedStream.h"
#include <stdio.h>
#define dump(x) fprintf(stderr, x "\n")
#define dumpv(x, ...) fprintf(stderr, x "\n", __VA_ARGS__)
#define dumpfail(x) { fprintf(stderr, x "\n"); fprintf(stderr, "%s : %d\n", __FILE__, __LINE__); report_fatal_error("fail"); }
#define dumpfailv(x, ...) { fprintf(stderr, x "\n", __VA_ARGS__); fprintf(stderr, "%s : %d\n", __FILE__, __LINE__); report_fatal_error("fail"); }
#define dumpIR(value) { \
std::string temp; \
raw_string_ostream stream(temp); \
stream << *(value); \
fprintf(stderr, "%s\n", temp.c_str()); \
}
#undef assert
#define assert(x) { if (!(x)) dumpfail(#x); }
// XXX
namespace llvm {
/*
* Find cases where an alloca is used only to load and store a single value,
* even though it is bitcast. Then replace it with a direct alloca of that
* simple type.
*/
struct SimplifyAllocas : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
SimplifyAllocas() : FunctionPass(ID) {}
// XXX initialize..(*PassRegistry::getPassRegistry()); }
virtual bool runOnFunction(Function &Func);
};
char SimplifyAllocas::ID = 0;
bool SimplifyAllocas::runOnFunction(Function &Func) {
bool Changed = false;
Type *i32 = Type::getInt32Ty(Func.getContext());
std::vector<Instruction*> ToRemove; // removing can invalidate our iterators, so do it all at the end
for (Function::iterator B = Func.begin(), E = Func.end(); B != E; ++B) {
for (BasicBlock::iterator BI = B->begin(), BE = B->end(); BI != BE; ) {
Instruction *I = BI++;
AllocaInst *AI = dyn_cast<AllocaInst>(I);
if (!AI) continue;
if (!isa<ConstantInt>(AI->getArraySize())) continue;
bool Fail = false;
Type *ActualType = NULL;
#define CHECK_TYPE(TT) { \
Type *T = TT; \
if (!ActualType) { \
ActualType = T; \
} else { \
if (T != ActualType) Fail = true; \
} \
}
std::vector<Instruction*> Aliases; // the bitcasts of this alloca
for (Instruction::use_iterator UI = AI->use_begin(), UE = AI->use_end(); UI != UE && !Fail; ++UI) {
Instruction *U = dyn_cast<Instruction>(*UI);
if (!U) { Fail = true; break; }
switch (U->getOpcode()) {
case Instruction::Load: {
CHECK_TYPE(U->getType());
break;
}
case Instruction::Store: {
CHECK_TYPE(U->getOperand(0)->getType());
if (U->getOperand(0) == AI) Fail = true;
break;
}
case Instruction::BitCast: {
// bitcasting just to do loads and stores is ok
for (Instruction::use_iterator BUI = U->use_begin(), BUE = U->use_end(); BUI != BUE && !Fail; ++BUI) {
Instruction *BU = dyn_cast<Instruction>(*BUI);
if (!BU) { Fail = true; break; }
if (BU->getOpcode() == Instruction::Load) {
CHECK_TYPE(BU->getType());
break;
}
if (BU->getOpcode() != Instruction::Store) { Fail = true; break; }
CHECK_TYPE(BU->getOperand(0)->getType());
if (BU->getOperand(0) == U) { Fail = true; break; }
}
if (!Fail) Aliases.push_back(U);
break;
}
default: { Fail = true; break; }
}
}
if (!Fail && Aliases.size() > 0) {
dump("win!");
dumpv("%s", Func.getName().str().c_str());
dumpIR(AI);
// success, replace the alloca and the bitcast aliases with a single simple alloca
AllocaInst *NA = new AllocaInst(ActualType, ConstantInt::get(i32, 1), "", I);
NA->takeName(AI);
NA->setAlignment(AI->getAlignment());
NA->setDebugLoc(AI->getDebugLoc());
AI->replaceAllUsesWith(NA);
ToRemove.push_back(AI);
for (unsigned i = 0; i < Aliases.size(); i++) {
Aliases[i]->replaceAllUsesWith(NA);
ToRemove.push_back(Aliases[i]);
}
Changed = true;
}
}
}
for (unsigned i = 0; i < ToRemove.size(); i++) {
ToRemove[i]->removeFromParent();
}
return Changed;
}
//
extern FunctionPass *createSimplifyAllocasPass() {
return new SimplifyAllocas();
}
} // End llvm namespace
|