void FaultLocalization::checkControlFlow(YicesSolver *solver) {
    std::cout << "Checking control flow...";
    assert(solver && "Solver is null!");
    // Iterate over basic blocks of the main function
    for (Function::iterator i=targetFun->begin(), e=targetFun->end(); i!=e; ++i) {
        BasicBlock *bb = i;
        // Get the values of the predecessor transitions
        unsigned nbPredTrans      = 0;
        unsigned nbTruePredTrans  = 0;
        unsigned nbUndefPredTrans = 0;
        for (pred_iterator PI = pred_begin(bb), E = pred_end(bb); PI != E; ++PI) {
            BasicBlock *predbb = *PI;
            int val = getBlockTransVal(solver, predbb, bb);
            if (val==l_true) {
                nbTruePredTrans++;
            }
            else if (val==l_undef) {
                nbUndefPredTrans++;
            }
            nbPredTrans++;
        }
        assert((nbTruePredTrans==0 || nbTruePredTrans==1) 
                && "Invalid control flow value!");
        if (nbPredTrans==0) { // Entry block doesn't have any predecessors
            nbTruePredTrans = 1;
        }
        const TerminatorInst *t = bb->getTerminator();
        if (isa<ReturnInst>(t)) {
            return; // End of recursion
        }
        const BranchInst *br = dyn_cast<BranchInst>(t);
        assert(br && "Unsupported terminal instruction!");
        if (br->isUnconditional()) {
            BasicBlock *nextbb = br->getSuccessor(0);
            int val = getBlockTransVal(solver, bb, nextbb);
            if (nbTruePredTrans==1 && val==l_false) {
                dumpTransValues(solver);
                assert("invalid control flow value (1)");
            }
            if (nbTruePredTrans==0 && nbUndefPredTrans==0 && val==l_true) {
                std::cout << bb->getName().str() << std::endl;
                dumpTransValues(solver);
                assert("invalid control flow value (2)");
            }
        } else {
            BasicBlock *nextbb1 = br->getSuccessor(0);
            BasicBlock *nextbb2 = br->getSuccessor(1);
            int val1 = getBlockTransVal(solver, bb, nextbb1);
            int val2 = getBlockTransVal(solver, bb, nextbb2);
            if (nbTruePredTrans==1 && val1==l_false && val2==l_false) {
                dumpTransValues(solver);
                assert("invalid control flow value (3)");
            }
            if (nbTruePredTrans==0 && nbUndefPredTrans ==0
                && (val1==l_true || val2==l_true)) {
                dumpTransValues(solver);
                assert("invalid control flow value (4)");
            }
            if (val1==l_true && val2==l_true) {
                dumpTransValues(solver);
                assert("invalid control flow value (5)");
            }
        }
    }
    std::cout << "OK\n";
}
Example #2
0
/** Given the statements implementing a function, emit the code that
    implements the function.  Most of the work do be done here just
    involves wiring up the function parameter values to be available in the
    function body code.
 */
void Function::emitCode(FunctionEmitContext *ctx, llvm::Function *function, SourcePos firstStmtPos) {
    // Connect the __mask builtin to the location in memory that stores its
    // value
    maskSymbol->storagePtr = ctx->GetFullMaskPointer();

    // add debugging info for __mask
    maskSymbol->pos = firstStmtPos;
    ctx->EmitVariableDebugInfo(maskSymbol);

#if ISPC_LLVM_VERSION >= ISPC_LLVM_3_7 // LLVM 3.7+
    if (g->NoOmitFramePointer)
        function->addFnAttr("no-frame-pointer-elim", "true");
#endif
    g->target->markFuncWithTargetAttr(function);
#if 0
    llvm::BasicBlock *entryBBlock = ctx->GetCurrentBasicBlock();
#endif
    const FunctionType *type = CastType<FunctionType>(sym->type);
    Assert(type != NULL);
    if (type->isTask == true
#ifdef ISPC_NVPTX_ENABLED
        && (g->target->getISA() != Target::NVPTX)
#endif
    ) {
        // For tasks, there should always be three parameters: the
        // pointer to the structure that holds all of the arguments, the
        // thread index, and the thread count variables.
        llvm::Function::arg_iterator argIter = function->arg_begin();
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_7 /* 3.2, 3.3, 3.4, 3.5, 3.6, 3.7 */
        llvm::Value *structParamPtr = argIter++;
        llvm::Value *threadIndex = argIter++;
        llvm::Value *threadCount = argIter++;
        llvm::Value *taskIndex = argIter++;
        llvm::Value *taskCount = argIter++;
        llvm::Value *taskIndex0 = argIter++;
        llvm::Value *taskIndex1 = argIter++;
        llvm::Value *taskIndex2 = argIter++;
        llvm::Value *taskCount0 = argIter++;
        llvm::Value *taskCount1 = argIter++;
        llvm::Value *taskCount2 = argIter++;
#else /* LLVM 3.8+ */
        llvm::Value *structParamPtr = &*(argIter++);
        llvm::Value *threadIndex = &*(argIter++);
        llvm::Value *threadCount = &*(argIter++);
        llvm::Value *taskIndex = &*(argIter++);
        llvm::Value *taskCount = &*(argIter++);
        llvm::Value *taskIndex0 = &*(argIter++);
        llvm::Value *taskIndex1 = &*(argIter++);
        llvm::Value *taskIndex2 = &*(argIter++);
        llvm::Value *taskCount0 = &*(argIter++);
        llvm::Value *taskCount1 = &*(argIter++);
        llvm::Value *taskCount2 = &*(argIter++);
#endif
        // Copy the function parameter values from the structure into local
        // storage
        for (unsigned int i = 0; i < args.size(); ++i)
            lCopyInTaskParameter(i, structParamPtr, args, ctx);

        if (type->isUnmasked == false) {
            // Copy in the mask as well.
            int nArgs = (int)args.size();
            // The mask is the last parameter in the argument structure
            llvm::Value *ptr = ctx->AddElementOffset(structParamPtr, nArgs, NULL, "task_struct_mask");
            llvm::Value *ptrval = ctx->LoadInst(ptr, "mask");
            ctx->SetFunctionMask(ptrval);
        }

        // Copy threadIndex and threadCount into stack-allocated storage so
        // that their symbols point to something reasonable.
        threadIndexSym->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "threadIndex");
        ctx->StoreInst(threadIndex, threadIndexSym->storagePtr);

        threadCountSym->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "threadCount");
        ctx->StoreInst(threadCount, threadCountSym->storagePtr);

        // Copy taskIndex and taskCount into stack-allocated storage so
        // that their symbols point to something reasonable.
        taskIndexSym->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex");
        ctx->StoreInst(taskIndex, taskIndexSym->storagePtr);

        taskCountSym->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount");
        ctx->StoreInst(taskCount, taskCountSym->storagePtr);

        taskIndexSym0->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex0");
        ctx->StoreInst(taskIndex0, taskIndexSym0->storagePtr);
        taskIndexSym1->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex1");
        ctx->StoreInst(taskIndex1, taskIndexSym1->storagePtr);
        taskIndexSym2->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskIndex2");
        ctx->StoreInst(taskIndex2, taskIndexSym2->storagePtr);

        taskCountSym0->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount0");
        ctx->StoreInst(taskCount0, taskCountSym0->storagePtr);
        taskCountSym1->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount1");
        ctx->StoreInst(taskCount1, taskCountSym1->storagePtr);
        taskCountSym2->storagePtr = ctx->AllocaInst(LLVMTypes::Int32Type, "taskCount2");
        ctx->StoreInst(taskCount2, taskCountSym2->storagePtr);
    } else {
        // Regular, non-task function
        llvm::Function::arg_iterator argIter = function->arg_begin();
        for (unsigned int i = 0; i < args.size(); ++i, ++argIter) {
            Symbol *sym = args[i];
            if (sym == NULL)
                // anonymous function parameter
                continue;

            argIter->setName(sym->name.c_str());

            // Allocate stack storage for the parameter and emit code
            // to store the its value there.
            sym->storagePtr = ctx->AllocaInst(argIter->getType(), sym->name.c_str());
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_7 /* 3.2, 3.3, 3.4, 3.5, 3.6, 3.7 */
            ctx->StoreInst(argIter, sym->storagePtr);
#else /* LLVM 3.8+ */
            ctx->StoreInst(&*argIter, sym->storagePtr);
#endif
            ctx->EmitFunctionParameterDebugInfo(sym, i);
        }

        // If the number of actual function arguments is equal to the
        // number of declared arguments in decl->functionParams, then we
        // don't have a mask parameter, so set it to be all on.  This
        // happens for exmaple with 'export'ed functions that the app
        // calls.
        if (argIter == function->arg_end()) {
            Assert(type->isUnmasked || type->isExported);
            ctx->SetFunctionMask(LLVMMaskAllOn);
        } else {
            Assert(type->isUnmasked == false);

            // Otherwise use the mask to set the entry mask value
            argIter->setName("__mask");
            Assert(argIter->getType() == LLVMTypes::MaskType);
#if ISPC_LLVM_VERSION <= ISPC_LLVM_3_7 /* 3.2, 3.3, 3.4, 3.5, 3.6, 3.7 */
            ctx->SetFunctionMask(argIter);
#else /* LLVM 3.8+ */
            ctx->SetFunctionMask(&*argIter);
#endif
            Assert(++argIter == function->arg_end());
        }
#ifdef ISPC_NVPTX_ENABLED
        if (type->isTask == true && g->target->getISA() == Target::NVPTX) {
            llvm::NamedMDNode *annotations = m->module->getOrInsertNamedMetadata("nvvm.annotations");
#if ISPC_LLVM_VERSION >= ISPC_LLVM_3_6 // LLVM 3.6+
            llvm::SmallVector<llvm::Metadata *, 3> av;
            av.push_back(llvm::ValueAsMetadata::get(function));
            av.push_back(llvm::MDString::get(*g->ctx, "kernel"));
            av.push_back(llvm::ConstantAsMetadata::get(LLVMInt32(1)));
            annotations->addOperand(llvm::MDNode::get(*g->ctx, llvm::ArrayRef<llvm::Metadata *>(av)));
#else
            llvm::SmallVector<llvm::Value *, 3> av;
            av.push_back(function);
            av.push_back(llvm::MDString::get(*g->ctx, "kernel"));
            av.push_back(LLVMInt32(1));
            annotations->addOperand(llvm::MDNode::get(*g->ctx, av));
#endif
        }
#endif /* ISPC_NVPTX_ENABLED */
    }

    // Finally, we can generate code for the function
    if (code != NULL) {
        ctx->SetDebugPos(code->pos);
        ctx->AddInstrumentationPoint("function entry");

        int costEstimate = EstimateCost(code);
        Debug(code->pos, "Estimated cost for function \"%s\" = %d\n", sym->name.c_str(), costEstimate);

        // If the body of the function is non-trivial, then we wrap the
        // entire thing inside code that tests to see if the mask is all
        // on, all off, or mixed.  If this is a simple function, then this
        // isn't worth the code bloat / overhead.
        bool checkMask = (type->isTask == true) ||
                         (
#if ISPC_LLVM_VERSION == ISPC_LLVM_3_2 // 3.2
                             (function->getFnAttributes().hasAttribute(llvm::Attributes::AlwaysInline) == false)
#elif ISPC_LLVM_VERSION <= ISPC_LLVM_4_0
                             (function->getAttributes().getFnAttributes().hasAttribute(
                                  llvm::AttributeSet::FunctionIndex, llvm::Attribute::AlwaysInline) == false)
#else // LLVM 5.0+
                             (function->getAttributes().getFnAttributes().hasAttribute(llvm::Attribute::AlwaysInline) ==
                              false)
#endif
                             && costEstimate > CHECK_MASK_AT_FUNCTION_START_COST);
        checkMask &= (type->isUnmasked == false);
        checkMask &= (g->target->getMaskingIsFree() == false);
        checkMask &= (g->opt.disableCoherentControlFlow == false);

        if (checkMask) {
            llvm::Value *mask = ctx->GetFunctionMask();
            llvm::Value *allOn = ctx->All(mask);
            llvm::BasicBlock *bbAllOn = ctx->CreateBasicBlock("all_on");
            llvm::BasicBlock *bbSomeOn = ctx->CreateBasicBlock("some_on");

            // Set up basic blocks for goto targets
            ctx->InitializeLabelMap(code);

            ctx->BranchInst(bbAllOn, bbSomeOn, allOn);
            // all on: we've determined dynamically that the mask is all
            // on.  Set the current mask to "all on" explicitly so that
            // codegen for this path can be improved with this knowledge in
            // hand...
            ctx->SetCurrentBasicBlock(bbAllOn);
            if (!g->opt.disableMaskAllOnOptimizations)
                ctx->SetFunctionMask(LLVMMaskAllOn);
            code->EmitCode(ctx);
            if (ctx->GetCurrentBasicBlock())
                ctx->ReturnInst();

            // not all on: however, at least one lane must be running,
            // since we should never run with all off...  some on: reset
            // the mask to the value it had at function entry and emit the
            // code.  Resetting the mask here is important, due to the "all
            // on" setting of it for the path above.
            ctx->SetCurrentBasicBlock(bbSomeOn);
            ctx->SetFunctionMask(mask);

            // Set up basic blocks for goto targets again; we want to have
            // one set of them for gotos in the 'all on' case, and a
            // distinct set for the 'mixed mask' case.
            ctx->InitializeLabelMap(code);

            code->EmitCode(ctx);
            if (ctx->GetCurrentBasicBlock())
                ctx->ReturnInst();
        } else {
            // Set up basic blocks for goto targets
            ctx->InitializeLabelMap(code);
            // No check, just emit the code
            code->EmitCode(ctx);
        }
    }

    if (ctx->GetCurrentBasicBlock()) {
        // FIXME: We'd like to issue a warning if we've reached the end of
        // the function without a return statement (for non-void
        // functions).  But the test below isn't right, since we can have
        // (with 'x' a varying test) "if (x) return a; else return b;", in
        // which case we have a valid basic block but its unreachable so ok
        // to not have return statement.
#if 0
        // If the bblock has no predecessors, then it doesn't matter if it
        // doesn't have a return; it'll never be reached.  If it does,
        // issue a warning.  Also need to warn if it's the entry block for
        // the function (in which case it will not have predeccesors but is
        // still reachable.)
        if (type->GetReturnType()->IsVoidType() == false &&
            (pred_begin(ec.bblock) != pred_end(ec.bblock) || (ec.bblock == entryBBlock)))
            Warning(sym->pos, "Missing return statement in function returning \"%s\".",
                    type->rType->GetString().c_str());
#endif

        // FIXME: would like to set the context's current position to
        // e.g. the end of the function code

        // if bblock is non-NULL, it hasn't been terminated by e.g. a
        // return instruction.  Need to add a return instruction.
        ctx->ReturnInst();
    }
}
Example #3
0
// =============================================================================
// propagatePointers
// =============================================================================
ExprPtr Context::propagatePointers(BasicBlock *bb) {
    
    // ------------------------
    // Entry BB 
    // ------------------------
    BasicBlock *entryBB = &bb->getParent()->getEntryBlock();
    if (bb==entryBB) {
        // Nothing to propagate
        this->bb2id[bb] = 0;
        return NULL;
    }
    // ------------------------
    // Only one pred BB
    // ------------------------
    BasicBlock *singlePredBB = bb->getSinglePredecessor();
    if (singlePredBB) {
        this->bb2id[bb] = this->bb2id[singlePredBB];
        return NULL;
    }
    // ------------------------
    // More than one pred BB
    // ------------------------
    std::vector<BasicBlock*> bbs;
    for(pred_iterator PI=pred_begin(bb), PE=pred_end(bb); PI!=PE; ++PI) {
        BasicBlock *predBB = *PI;
        if(this->bb2id[predBB]>0) {
            bbs.push_back(predBB);
        }
    }
    // No store in pred BBs
    if (bbs.size()==0) {
        // Nothing to propagate
        this->bb2id[bb] = 0;
        return NULL;
    } 
    // One store in one of the pred BBs
    else if (bbs.size()==1) {  
        this->bb2id[bb] = this->bb2id[bbs.front()];
        return NULL;
    } 
    // else: More than one store in pred BBs
    std::vector<BasicBlock*>::reverse_iterator rit;
    rit = bbs.rbegin();
    ExprPtr iteExpr = NULL;
    ExprPtr lastValVar = NULL;
    // Check if MEMs used in the previous
    // blocks are the same
    bool differentMems = false;
    for(BasicBlock *bb1 : bbs) {
        int id1 = this->bb2id[bb1];
        for(BasicBlock *bb2 : bbs) {
            if (bb1==bb2) {
                continue;
            }
            int id2 = this->bb2id[bb2];
            if (id1!=id2) {
                differentMems = true;
                break;
            }
        }
        if (differentMems) {
            break;
        }
    }
    if (!differentMems) {
        // Propagate the ID to the current block
        this->bb2id[bb] = memID;
        return NULL;
    }
    // Last mem variable
    std::stringstream sstm;
    sstm << "MEM" << this->bb2id[bbs.back()];
    std::string name = sstm.str();
    lastValVar = Expression::mkIntToIntVar(name);
    rit++;
    for (; rit!=bbs.rend(); ++rit) { // reverse order
        BasicBlock *pbb = *rit;
        // Get the mem variable
        std::stringstream sstm1;
        sstm1 << "MEM" << this->bb2id[pbb];
        std::string name1 = sstm1.str();
        ExprPtr valVar = Expression::mkIntToIntVar(name1);
        // Make the PHI formula
        // (= MEM3 (ite bb1 MEM1 MEM2))
        //ExprPtr arg1 = getCondVariable(pbb); // bb0
        //iteExpr = Expression::mkIte(arg1, valVar, lastValVar);
        
        // (= MEM3 (ite predbb_bb MEM1 MEM2))
        ExprPtr transExpr = getTransition(pbb, bb);
        iteExpr = Expression::mkIte(transExpr, valVar, lastValVar);
        lastValVar = iteExpr;
    }      
    // New mem variable
    memID++;
    this->bb2id[bb] = memID;
    std::stringstream sstm2;
    sstm2 << "MEM" << memID;
    std::string name2 = sstm2.str();    
    ExprPtr phiVar = Expression::mkIntToIntVar(name2);
    // (assert (= a [ITE]))
    ExprPtr eqExpr = Expression::mkEq(phiVar, iteExpr);
    return eqExpr; // hard
}
  void ProfileVerifierPassT<FType, BType>::recurseBasicBlock(const BType *BB) {

    // Break the recursion by remembering all visited blocks.
    if (BBisVisited.find(BB) != BBisVisited.end()) return;

    // Use a data structure to store all the information, this can then be handed
    // to debug printers.
    DetailedBlockInfo DI;
    DI.BB = BB;
    DI.outCount = DI.inCount = 0;
    DI.inWeight = DI.outWeight = 0;

    // Read predecessors.
    std::set<const BType*> ProcessedPreds;
    const_pred_iterator bpi = pred_begin(BB), bpe = pred_end(BB);
    // If there are none, check for (0,BB) edge.
    if (bpi == bpe) {
      DI.inWeight += ReadOrAssert(PI->getEdge(0,BB));
      DI.inCount++;
    }
    for (;bpi != bpe; ++bpi) {
      if (ProcessedPreds.insert(*bpi).second) {
        DI.inWeight += ReadOrAssert(PI->getEdge(*bpi,BB));
        DI.inCount++;
      }
    }

    // Read successors.
    std::set<const BType*> ProcessedSuccs;
    succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
    // If there is an (0,BB) edge, consider it too. (This is done not only when
    // there are no successors, but every time; not every function contains
    // return blocks with no successors (think loop latch as return block)).
    double w = PI->getEdgeWeight(PI->getEdge(BB,0));
    if (w != ProfileInfoT<FType, BType>::MissingValue) {
      DI.outWeight += w;
      DI.outCount++;
    }
    for (;bbi != bbe; ++bbi) {
      if (ProcessedSuccs.insert(*bbi).second) {
        DI.outWeight += ReadOrAssert(PI->getEdge(BB,*bbi));
        DI.outCount++;
      }
    }

    // Read block weight.
    DI.BBWeight = PI->getExecutionCount(BB);
    CheckValue(DI.BBWeight == ProfileInfoT<FType, BType>::MissingValue,
               "BasicBlock has missing value", &DI);
    CheckValue(DI.BBWeight < 0,
               "BasicBlock has negative value", &DI);

    // Check if this block is a setjmp target.
    bool isSetJmpTarget = false;
    if (DI.outWeight > DI.inWeight) {
      for (typename BType::const_iterator i = BB->begin(), ie = BB->end();
           i != ie; ++i) {
        if (const CallInst *CI = dyn_cast<CallInst>(&*i)) {
          FType *F = CI->getCalledFunction();
          if (F && (F->getName() == "_setjmp")) {
            isSetJmpTarget = true; break;
          }
        }
      }
    }
    // Check if this block is eventually reaching exit.
    bool isExitReachable = false;
    if (DI.inWeight > DI.outWeight) {
      for (typename BType::const_iterator i = BB->begin(), ie = BB->end();
           i != ie; ++i) {
        if (const CallInst *CI = dyn_cast<CallInst>(&*i)) {
          FType *F = CI->getCalledFunction();
          if (F) {
            FisVisited.clear();
            isExitReachable |= exitReachable(F);
          } else {
            // This is a call to a pointer, all bets are off...
            isExitReachable = true;
          }
          if (isExitReachable) break;
        }
      }
    }

    if (DI.inCount > 0 && DI.outCount == 0) {
       // If this is a block with no successors.
      if (!isSetJmpTarget) {
        CheckValue(!Equals(DI.inWeight,DI.BBWeight), 
                   "inWeight and BBWeight do not match", &DI);
      }
    } else if (DI.inCount == 0 && DI.outCount > 0) {
      // If this is a block with no predecessors.
      if (!isExitReachable)
        CheckValue(!Equals(DI.BBWeight,DI.outWeight), 
                   "BBWeight and outWeight do not match", &DI);
    } else {
      // If this block has successors and predecessors.
      if (DI.inWeight > DI.outWeight && !isExitReachable)
        CheckValue(!Equals(DI.inWeight,DI.outWeight), 
                   "inWeight and outWeight do not match", &DI);
      if (DI.inWeight < DI.outWeight && !isSetJmpTarget)
        CheckValue(!Equals(DI.inWeight,DI.outWeight), 
                   "inWeight and outWeight do not match", &DI);
    }


    // Mark this block as visited, rescurse into successors.
    BBisVisited.insert(BB);
    for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB); 
          bbi != bbe; ++bbi ) {
      recurseBasicBlock(*bbi);
    }
  }
void BlockFlow::identifyInSet()
{
#if DEBUG_GLOBAL
  errs() << "Generating In-Set: " << blk->getName() << "\n";
#endif
  inSet.checks.clear();
  std::vector<GlobalCheck*> inChecks;
  bool foundChecks = false;
  for (pred_iterator PI = pred_begin(blk), E = pred_end(blk); PI != E; ++PI) {
    BasicBlock *pred = *PI;
    BlockFlow *pred_flow = (*flows)[pred];
    if (!pred_flow->outSet.allChecks) {
      #if DEBUG_GLOBAL
        errs() << "Adding checks from predecessor: " << pred->getName() << "\n";
      #endif
      foundChecks = true;
      for (std::vector<GlobalCheck*>::iterator i = pred_flow->outSet.checks.begin(), e = pred_flow->outSet.checks.end();
              i != e; i++) {
        inChecks.push_back(*i);
      }
      break;
    }
  }

  if (inChecks.empty() && foundChecks) {
    inSet.allChecks = false;
    return;
  } else if (inChecks.empty()) {
    inSet.allChecks = true;
    return;
  }

  inSet.allChecks = false;
  for (std::vector<GlobalCheck*>::iterator i = inChecks.begin(), e = inChecks.end(); i != e; i++) {
    GlobalCheck* chk = *i;
    bool existsInAllPreds = true;
    for (pred_iterator PI = pred_begin(blk), E = pred_end(blk); PI != E; ++PI) {
      BasicBlock *pred = *PI;
      BlockFlow *pred_flow = (*flows)[pred];
      bool found = false;
      if (!pred_flow->outSet.allChecks) {
        for (std::vector<GlobalCheck*>::iterator pred_i = pred_flow->outSet.checks.begin(), pred_e = pred_flow->outSet.checks.end();
              pred_i != pred_e; pred_i++) {
          GlobalCheck *predCheck = *pred_i;
          ConstantInt *const1 = dyn_cast<ConstantInt>(chk->var);
          ConstantInt *const2 = dyn_cast<ConstantInt>(predCheck->var);
          if (chk->isUpper && predCheck->isUpper) {
            // Both upper bounds checks
            if (const1 != NULL && const2 != NULL) {
              // If both constants, replace with the less strict version
              if (const1->getSExtValue() > const2->getSExtValue()) {
                chk = predCheck;
              }
              found = true;
              break;
            } else if (const1 == NULL && const2 == NULL) {
              if (chk->var == predCheck->var) {
                ConstantInt *bound1 = dyn_cast<ConstantInt>(chk->bound);
                ConstantInt *bound2 = dyn_cast<ConstantInt>(predCheck->bound);
                if (bound1 != NULL && bound2 != NULL) {
                  if (bound1->getZExtValue() < bound2->getZExtValue()) {
                    // Replace with larger upper bound
                    chk = predCheck;
                  }
                  found = true;
                  break;
                } else if (bound1 == NULL && bound2 == NULL) {
                  if (bound1 == bound2) {
                    found = true;
                    break;
                  }
                }
              }
            }
          } else if (!chk->isUpper && !predCheck->isUpper) {
            // Both lower bounds checks
            if (const1 != NULL && const2 != NULL) {
              // If both constants, replace with the less strict version
              if (const1->getSExtValue() < const2->getSExtValue()) {
                chk = predCheck;
              }
              found = true;
              break;
            } else if (const1 == NULL && const2 == NULL) {
              if (chk->var == predCheck->var) {
                found = true;
                break;
              }
            }
          }
        }
      } else {
        found = true;
      }
      if (!found) {
        existsInAllPreds = false;
        break;
      }
    }
    // If we found the check in all predecessors
    if (existsInAllPreds) {
      inSet.addCheck(chk);
    }
  }
}
Example #6
0
void DtoDefineFunction(FuncDeclaration* fd)
{
    IF_LOG Logger::println("DtoDefineFunction(%s): %s", fd->toPrettyChars(), fd->loc.toChars());
    LOG_SCOPE;

    if (fd->ir.isDefined()) return;

    if ((fd->type && fd->type->ty == Terror) ||
        (fd->type && fd->type->ty == Tfunction && static_cast<TypeFunction *>(fd->type)->next == NULL) ||
        (fd->type && fd->type->ty == Tfunction && static_cast<TypeFunction *>(fd->type)->next->ty == Terror))
    {
        IF_LOG Logger::println("Ignoring; has error type, no return type or returns error type");
        fd->ir.setDefined();
        return;
    }

    if (fd->semanticRun == PASSsemanticdone)
    {
        /* What happened is this function failed semantic3() with errors,
         * but the errors were gagged.
         * Try to reproduce those errors, and then fail.
         */
        error(fd->loc, "errors compiling function %s", fd->toPrettyChars());
        fd->ir.setDefined();
        return;
    }

    DtoResolveFunction(fd);

    if (fd->isUnitTestDeclaration() && !global.params.useUnitTests)
    {
        IF_LOG Logger::println("No code generation for unit test declaration %s", fd->toChars());
        fd->ir.setDefined();
        return;
    }

    // Skip array ops implemented in druntime
    if (fd->isArrayOp && isDruntimeArrayOp(fd))
    {
        IF_LOG Logger::println("No code generation for array op %s implemented in druntime", fd->toChars());
        fd->ir.setDefined();
        return;
    }

    // Check whether the frontend knows that the function is already defined
    // in some other module (see DMD's FuncDeclaration::toObjFile).
    for (FuncDeclaration *f = fd; f; )
    {
        if (!f->isInstantiated() && f->inNonRoot())
        {
            IF_LOG Logger::println("Skipping '%s'.", fd->toPrettyChars());
            // TODO: Emit as available_externally for inlining purposes instead
            // (see #673).
            fd->ir.setDefined();
            return;
        }
        if (f->isNested())
            f = f->toParent2()->isFuncDeclaration();
        else
            break;
    }

    DtoDeclareFunction(fd);
    assert(fd->ir.isDeclared());

    // DtoResolveFunction might also set the defined flag for functions we
    // should not touch.
    if (fd->ir.isDefined()) return;
    fd->ir.setDefined();

    // We cannot emit nested functions with parents that have not gone through
    // semantic analysis. This can happen as DMD leaks some template instances
    // from constraints into the module member list. DMD gets away with being
    // sloppy as functions in template contraints obviously never need to access
    // data from the template function itself, but it would still mess up our
    // nested context creation code.
    FuncDeclaration* parent = fd;
    while ((parent = getParentFunc(parent, true)))
    {
        if (parent->semanticRun != PASSsemantic3done || parent->semantic3Errors)
        {
            IF_LOG Logger::println("Ignoring nested function with unanalyzed parent.");
            return;
        }
    }

    assert(fd->semanticRun == PASSsemantic3done);
    assert(fd->ident != Id::empty);

    if (fd->isUnitTestDeclaration()) {
        gIR->unitTests.push_back(fd);
    } else if (fd->isSharedStaticCtorDeclaration()) {
        gIR->sharedCtors.push_back(fd);
    } else if (StaticDtorDeclaration *dtorDecl = fd->isSharedStaticDtorDeclaration()) {
        gIR->sharedDtors.push_front(fd);
        if (dtorDecl->vgate)
            gIR->sharedGates.push_front(dtorDecl->vgate);
    } else if (fd->isStaticCtorDeclaration()) {
        gIR->ctors.push_back(fd);
    } else if (StaticDtorDeclaration *dtorDecl = fd->isStaticDtorDeclaration()) {
        gIR->dtors.push_front(fd);
        if (dtorDecl->vgate)
            gIR->gates.push_front(dtorDecl->vgate);
    }


    // if this function is naked, we take over right away! no standard processing!
    if (fd->naked)
    {
        DtoDefineNakedFunction(fd);
        return;
    }

    IrFunction *irFunc = getIrFunc(fd);
    IrFuncTy &irFty = irFunc->irFty;

    // debug info
    irFunc->diSubprogram = gIR->DBuilder.EmitSubProgram(fd);

    Type* t = fd->type->toBasetype();
    TypeFunction* f = static_cast<TypeFunction*>(t);
    // assert(f->ctype);

    llvm::Function* func = irFunc->func;

    // is there a body?
    if (fd->fbody == NULL)
        return;

    IF_LOG Logger::println("Doing function body for: %s", fd->toChars());
    gIR->functions.push_back(irFunc);

    if (fd->isMain())
        gIR->emitMain = true;

    func->setLinkage(lowerFuncLinkage(fd));

    // On x86_64, always set 'uwtable' for System V ABI compatibility.
    // TODO: Find a better place for this.
    // TODO: Is this required for Win64 as well?
    if (global.params.targetTriple.getArch() == llvm::Triple::x86_64)
    {
        func->addFnAttr(LDC_ATTRIBUTE(UWTable));
    }
#if LDC_LLVM_VER >= 303
    if (opts::sanitize != opts::None) {
        // Set the required sanitizer attribute.
        if (opts::sanitize == opts::AddressSanitizer) {
            func->addFnAttr(LDC_ATTRIBUTE(SanitizeAddress));
        }

        if (opts::sanitize == opts::MemorySanitizer) {
            func->addFnAttr(LDC_ATTRIBUTE(SanitizeMemory));
        }

        if (opts::sanitize == opts::ThreadSanitizer) {
            func->addFnAttr(LDC_ATTRIBUTE(SanitizeThread));
        }
    }
#endif

    llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(gIR->context(), "", func);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endentry", func);

    //assert(gIR->scopes.empty());
    gIR->scopes.push_back(IRScope(beginbb, endbb));

    // create alloca point
    // this gets erased when the function is complete, so alignment etc does not matter at all
    llvm::Instruction* allocaPoint = new llvm::AllocaInst(LLType::getInt32Ty(gIR->context()), "alloca point", beginbb);
    irFunc->allocapoint = allocaPoint;

    // debug info - after all allocas, but before any llvm.dbg.declare etc
    gIR->DBuilder.EmitFuncStart(fd);

    // this hack makes sure the frame pointer elimination optimization is disabled.
    // this this eliminates a bunch of inline asm related issues.
    if (fd->hasReturnExp & 8) // has inline asm
    {
        // emit a call to llvm_eh_unwind_init
        LLFunction* hack = GET_INTRINSIC_DECL(eh_unwind_init);
        gIR->ir->CreateCall(hack, "");
    }

    // give the 'this' argument storage and debug info
    if (irFty.arg_this)
    {
        LLValue* thisvar = irFunc->thisArg;
        assert(thisvar);

        LLValue* thismem = thisvar;
        if (!irFty.arg_this->byref)
        {
            thismem = DtoRawAlloca(thisvar->getType(), 0, "this"); // FIXME: align?
            DtoStore(thisvar, thismem);
            irFunc->thisArg = thismem;
        }

        assert(getIrParameter(fd->vthis)->value == thisvar);
        getIrParameter(fd->vthis)->value = thismem;

        gIR->DBuilder.EmitLocalVariable(thismem, fd->vthis);
    }

    // give the 'nestArg' storage
    if (irFty.arg_nest)
    {
        LLValue *nestArg = irFunc->nestArg;
        LLValue *val = DtoRawAlloca(nestArg->getType(), 0, "nestedFrame");
        DtoStore(nestArg, val);
        irFunc->nestArg = val;
    }

    // give arguments storage
    // and debug info
    if (fd->parameters)
    {
        size_t n = irFty.args.size();
        assert(n == fd->parameters->dim);
        for (size_t i=0; i < n; ++i)
        {
            Dsymbol* argsym = static_cast<Dsymbol*>(fd->parameters->data[i]);
            VarDeclaration* vd = argsym->isVarDeclaration();
            assert(vd);

            IrParameter* irparam = getIrParameter(vd);
            assert(irparam);

            bool refout = vd->storage_class & (STCref | STCout);
            bool lazy = vd->storage_class & STClazy;
            if (!refout && (!irparam->arg->byref || lazy))
            {
                // alloca a stack slot for this first class value arg
                LLValue* mem = DtoAlloca(irparam->arg->type, vd->ident->toChars());

                // let the abi transform the argument back first
                DImValue arg_dval(vd->type, irparam->value);
                irFty.getParam(vd->type, i, &arg_dval, mem);

                // set the arg var value to the alloca
                irparam->value = mem;
            }

            if (global.params.symdebug && !(isaArgument(irparam->value) && isaArgument(irparam->value)->hasByValAttr()) && !refout)
                gIR->DBuilder.EmitLocalVariable(irparam->value, vd);
        }
    }

    FuncGen fg;
    irFunc->gen = &fg;

    DtoCreateNestedContext(fd);

    if (fd->vresult && !
        fd->vresult->nestedrefs.dim // FIXME: not sure here :/
    )
    {
        DtoVarDeclaration(fd->vresult);
    }

    // D varargs: prepare _argptr and _arguments
    if (f->linkage == LINKd && f->varargs == 1)
    {
        // allocate _argptr (of type core.stdc.stdarg.va_list)
        LLValue* argptrmem = DtoAlloca(Type::tvalist, "_argptr_mem");
        irFunc->_argptr = argptrmem;

        // initialize _argptr with a call to the va_start intrinsic
        LLValue* vaStartArg = gABI->prepareVaStart(argptrmem);
        llvm::CallInst::Create(GET_INTRINSIC_DECL(vastart), vaStartArg, "", gIR->scopebb());

        // copy _arguments to a memory location
        LLType* argumentsType = irFunc->_arguments->getType();
        LLValue* argumentsmem = DtoRawAlloca(argumentsType, 0, "_arguments_mem");
        new llvm::StoreInst(irFunc->_arguments, argumentsmem, gIR->scopebb());
        irFunc->_arguments = argumentsmem;
    }

    // output function body
    codegenFunction(fd->fbody, gIR);
    irFunc->gen = 0;

    llvm::BasicBlock* bb = gIR->scopebb();
    if (pred_begin(bb) == pred_end(bb) && bb != &bb->getParent()->getEntryBlock()) {
        // This block is trivially unreachable, so just delete it.
        // (This is a common case because it happens when 'return'
        // is the last statement in a function)
        bb->eraseFromParent();
    } else if (!gIR->scopereturned()) {
        // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
        // in automatically, so we do it here.

        // pass the previous block into this block
        gIR->DBuilder.EmitFuncEnd(fd);
        if (func->getReturnType() == LLType::getVoidTy(gIR->context())) {
            llvm::ReturnInst::Create(gIR->context(), gIR->scopebb());
        }
        else if (!fd->isMain()) {
            AsmBlockStatement* asmb = fd->fbody->endsWithAsm();
            if (asmb) {
                assert(asmb->abiret);
                llvm::ReturnInst::Create(gIR->context(), asmb->abiret, bb);
            }
            else {
                llvm::ReturnInst::Create(gIR->context(), llvm::UndefValue::get(func->getReturnType()), bb);
            }
        }
        else
            llvm::ReturnInst::Create(gIR->context(), LLConstant::getNullValue(func->getReturnType()), bb);
    }

    // erase alloca point
    if (allocaPoint->getParent())
        allocaPoint->eraseFromParent();
    allocaPoint = 0;
    gIR->func()->allocapoint = 0;

    gIR->scopes.pop_back();

    // get rid of the endentry block, it's never used
    assert(!func->getBasicBlockList().empty());
    func->getBasicBlockList().pop_back();

    gIR->functions.pop_back();
}