diff --git a/llvm/include/llvm/AutoUpgrade.h b/llvm/include/llvm/AutoUpgrade.h index e3a32b93c987..d0d8e95e3218 100644 --- a/llvm/include/llvm/AutoUpgrade.h +++ b/llvm/include/llvm/AutoUpgrade.h @@ -20,8 +20,10 @@ namespace llvm { class BasicBlock; /// This is a more granular function that simply checks an intrinsic function - /// for upgrading, and if it requires upgrading provides the new function. - Function* UpgradeIntrinsicFunction(Function *F); + /// for upgrading, and returns true if it requires upgrading. It may return + /// null in NewFn if the all calls to the original intrinsic function + /// should be transformed to non-function-call instructions. + bool UpgradeIntrinsicFunction(Function *F, Function *&NewFn); /// This is the complement to the above, replacing a specific call to an /// intrinsic function with a call to the specified new function. diff --git a/llvm/include/llvm/IntrinsicsX86.td b/llvm/include/llvm/IntrinsicsX86.td index 4a553afc128e..12e76339da42 100644 --- a/llvm/include/llvm/IntrinsicsX86.td +++ b/llvm/include/llvm/IntrinsicsX86.td @@ -460,6 +460,8 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse2_packuswb_128 : GCCBuiltin<"__builtin_ia32_packuswb128">, Intrinsic<[llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; + def int_x86_sse2_movl_dq : GCCBuiltin<"__builtin_ia32_movqv4si">, + Intrinsic<[llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; def int_x86_sse2_movmsk_pd : GCCBuiltin<"__builtin_ia32_movmskpd">, Intrinsic<[llvm_i32_ty, llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse2_pmovmskb_128 : GCCBuiltin<"__builtin_ia32_pmovmskb128">, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 4e761e402b85..19b7aa5b8197 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -873,7 +873,8 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) { // Look for intrinsic functions which need to be upgraded at some point for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); FI != FE; ++FI) { - if (Function* NewFn = UpgradeIntrinsicFunction(FI)) + Function* NewFn; + if (UpgradeIntrinsicFunction(FI, NewFn)) UpgradedIntrinsics.push_back(std::make_pair(FI, NewFn)); } diff --git a/llvm/lib/VMCore/AutoUpgrade.cpp b/llvm/lib/VMCore/AutoUpgrade.cpp index 005b1f8a239d..e2f61378b7cd 100644 --- a/llvm/lib/VMCore/AutoUpgrade.cpp +++ b/llvm/lib/VMCore/AutoUpgrade.cpp @@ -21,7 +21,7 @@ using namespace llvm; -static Function* UpgradeIntrinsicFunction1(Function *F) { +static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { assert(F && "Illegal to upgrade a non-existent Function."); // Get the Function's name. @@ -33,7 +33,7 @@ static Function* UpgradeIntrinsicFunction1(Function *F) { // Quickly eliminate it, if it's not a candidate. if (Name.length() <= 8 || Name[0] != 'l' || Name[1] != 'l' || Name[2] != 'v' || Name[3] != 'm' || Name[4] != '.') - return 0; + return false; Module *M = F->getParent(); switch (Name[5]) { @@ -49,7 +49,8 @@ static Function* UpgradeIntrinsicFunction1(Function *F) { if (delim != std::string::npos) { // Construct the new name as 'llvm.bswap' + '.i*' F->setName(Name.substr(0,10)+Name.substr(delim)); - return F; + NewFn = F; + return true; } } break; @@ -71,10 +72,11 @@ static Function* UpgradeIntrinsicFunction1(Function *F) { // Now construct the new intrinsic with the correct name and type. We // leave the old function around in order to query its type, whatever it // may be, and correctly convert up to the new type. - return cast(M->getOrInsertFunction(Name, - FTy->getParamType(0), - FTy->getParamType(0), - (Type *)0)); + NewFn = cast(M->getOrInsertFunction(Name, + FTy->getParamType(0), + FTy->getParamType(0), + (Type *)0)); + return true; } break; @@ -88,7 +90,8 @@ static Function* UpgradeIntrinsicFunction1(Function *F) { if (delim != std::string::npos) { // Construct a new name as 'llvm.part.select' + '.i*' F->setName(Name.substr(0,16)+Name.substr(delim)); - return F; + NewFn = F; + return true; } break; } @@ -105,7 +108,8 @@ static Function* UpgradeIntrinsicFunction1(Function *F) { Name.find('.',delim+1) != std::string::npos) { // Construct a new name as 'llvm.part.select' + '.i*.i*' F->setName(Name.substr(0,13)+Name.substr(delim)); - return F; + NewFn = F; + return true; } break; } @@ -137,12 +141,18 @@ static Function* UpgradeIntrinsicFunction1(Function *F) { // Now construct the new intrinsic with the correct name and type. We // leave the old function around in order to query its type, whatever it // may be, and correctly convert up to the new type. - return cast(M->getOrInsertFunction(Name, - FTy->getReturnType(), - FTy->getParamType(0), - VT, - (Type *)0)); + NewFn = cast(M->getOrInsertFunction(Name, + FTy->getReturnType(), + FTy->getParamType(0), + VT, + (Type *)0)); + return true; + } else if (Name.compare(5,16,"x86.sse2.movl.dq",16) == 0) { + // Calls to this intrinsic are transformed into ShuffleVector's. + NewFn = 0; + return true; } + break; } @@ -150,15 +160,16 @@ static Function* UpgradeIntrinsicFunction1(Function *F) { // to both detect an intrinsic which needs upgrading, and to provide the // upgraded form of the intrinsic. We should perhaps have two separate // functions for this. - return 0; + return false; } -Function* llvm::UpgradeIntrinsicFunction(Function *F) { - Function *Upgraded = UpgradeIntrinsicFunction1(F); +bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn) { + NewFn = 0; + bool Upgraded = UpgradeIntrinsicFunction1(F, NewFn); // Upgrade intrinsic attributes. This does not change the function. - if (Upgraded) - F = Upgraded; + if (NewFn) + F = NewFn; if (unsigned id = F->getIntrinsicID(true)) F->setParamAttrs(Intrinsic::getParamAttrs((Intrinsic::ID)id)); return Upgraded; @@ -168,11 +179,44 @@ Function* llvm::UpgradeIntrinsicFunction(Function *F) { // 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) { - assert(NewFn && "Cannot upgrade an intrinsic call without a new function."); - Function *F = CI->getCalledFunction(); assert(F && "CallInst has no function associated with it."); - + + if (!NewFn) { + switch(F->getIntrinsicID()) { + default: assert(0 && "Unknown function for CallInst upgrade."); + case Intrinsic::x86_sse2_movl_dq: { + std::vector Idxs; + 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); + ShuffleVectorInst *SI = new ShuffleVectorInst(ZeroV, CI->getOperand(1), + Mask, "upgraded", CI); + + // Handle any uses of the old CallInst. + if (!CI->use_empty()) + // Replace all uses of the old call with the new cast which has the + // correct type. + CI->replaceAllUsesWith(SI); + + // Clean up the old call now that it has been completely upgraded. + CI->eraseFromParent(); + break; + } + } + return; + } + switch(NewFn->getIntrinsicID()) { default: assert(0 && "Unknown function for CallInst upgrade."); case Intrinsic::x86_mmx_psll_d: @@ -257,7 +301,8 @@ void llvm::UpgradeCallsToIntrinsic(Function* F) { assert(F && "Illegal attempt to upgrade a non-existent intrinsic."); // Upgrade the function and check if it is a totaly new function. - if (Function* NewFn = UpgradeIntrinsicFunction(F)) { + Function* NewFn; + if (UpgradeIntrinsicFunction(F, NewFn)) { if (NewFn != F) { // Replace all uses to the old function with the new one if necessary. for (Value::use_iterator UI = F->use_begin(), UE = F->use_end(); diff --git a/llvm/test/Bitcode/sse2_movl_dq.ll b/llvm/test/Bitcode/sse2_movl_dq.ll new file mode 100644 index 000000000000..093d8213ed4a --- /dev/null +++ b/llvm/test/Bitcode/sse2_movl_dq.ll @@ -0,0 +1,2 @@ +; RUN: llvm-dis < %s.bc | not grep {i32 @llvm\\.movl.dq} +; RUN: llvm-dis < %s.bc | grep shufflevector diff --git a/llvm/test/Bitcode/sse2_movl_dq.ll.bc b/llvm/test/Bitcode/sse2_movl_dq.ll.bc new file mode 100644 index 000000000000..74d1826d2e1c Binary files /dev/null and b/llvm/test/Bitcode/sse2_movl_dq.ll.bc differ