/// Upgrade a call to an old intrinsic. All argument and return casting must be
/// provided to seamlessly integrate with existing context.
void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) {
- Function *F = CI->getCalledFunction();
+ // Note dyn_cast to Function is not quite the same as getCalledFunction, which
+ // checks the callee's function type matches. It's likely we need to handle
+ // type changes here.
+ Function *F = dyn_cast<Function>(CI->getCalledOperand());
+ if (!F)
+ return;
+
LLVMContext &C = CI->getContext();
IRBuilder<> Builder(C);
Builder.SetInsertPoint(CI->getParent(), CI->getIterator());
- assert(F && "Intrinsic call is not direct?");
-
if (!NewFn) {
// Get the Function's name.
StringRef Name = F->getName();
}
// This must be an upgrade from a named to a literal struct.
- auto *OldST = cast<StructType>(CI->getType());
- assert(OldST != NewFn->getReturnType() && "Return type must have changed");
- assert(OldST->getNumElements() ==
- cast<StructType>(NewFn->getReturnType())->getNumElements() &&
- "Must have same number of elements");
-
- SmallVector<Value *> Args(CI->args());
- Value *NewCI = Builder.CreateCall(NewFn, Args);
- Value *Res = PoisonValue::get(OldST);
- for (unsigned Idx = 0; Idx < OldST->getNumElements(); ++Idx) {
- Value *Elem = Builder.CreateExtractValue(NewCI, Idx);
- Res = Builder.CreateInsertValue(Res, Elem, Idx);
+ if (auto *OldST = dyn_cast<StructType>(CI->getType())) {
+ assert(OldST != NewFn->getReturnType() &&
+ "Return type must have changed");
+ assert(OldST->getNumElements() ==
+ cast<StructType>(NewFn->getReturnType())->getNumElements() &&
+ "Must have same number of elements");
+
+ SmallVector<Value *> Args(CI->args());
+ Value *NewCI = Builder.CreateCall(NewFn, Args);
+ Value *Res = PoisonValue::get(OldST);
+ for (unsigned Idx = 0; Idx < OldST->getNumElements(); ++Idx) {
+ Value *Elem = Builder.CreateExtractValue(NewCI, Idx);
+ Res = Builder.CreateInsertValue(Res, Elem, Idx);
+ }
+ CI->replaceAllUsesWith(Res);
+ CI->eraseFromParent();
+ return;
}
- CI->replaceAllUsesWith(Res);
- CI->eraseFromParent();
+
+ // We're probably about to produce something invalid. Let the verifier catch
+ // it instead of dying here.
+ CI->setCalledOperand(
+ ConstantExpr::getPointerCast(NewFn, CI->getCalledOperand()->getType()));
return;
};
CallInst *NewCall = nullptr;