PageRenderTime 72ms CodeModel.GetById 14ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 0ms

/JIT/PyTBAliasAnalysis.cc

http://unladen-swallow.googlecode.com/
C++ | 439 lines | 312 code | 98 blank | 29 comment | 59 complexity | fca8323aae91be5bc81b6f94540aad55 MD5 | raw file
  1#include "JIT/PyTBAliasAnalysis.h"
  2
  3#include "JIT/ConstantMirror.h"
  4#include "JIT/PyTypeBuilder.h"
  5
  6#include "llvm/Analysis/AliasAnalysis.h"
  7#include "llvm/ADT/SmallPtrSet.h"
  8#include "llvm/ADT/DenseMap.h"
  9#include "llvm/ADT/StringMap.h"
 10
 11#include <utility>
 12
 13namespace {
 14
 15using llvm::AliasAnalysis;
 16using llvm::BasicBlock;
 17using llvm::BranchInst;
 18using llvm::CallInst;
 19using llvm::Function;
 20using llvm::FunctionPass;
 21using llvm::ICmpInst;
 22using llvm::Instruction;
 23using llvm::LLVMContext;
 24using llvm::MDNode;
 25using llvm::Module;
 26using llvm::Pass;
 27using llvm::PassInfo;
 28using llvm::Value;
 29using llvm::dyn_cast;
 30using llvm::isa;
 31
 32// This function unwinds casts and GEPs until it finds an instruction with
 33// a TBAA Metadata node. Returns NULL if no metadata is found. Automatically
 34// tags pointers to PyObject.
 35static MDNode *getFirstMDNode(const PyGlobalLlvmData *const llvm_data,
 36                              const unsigned kind, const Value *V)
 37{
 38    unsigned MaxLookup = 10;
 39    bool is_pyobject = false;
 40    const llvm::Type *pyobject_type =
 41        PyTypeBuilder<PyObject*>::get(V->getContext());
 42
 43    do {
 44        if (const Instruction *instr = dyn_cast<Instruction>(V))
 45            if (MDNode *n = instr->getMetadata(kind))
 46                return n;
 47
 48        // TODO: This makes the assumption that there is only one struct
 49        // with the structure of a PyObject. If this changes, this may mark
 50        // Values wrongly.
 51        if (V->getType() == pyobject_type)
 52            is_pyobject = true;
 53
 54        // It's save to remove any GEPs. Even if the type of the value changes,
 55        // it is still within some outer structure about which we can make
 56        // aliasing assumptions.
 57        if (const llvm::GEPOperator *GEP = dyn_cast<llvm::GEPOperator>(V)) {
 58            V = GEP->getPointerOperand();
 59        } else if (llvm::Operator::getOpcode(V) == llvm::Instruction::BitCast) {
 60            V = llvm::cast<llvm::Operator>(V)->getOperand(0);
 61        } else if (const llvm::GlobalAlias *GA =
 62                   dyn_cast<llvm::GlobalAlias>(V)) {
 63            if (GA->mayBeOverridden()) {
 64                break;
 65            }
 66            V = GA->getAliasee();
 67        } else {
 68            break;
 69        }
 70    } while (--MaxLookup);
 71
 72    if (is_pyobject) {
 73        return llvm_data->tbaa_PyObject.type();
 74    }
 75    return NULL;
 76}
 77
 78
 79
 80class PyTBAliasAnalysis : public FunctionPass, public AliasAnalysis {
 81public:
 82    static char ID;
 83    PyTBAliasAnalysis(PyGlobalLlvmData &global_data)
 84        : FunctionPass(&ID), context_(&global_data.context()),
 85          llvm_data_(&global_data),
 86          kind_(global_data.GetTBAAKind())
 87    {}
 88
 89    PyTBAliasAnalysis()
 90        : FunctionPass(&ID), context_(NULL), llvm_data_(NULL),
 91          kind_(0)
 92    {}
 93
 94    virtual void getAnalysisUsage(llvm::AnalysisUsage &usage) const {
 95        AliasAnalysis::getAnalysisUsage(usage);
 96        usage.setPreservesAll();
 97    }
 98
 99    virtual bool runOnFunction(Function&);
100
101    virtual AliasResult alias(const Value *V1, unsigned V1Size,
102                              const Value *V2, unsigned V2Size);
103
104    virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) {
105        if (PI->isPassID(&AliasAnalysis::ID))
106            return (AliasAnalysis*)this;
107        return this;
108    }
109
110private:
111    bool typesMayAlias(MDNode *T1, MDNode *T2) const;
112
113    const LLVMContext *const context_;
114    const PyGlobalLlvmData *const llvm_data_;
115    const unsigned kind_;
116};
117
118
119// The address of this variable identifies the pass.  See
120// http://llvm.org/docs/WritingAnLLVMPass.html#basiccode.
121char PyTBAliasAnalysis::ID = 0;
122
123// Register this pass.
124static llvm::RegisterPass<PyTBAliasAnalysis>
125U("python-tbaa", "Python-specific Type Based Alias Analysis", false, true);
126
127// Declare that we implement the AliasAnalysis interface.
128static llvm::RegisterAnalysisGroup<AliasAnalysis> V(U);
129
130
131bool
132PyTBAliasAnalysis::runOnFunction(Function &f)
133{
134    AliasAnalysis::InitializeAliasAnalysis(this);
135    return false;
136}
137
138
139AliasAnalysis::AliasResult
140PyTBAliasAnalysis::alias(const Value *V1, unsigned V1Size,
141                         const Value *V2, unsigned V2Size)
142{
143    MDNode *T1 = getFirstMDNode(this->llvm_data_, this->kind_,
144                                const_cast<Value*>(V1));
145    MDNode *T2 = getFirstMDNode(this->llvm_data_, this->kind_,
146                                const_cast<Value*>(V2));
147
148    if (T1 == NULL || T2 == NULL) {
149        return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
150    }
151
152    if (!this->typesMayAlias(T1, T2)) {
153        return NoAlias;
154    }
155    return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
156}
157
158bool
159PyTBAliasAnalysis::typesMayAlias(MDNode *T1, MDNode *T2) const
160{
161    if (T1 == T2)
162        return true;
163
164    if (llvm_data_->IsTBAASubtype(T1, T2))
165        return true;
166
167    if (llvm_data_->IsTBAASubtype(T2, T1))
168        return true;
169
170    return false;
171}
172
173} // End of anonymous namespace
174
175Pass *
176CreatePyTBAliasAnalysis(PyGlobalLlvmData &global_data)
177{
178    return new PyTBAliasAnalysis(global_data);
179}
180
181
182namespace {
183
184class PyTypeMarkingPass : public FunctionPass {
185public:
186    static char ID;
187    PyTypeMarkingPass(PyGlobalLlvmData &global_data);
188
189    PyTypeMarkingPass()
190        : FunctionPass(&ID), context_(NULL), llvm_data_(NULL), kind_(0)
191    {}
192
193    virtual void getAnalysisUsage(llvm::AnalysisUsage &usage) const {
194        usage.setPreservesAll();
195    }
196
197    virtual bool runOnFunction(Function&);
198
199private:
200    void addMark(const char *name, const PyTBAAType &type);
201    bool markFunction(CallInst *callInst);
202
203    const LLVMContext *const context_;
204    const PyGlobalLlvmData *const llvm_data_;
205    const unsigned kind_;
206
207    llvm::ValueMap<Function *, const PyTBAAType *> func_map_;
208};
209
210
211// The address of this variable identifies the pass.  See
212// http://llvm.org/docs/WritingAnLLVMPass.html#basiccode.
213char PyTypeMarkingPass::ID = 0;
214
215// Register this pass.
216static llvm::RegisterPass<PyTypeMarkingPass>
217W("python-typemarking", "Python-specific Type Marking pass", false, true);
218
219
220PyTypeMarkingPass::PyTypeMarkingPass(PyGlobalLlvmData &global_data)
221    : FunctionPass(&ID), context_(&global_data.context()),
222      llvm_data_(&global_data),
223      kind_(global_data.GetTBAAKind())
224{
225}
226
227bool
228PyTypeMarkingPass::runOnFunction(Function &F)
229{
230    if (this->func_map_.empty()) {
231        // This functions should get loaded with the BC file.
232        addMark("PyInt_FromLong", llvm_data_->tbaa_PyIntObject);
233        addMark("PyInt_FromSsize_t", llvm_data_->tbaa_PyIntObject);
234        // PyBoolObject is a subtype of PyIntObject
235        addMark("PyBool_FromLong", llvm_data_->tbaa_PyIntObject);
236        addMark("PyFloat_FromDouble", llvm_data_->tbaa_PyFloatObject);
237        addMark("PyString_Format", llvm_data_->tbaa_PyStringObject);
238
239        // getFunction needs the real function name. Expand macros.
240#ifndef Py_UNICODE_WIDE
241        addMark("PyUnicodeUCS2_Format", llvm_data_->tbaa_PyUnicodeObject);
242#else
243        addMark("PyUnicodeUCS4_Format", llvm_data_->tbaa_PyUnicodeObject);
244#endif
245
246    }
247
248    bool changed = false;
249
250    for (Function::iterator b = F.begin(), be = F.end(); b != be; ++b) {
251        for (BasicBlock::iterator i = b->begin(), ie = b->end(); i != ie; ++i) {
252            if (CallInst* callInst = dyn_cast<CallInst>(&*i)) {
253                changed |= this->markFunction(callInst);
254            }
255        }
256    }
257
258    return changed;
259}
260
261void
262PyTypeMarkingPass::addMark(const char *name, const PyTBAAType &type)
263{
264    const Module *module = this->llvm_data_->module();
265    Function *func = module->getFunction(name);
266
267    // There should already be GVs for functions in the runtime library.
268    assert(func != NULL);
269
270    this->func_map_[func] = &type;
271}
272
273bool
274PyTypeMarkingPass::markFunction(CallInst *callInst)
275{
276    Function *called = callInst->getCalledFunction();
277    if (called == NULL)
278        return false;
279
280    if (callInst->getMetadata(this->kind_) != NULL)
281        return false;
282
283    const PyTBAAType *type = this->func_map_.lookup(called);
284    if (type == NULL)
285        return false;
286
287    type->MarkInstruction(callInst);
288    return true;
289}
290
291} // End of anonymous namespace
292
293Pass *
294CreatePyTypeMarkingPass(PyGlobalLlvmData &global_data)
295{
296    return new PyTypeMarkingPass(global_data);
297}
298
299
300
301namespace {
302
303class PyTypeGuardRemovalPass : public FunctionPass {
304public:
305    static char ID;
306    PyTypeGuardRemovalPass(PyGlobalLlvmData &global_data);
307
308    PyTypeGuardRemovalPass()
309        : FunctionPass(&ID), context_(NULL), llvm_data_(NULL), kind_(0)
310    {}
311
312    virtual bool runOnFunction(Function&);
313
314private:
315    void addGuardType(PyObject *obj, const PyTBAAType &type);
316    bool checkICmp(ICmpInst *icmpIns);
317
318    LLVMContext *const context_;
319    const PyGlobalLlvmData *const llvm_data_;
320    const unsigned kind_;
321
322    typedef llvm::ValueMap<const Value *,
323                           llvm::TrackingVH<MDNode> > GuardTypes;
324
325    // Type checks in LlvmIR compare the type field of a PyObject with a
326    // instance of PyTypeObject. This maps the Python type to a TBAA MDNode.
327    GuardTypes type_map_;
328
329};
330
331// The address of this variable identifies the pass.  See
332// http://llvm.org/docs/WritingAnLLVMPass.html#basiccode.
333char PyTypeGuardRemovalPass::ID = 0;
334
335// Register this pass.
336static llvm::RegisterPass<PyTypeGuardRemovalPass>
337X("python-typeguard", "Python-specific Type Guard Removal Pass", false, true);
338
339PyTypeGuardRemovalPass::PyTypeGuardRemovalPass(PyGlobalLlvmData &global_data)
340    : FunctionPass(&ID), context_(&global_data.context()),
341      llvm_data_(&global_data),
342      kind_(global_data.GetTBAAKind())
343{
344}
345
346void
347PyTypeGuardRemovalPass::addGuardType(PyObject *obj, const PyTBAAType &type)
348{
349    const llvm::Value *value =
350        this->llvm_data_->constant_mirror().GetGlobalVariableFor(obj);
351    type_map_[value] = type.type();
352}
353
354bool
355PyTypeGuardRemovalPass::runOnFunction(Function &F)
356{
357
358    if (type_map_.empty()) {
359        // Lazy initialisation. GetGlobalVariable does not work during init.
360        // Connects type objects with Metadata. Do this for every
361        // *_CheckExact you want to remove.
362        this->addGuardType((PyObject *)&PyInt_Type,
363                           llvm_data_->tbaa_PyIntObject);
364        this->addGuardType((PyObject *)&PyFloat_Type,
365                           llvm_data_->tbaa_PyFloatObject);
366    }
367
368    bool changed = false;
369
370    for (Function::iterator b = F.begin(), be = F.end(); b != be; ++b) {
371        for (BasicBlock::iterator i = b->begin(), ie = b->end(); i != ie; ++i) {
372            if (ICmpInst *icmpInst = dyn_cast<ICmpInst>(&*i)) {
373                changed |= this->checkICmp(icmpInst);
374            }
375        }
376    }
377
378    return changed;
379}
380
381bool
382PyTypeGuardRemovalPass::checkICmp(ICmpInst *icmpInst)
383{
384    const llvm::Type *type_object =
385        PyTypeBuilder<PyTypeObject*>::get(*this->context_);
386
387    if (icmpInst->getPredicate() != ICmpInst::ICMP_EQ) {
388        return false;
389    }
390
391    Value *op1 = icmpInst->getOperand(0);
392    if (op1->getType() != type_object) {
393        return false;
394    }
395
396    Value *load = op1->getUnderlyingObject();
397    llvm::LoadInst *loadInst = dyn_cast<llvm::LoadInst>(load);
398    if (loadInst == NULL) {
399        return false;
400    }
401
402    Value *src = loadInst->getOperand(0);
403
404    MDNode *type_hint = getFirstMDNode(this->llvm_data_, this->kind_, src);
405
406    if (type_hint == NULL)
407        return false;
408
409    GuardTypes::iterator it = type_map_.find(icmpInst->getOperand(1));
410    if (it == type_map_.end())
411        return false;
412
413    MDNode *req_type = it->second;
414
415    /* This only removes type checks which would result in true */
416    if (type_hint != req_type)
417        return false;
418
419    bool changed = false;
420    for (Value::use_iterator i = icmpInst->use_begin(), e = icmpInst->use_end();
421            i != e; ++i) {
422        if (BranchInst *branch = dyn_cast<BranchInst>(*i)) {
423            if (branch->isConditional()) {
424                changed = true;
425                BasicBlock *true_block = branch->getSuccessor(0);
426                branch->setUnconditionalDest(true_block);
427            }
428        }
429    }
430    return changed;
431}
432
433} // End of anonymous namespace
434
435Pass *
436CreatePyTypeGuardRemovalPass(PyGlobalLlvmData &global_data)
437{
438    return new PyTypeGuardRemovalPass(global_data);
439}