-/// isReturnSlotOptznProfitable - Determine if performing a return slot
-/// fusion with the slot dest is profitable
-static bool isReturnSlotOptznProfitable(Value* dest, MemCpyInst* cpy) {
- // We currently consider it profitable if dest is otherwise dead.
- SmallVector<User*, 8> useList(dest->use_begin(), dest->use_end());
- while (!useList.empty()) {
- User* UI = useList.back();
-
- if (isa<GetElementPtrInst>(UI) || isa<BitCastInst>(UI)) {
- useList.pop_back();
- for (User::use_iterator I = UI->use_begin(), E = UI->use_end();
- I != E; ++I)
- useList.push_back(*I);
- } else if (UI == cpy)
- useList.pop_back();
- else
- return false;
- }
-
- return true;
-}
-
-/// performReturnSlotOptzn - takes a memcpy and a call that it depends on,
-/// and checks for the possibility of a return slot optimization by having
-/// the call write its result directly into the callees return parameter
-/// rather than using memcpy
-bool GVN::performReturnSlotOptzn(MemCpyInst* cpy, CallInst* C,
- SmallVector<Instruction*, 4>& toErase) {
- Value* cpyDest = cpy->getDest();
- Value* cpySrc = cpy->getSource();
- CallSite CS = CallSite::get(C);
-
- // Since this is a return slot optimization, we need to make sure that
- // the value being copied is, in fact, in a return slot. We also need to
- // check that the return slot parameter is marked noalias, so that we can
- // be sure that changing it will not cause unexpected behavior changes due
- // to it being accessed through a global or another parameter.
- if (CS.arg_size() == 0 ||
- cpySrc != CS.getArgument(0) ||
- !CS.paramHasAttr(1, ParamAttr::NoAlias | ParamAttr::StructRet))
- return false;
-
- // We only perform the transformation if it will be profitable.
- if (!isReturnSlotOptznProfitable(cpyDest, cpy))
- return false;
-
- // Check that something sneaky is not happening involving casting
- // return slot types around.
- if (CS.getArgument(0)->getType() != cpyDest->getType())
- return false;
-
- // We can only perform the transformation if the size of the memcpy
- // is constant and equal to the size of the structure.
- if (!isa<ConstantInt>(cpy->getLength()))
- return false;
-
- ConstantInt* cpyLength = cast<ConstantInt>(cpy->getLength());
- TargetData& TD = getAnalysis<TargetData>();
- if (TD.getTypeStoreSize(cpyDest->getType()) == cpyLength->getZExtValue())
- return false;
-
- // In addition to knowing that the call does not access the return slot
- // in some unexpected manner, which we derive from the noalias attribute,
- // we also need to know that it does not sneakily modify the destination
- // slot in the caller. We don't have parameter attributes to go by
- // for this one, so we just rely on AA to figure it out for us.
- AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
- if (AA.getModRefInfo(C, cpy->getRawDest(), cpyLength->getZExtValue()) !=
- AliasAnalysis::NoModRef)
- return false;
-
- // If all the checks have passed, then we're alright to do the transformation.
- CS.setArgument(0, cpyDest);
-
- // Drop any cached information about the call, because we may have changed
- // its dependence information by changing its parameter.
- MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
- MD.dropInstruction(C);
-
- // Remove the memcpy
- toErase.push_back(cpy);
-
- return true;
-}
-
-/// processMemCpy - perform simplication of memcpy's. If we have memcpy A which
-/// copies X to Y, and memcpy B which copies Y to Z, then we can rewrite B to be
-/// a memcpy from X to Z (or potentially a memmove, depending on circumstances).
-/// This allows later passes to remove the first memcpy altogether.
-bool GVN::processMemCpy(MemCpyInst* M, MemCpyInst* MDep,
- SmallVector<Instruction*, 4>& toErase) {
- // We can only transforms memcpy's where the dest of one is the source of the
- // other
- if (M->getSource() != MDep->getDest())
- return false;
-
- // Second, the length of the memcpy's must be the same, or the preceeding one
- // must be larger than the following one.
- ConstantInt* C1 = dyn_cast<ConstantInt>(MDep->getLength());
- ConstantInt* C2 = dyn_cast<ConstantInt>(M->getLength());
- if (!C1 || !C2)
- return false;
-
- uint64_t CpySize = C1->getValue().getZExtValue();
- uint64_t DepSize = C2->getValue().getZExtValue();
-
- if (DepSize < CpySize)
- return false;
-
- // Finally, we have to make sure that the dest of the second does not
- // alias the source of the first
- AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
- if (AA.alias(M->getRawDest(), CpySize, MDep->getRawSource(), DepSize) !=
- AliasAnalysis::NoAlias)
- return false;
- else if (AA.alias(M->getRawDest(), CpySize, M->getRawSource(), CpySize) !=
- AliasAnalysis::NoAlias)
- return false;
- else if (AA.alias(MDep->getRawDest(), DepSize, MDep->getRawSource(), DepSize)
- != AliasAnalysis::NoAlias)
- return false;
-
- // If all checks passed, then we can transform these memcpy's
- Function* MemCpyFun = Intrinsic::getDeclaration(
- M->getParent()->getParent()->getParent(),
- M->getIntrinsicID());
-
- std::vector<Value*> args;
- args.push_back(M->getRawDest());
- args.push_back(MDep->getRawSource());
- args.push_back(M->getLength());
- args.push_back(M->getAlignment());
-
- CallInst* C = new CallInst(MemCpyFun, args.begin(), args.end(), "", M);
-
- MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();
- if (MD.getDependency(C) == MDep) {
- MD.dropInstruction(M);
- toErase.push_back(M);
- return true;
- } else {
- MD.removeInstruction(C);
- toErase.push_back(C);
- return false;
- }
-}
-