diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h index 70641ba25d2e..0af53c5b3f41 100644 --- a/llvm/include/llvm/IR/IRBuilder.h +++ b/llvm/include/llvm/IR/IRBuilder.h @@ -651,7 +651,7 @@ public: ArrayRef DeoptArgs, ArrayRef GCArgs, const Twine &Name = ""); - // Conveninence function for the common case when CallArgs are filled in using + // Convenience function for the common case when CallArgs are filled in using // makeArrayRef(CS.arg_begin(), CS.arg_end()); Use needs to be .get()'ed to // get the Value *. InvokeInst * @@ -675,32 +675,34 @@ public: Type *ResultType, const Twine &Name = ""); + /// Create a call to intrinsic \p ID with 1 operand which is mangled on its + /// type. + CallInst *CreateUnaryIntrinsic(Intrinsic::ID ID, Value *V, + Instruction *FMFSource = nullptr, + const Twine &Name = ""); + /// Create a call to intrinsic \p ID with 2 operands which is mangled on the /// first type. - CallInst *CreateBinaryIntrinsic(Intrinsic::ID ID, - Value *LHS, Value *RHS, + CallInst *CreateBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, + Instruction *FMFSource = nullptr, const Twine &Name = ""); - /// Create a call to intrinsic \p ID with no operands. - CallInst *CreateIntrinsic(Intrinsic::ID ID, - Instruction *FMFSource = nullptr, - const Twine &Name = ""); - - /// Create a call to intrinsic \p ID with 1 or more operands assuming the - /// intrinsic and all operands have the same type. If \p FMFSource is - /// provided, copy fast-math-flags from that instruction to the intrinsic. - CallInst *CreateIntrinsic(Intrinsic::ID ID, ArrayRef Args, + /// Create a call to intrinsic \p ID with \p args, mangled using \p Types. If + /// \p FMFSource is provided, copy fast-math-flags from that instruction to + /// the intrinsic. + CallInst *CreateIntrinsic(Intrinsic::ID ID, ArrayRef Types, + ArrayRef Args, Instruction *FMFSource = nullptr, const Twine &Name = ""); /// Create call to the minnum intrinsic. CallInst *CreateMinNum(Value *LHS, Value *RHS, const Twine &Name = "") { - return CreateBinaryIntrinsic(Intrinsic::minnum, LHS, RHS, Name); + return CreateBinaryIntrinsic(Intrinsic::minnum, LHS, RHS, nullptr, Name); } /// Create call to the maxnum intrinsic. CallInst *CreateMaxNum(Value *LHS, Value *RHS, const Twine &Name = "") { - return CreateBinaryIntrinsic(Intrinsic::maxnum, LHS, RHS, Name); + return CreateBinaryIntrinsic(Intrinsic::maxnum, LHS, RHS, nullptr, Name); } private: diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp index 91c950da71b5..a98189956770 100644 --- a/llvm/lib/IR/IRBuilder.cpp +++ b/llvm/lib/IR/IRBuilder.cpp @@ -731,28 +731,29 @@ CallInst *IRBuilderBase::CreateGCRelocate(Instruction *Statepoint, return createCallHelper(FnGCRelocate, Args, this, Name); } -CallInst *IRBuilderBase::CreateBinaryIntrinsic(Intrinsic::ID ID, - Value *LHS, Value *RHS, +CallInst *IRBuilderBase::CreateUnaryIntrinsic(Intrinsic::ID ID, Value *V, + Instruction *FMFSource, + const Twine &Name) { + Module *M = BB->getModule(); + Function *Fn = Intrinsic::getDeclaration(M, ID, {V->getType()}); + return createCallHelper(Fn, {V}, this, Name, FMFSource); +} + +CallInst *IRBuilderBase::CreateBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, + Value *RHS, + Instruction *FMFSource, const Twine &Name) { Module *M = BB->getModule(); Function *Fn = Intrinsic::getDeclaration(M, ID, { LHS->getType() }); - return createCallHelper(Fn, { LHS, RHS }, this, Name); -} - -CallInst *IRBuilderBase::CreateIntrinsic(Intrinsic::ID ID, - Instruction *FMFSource, - const Twine &Name) { - Module *M = BB->getModule(); - Function *Fn = Intrinsic::getDeclaration(M, ID); - return createCallHelper(Fn, {}, this, Name); + return createCallHelper(Fn, {LHS, RHS}, this, Name, FMFSource); } CallInst *IRBuilderBase::CreateIntrinsic(Intrinsic::ID ID, + ArrayRef Types, ArrayRef Args, Instruction *FMFSource, const Twine &Name) { - assert(!Args.empty() && "Expected at least one argument to intrinsic"); Module *M = BB->getModule(); - Function *Fn = Intrinsic::getDeclaration(M, ID, { Args.front()->getType() }); + Function *Fn = Intrinsic::getDeclaration(M, ID, Types); return createCallHelper(Fn, Args, this, Name, FMFSource); } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp index 6fcb92efb049..4dc1e67c573d 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp @@ -558,7 +558,7 @@ Value* AMDGPUCodeGenPrepare::expandDivRem24(IRBuilder<> &Builder, Value *FQM = Builder.CreateFMul(FA, RCP); // fq = trunc(fqm); - CallInst* FQ = Builder.CreateIntrinsic(Intrinsic::trunc, { FQM }); + CallInst *FQ = Builder.CreateUnaryIntrinsic(Intrinsic::trunc, FQM); FQ->copyFastMathFlags(Builder.getFastMathFlags()); // float fqneg = -fq; @@ -566,17 +566,17 @@ Value* AMDGPUCodeGenPrepare::expandDivRem24(IRBuilder<> &Builder, // float fr = mad(fqneg, fb, fa); Value *FR = Builder.CreateIntrinsic(Intrinsic::amdgcn_fmad_ftz, - { FQNeg, FB, FA }, FQ); + {FQNeg->getType()}, {FQNeg, FB, FA}, FQ); // int iq = (int)fq; Value *IQ = IsSigned ? Builder.CreateFPToSI(FQ, I32Ty) : Builder.CreateFPToUI(FQ, I32Ty); // fr = fabs(fr); - FR = Builder.CreateIntrinsic(Intrinsic::fabs, { FR }, FQ); + FR = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, FR, FQ); // fb = fabs(fb); - FB = Builder.CreateIntrinsic(Intrinsic::fabs, { FB }, FQ); + FB = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, FB, FQ); // int cv = fr >= fb; Value *CV = Builder.CreateFCmpOGE(FR, FB); diff --git a/llvm/lib/Target/AMDGPU/AMDGPULowerKernelArguments.cpp b/llvm/lib/Target/AMDGPU/AMDGPULowerKernelArguments.cpp index 2a25f1afa65c..fae1da923377 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPULowerKernelArguments.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPULowerKernelArguments.cpp @@ -83,8 +83,8 @@ bool AMDGPULowerKernelArguments::runOnFunction(Function &F) { return false; CallInst *KernArgSegment = - Builder.CreateIntrinsic(Intrinsic::amdgcn_kernarg_segment_ptr, nullptr, - F.getName() + ".kernarg.segment"); + Builder.CreateIntrinsic(Intrinsic::amdgcn_kernarg_segment_ptr, {}, {}, + nullptr, F.getName() + ".kernarg.segment"); KernArgSegment->addAttribute(AttributeList::ReturnIndex, Attribute::NonNull); KernArgSegment->addAttribute(AttributeList::ReturnIndex, diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index efe41b492746..4e404933a22b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -709,7 +709,7 @@ static Value *simplifyX86round(IntrinsicInst &II, } Intrinsic::ID ID = (RoundControl == 2) ? Intrinsic::ceil : Intrinsic::floor; - Value *Res = Builder.CreateIntrinsic(ID, {Src}, &II); + Value *Res = Builder.CreateUnaryIntrinsic(ID, Src, &II); if (!IsScalar) { if (auto *C = dyn_cast(Mask)) if (C->isAllOnesValue()) @@ -2038,7 +2038,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { // maxnum(-X, -Y) --> -(minnum(X, Y)) Intrinsic::ID NewIID = II->getIntrinsicID() == Intrinsic::maxnum ? Intrinsic::minnum : Intrinsic::maxnum; - Value *NewCall = Builder.CreateIntrinsic(NewIID, { X, Y }, II); + Value *NewCall = Builder.CreateBinaryIntrinsic(NewIID, X, Y, II); Instruction *FNeg = BinaryOperator::CreateFNeg(NewCall); FNeg->copyIRFlags(II); return FNeg; @@ -2116,8 +2116,8 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { Value *ExtSrc; if (match(II->getArgOperand(0), m_OneUse(m_FPExt(m_Value(ExtSrc))))) { // Narrow the call: intrinsic (fpext x) -> fpext (intrinsic x) - Value *NarrowII = Builder.CreateIntrinsic(II->getIntrinsicID(), - { ExtSrc }, II); + Value *NarrowII = + Builder.CreateUnaryIntrinsic(II->getIntrinsicID(), ExtSrc, II); return new FPExtInst(NarrowII, II->getType()); } break; @@ -2138,7 +2138,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { Value *X; if (match(II->getArgOperand(0), m_OneUse(m_FNeg(m_Value(X))))) { // sin(-x) --> -sin(x) - Value *NewSin = Builder.CreateIntrinsic(Intrinsic::sin, { X }, II); + Value *NewSin = Builder.CreateUnaryIntrinsic(Intrinsic::sin, X, II); Instruction *FNeg = BinaryOperator::CreateFNeg(NewSin); FNeg->copyFastMathFlags(II); return FNeg; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index f99dba49cb55..6427c818e029 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -433,7 +433,7 @@ Instruction *InstCombiner::visitFMul(BinaryOperator &I) { match(Op0, m_OneUse(m_Intrinsic(m_Value(X)))) && match(Op1, m_OneUse(m_Intrinsic(m_Value(Y))))) { Value *XY = Builder.CreateFMulFMF(X, Y, &I); - Value *Sqrt = Builder.CreateIntrinsic(Intrinsic::sqrt, { XY }, &I); + Value *Sqrt = Builder.CreateUnaryIntrinsic(Intrinsic::sqrt, XY, &I); return replaceInstUsesWith(I, Sqrt); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index f42deff74097..3d346dff2f8d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1751,7 +1751,7 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { match(TrueVal, m_FSub(m_PosZeroFP(), m_Specific(X)))) || (X == TrueVal && Pred == FCmpInst::FCMP_OGT && match(FalseVal, m_FSub(m_PosZeroFP(), m_Specific(X))))) { - Value *Fabs = Builder.CreateIntrinsic(Intrinsic::fabs, { X }, FCI); + Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X, FCI); return replaceInstUsesWith(SI, Fabs); } // With nsz: @@ -1764,7 +1764,7 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { (Pred == FCmpInst::FCMP_OLT || Pred == FCmpInst::FCMP_OLE)) || (X == TrueVal && match(FalseVal, m_FNeg(m_Specific(X))) && (Pred == FCmpInst::FCMP_OGT || Pred == FCmpInst::FCMP_OGE)))) { - Value *Fabs = Builder.CreateIntrinsic(Intrinsic::fabs, { X }, FCI); + Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, X, FCI); return replaceInstUsesWith(SI, Fabs); } } diff --git a/llvm/unittests/IR/IRBuilderTest.cpp b/llvm/unittests/IR/IRBuilderTest.cpp index 720967cb136d..42c0393d3821 100644 --- a/llvm/unittests/IR/IRBuilderTest.cpp +++ b/llvm/unittests/IR/IRBuilderTest.cpp @@ -51,10 +51,14 @@ protected: TEST_F(IRBuilderTest, Intrinsics) { IRBuilder<> Builder(BB); Value *V; + Instruction *I; CallInst *Call; IntrinsicInst *II; V = Builder.CreateLoad(GV); + I = cast(Builder.CreateFAdd(V, V)); + I->setHasNoInfs(true); + I->setHasNoNaNs(false); Call = Builder.CreateMinNum(V, V); II = cast(Call); @@ -64,9 +68,51 @@ TEST_F(IRBuilderTest, Intrinsics) { II = cast(Call); EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maxnum); - Call = Builder.CreateIntrinsic(Intrinsic::readcyclecounter); + Call = Builder.CreateIntrinsic(Intrinsic::readcyclecounter, {}, {}); II = cast(Call); EXPECT_EQ(II->getIntrinsicID(), Intrinsic::readcyclecounter); + + Call = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fabs); + EXPECT_FALSE(II->hasNoInfs()); + EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, V, I); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fabs); + EXPECT_TRUE(II->hasNoInfs()); + EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateBinaryIntrinsic(Intrinsic::pow, V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::pow); + EXPECT_FALSE(II->hasNoInfs()); + EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateBinaryIntrinsic(Intrinsic::pow, V, V, I); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::pow); + EXPECT_TRUE(II->hasNoInfs()); + EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma); + EXPECT_FALSE(II->hasNoInfs()); + EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}, I); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma); + EXPECT_TRUE(II->hasNoInfs()); + EXPECT_FALSE(II->hasNoNaNs()); + + Call = Builder.CreateIntrinsic(Intrinsic::fma, {V->getType()}, {V, V, V}, I); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma); + EXPECT_TRUE(II->hasNoInfs()); + EXPECT_FALSE(II->hasNoNaNs()); } TEST_F(IRBuilderTest, Lifetime) {