+// UpgradeIntrinsicCall - Upgrade a call to an old intrinsic to be a call the
+// upgraded intrinsic. All argument and return casting must be provided in
+// order to seamlessly integrate with existing context.
+void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) {
+ Function *F = CI->getCalledFunction();
+ assert(F && "CallInst has no function associated with it.");
+
+ if (!NewFn) {
+ bool isLoadH = false, isLoadL = false, isMovL = false;
+ bool isMovSD = false, isShufPD = false;
+ bool isUnpckhPD = false, isUnpcklPD = false;
+ bool isPunpckhQPD = false, isPunpcklQPD = false;
+ if (strcmp(F->getNameStart(), "llvm.x86.sse2.loadh.pd") == 0)
+ isLoadH = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.loadl.pd") == 0)
+ isLoadL = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.movl.dq") == 0)
+ isMovL = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.movs.d") == 0)
+ isMovSD = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.shuf.pd") == 0)
+ isShufPD = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.unpckh.pd") == 0)
+ isUnpckhPD = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.unpckl.pd") == 0)
+ isUnpcklPD = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.punpckh.qdq") == 0)
+ isPunpckhQPD = true;
+ else if (strcmp(F->getNameStart(), "llvm.x86.sse2.punpckl.qdq") == 0)
+ isPunpcklQPD = true;
+
+ if (isLoadH || isLoadL || isMovL || isMovSD || isShufPD ||
+ isUnpckhPD || isUnpcklPD || isPunpckhQPD || isPunpcklQPD) {
+ std::vector<Constant*> Idxs;
+ Value *Op0 = CI->getOperand(1);
+ ShuffleVectorInst *SI = NULL;
+ if (isLoadH || isLoadL) {
+ Value *Op1 = UndefValue::get(Op0->getType());
+ Value *Addr = new BitCastInst(CI->getOperand(2),
+ PointerType::getUnqual(Type::DoubleTy),
+ "upgraded.", CI);
+ Value *Load = new LoadInst(Addr, "upgraded.", false, 8, CI);
+ Value *Idx = ConstantInt::get(Type::Int32Ty, 0);
+ Op1 = InsertElementInst::Create(Op1, Load, Idx, "upgraded.", CI);
+
+ if (isLoadH) {
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 0));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 2));
+ } else {
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 2));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 1));
+ }
+ Value *Mask = ConstantVector::get(Idxs);
+ SI = new ShuffleVectorInst(Op0, Op1, Mask, "upgraded.", CI);
+ } else if (isMovL) {
+ Constant *Zero = ConstantInt::get(Type::Int32Ty, 0);
+ Idxs.push_back(Zero);
+ Idxs.push_back(Zero);
+ Idxs.push_back(Zero);
+ Idxs.push_back(Zero);
+ Value *ZeroV = ConstantVector::get(Idxs);
+
+ Idxs.clear();
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 4));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 5));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 2));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 3));
+ Value *Mask = ConstantVector::get(Idxs);
+ SI = new ShuffleVectorInst(ZeroV, Op0, Mask, "upgraded.", CI);
+ } else if (isMovSD ||
+ isUnpckhPD || isUnpcklPD || isPunpckhQPD || isPunpcklQPD) {
+ Value *Op1 = CI->getOperand(2);
+ if (isMovSD) {
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 2));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 1));
+ } else if (isUnpckhPD || isPunpckhQPD) {
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 1));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 3));
+ } else {
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 0));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, 2));
+ }
+ Value *Mask = ConstantVector::get(Idxs);
+ SI = new ShuffleVectorInst(Op0, Op1, Mask, "upgraded.", CI);
+ } else if (isShufPD) {
+ Value *Op1 = CI->getOperand(2);
+ unsigned MaskVal = cast<ConstantInt>(CI->getOperand(3))->getZExtValue();
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, MaskVal & 1));
+ Idxs.push_back(ConstantInt::get(Type::Int32Ty, ((MaskVal >> 1) & 1)+2));
+ Value *Mask = ConstantVector::get(Idxs);
+ SI = new ShuffleVectorInst(Op0, Op1, Mask, "upgraded.", CI);
+ }