Ejemplo n.º 1
0
void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node, llvm::Value *rdval)
{
    LLVMNode *rdnode = dg->getNode(rdval);
    if (!rdnode) {
        // that means that the value is not from this graph.
        // We need to add interprocedural edge
        llvm::Function *F
            = llvm::cast<llvm::Instruction>(rdval)->getParent()->getParent();
        LLVMNode *entryNode = dg->getGlobalNode(F);
        assert(entryNode && "Don't have built function");

        // get the graph where the node lives
        LLVMDependenceGraph *graph = entryNode->getDG();
        assert(graph != dg && "Cannot find a node");
        rdnode = graph->getNode(rdval);
        if (!rdnode) {
            llvmutils::printerr("[DU] error: DG doesn't have val: ", rdval);
            abort();
            return;
        }
    }

    assert(rdnode);
    rdnode->addDataDependence(node);
}
Ejemplo n.º 2
0
void LLVMDGVerifier::checkGraph(llvm::Function *F, LLVMDependenceGraph *g)
{
    using namespace llvm;

    LLVMNode *entry = g->getEntry();
    if (!entry) {
        fault("has no entry for %s", F->getName().data());
        return;
    }

    const llvm::Function *func = dyn_cast<Function>(entry->getKey());
    if (!func) {
        fault("key in entry node is not a llvm::Function");
        return;
    }

    size_t a, b;
    a = g->getBlocks().size();
    b = func->size();
    if (a != b)
        fault("have constructed %lu BBlocks but function has %lu basic blocks", a, b);

    for (BasicBlock& llvmBB : *F) {
        LLVMBBlock *BB = g->getBlocks()[&llvmBB];
        if (!BB) {
            fault("missing BasicBlock");
            errs() << llvmBB << "\n";
        } else
            checkBBlock(&llvmBB, BB);
    }
}
Ejemplo n.º 3
0
bool LLVMReachingDefsAnalysis::handleStoreInst(LLVMNode *storeNode, DefMap *df,
                                               PointsToSetT *&strong_update)
{
    bool changed = false;
    llvm::StoreInst *SI = cast<StoreInst>(storeNode->getValue());
    LLVMNode *ptrNode = getOperand(storeNode, SI->getPointerOperand(), 0);
    assert(ptrNode && "No pointer operand");

    // update definitions
    PointsToSetT& S = ptrNode->getPointsTo();
    // if we have only one concrete pointer (known pointer
    // with known offset), it is safe to do strong update
    if (S.size() == 1) {
        const Pointer& ptr = *S.begin();
        // NOTE: we don't have good mechanism to diferentiate
        // heap-allocated objects yet, so if the pointer points to heap,
        // we must do weak update
        if (ptr.isKnown() && !ptr.offset.isUnknown() && !ptr.pointsToHeap()) {
            changed |= df->update(ptr, storeNode);
            strong_update = &S;
            return changed;
        }

        // else fall-through to weak update
    }

    // weak update
    for (const Pointer& ptr : ptrNode->getPointsTo())
        changed |= df->add(ptr, storeNode);

    return changed;
}
Ejemplo n.º 4
0
bool LLVMReachingDefsAnalysis::handleIntrinsicCall(LLVMNode *callNode,
                                                   CallInst *CI,
                                                   DefMap *df)
{
    bool changed = false;
    IntrinsicInst *I = cast<IntrinsicInst>(CI);
    Value *dest;

    switch (I->getIntrinsicID())
    {
        case Intrinsic::memmove:
        case Intrinsic::memcpy:
        case Intrinsic::memset:
            dest = I->getOperand(0);
            break;
        default:
            return handleUndefinedCall(callNode, CI, df);
    }

    LLVMNode *destNode = getOperand(callNode, dest, 1);
    assert(destNode && "No operand for intrinsic call");

    for (const Pointer& ptr : destNode->getPointsTo()) {
        // we could compute all the concrete offsets, but
        // these functions usually set the whole memory,
        // so if we use UNKNOWN_OFFSET, the effect is the same
        changed |= df->add(Pointer(ptr.obj, UNKNOWN_OFFSET), callNode);
    }

    return changed;
}
Ejemplo n.º 5
0
bool LLVMReachingDefsAnalysis::handleUndefinedCall(LLVMNode *callNode,
                                                   CallInst *CI,
                                                   DefMap *df)
{
    bool changed = false;
    for (unsigned n = 1, e = callNode->getOperandsNum(); n < e; ++n) {
        Value *llvmOp = CI->getOperand(n - 1);
        if (!llvmOp->getType()->isPointerTy())
            continue;

        if (isa<Constant>(llvmOp->stripInBoundsOffsets()))
            continue;

        LLVMNode *op = getOperand(callNode, llvmOp, n);
        assert(op && "unhandled pointer operand in undef call");

        // with undefined call we must assume that any
        // memory that was passed via pointer was modified
        // and on unknown offset
        // XXX we should handle external globals too
        for (const Pointer& ptr : op->getPointsTo())
            changed |= df->add(Pointer(ptr.obj, UNKNOWN_OFFSET), callNode);
    }

    return changed;
}
Ejemplo n.º 6
0
static bool handleParams(LLVMNode *callNode, unsigned vararg,
                         LLVMDGParameters *params,
                         DefMap *df, DefMap *subgraph_df)
{
    bool changed = false;

    // operand[0] is the called func
    for (int i = 1, e = callNode->getOperandsNum(); i < e; ++i) {
        LLVMNode *op = callNode->getOperand(i);
        if (!op)
            continue;

        if (!op->isPointerTy())
            continue;

        LLVMDGParameter *p = params->find(op->getKey());
        if (!p) {
#ifdef DEBUG_ENABLED
            if (i - 1 < (int) vararg)
                DBG("ERR: no actual param for " << *op->getKey());
#endif
            continue;
        }

        changed |= handleParam(op, p->out, df, subgraph_df);
    }

    return changed;
}
Ejemplo n.º 7
0
void LLVMDGVerifier::checkBBlock(const llvm::BasicBlock *llvmBB, LLVMBBlock *BB)
{
    using namespace llvm;
    auto BBIT = BB->getNodes().begin();

    for (const Instruction& I : *llvmBB) {
        LLVMNode *node = *BBIT;

        // check if we have the CFG edges set
        if (node->getKey() != &I)
            fault("wrong node in BB");

        checkNode(&I, node);
        ++BBIT;
    }

    // FIXME: check successors and predecessors
}
Ejemplo n.º 8
0
void LLVMDefUseAnalysis::handleInlineAsm(LLVMNode *callNode)
{
    CallInst *CI = cast<CallInst>(callNode->getValue());
    LLVMDependenceGraph *dg = callNode->getDG();

    // the last operand is the asm itself, so iterate only to e - 1
    for (unsigned i = 0, e = CI->getNumOperands(); i < e - 1; ++i) {
        Value *opVal = CI->getOperand(i);
        if (!opVal->getType()->isPointerTy())
            continue;

        LLVMNode *opNode = dg->getNode(opVal->stripInBoundsOffsets());
        if (!opNode) {
            // FIXME: ConstantExpr
            llvmutils::printerr("WARN: unhandled inline asm operand: ", opVal);
            continue;
        }

        assert(opNode && "Do not have an operand for inline asm");

        // if nothing else, this call at least uses the operands
        opNode->addDataDependence(callNode);
    }
}
Ejemplo n.º 9
0
static std::set<LLVMNode *> getSlicingCriteriaNodes(LLVMDependenceGraph& dg,
                                                    const std::string& slicingCriteria)
{
    std::set<LLVMNode *> nodes;
    std::vector<std::string> criteria = splitList(slicingCriteria);
    assert(!criteria.empty() && "Did not get slicing criteria");

    std::vector<std::string> line_criteria;
    std::vector<std::string> node_criteria;
    std::tie(line_criteria, node_criteria)
        = splitStringVector(criteria, [](std::string& s) -> bool
            { return s.find(':') != std::string::npos; }
          );

    // if user wants to slice with respect to the return of main,
    // insert the ret instructions to the nodes.
    for (const auto& c : node_criteria) {
        if (c == "ret") {
            LLVMNode *exit = dg.getExit();
            // We could insert just the exit node, but this way we will
            // get annotations to the functions.
            for (auto it = exit->rev_control_begin(), et = exit->rev_control_end();
                 it != et; ++it) {
                nodes.insert(*it);
            }
        }
    }

    // map the criteria to nodes
    if (!node_criteria.empty())
        dg.getCallSites(node_criteria, &nodes);
    if (!line_criteria.empty())
        getLineCriteriaNodes(dg, line_criteria, nodes);

    return nodes;
}