void TestInstVisitor::visitSwitchInst(SwitchInst &I){ if (except){ return; } DynValEntry entry; size_t n = fread(&entry, sizeof(DynValEntry), 1, dlog); if (entry.entrytype == EXCEPTIONENTRY){ except = true; return; } assert(entry.entrytype == SWITCHENTRY); //printf("switch %d\n", entry.entry.switchstmt.cond); IntegerType *intType = IntegerType::get(getGlobalContext(), sizeof(int)*8); ConstantInt *caseVal = ConstantInt::get(intType, entry.entry.switchstmt.cond); SwitchInst::CaseIt caseIndex = I.findCaseValue(caseVal); TFP->setNextBB(I.getSuccessor(caseIndex.getSuccessorIndex())); }
// RewriteLoopBodyWithConditionConstant - We know either that the value LIC has // the value specified by Val in the specified loop, or we know it does NOT have // that value. Rewrite any uses of LIC or of properties correlated to it. void LoopUnswitch::RewriteLoopBodyWithConditionConstant(Loop *L, Value *LIC, Constant *Val, bool IsEqual) { assert(!isa<Constant>(LIC) && "Why are we unswitching on a constant?"); // FIXME: Support correlated properties, like: // for (...) // if (li1 < li2) // ... // if (li1 > li2) // ... // FOLD boolean conditions (X|LIC), (X&LIC). Fold conditional branches, // selects, switches. std::vector<User*> Users(LIC->use_begin(), LIC->use_end()); std::vector<Instruction*> Worklist; LLVMContext &Context = Val->getContext(); // If we know that LIC == Val, or that LIC == NotVal, just replace uses of LIC // in the loop with the appropriate one directly. if (IsEqual || (isa<ConstantInt>(Val) && Val->getType()->isIntegerTy(1))) { Value *Replacement; if (IsEqual) Replacement = Val; else Replacement = ConstantInt::get(Type::getInt1Ty(Val->getContext()), !cast<ConstantInt>(Val)->getZExtValue()); for (unsigned i = 0, e = Users.size(); i != e; ++i) if (Instruction *U = cast<Instruction>(Users[i])) { if (!L->contains(U)) continue; U->replaceUsesOfWith(LIC, Replacement); Worklist.push_back(U); } SimplifyCode(Worklist, L); return; } // Otherwise, we don't know the precise value of LIC, but we do know that it // is certainly NOT "Val". As such, simplify any uses in the loop that we // can. This case occurs when we unswitch switch statements. for (unsigned i = 0, e = Users.size(); i != e; ++i) { Instruction *U = cast<Instruction>(Users[i]); if (!L->contains(U)) continue; Worklist.push_back(U); // TODO: We could do other simplifications, for example, turning // 'icmp eq LIC, Val' -> false. // If we know that LIC is not Val, use this info to simplify code. SwitchInst *SI = dyn_cast<SwitchInst>(U); if (SI == 0 || !isa<ConstantInt>(Val)) continue; unsigned DeadCase = SI->findCaseValue(cast<ConstantInt>(Val)); if (DeadCase == 0) continue; // Default case is live for multiple values. // Found a dead case value. Don't remove PHI nodes in the // successor if they become single-entry, those PHI nodes may // be in the Users list. // FIXME: This is a hack. We need to keep the successor around // and hooked up so as to preserve the loop structure, because // trying to update it is complicated. So instead we preserve the // loop structure and put the block on a dead code path. BasicBlock *Switch = SI->getParent(); SplitEdge(Switch, SI->getSuccessor(DeadCase), this); // Compute the successors instead of relying on the return value // of SplitEdge, since it may have split the switch successor // after PHI nodes. BasicBlock *NewSISucc = SI->getSuccessor(DeadCase); BasicBlock *OldSISucc = *succ_begin(NewSISucc); // Create an "unreachable" destination. BasicBlock *Abort = BasicBlock::Create(Context, "us-unreachable", Switch->getParent(), OldSISucc); new UnreachableInst(Context, Abort); // Force the new case destination to branch to the "unreachable" // block while maintaining a (dead) CFG edge to the old block. NewSISucc->getTerminator()->eraseFromParent(); BranchInst::Create(Abort, OldSISucc, ConstantInt::getTrue(Context), NewSISucc); // Release the PHI operands for this edge. for (BasicBlock::iterator II = NewSISucc->begin(); PHINode *PN = dyn_cast<PHINode>(II); ++II) PN->setIncomingValue(PN->getBasicBlockIndex(Switch), UndefValue::get(PN->getType())); // Tell the domtree about the new block. We don't fully update the // domtree here -- instead we force it to do a full recomputation // after the pass is complete -- but we do need to inform it of // new blocks. if (DT) DT->addNewBlock(Abort, NewSISucc); } SimplifyCode(Worklist, L); }
// Set outgoing edges alive dependent on the terminator instruction SI. // If the terminator is an Invoke instruction, the call has already been run. // Return true if anything changed. bool IntegrationAttempt::checkBlockOutgoingEdges(ShadowInstruction* SI) { // TOCHECK: I think this only returns false if the block ends with an Unreachable inst? switch(SI->invar->I->getOpcode()) { case Instruction::Br: case Instruction::Switch: case Instruction::Invoke: case Instruction::Resume: break; default: return false; } if(inst_is<InvokeInst>(SI)) { InlineAttempt* IA = getInlineAttempt(SI); bool changed = false; // !localStore indicates the invoke instruction doesn't return normally if(SI->parent->localStore) { changed |= !SI->parent->succsAlive[0]; SI->parent->succsAlive[0] = true; } // I mark the exceptional edge reachable here if the call is disabled, even though // we might have proved it isn't feasible. This could be improved by converting the // invoke into a call in the final program. if((!IA) || (!IA->isEnabled()) || IA->mayUnwind) { changed |= !SI->parent->succsAlive[1]; SI->parent->succsAlive[1] = true; } return changed; } else if(inst_is<ResumeInst>(SI)) { bool changed = !mayUnwind; mayUnwind = true; return changed; } else if(BranchInst* BI = dyn_cast_inst<BranchInst>(SI)) { if(BI->isUnconditional()) { bool changed = !SI->parent->succsAlive[0]; SI->parent->succsAlive[0] = true; return changed; } } // Both switches and conditional branches use operand 0 for the condition. ShadowValue Condition = SI->getOperand(0); bool changed = false; ConstantInt* ConstCondition = dyn_cast_or_null<ConstantInt>(getConstReplacement(Condition)); if(!ConstCondition) { if(Condition.t == SHADOWVAL_INST || Condition.t == SHADOWVAL_ARG) { // Switch statements can operate on a ptrtoint operand, of which only ptrtoint(null) is useful: if(ImprovedValSetSingle* IVS = dyn_cast_or_null<ImprovedValSetSingle>(getIVSRef(Condition))) { if(IVS->onlyContainsNulls()) { ConstCondition = cast<ConstantInt>(Constant::getNullValue(SI->invar->I->getOperand(0)->getType())); } } } } if(!ConstCondition) { std::pair<ValSetType, ImprovedVal> PathVal; if(tryGetPathValue(Condition, SI->parent, PathVal)) ConstCondition = dyn_cast_val<ConstantInt>(PathVal.second.V); } TerminatorInst* TI = cast_inst<TerminatorInst>(SI); const unsigned NumSucc = TI->getNumSuccessors(); if(ConstCondition) { BasicBlock* takenTarget = 0; if(BranchInst* BI = dyn_cast_inst<BranchInst>(SI)) { // This ought to be a boolean. if(ConstCondition->isZero()) takenTarget = BI->getSuccessor(1); else takenTarget = BI->getSuccessor(0); } else { SwitchInst* SwI = cast_inst<SwitchInst>(SI); SwitchInst::CaseIt targetidx = SwI->findCaseValue(ConstCondition); takenTarget = targetidx.getCaseSuccessor(); } if(takenTarget) { // We know where the instruction is going -- remove this block as a predecessor for its other targets. LPDEBUG("Branch or switch instruction given known target: " << takenTarget->getName() << "\n"); return setEdgeAlive(TI, SI->parent, takenTarget); } // Else fall through to set all alive. } SwitchInst* Switch; ImprovedValSetSingle* IVS; if((Switch = dyn_cast_inst<SwitchInst>(SI)) && (IVS = dyn_cast<ImprovedValSetSingle>(getIVSRef(Condition))) && IVS->SetType == ValSetTypeScalar && !IVS->Values.empty()) { // A set of values feeding a switch. Set each corresponding edge alive. bool changed = false; for (unsigned i = 0, ilim = IVS->Values.size(); i != ilim; ++i) { SwitchInst::CaseIt targetit = Switch->findCaseValue(cast<ConstantInt>(getConstReplacement(IVS->Values[i].V))); BasicBlock* target = targetit.getCaseSuccessor(); changed |= setEdgeAlive(TI, SI->parent, target); } return changed; } // Condition unknown -- set all successors alive. for (unsigned I = 0; I != NumSucc; ++I) { // Mark outgoing edge alive if(!SI->parent->succsAlive[I]) changed = true; SI->parent->succsAlive[I] = true; } return changed; }