diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -574,9 +574,17 @@ // Mark I's users as changed, including AdditionalUsers. void markUsersAsChanged(Value *I) { - for (User *U : I->users()) - if (auto *UI = dyn_cast(U)) - OperandChangedState(UI); + // Functions include their arguments in the use-list. Changed function values mean that the result of the function changed. We only need to update the call sites with the new function result and do not have to propagate the call arguments. + if (auto *Fn = dyn_cast(I)) { + for (User *U : I->users()) { + if (auto CS = CallSite(U)) + handleCallResult(CS); + } + } else { + for (User *U : I->users()) + if (auto *UI = dyn_cast(U)) + OperandChangedState(UI); + } auto Iter = AdditionalUsers.find(I); if (Iter != AdditionalUsers.end()) { @@ -585,6 +593,9 @@ OperandChangedState(UI); } } + void handleCallOverdefined(CallSite CS); + void handleCallResult(CallSite CS); + void handleCallArguments(CallSite CS); private: friend class InstVisitor; @@ -1219,6 +1230,100 @@ } void SCCPSolver::visitCallSite(CallSite CS) { + handleCallResult(CS); + handleCallArguments(CS); +} + +void SCCPSolver::handleCallOverdefined(CallSite CS) { + Function *F = CS.getCalledFunction(); + Instruction *I = CS.getInstruction(); + + // Void return and not tracking callee, just bail. + if (I->getType()->isVoidTy()) + return; + + // Otherwise, if we have a single return value case, and if the function is + // a declaration, maybe we can constant fold it. + if (F && F->isDeclaration() && !I->getType()->isStructTy() && + canConstantFoldCallTo(cast(CS.getInstruction()), F)) { + SmallVector Operands; + for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); AI != E; + ++AI) { + if (AI->get()->getType()->isStructTy()) + return markOverdefined(I); // Can't handle struct args. + LatticeVal State = getValueState(*AI); + + if (State.isUnknown()) + return; // Operands are not resolved yet. + if (State.isOverdefined()) + return (void)markOverdefined(I); + assert(State.isConstant() && "Unknown state!"); + Operands.push_back(State.getConstant()); + } + + if (getValueState(I).isOverdefined()) + return; + + // If we can constant fold this, mark the result of the call as a + // constant. + if (Constant *C = ConstantFoldCall(cast(CS.getInstruction()), F, + Operands, &GetTLI(*F))) { + // call -> undef. + if (isa(C)) + return; + return (void)markConstant(I, C); + } + } + + // Otherwise, we don't know anything about this call, mark it overdefined. + return (void)markOverdefined(I); +} + +void SCCPSolver::handleCallArguments(CallSite CS) { + Function *F = CS.getCalledFunction(); + // If this is a local function that doesn't have its address taken, mark its + // entry block executable and merge in the actual arguments to the call into + // the formal arguments of the function. + if (!TrackingIncomingArguments.empty() && TrackingIncomingArguments.count(F)){ + MarkBlockExecutable(&F->front()); + + // Propagate information from this call site into the callee. + CallSite::arg_iterator CAI = CS.arg_begin(); + for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); + AI != E; ++AI, ++CAI) { + // If this argument is byval, and if the function is not readonly, there + // will be an implicit copy formed of the input aggregate. + if (AI->hasByValAttr() && !F->onlyReadsMemory()) { + markOverdefined(&*AI); + continue; + } + + if (auto *STy = dyn_cast(AI->getType())) { + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { + LatticeVal CallArg = getStructValueState(*CAI, i); + mergeInValue(getStructValueState(&*AI, i), &*AI, CallArg); + } + } else { + // Most other parts of the Solver still only use the simpler value + // lattice, so we propagate changes for parameters to both lattices. + ValueLatticeElement ConcreteArgument = + isa(*CAI) ? getParamState(*CAI) + : getValueState(*CAI).toValueLattice(); + bool ParamChanged = getParamState(&*AI).mergeIn(ConcreteArgument, DL); + bool ValueChanged = + mergeInValue(&*AI, toLatticeVal(ConcreteArgument, AI->getType())); + // Add argument to work list, if the state of a parameter changes but + // ValueState does not change (because it is already overdefined there), + // We have to take changes in ParamState into account, as it is used + // when evaluating Cmp instructions. + if (!ValueChanged && ParamChanged) + pushToWorkList(ValueState[&*AI], &*AI); + } + } + } +} + +void SCCPSolver::handleCallResult(CallSite CS) { Function *F = CS.getCalledFunction(); Instruction *I = CS.getInstruction(); @@ -1284,93 +1389,13 @@ // The common case is that we aren't tracking the callee, either because we // are not doing interprocedural analysis or the callee is indirect, or is // external. Handle these cases first. - if (!F || F->isDeclaration()) { -CallOverdefined: - // Void return and not tracking callee, just bail. - if (I->getType()->isVoidTy()) return; - - // Otherwise, if we have a single return value case, and if the function is - // a declaration, maybe we can constant fold it. - if (F && F->isDeclaration() && !I->getType()->isStructTy() && - canConstantFoldCallTo(cast(CS.getInstruction()), F)) { - SmallVector Operands; - for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); - AI != E; ++AI) { - if (AI->get()->getType()->isStructTy()) - return markOverdefined(I); // Can't handle struct args. - LatticeVal State = getValueState(*AI); - - if (State.isUnknown()) - return; // Operands are not resolved yet. - if (State.isOverdefined()) - return (void)markOverdefined(I); - assert(State.isConstant() && "Unknown state!"); - Operands.push_back(State.getConstant()); - } - - if (getValueState(I).isOverdefined()) - return; - - // If we can constant fold this, mark the result of the call as a - // constant. - if (Constant *C = ConstantFoldCall(cast(CS.getInstruction()), F, - Operands, &GetTLI(*F))) { - // call -> undef. - if (isa(C)) - return; - return (void)markConstant(I, C); - } - } - - // Otherwise, we don't know anything about this call, mark it overdefined. - return (void)markOverdefined(I); - } - - // If this is a local function that doesn't have its address taken, mark its - // entry block executable and merge in the actual arguments to the call into - // the formal arguments of the function. - if (!TrackingIncomingArguments.empty() && TrackingIncomingArguments.count(F)){ - MarkBlockExecutable(&F->front()); - - // Propagate information from this call site into the callee. - CallSite::arg_iterator CAI = CS.arg_begin(); - for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); - AI != E; ++AI, ++CAI) { - // If this argument is byval, and if the function is not readonly, there - // will be an implicit copy formed of the input aggregate. - if (AI->hasByValAttr() && !F->onlyReadsMemory()) { - markOverdefined(&*AI); - continue; - } - - if (auto *STy = dyn_cast(AI->getType())) { - for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { - LatticeVal CallArg = getStructValueState(*CAI, i); - mergeInValue(getStructValueState(&*AI, i), &*AI, CallArg); - } - } else { - // Most other parts of the Solver still only use the simpler value - // lattice, so we propagate changes for parameters to both lattices. - ValueLatticeElement ConcreteArgument = - isa(*CAI) ? getParamState(*CAI) - : getValueState(*CAI).toValueLattice(); - bool ParamChanged = getParamState(&*AI).mergeIn(ConcreteArgument, DL); - bool ValueChanged = - mergeInValue(&*AI, toLatticeVal(ConcreteArgument, AI->getType())); - // Add argument to work list, if the state of a parameter changes but - // ValueState does not change (because it is already overdefined there), - // We have to take changes in ParamState into account, as it is used - // when evaluating Cmp instructions. - if (!ValueChanged && ParamChanged) - pushToWorkList(ValueState[&*AI], &*AI); - } - } - } + if (!F || F->isDeclaration()) + return handleCallOverdefined(CS); // If this is a single/zero retval case, see if we're tracking the function. if (auto *STy = dyn_cast(F->getReturnType())) { if (!MRVFunctionsTracked.count(F)) - goto CallOverdefined; // Not tracking this callee. + return handleCallOverdefined(CS); // Not tracking this callee. // If we are tracking this callee, propagate the result of the function // into this call site. @@ -1380,7 +1405,7 @@ } else { MapVector::iterator TFRVI = TrackedRetVals.find(F); if (TFRVI == TrackedRetVals.end()) - goto CallOverdefined; // Not tracking this callee. + return handleCallOverdefined(CS); // Not tracking this callee. // If so, propagate the return value of the callee into this call result. mergeInValue(I, TFRVI->second);