Example #1
0
    //------------------------------------------------------------------
    /// Scan a function to see if any instructions are interesting
    ///
    /// @param[in] f
    ///     The function to be inspected.
    ///
    /// @return
    ///     False if there was an error scanning; true otherwise.
    //------------------------------------------------------------------
    virtual bool InspectFunction(llvm::Function &f)
    {
        for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();
             bbi != last_bbi;
             ++bbi)
        {
            if (!InspectBasicBlock(*bbi))
                return false;
        }

        return true;
    }
bool BitcastCallEliminator::runOnFunction(llvm::Function &function)
{
    bool res = false;
    bool doLoop = true;
    while (doLoop) {
        doLoop = false;
        for (llvm::Function::iterator i = function.begin(), e = function.end(); i != e; ++i) {
            llvm::BasicBlock *bb = &*i;
            bool bbchanged = false;
            for (llvm::BasicBlock::iterator ibb = bb->begin(), ebb = bb->end(); ibb != ebb; ++ibb) {
                llvm::Instruction *inst = &*ibb;
                if (llvm::isa<llvm::CallInst>(inst) && llvm::cast<llvm::CallInst>(inst)->getCalledFunction() == NULL) {
                    llvm::CallInst *callInst = llvm::cast<llvm::CallInst>(inst);
                    llvm::Value *calledValue = callInst->getCalledValue();
                    llvm::Value *bareCalledValue = calledValue->stripPointerCasts();
                    if (llvm::isa<llvm::Function>(bareCalledValue)) {
                        const llvm::FunctionType *calledType = llvm::cast<llvm::FunctionType>(llvm::cast<llvm::PointerType>(calledValue->getType())->getContainedType(0));
                        const llvm::FunctionType *calleeType = llvm::cast<llvm::Function>(bareCalledValue)->getFunctionType();
                        if (calledType->getReturnType() == calleeType->getReturnType()) {
                            if (argsMatch(calleeType, callInst)) {
                                std::vector<llvm::Value*> args;
                                unsigned int numArgs = callInst->getNumArgOperands();
                                for (unsigned int k = 0; k < numArgs; ++k) {
                                    args.push_back(callInst->getArgOperand(k));
                                }
#if LLVM_VERSION < VERSION(3, 0)
                                llvm::CallInst *newCall = llvm::CallInst::Create(bareCalledValue, args.begin(), args.end(), "", inst);
#else
                                llvm::CallInst *newCall = llvm::CallInst::Create(bareCalledValue, args, "", inst);
#endif
                                inst->replaceAllUsesWith(newCall);
                                llvm::StringRef name = inst->getName();
                                inst->eraseFromParent();
                                newCall->setName(name);
                                res = true;
                                doLoop = true;
                                bbchanged = true;
                            }
                        }
                    }
                }
                if (bbchanged) {
                    break;
                }
            }
        }
    }
    return res;
}
bool InstructionCount::runOnFunction(llvm::Function &Fun) {
  ICount = 0;

  // A llvm::Function is just a list of llvm::BasicBlock. In order to get
  // instruction count we can visit all llvm::BasicBlocks ...
  for(llvm::Function::const_iterator I = Fun.begin(),
                                     E = Fun.end();
                                     I != E;
                                     ++I)
    // ... and sum the llvm::BasicBlock size -- A llvm::BasicBlock size is just
    // a list of instructions!
    ICount += I->size();

  return false;
}
Example #4
0
    bool _runOnFunction(llvm::Function& f) {
        Timer _t2("(sum)");
        Timer _t("initializing");
        initialize();
        _t.split("overhead");

        // f.dump();

        llvm::Module* cur_module = f.getParent();

#if LLVMREV < 217548
        llvm::PassManager fake_pm;
#else
        llvm::legacy::PassManager fake_pm;
#endif
        llvm::InlineCostAnalysis* cost_analysis = new llvm::InlineCostAnalysis();
        fake_pm.add(cost_analysis);
        // llvm::errs() << "doing fake run\n";
        fake_pm.run(*fake_module);
        // llvm::errs() << "done with fake run\n";

        bool did_any_inlining = false;

        // TODO I haven't gotten the callgraph-updating part of the inliner to work,
        // so it's not easy to tell what callsites have been inlined into (ie added to)
        // the function.
        // One simple-but-not-great way to handle it is to just iterate over the entire function
        // multiple times and re-inline things until we don't want to inline any more;
        // NPASSES controls the maximum number of times to attempt that.
        // Right now we actually don't need that, since we only inline fully-optimized
        // functions (from the stdlib), and those will already have had inlining
        // applied recursively.
        const int NPASSES = 1;
        for (int passnum = 0; passnum < NPASSES; passnum++) {
            _t.split("collecting calls");

            std::vector<llvm::CallSite> calls;
            for (llvm::inst_iterator I = llvm::inst_begin(f), E = llvm::inst_end(f); I != E; ++I) {
                llvm::CallInst* call = llvm::dyn_cast<llvm::CallInst>(&(*I));
                // From Inliner.cpp:
                if (!call || llvm::isa<llvm::IntrinsicInst>(call))
                    continue;
                // I->dump();
                llvm::CallSite CS(call);

                llvm::Value* v = CS.getCalledValue();
                llvm::ConstantExpr* ce = llvm::dyn_cast<llvm::ConstantExpr>(v);
                if (!ce)
                    continue;

                assert(ce->isCast());
                llvm::ConstantInt* l_addr = llvm::cast<llvm::ConstantInt>(ce->getOperand(0));
                int64_t addr = l_addr->getSExtValue();

                if (addr == (int64_t)printf)
                    continue;
                llvm::Function* f = g.func_addr_registry.getLLVMFuncAtAddress((void*)addr);
                if (f == NULL) {
                    if (VERBOSITY()) {
                        printf("Giving up on inlining %s:\n",
                               g.func_addr_registry.getFuncNameAtAddress((void*)addr, true).c_str());
                        call->dump();
                    }
                    continue;
                }

                // We load the bitcode lazily, so check if we haven't yet fully loaded the function:
                if (f->isMaterializable()) {
#if LLVMREV < 220600
                    f->Materialize();
#else
                    f->materialize();
#endif
                }

                // It could still be a declaration, though I think the code won't generate this case any more:
                if (f->isDeclaration())
                    continue;

                // Keep this section as a release_assert since the code-to-be-inlined, as well as the inlining
                // decisions, can be different in release mode:
                int op_idx = -1;
                for (llvm::Argument& arg : f->args()) {
                    ++op_idx;
                    llvm::Type* op_type = call->getOperand(op_idx)->getType();
                    if (arg.getType() != op_type) {
                        llvm::errs() << f->getName() << " has arg " << op_idx << " mismatched!\n";
                        llvm::errs() << "Given ";
                        op_type->dump();
                        llvm::errs() << " but underlying function expected ";
                        arg.getType()->dump();
                        llvm::errs() << '\n';
                    }
                    RELEASE_ASSERT(arg.getType() == call->getOperand(op_idx)->getType(), "");
                }

                assert(!f->isDeclaration());
                CS.setCalledFunction(f);
                calls.push_back(CS);
            }

            // assert(0 && "TODO");
            // printf("%ld\n", calls.size());

            bool did_inline = false;
            _t.split("doing inlining");
            while (calls.size()) {
                llvm::CallSite cs = calls.back();
                calls.pop_back();

                // if (VERBOSITY("irgen.inlining") >= 1) {
                // llvm::errs() << "Evaluating callsite ";
                // cs->dump();
                //}
                llvm::InlineCost IC = cost_analysis->getInlineCost(cs, threshold);
                bool do_inline = false;
                if (IC.isAlways()) {
                    if (VERBOSITY("irgen.inlining") >= 2)
                        llvm::errs() << "always inline\n";
                    do_inline = true;
                } else if (IC.isNever()) {
                    if (VERBOSITY("irgen.inlining") >= 2)
                        llvm::errs() << "never inline\n";
                    do_inline = false;
                } else {
                    if (VERBOSITY("irgen.inlining") >= 2)
                        llvm::errs() << "Inline cost: " << IC.getCost() << '\n';
                    do_inline = (bool)IC;
                }

                if (VERBOSITY("irgen.inlining") >= 1) {
                    if (!do_inline)
                        llvm::outs() << "not ";
                    llvm::outs() << "inlining ";
                    cs->dump();
                }

                if (do_inline) {
                    static StatCounter num_inlines("num_inlines");
                    num_inlines.log();

                    // llvm::CallGraph cg(*f.getParent());
                    ////cg.addToCallGraph(cs->getCalledFunction());
                    // llvm::InlineFunctionInfo InlineInfo(&cg);

                    llvm::InlineFunctionInfo InlineInfo;
                    bool inlined = llvm::InlineFunction(cs, InlineInfo, false);
                    did_inline = did_inline || inlined;
                    did_any_inlining = did_any_inlining || inlined;

                    // if (inlined)
                    // f.dump();
                }
            }

            if (!did_inline) {
                if (passnum >= NPASSES - 1 && VERBOSITY("irgen.inlining"))
                    printf("quitting after %d passes\n", passnum + 1);
                break;
            }
        }

        // TODO would be nice to break out here and not have to rematerialize the function;
        // I think I have to do that even if no inlining happened from the "setCalledFunction" call above.
        // I thought that'd just change the CS object, but maybe it changes the underlying instruction as well?
        // if (!did_any_inlining)
        // return false;

        _t.split("remapping");

        llvm::ValueToValueMapTy VMap;
        for (llvm::Function::iterator I = f.begin(), E = f.end(); I != E; ++I) {
            VMap[I] = I;
        }
        MyMaterializer materializer(cur_module);
        for (llvm::inst_iterator I = llvm::inst_begin(f), E = llvm::inst_end(f); I != E; ++I) {
            RemapInstruction(&(*I), VMap, llvm::RF_None, NULL, &materializer);
        }

        _t.split("cleaning up");

        std::vector<llvm::GlobalValue*> to_remove;
        for (llvm::Module::global_iterator I = cur_module->global_begin(), E = cur_module->global_end(); I != E; ++I) {
            if (I->use_empty()) {
                to_remove.push_back(I);
                continue;
            }
        }

        for (int i = 0; i < to_remove.size(); i++) {
            to_remove[i]->eraseFromParent();
        }

        for (llvm::Module::iterator I = cur_module->begin(), E = cur_module->end(); I != E;) {
            if (!I->isDeclaration()) {
                ++I;
                continue;
            }

            if (I->use_empty()) {
                I = cur_module->getFunctionList().erase(I);
            } else {
                ++I;
            }
        }

        return did_any_inlining;
    }
// Propagate conditions
bool ConditionPropagator::runOnFunction(llvm::Function &F)
{
    m_map.clear();
    llvm::SmallVector<std::pair<const llvm::BasicBlock*, const llvm::BasicBlock*>, 32> backedgesVector;
    llvm::FindFunctionBackedges(F, backedgesVector);
    std::set<std::pair<const llvm::BasicBlock*, const llvm::BasicBlock*> > backedges;
    backedges.insert(backedgesVector.begin(), backedgesVector.end());
    if (m_debug) {
        std::cout << "========================================" << std::endl;
    }
    for (llvm::Function::iterator bbi = F.begin(), bbe = F.end(); bbi != bbe; ++bbi) {
        llvm::BasicBlock *bb = &*bbi;
        std::set<llvm::BasicBlock*> preds;
        for (llvm::Function::iterator tmpi = F.begin(), tmpe = F.end(); tmpi != tmpe; ++tmpi) {
            if (isPred(&*tmpi, bb) && backedges.find(std::make_pair(&*tmpi, bb)) == backedges.end()) {
                if (m_debug) {
                    std::cout << bb->getName().str() << " has non-backedge predecessor " << tmpi->getName().str() << std::endl;
                }
                preds.insert(&*tmpi);
            }
        }
        std::set<llvm::Value*> trueSet;
        std::set<llvm::Value*> falseSet;
        bool haveStarted = false;
        for (std::set<llvm::BasicBlock*>::iterator i = preds.begin(), e = preds.end(); i != e; ++i) {
            TrueFalseMap::iterator it = m_map.find(*i);
            if (it == m_map.end()) {
                std::cerr << "Did not find condition information for predecessor " << (*i)->getName().str() << "!" << std::endl;
                exit(99999);
            }
            if (!haveStarted) {
                trueSet = it->second.first;
                falseSet = it->second.second;
                haveStarted = true;
            } else {
                // intersect
                trueSet = intersect(trueSet, it->second.first);
                falseSet = intersect(falseSet, it->second.second);
            }
        }
        if (preds.size() == 1) {
            llvm::BasicBlock *pred = *(preds.begin());
            // branch condition!
            if (!m_onlyLoopConditions || m_lcbs.find(pred) != m_lcbs.end()) {
                llvm::TerminatorInst *termi = pred->getTerminator();
                if (llvm::isa<llvm::BranchInst>(termi)) {
                    llvm::BranchInst *br = llvm::cast<llvm::BranchInst>(termi);
                    if (br->isConditional()) {
                        if (br->getSuccessor(0) == bb) {
                            // branch on true
                            trueSet.insert(br->getCondition());
                        } else {
                            // branch on false
                            falseSet.insert(br->getCondition());
                        }
                    }
                }
            }
            // assumes!
            if (!m_onlyLoopConditions) {
                for (llvm::BasicBlock::iterator insti = pred->begin(), inste = pred->end(); insti != inste; ++insti) {
                    if (llvm::isa<llvm::CallInst>(insti)) {
                        llvm::CallInst *ci = llvm::cast<llvm::CallInst>(insti);
                        llvm::Function *calledFunction = ci->getCalledFunction();
                        if (calledFunction != NULL) {
                            std::string functionName = calledFunction->getName().str();
                            if (functionName == "__kittel_assume") {
                                llvm::CallSite callSite(ci);
                                trueSet.insert(callSite.getArgument(0));
                            }
                        }
                    }
                }
            }
        }
        if (m_debug) {
            std::cout << "In " << bb->getName().str() << ":" << std::endl;
            std::cout << "TRUE: "; printSet(trueSet); std::cout << std::endl;
            std::cout << "FALSE: "; printSet(falseSet); std::cout << std::endl;
            if (++bbi != bbe) {
                std::cout << std::endl;
            }
            --bbi;
        }
        m_map.insert(std::make_pair(bb, std::make_pair(trueSet, falseSet)));
    }
    return false;
}