#include "llvm/AutoUpgrade.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
+#include "llvm/IRBuilder.h"
#include "llvm/Instruction.h"
+#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
-#include "llvm/IntrinsicInst.h"
-#include "llvm/Support/CallSite.h"
#include "llvm/Support/CFG.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/IRBuilder.h"
#include <cstring>
using namespace llvm;
+// Upgrade the declarations of the SSE4.1 functions whose arguments have
+// changed their type from v4f32 to v2i64.
+static bool UpgradeSSE41Function(Function* F, Intrinsic::ID IID,
+ Function *&NewFn) {
+ // Check whether this is an old version of the function, which received
+ // v4f32 arguments.
+ Type *Arg0Type = F->getFunctionType()->getParamType(0);
+ if (Arg0Type != VectorType::get(Type::getFloatTy(F->getContext()), 4))
+ return false;
+
+ // Yes, it's old, replace it with new version.
+ F->setName(F->getName() + ".old");
+ NewFn = Intrinsic::getDeclaration(F->getParent(), IID);
+ return true;
+}
static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
assert(F && "Illegal to upgrade a non-existent Function.");
switch (Name[0]) {
default: break;
+ case 'a': {
+ if (Name.startswith("arm.neon.vclz")) {
+ Type* args[2] = {
+ F->arg_begin()->getType(),
+ Type::getInt1Ty(F->getContext())
+ };
+ // Can't use Intrinsic::getDeclaration here as it adds a ".i1" to
+ // the end of the name. Change name from llvm.arm.neon.vclz.* to
+ // llvm.ctlz.*
+ FunctionType* fType = FunctionType::get(F->getReturnType(), args, false);
+ NewFn = Function::Create(fType, F->getLinkage(),
+ "llvm.ctlz." + Name.substr(14), F->getParent());
+ return true;
+ }
+ if (Name.startswith("arm.neon.vcnt")) {
+ NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctpop,
+ F->arg_begin()->getType());
+ return true;
+ }
+ break;
+ }
case 'c': {
if (Name.startswith("ctlz.") && F->arg_size() == 1) {
F->setName(Name + ".old");
Name.startswith("x86.avx.vpermil.") ||
Name == "x86.avx.movnt.dq.256" ||
Name == "x86.avx.movnt.pd.256" ||
- Name == "x86.avx.movnt.ps.256") {
+ Name == "x86.avx.movnt.ps.256" ||
+ (Name.startswith("x86.xop.vpcom") && F->arg_size() == 2)) {
NewFn = 0;
return true;
}
+ // SSE4.1 ptest functions may have an old signature.
+ if (Name.startswith("x86.sse41.ptest")) {
+ if (Name == "x86.sse41.ptestc")
+ return UpgradeSSE41Function(F, Intrinsic::x86_sse41_ptestc, NewFn);
+ if (Name == "x86.sse41.ptestz")
+ return UpgradeSSE41Function(F, Intrinsic::x86_sse41_ptestz, NewFn);
+ if (Name == "x86.sse41.ptestnzc")
+ return UpgradeSSE41Function(F, Intrinsic::x86_sse41_ptestnzc, NewFn);
+ }
+ // frcz.ss/sd may need to have an argument dropped
+ if (Name.startswith("x86.xop.vfrcz.ss") && F->arg_size() == 2) {
+ F->setName(Name + ".old");
+ NewFn = Intrinsic::getDeclaration(F->getParent(),
+ Intrinsic::x86_xop_vfrcz_ss);
+ return true;
+ }
+ if (Name.startswith("x86.xop.vfrcz.sd") && F->arg_size() == 2) {
+ F->setName(Name + ".old");
+ NewFn = Intrinsic::getDeclaration(F->getParent(),
+ Intrinsic::x86_xop_vfrcz_sd);
+ return true;
+ }
// Fix the FMA4 intrinsics to remove the 4
if (Name.startswith("x86.fma4.")) {
- const char* NewFnName = 0;
- if (Name == "x86.fma4.vfmadd.ss")
- NewFnName = "llvm.x86.fma.vfmadd.ss";
- else if (Name == "x86.fma4.vfmadd.sd")
- NewFnName = "llvm.x86.fma.vfmadd.sd";
- else if (Name == "x86.fma4.vfmadd.ps")
- NewFnName = "llvm.x86.fma.vfmadd.ps";
- else if (Name == "x86.fma4.vfmadd.pd")
- NewFnName = "llvm.x86.fma.vfmadd.pd";
- else if (Name == "x86.fma4.vfmadd.ps.256")
- NewFnName = "llvm.x86.fma.vfmadd.ps.256";
- else if (Name == "x86.fma4.vfmadd.pd.256")
- NewFnName = "llvm.x86.fma.vfmadd.pd.256";
- else if (Name == "x86.fma4.vfmsub.ss")
- NewFnName = "llvm.x86.fma.vfmsub.ss";
- else if (Name == "x86.fma4.vfmsub.sd")
- NewFnName = "llvm.x86.fma.vfmsub.sd";
- else if (Name == "x86.fma4.vfmsub.ps")
- NewFnName = "llvm.x86.fma.vfmsub.ps";
- else if (Name == "x86.fma4.vfmsub.pd")
- NewFnName = "llvm.x86.fma.vfmsub.pd";
- else if (Name == "x86.fma4.vfmsub.ps.256")
- NewFnName = "llvm.x86.fma.vfmsub.ps.256";
- else if (Name == "x86.fma4.vfmsub.pd.256")
- NewFnName = "llvm.x86.fma.vfmsub.pd.256";
- else if (Name == "x86.fma4.vfnmadd.ss")
- NewFnName = "llvm.x86.fma.vfnmadd.ss";
- else if (Name == "x86.fma4.vfnmadd.sd")
- NewFnName = "llvm.x86.fma.vfnmadd.sd";
- else if (Name == "x86.fma4.vfnmadd.ps")
- NewFnName = "llvm.x86.fma.vfnmadd.ps";
- else if (Name == "x86.fma4.vfnmadd.pd")
- NewFnName = "llvm.x86.fma.vfnmadd.pd";
- else if (Name == "x86.fma4.vfnmadd.ps.256")
- NewFnName = "llvm.x86.fma.vfnmadd.ps.256";
- else if (Name == "x86.fma4.vfnmadd.pd.256")
- NewFnName = "llvm.x86.fma.vfnmadd.pd.256";
- else if (Name == "x86.fma4.vfnmsub.ss")
- NewFnName = "llvm.x86.fma.vfnmsub.ss";
- else if (Name == "x86.fma4.vfnmsub.sd")
- NewFnName = "llvm.x86.fma.vfnmsub.sd";
- else if (Name == "x86.fma4.vfnmsub.ps")
- NewFnName = "llvm.x86.fma.vfnmsub.ps";
- else if (Name == "x86.fma4.vfnmsub.pd")
- NewFnName = "llvm.x86.fma.vfnmsub.pd";
- else if (Name == "x86.fma4.vfnmsub.ps.256")
- NewFnName = "llvm.x86.fma.vfnmsub.ps.256";
- else if (Name == "x86.fma4.vfnmsub.pd.256")
- NewFnName = "llvm.x86.fma.vfnmsub.pd.256";
- else if (Name == "x86.fma4.vfmaddsub.ps")
- NewFnName = "llvm.x86.fma.vfmaddsub.ps";
- else if (Name == "x86.fma4.vfmaddsub.pd")
- NewFnName = "llvm.x86.fma.vfmaddsub.pd";
- else if (Name == "x86.fma4.vfmaddsub.ps.256")
- NewFnName = "llvm.x86.fma.vfmaddsub.ps.256";
- else if (Name == "x86.fma4.vfmaddsub.pd.256")
- NewFnName = "llvm.x86.fma.vfmaddsub.pd.256";
- else if (Name == "x86.fma4.vfmsubadd.ps")
- NewFnName = "llvm.x86.fma.vfmsubadd.ps";
- else if (Name == "x86.fma4.vfmsubadd.pd")
- NewFnName = "llvm.x86.fma.vfmsubadd.pd";
- else if (Name == "x86.fma4.vfmsubadd.ps.256")
- NewFnName = "llvm.x86.fma.vfmsubadd.ps.256";
- else if (Name == "x86.fma4.vfmsubadd.pd.256")
- NewFnName = "llvm.x86.fma.vfmsubadd.pd.256";
-
- if (NewFnName) {
- F->setName(NewFnName);
- NewFn = F;
- return true;
- }
+ F->setName("llvm.x86.fma" + Name.substr(8));
+ NewFn = F;
+ return true;
}
break;
}
}
- // This may not belong here. This function is effectively being overloaded
- // to both detect an intrinsic which needs upgrading, and to provide the
- // upgraded form of the intrinsic. We should perhaps have two separate
+ // This may not belong here. This function is effectively being overloaded
+ // 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 false;
}
if (NewFn)
F = NewFn;
if (unsigned id = F->getIntrinsicID())
- F->setAttributes(Intrinsic::getAttributes((Intrinsic::ID)id));
+ F->setAttributes(Intrinsic::getAttributes(F->getContext(),
+ (Intrinsic::ID)id));
return Upgraded;
}
return false;
}
-// UpgradeIntrinsicCall - Upgrade a call to an old intrinsic to be a call the
-// upgraded intrinsic. All argument and return casting must be provided in
+// 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();
// Remove intrinsic.
CI->eraseFromParent();
return;
+ } else if (Name.startswith("llvm.x86.xop.vpcom")) {
+ Intrinsic::ID intID;
+ if (Name.endswith("ub"))
+ intID = Intrinsic::x86_xop_vpcomub;
+ else if (Name.endswith("uw"))
+ intID = Intrinsic::x86_xop_vpcomuw;
+ else if (Name.endswith("ud"))
+ intID = Intrinsic::x86_xop_vpcomud;
+ else if (Name.endswith("uq"))
+ intID = Intrinsic::x86_xop_vpcomuq;
+ else if (Name.endswith("b"))
+ intID = Intrinsic::x86_xop_vpcomb;
+ else if (Name.endswith("w"))
+ intID = Intrinsic::x86_xop_vpcomw;
+ else if (Name.endswith("d"))
+ intID = Intrinsic::x86_xop_vpcomd;
+ else if (Name.endswith("q"))
+ intID = Intrinsic::x86_xop_vpcomq;
+ else
+ llvm_unreachable("Unknown suffix");
+
+ Name = Name.substr(18); // strip off "llvm.x86.xop.vpcom"
+ unsigned Imm;
+ if (Name.startswith("lt"))
+ Imm = 0;
+ else if (Name.startswith("le"))
+ Imm = 1;
+ else if (Name.startswith("gt"))
+ Imm = 2;
+ else if (Name.startswith("ge"))
+ Imm = 3;
+ else if (Name.startswith("eq"))
+ Imm = 4;
+ else if (Name.startswith("ne"))
+ Imm = 5;
+ else if (Name.startswith("true"))
+ Imm = 6;
+ else if (Name.startswith("false"))
+ Imm = 7;
+ else
+ llvm_unreachable("Unknown condition");
+
+ Function *VPCOM = Intrinsic::getDeclaration(F->getParent(), intID);
+ Rep = Builder.CreateCall3(VPCOM, CI->getArgOperand(0),
+ CI->getArgOperand(1), Builder.getInt8(Imm));
} else {
bool PD128 = false, PD256 = false, PS128 = false, PS256 = false;
if (Name == "llvm.x86.avx.vpermil.pd.256")
return;
}
+ std::string Name = CI->getName().str();
+ CI->setName(Name + ".old");
+
switch (NewFn->getIntrinsicID()) {
default:
llvm_unreachable("Unknown function for CallInst upgrade.");
case Intrinsic::cttz:
assert(CI->getNumArgOperands() == 1 &&
"Mismatch between function args and call args");
- StringRef Name = CI->getName();
- CI->setName(Name + ".old");
CI->replaceAllUsesWith(Builder.CreateCall2(NewFn, CI->getArgOperand(0),
Builder.getFalse(), Name));
CI->eraseFromParent();
return;
+
+ case Intrinsic::arm_neon_vclz: {
+ // Change name from llvm.arm.neon.vclz.* to llvm.ctlz.*
+ CI->replaceAllUsesWith(Builder.CreateCall2(NewFn, CI->getArgOperand(0),
+ Builder.getFalse(),
+ "llvm.ctlz." + Name.substr(14)));
+ CI->eraseFromParent();
+ return;
+ }
+ case Intrinsic::ctpop: {
+ CI->replaceAllUsesWith(Builder.CreateCall(NewFn, CI->getArgOperand(0)));
+ CI->eraseFromParent();
+ return;
+ }
+
+ case Intrinsic::x86_xop_vfrcz_ss:
+ case Intrinsic::x86_xop_vfrcz_sd:
+ CI->replaceAllUsesWith(Builder.CreateCall(NewFn, CI->getArgOperand(1),
+ Name));
+ CI->eraseFromParent();
+ return;
+
+ case Intrinsic::x86_sse41_ptestc:
+ case Intrinsic::x86_sse41_ptestz:
+ case Intrinsic::x86_sse41_ptestnzc: {
+ // The arguments for these intrinsics used to be v4f32, and changed
+ // to v2i64. This is purely a nop, since those are bitwise intrinsics.
+ // So, the only thing required is a bitcast for both arguments.
+ // First, check the arguments have the old type.
+ Value *Arg0 = CI->getArgOperand(0);
+ if (Arg0->getType() != VectorType::get(Type::getFloatTy(C), 4))
+ return;
+
+ // Old intrinsic, add bitcasts
+ Value *Arg1 = CI->getArgOperand(1);
+
+ Value *BC0 =
+ Builder.CreateBitCast(Arg0,
+ VectorType::get(Type::getInt64Ty(C), 2),
+ "cast");
+ Value *BC1 =
+ Builder.CreateBitCast(Arg1,
+ VectorType::get(Type::getInt64Ty(C), 2),
+ "cast");
+
+ CallInst* NewCall = Builder.CreateCall2(NewFn, BC0, BC1, Name);
+ CI->replaceAllUsesWith(NewCall);
+ CI->eraseFromParent();
+ return;
+ }
}
}