https://github.com/kito-cheng updated https://github.com/llvm/llvm-project/pull/194616
>From 956c8941cb561f5b0d5a571a2ebb4efcb9314dc4 Mon Sep 17 00:00:00 2001 From: Kito Cheng <[email protected]> Date: Tue, 28 Apr 2026 21:20:25 +0800 Subject: [PATCH 1/3] Reland "[InstCombine] Combine llvm.sin/llvm.cos libcall pairs into llvm.sincos" This reland #184760 it fix https://lab.llvm.org/buildbot/#/builders/123/builds/39337 The root cause is new created llvm.sincos is inserted into the right after of the sin/cos's argument, however we didn't check if it's PHI, it may cause it inserted into the middle of PHIs, and then fail the verification. Teach InstCombine to recognize pairs of `llvm.sin(x)` and `llvm.cos(x)` intrinsic calls that share the same argument and replace them with a single `llvm.sincos(x)` call, extracting the individual results. The optimization works in two phases: 1. **SimplifyLibCalls**: Convert `sin`/`cos` C library calls (e.g. `sinf`, `cosf`, `sin`, `cos`, `sinl`, `cosl`) into `llvm.sin` / `llvm.cos` intrinsics when the call does not access memory (i.e. does not set `errno`). This normalization step brings library calls into the same form as compiler-generated intrinsics. 2. **InstCombineCalls**: When visiting an `llvm.sin` or `llvm.cos` intrinsic, scan the users of the shared argument for a matching counterpart. If found, emit a single `llvm.sincos` call placed right after the argument definition, replace both original calls, and erase the matched instruction. Also remove the completed sincos TODO from Target/README.txt. --- clang/test/CodeGenOpenCL/builtins-f16.cl | 19 +- llvm/lib/Target/README.txt | 15 - .../InstCombine/InstCombineCalls.cpp | 67 +++ .../lib/Transforms/Utils/SimplifyLibCalls.cpp | 22 +- .../test/Transforms/InstCombine/AMDGPU/tan.ll | 3 +- .../Transforms/InstCombine/fdiv-cos-sin.ll | 50 ++- .../Transforms/InstCombine/fdiv-sin-cos.ll | 40 +- .../Transforms/InstCombine/may-alias-errno.ll | 4 +- .../Transforms/InstCombine/sincos-fpmath.ll | 77 ++++ llvm/test/Transforms/InstCombine/sincos.ll | 421 ++++++++++++++++++ 10 files changed, 662 insertions(+), 56 deletions(-) create mode 100644 llvm/test/Transforms/InstCombine/sincos-fpmath.ll create mode 100644 llvm/test/Transforms/InstCombine/sincos.ll diff --git a/clang/test/CodeGenOpenCL/builtins-f16.cl b/clang/test/CodeGenOpenCL/builtins-f16.cl index f30ed0a1944ff..a534cf5e9050f 100644 --- a/clang/test/CodeGenOpenCL/builtins-f16.cl +++ b/clang/test/CodeGenOpenCL/builtins-f16.cl @@ -27,9 +27,6 @@ void test_half_builtins(half h0, half h1, half h2, int i0) { // CHECK: call half @llvm.ceil.f16(half %h0) res = __builtin_ceilf16(h0); - // CHECK: call half @llvm.cos.f16(half %h0) - res = __builtin_cosf16(h0); - // CHECK: call half @llvm.cosh.f16(half %h0) res = __builtin_coshf16(h0); @@ -75,9 +72,6 @@ void test_half_builtins(half h0, half h1, half h2, int i0) { // CHECK: call half @llvm.round.f16(half %h0) res = __builtin_roundf16(h0); - // CHECK: call half @llvm.sin.f16(half %h0) - res = __builtin_sinf16(h0); - // CHECK: call half @llvm.sinh.f16(half %h0) res = __builtin_sinhf16(h0); @@ -99,3 +93,16 @@ void test_half_builtins(half h0, half h1, half h2, int i0) { // CHECK: call half @llvm.ldexp.f16.i32(half %h0, i32 %i0) res = __builtin_ldexpf16(h0, i0); } + +// sin and cos are split into separate functions to avoid sincos combining. +// CHECK-LABEL: define{{.*}} half @test_half_sin +// CHECK: call half @llvm.sin.f16(half %h0) +half test_half_sin(half h0) { + return __builtin_sinf16(h0); +} + +// CHECK-LABEL: define{{.*}} half @test_half_cos +// CHECK: call half @llvm.cos.f16(half %h0) +half test_half_cos(half h0) { + return __builtin_cosf16(h0); +} diff --git a/llvm/lib/Target/README.txt b/llvm/lib/Target/README.txt index adf75c3368677..4d98a5fac3984 100644 --- a/llvm/lib/Target/README.txt +++ b/llvm/lib/Target/README.txt @@ -132,21 +132,6 @@ emit: //===---------------------------------------------------------------------===// -Combine: a = sin(x), b = cos(x) into a,b = sincos(x). - -Expand these to calls of sin/cos and stores: - double sincos(double x, double *sin, double *cos); - float sincosf(float x, float *sin, float *cos); - long double sincosl(long double x, long double *sin, long double *cos); - -Doing so could allow SROA of the destination pointers. See also: -http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17687 - -This is now easily doable with MRVs. We could even make an intrinsic for this -if anyone cared enough about sincos. - -//===---------------------------------------------------------------------===// - quantum_sigma_x in 462.libquantum contains the following loop: for(i=0; i<reg->size; i++) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 131982ad7c1d2..ec5deea9f454d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1881,6 +1881,65 @@ static Instruction *foldNeonShift(IntrinsicInst *II, InstCombinerImpl &IC) { return IC.replaceInstUsesWith(*II, Result); } +// If II is llvm.sin(x) or llvm.cos(x), and there is a matching +// llvm.cos(x) or llvm.sin(x) using the same argument, combine them +// into a single llvm.sincos(x) call. Returns the result for II +// extracted from sincos, or nullptr if no match is found. +static Value *foldSinAndCosToSinCos(IntrinsicInst *II, IRBuilderBase &B, + InstCombinerImpl &IC) { + Intrinsic::ID IID = II->getIntrinsicID(); + bool IsSin = IID == Intrinsic::sin; + Intrinsic::ID MatchID = IsSin ? Intrinsic::cos : Intrinsic::sin; + + Value *Arg = II->getArgOperand(0); + + // Don't bother looking through uses of constants. + if (isa<Constant>(Arg)) + return nullptr; + + // Look for a matching cos/sin intrinsic with the same argument. + IntrinsicInst *Match = nullptr; + for (User *U : Arg->users()) { + if (auto *Cand = dyn_cast<IntrinsicInst>(U)) { + if (Cand != II && !Cand->use_empty() && + Cand->getIntrinsicID() == MatchID) { + Match = Cand; + break; + } + } + } + + if (!Match) + return nullptr; + + // Insert sincos right after the argument definition. + IRBuilderBase::InsertPointGuard Guard(B); + if (auto *ArgInst = dyn_cast<Instruction>(Arg)) + B.SetInsertPoint(ArgInst->getParent(), std::next(ArgInst->getIterator())); + else { + BasicBlock &EntryBB = II->getFunction()->getEntryBlock(); + B.SetInsertPoint(&EntryBB, EntryBB.begin()); + } + + Function *SinCosFunc = Intrinsic::getOrInsertDeclaration( + II->getModule(), Intrinsic::sincos, Arg->getType()); + CallInst *SinCos = B.CreateCall(SinCosFunc, Arg, "sincos"); + // Intersect fast-math flags from the two calls. + SinCos->setFastMathFlags(II->getFastMathFlags() & Match->getFastMathFlags()); + // Propagate the most-generic fpmath metadata from the two original calls. + if (MDNode *MD = MDNode::getMostGenericFPMath( + II->getMetadata(LLVMContext::MD_fpmath), + Match->getMetadata(LLVMContext::MD_fpmath))) + SinCos->setMetadata(LLVMContext::MD_fpmath, MD); + Value *Sin = B.CreateExtractValue(SinCos, 0, "sin"); + Value *Cos = B.CreateExtractValue(SinCos, 1, "cos"); + + // Replace the matching call and erase it. + IC.replaceInstUsesWith(*Match, IsSin ? Cos : Sin); + IC.eraseInstFromFunction(*Match); + return IsSin ? Sin : Cos; +} + /// CallInst simplification. This mostly only handles folding of intrinsic /// instructions. For normal calls, it allows visitCallBase to do the heavy /// lifting. @@ -3181,6 +3240,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { // for f in {cos, cosh} return replaceOperand(*II, 0, X); } + if (IID == Intrinsic::cos) { + if (Value *Result = foldSinAndCosToSinCos(II, Builder, *this)) + return replaceInstUsesWith(*II, Result); + } break; } case Intrinsic::sin: @@ -3195,6 +3258,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { Value *NewFunc = Builder.CreateUnaryIntrinsic(IID, X, II); return UnaryOperator::CreateFNegFMF(NewFunc, II); } + if (IID == Intrinsic::sin) { + if (Value *Result = foldSinAndCosToSinCos(II, Builder, *this)) + return replaceInstUsesWith(*II, Result); + } break; } case Intrinsic::ldexp: { diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index b60f0c7021d51..fdb142f5af350 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -4043,6 +4043,16 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI, case LibFunc_cospif: case LibFunc_cospi: return optimizeSinCosPi(CI, /*IsSin*/false, Builder); + case LibFunc_sinf: + case LibFunc_sinl: + if (CI->doesNotAccessMemory()) + return replaceUnaryCall(CI, Builder, Intrinsic::sin); + return nullptr; + case LibFunc_cosf: + case LibFunc_cosl: + if (CI->doesNotAccessMemory()) + return replaceUnaryCall(CI, Builder, Intrinsic::cos); + return nullptr; case LibFunc_powf: case LibFunc_pow: case LibFunc_powl: @@ -4109,6 +4119,16 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI, return replaceUnaryCall(CI, Builder, Intrinsic::rint); case LibFunc_trunc: return replaceUnaryCall(CI, Builder, Intrinsic::trunc); + case LibFunc_sin: + case LibFunc_cos: + if (UnsafeFPShrink && + hasFloatVersion(M, CI->getCalledFunction()->getName())) + if (Value *V = optimizeUnaryDoubleFP(CI, Builder, TLI, true)) + return V; + if (CI->doesNotAccessMemory()) + return replaceUnaryCall( + CI, Builder, Func == LibFunc_sin ? Intrinsic::sin : Intrinsic::cos); + return nullptr; case LibFunc_acos: case LibFunc_acosh: case LibFunc_asin: @@ -4117,8 +4137,6 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI, case LibFunc_exp: case LibFunc_exp10: case LibFunc_expm1: - case LibFunc_cos: - case LibFunc_sin: case LibFunc_tanh: if (UnsafeFPShrink && hasFloatVersion(M, CI->getCalledFunction()->getName())) return optimizeUnaryDoubleFP(CI, Builder, TLI, true); diff --git a/llvm/test/Transforms/InstCombine/AMDGPU/tan.ll b/llvm/test/Transforms/InstCombine/AMDGPU/tan.ll index 62160a6d3063a..f8103f0cc229b 100644 --- a/llvm/test/Transforms/InstCombine/AMDGPU/tan.ll +++ b/llvm/test/Transforms/InstCombine/AMDGPU/tan.ll @@ -3,8 +3,7 @@ ; Check that sin/cos is not folded to tan on amdgcn. ; GCN-LABEL: define amdgpu_ps float @llpc.shader.FS.main -; GCN: call float @llvm.sin.f32 -; GCN: call float @llvm.cos.f32 +; GCN: call { float, float } @llvm.sincos.f32 declare float @llvm.sin.f32(float) #0 declare float @llvm.cos.f32(float) #0 diff --git a/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll b/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll index 6d945ede3b387..2450f4b54dcab 100644 --- a/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll +++ b/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll @@ -3,8 +3,9 @@ define double @fdiv_cos_sin(double %a) { ; CHECK-LABEL: @fdiv_cos_sin( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret double [[DIV]] ; @@ -16,8 +17,9 @@ define double @fdiv_cos_sin(double %a) { define double @fdiv_strict_cos_strict_sin_reassoc(double %a) { ; CHECK-LABEL: @fdiv_strict_cos_strict_sin_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret double [[DIV]] ; @@ -29,8 +31,10 @@ define double @fdiv_strict_cos_strict_sin_reassoc(double %a) { define double @fdiv_reassoc_cos_strict_sin_strict(double %a, ptr dereferenceable(2) %dummy) { ; CHECK-LABEL: @fdiv_reassoc_cos_strict_sin_strict( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1:[0-9]+]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]] +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[COS]], [[SIN]] ; CHECK-NEXT: ret double [[DIV]] ; %1 = call double @llvm.cos.f64(double %a) @@ -41,8 +45,10 @@ define double @fdiv_reassoc_cos_strict_sin_strict(double %a, ptr dereferenceable define double @fdiv_reassoc_cos_reassoc_sin_strict(double %a) { ; CHECK-LABEL: @fdiv_reassoc_cos_reassoc_sin_strict( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]] +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[COS]], [[SIN]] ; CHECK-NEXT: ret double [[DIV]] ; %1 = call reassoc double @llvm.cos.f64(double %a) @@ -53,8 +59,9 @@ define double @fdiv_reassoc_cos_reassoc_sin_strict(double %a) { define double @fdiv_cos_sin_reassoc_multiple_uses(double %a) { ; CHECK-LABEL: @fdiv_cos_sin_reassoc_multiple_uses( -; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.cos.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use(double [[TMP2]]) ; CHECK-NEXT: ret double [[DIV]] @@ -68,8 +75,10 @@ define double @fdiv_cos_sin_reassoc_multiple_uses(double %a) { define double @fdiv_cos_sin_reassoc(double %a) { ; CHECK-LABEL: @fdiv_cos_sin_reassoc( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[COS]], [[SIN]] ; CHECK-NEXT: ret double [[DIV]] ; %1 = call reassoc double @llvm.cos.f64(double %a) @@ -80,8 +89,9 @@ define double @fdiv_cos_sin_reassoc(double %a) { define half @fdiv_cosf16_sinf16_reassoc(half %a) { ; CHECK-LABEL: @fdiv_cosf16_sinf16_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = call reassoc half @llvm.cos.f16(half [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc half @llvm.sin.f16(half [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { half, half } @llvm.sincos.f16(half [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { half, half } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { half, half } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc half [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret half [[DIV]] ; @@ -93,8 +103,10 @@ define half @fdiv_cosf16_sinf16_reassoc(half %a) { define float @fdiv_cosf_sinf_reassoc(float %a) { ; CHECK-LABEL: @fdiv_cosf_sinf_reassoc( -; CHECK-NEXT: [[TANF:%.*]] = call reassoc float @tanf(float [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc float 1.000000e+00, [[TANF]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { float, float } @llvm.sincos.f32(float [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc float [[COS]], [[SIN]] ; CHECK-NEXT: ret float [[DIV]] ; %1 = call reassoc float @llvm.cos.f32(float %a) @@ -105,8 +117,10 @@ define float @fdiv_cosf_sinf_reassoc(float %a) { define fp128 @fdiv_cosfp128_sinfp128_reassoc(fp128 %a) { ; CHECK-LABEL: @fdiv_cosfp128_sinfp128_reassoc( -; CHECK-NEXT: [[TANL:%.*]] = call reassoc fp128 @tanl(fp128 [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc fp128 0xL00000000000000003FFF000000000000, [[TANL]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { fp128, fp128 } @llvm.sincos.f128(fp128 [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc fp128 [[COS]], [[SIN]] ; CHECK-NEXT: ret fp128 [[DIV]] ; %1 = call reassoc fp128 @llvm.cos.fp128(fp128 %a) diff --git a/llvm/test/Transforms/InstCombine/fdiv-sin-cos.ll b/llvm/test/Transforms/InstCombine/fdiv-sin-cos.ll index a9b8af345f96d..edfc1036014c7 100644 --- a/llvm/test/Transforms/InstCombine/fdiv-sin-cos.ll +++ b/llvm/test/Transforms/InstCombine/fdiv-sin-cos.ll @@ -3,8 +3,9 @@ define double @fdiv_sin_cos(double %a) { ; CHECK-LABEL: @fdiv_sin_cos( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.sin.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.cos.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret double [[DIV]] ; @@ -16,8 +17,9 @@ define double @fdiv_sin_cos(double %a) { define double @fdiv_strict_sin_strict_cos_reassoc(double %a) { ; CHECK-LABEL: @fdiv_strict_sin_strict_cos_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.sin.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.cos.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret double [[DIV]] ; @@ -29,7 +31,10 @@ define double @fdiv_strict_sin_strict_cos_reassoc(double %a) { define double @fdiv_reassoc_sin_strict_cos_strict(double %a, ptr dereferenceable(2) %dummy) { ; CHECK-LABEL: @fdiv_reassoc_sin_strict_cos_strict( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1:[0-9]+]] +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[TAN:%.*]] = fdiv reassoc double [[SIN]], [[COS]] ; CHECK-NEXT: ret double [[TAN]] ; %1 = call double @llvm.sin.f64(double %a) @@ -40,7 +45,10 @@ define double @fdiv_reassoc_sin_strict_cos_strict(double %a, ptr dereferenceable define double @fdiv_reassoc_sin_reassoc_cos_strict(double %a) { ; CHECK-LABEL: @fdiv_reassoc_sin_reassoc_cos_strict( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1]] +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[TAN:%.*]] = fdiv reassoc double [[SIN]], [[COS]] ; CHECK-NEXT: ret double [[TAN]] ; %1 = call reassoc double @llvm.sin.f64(double %a) @@ -51,8 +59,9 @@ define double @fdiv_reassoc_sin_reassoc_cos_strict(double %a) { define double @fdiv_sin_cos_reassoc_multiple_uses(double %a) { ; CHECK-LABEL: @fdiv_sin_cos_reassoc_multiple_uses( -; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.sin.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.cos.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use(double [[TMP2]]) ; CHECK-NEXT: ret double [[DIV]] @@ -66,7 +75,10 @@ define double @fdiv_sin_cos_reassoc_multiple_uses(double %a) { define double @fdiv_sin_cos_reassoc(double %a) { ; CHECK-LABEL: @fdiv_sin_cos_reassoc( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[TAN:%.*]] = fdiv reassoc double [[SIN]], [[COS]] ; CHECK-NEXT: ret double [[TAN]] ; %1 = call reassoc double @llvm.sin.f64(double %a) @@ -77,7 +89,10 @@ define double @fdiv_sin_cos_reassoc(double %a) { define float @fdiv_sinf_cosf_reassoc(float %a) { ; CHECK-LABEL: @fdiv_sinf_cosf_reassoc( -; CHECK-NEXT: [[TANF:%.*]] = call reassoc float @tanf(float [[A:%.*]]) #[[ATTR1]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { float, float } @llvm.sincos.f32(float [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[TANF:%.*]] = fdiv reassoc float [[SIN]], [[COS]] ; CHECK-NEXT: ret float [[TANF]] ; %1 = call reassoc float @llvm.sin.f32(float %a) @@ -88,7 +103,10 @@ define float @fdiv_sinf_cosf_reassoc(float %a) { define fp128 @fdiv_sinfp128_cosfp128_reassoc(fp128 %a) { ; CHECK-LABEL: @fdiv_sinfp128_cosfp128_reassoc( -; CHECK-NEXT: [[TANL:%.*]] = call reassoc fp128 @tanl(fp128 [[A:%.*]]) #[[ATTR1]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { fp128, fp128 } @llvm.sincos.f128(fp128 [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 1 +; CHECK-NEXT: [[TANL:%.*]] = fdiv reassoc fp128 [[SIN]], [[COS]] ; CHECK-NEXT: ret fp128 [[TANL]] ; %1 = call reassoc fp128 @llvm.sin.fp128(fp128 %a) diff --git a/llvm/test/Transforms/InstCombine/may-alias-errno.ll b/llvm/test/Transforms/InstCombine/may-alias-errno.ll index 40fab8024b362..89f5e49cdf581 100644 --- a/llvm/test/Transforms/InstCombine/may-alias-errno.ll +++ b/llvm/test/Transforms/InstCombine/may-alias-errno.ll @@ -27,7 +27,7 @@ define float @does_not_alias_errno_2(float %f) { ; CHECK-NEXT: [[P:%.*]] = alloca float, align 4 ; CHECK-NEXT: call void @escape(ptr nonnull [[P]]) ; CHECK-NEXT: store float 0.000000e+00, ptr [[P]], align 4 -; CHECK-NEXT: [[TMP1:%.*]] = call float @sinf(float [[F]]) +; CHECK-NEXT: [[TMP0:%.*]] = call float @sinf(float [[F]]) ; CHECK-NEXT: ret float 0.000000e+00 ; entry: @@ -47,7 +47,7 @@ define double @does_not_alias_errno_3(ptr %p, float %f) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: call void @escape(ptr [[P]]) ; CHECK-NEXT: store double 0.000000e+00, ptr [[P]], align 8 -; CHECK-NEXT: [[TMP1:%.*]] = call float @sinf(float [[F]]) +; CHECK-NEXT: [[TMP0:%.*]] = call float @sinf(float [[F]]) ; CHECK-NEXT: ret double 0.000000e+00 ; entry: diff --git a/llvm/test/Transforms/InstCombine/sincos-fpmath.ll b/llvm/test/Transforms/InstCombine/sincos-fpmath.ll new file mode 100644 index 0000000000000..7d30e8333b7ac --- /dev/null +++ b/llvm/test/Transforms/InstCombine/sincos-fpmath.ll @@ -0,0 +1,77 @@ +; RUN: opt -passes=instcombine -S < %s -mtriple=x86_64-apple-macosx10.9 | FileCheck %s + +; Verify that when sin/cos libcalls are combined into llvm.sincos, the +; !fpmath metadata from the two original calls is merged via +; MDNode::getMostGenericFPMath and attached to the new sincos call. + +declare float @llvm.sin.f32(float) +declare float @llvm.cos.f32(float) + +; Both sin and cos carry !fpmath; the combined call should pick the tighter +; (smaller) accuracy bound, which is !0 (2.5 ULP). +define float @sincos_fpmath_metadata(float %x) { +; CHECK-LABEL: @sincos_fpmath_metadata( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float %x), !fpmath !0 +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; + %s = call float @llvm.sin.f32(float %x), !fpmath !0 + %c = call float @llvm.cos.f32(float %x), !fpmath !1 + %res = fadd float %s, %c + ret float %res +} + +; Reversed order: sin uses !1 (4.0 ULP), cos uses !0 (2.5 ULP). The merge is +; symmetric, so the combined call should still pick the tighter bound (!0). +define float @sincos_fpmath_metadata_swapped(float %x) { +; CHECK-LABEL: @sincos_fpmath_metadata_swapped( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float %x), !fpmath !0 +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; + %s = call float @llvm.sin.f32(float %x), !fpmath !1 + %c = call float @llvm.cos.f32(float %x), !fpmath !0 + %res = fadd float %s, %c + ret float %res +} + +; Both sin and cos carry the same !fpmath !1 (4.0 ULP); the combined call +; should keep that same bound. +define float @sincos_fpmath_metadata_same(float %x) { +; CHECK-LABEL: @sincos_fpmath_metadata_same( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float %x), !fpmath !1 +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; + %s = call float @llvm.sin.f32(float %x), !fpmath !1 + %c = call float @llvm.cos.f32(float %x), !fpmath !1 + %res = fadd float %s, %c + ret float %res +} + +; If only one of the calls has fpmath, the combined call should have no fpmath. +define float @sincos_fpmath_one_unset(float %x) { +; CHECK-LABEL: @sincos_fpmath_one_unset( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float %x) +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; + %s = call float @llvm.sin.f32(float %x), !fpmath !0 + %c = call float @llvm.cos.f32(float %x) + %res = fadd float %s, %c + ret float %res +} + +; CHECK: !0 = !{float 2.500000e+00} +; CHECK: !1 = !{float 4.000000e+00} + +!0 = !{float 2.5} +!1 = !{float 4.0} diff --git a/llvm/test/Transforms/InstCombine/sincos.ll b/llvm/test/Transforms/InstCombine/sincos.ll new file mode 100644 index 0000000000000..31577c871d608 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/sincos.ll @@ -0,0 +1,421 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=instcombine -S < %s -mtriple=x86_64-apple-macosx10.9 | FileCheck %s --check-prefixes=CHECK,CHECK-DOUBLE-ALIGN8 +; RUN: opt -passes=instcombine -S < %s -mtriple=arm-apple-ios7.0 | FileCheck %s --check-prefixes=CHECK,CHECK-DOUBLE-ALIGN4 +; RUN: opt -passes=instcombine -S < %s -mtriple=x86_64-none-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-DOUBLE-ALIGN8-LINUX +; RUN: opt -passes=instcombine -S < %s -mtriple=x86_64-apple-macosx10.9 -enable-double-float-shrink | FileCheck %s --check-prefixes=CHECK-SHRINK +; REQUIRES: arm-registered-target, x86-registered-target + +declare float @sinf(float) #0 +declare float @cosf(float) #0 +declare double @sin(double) #0 +declare double @cos(double) #0 + +@var32 = global float 0.0 +@var64 = global double 0.0 + +; Basic sin+cos combination for float +define float @sincos_f32() { +; CHECK-LABEL: @sincos_f32( +; CHECK-NEXT: [[VAL:%.*]] = load float, ptr @var32, align 4 +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[VAL]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_f32( +; CHECK-SHRINK-NEXT: [[VAL:%.*]] = load float, ptr @var32, align 4 +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[VAL]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %val = load float, ptr @var32 + %s = call float @sinf(float %val) #0 + %c = call float @cosf(float %val) #0 + %res = fadd float %s, %c + ret float %res +} + +; Basic sin+cos combination for double +define double @sincos_f64() { +; CHECK-DOUBLE-ALIGN8-LABEL: @sincos_f64( +; CHECK-DOUBLE-ALIGN8-NEXT: [[VAL:%.*]] = load double, ptr @var64, align 8 +; CHECK-DOUBLE-ALIGN8-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[VAL]]) +; CHECK-DOUBLE-ALIGN8-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-DOUBLE-ALIGN8-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-DOUBLE-ALIGN8-NEXT: [[RES:%.*]] = fadd double [[SIN]], [[COS]] +; CHECK-DOUBLE-ALIGN8-NEXT: ret double [[RES]] +; +; CHECK-DOUBLE-ALIGN4-LABEL: @sincos_f64( +; CHECK-DOUBLE-ALIGN4-NEXT: [[VAL:%.*]] = load double, ptr @var64, align 4 +; CHECK-DOUBLE-ALIGN4-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[VAL]]) +; CHECK-DOUBLE-ALIGN4-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-DOUBLE-ALIGN4-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-DOUBLE-ALIGN4-NEXT: [[RES:%.*]] = fadd double [[SIN]], [[COS]] +; CHECK-DOUBLE-ALIGN4-NEXT: ret double [[RES]] +; +; CHECK-DOUBLE-ALIGN8-LINUX-LABEL: @sincos_f64( +; CHECK-DOUBLE-ALIGN8-LINUX-NEXT: [[VAL:%.*]] = load double, ptr @var64, align 8 +; CHECK-DOUBLE-ALIGN8-LINUX-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[VAL]]) +; CHECK-DOUBLE-ALIGN8-LINUX-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-DOUBLE-ALIGN8-LINUX-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-DOUBLE-ALIGN8-LINUX-NEXT: [[RES:%.*]] = fadd double [[SIN]], [[COS]] +; CHECK-DOUBLE-ALIGN8-LINUX-NEXT: ret double [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_f64( +; CHECK-SHRINK-NEXT: [[VAL:%.*]] = load double, ptr @var64, align 8 +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[VAL]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd double [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret double [[RES]] +; + %val = load double, ptr @var64 + %s = call double @sin(double %val) #0 + %c = call double @cos(double %val) #0 + %res = fadd double %s, %c + ret double %res +} + +; Only sin, no cos - should NOT combine +define float @sin_only_f32(float %x) { +; CHECK-LABEL: @sin_only_f32( +; CHECK-NEXT: [[S:%.*]] = call float @llvm.sin.f32(float [[X:%.*]]) +; CHECK-NEXT: ret float [[S]] +; +; CHECK-SHRINK-LABEL: @sin_only_f32( +; CHECK-SHRINK-NEXT: [[S:%.*]] = call float @llvm.sin.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: ret float [[S]] +; + %s = call float @sinf(float %x) #0 + ret float %s +} + +; Only cos, no sin - should NOT combine +define float @cos_only_f32(float %x) { +; CHECK-LABEL: @cos_only_f32( +; CHECK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X:%.*]]) +; CHECK-NEXT: ret float [[C]] +; +; CHECK-SHRINK-LABEL: @cos_only_f32( +; CHECK-SHRINK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: ret float [[C]] +; + %c = call float @cosf(float %x) #0 + ret float %c +} + +; Different arguments - should NOT combine +define float @sincos_different_args(float %x, float %y) { +; CHECK-LABEL: @sincos_different_args( +; CHECK-NEXT: [[S:%.*]] = call float @llvm.sin.f32(float [[X:%.*]]) +; CHECK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[Y:%.*]]) +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_different_args( +; CHECK-SHRINK-NEXT: [[S:%.*]] = call float @llvm.sin.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[Y:%.*]]) +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %s = call float @sinf(float %x) #0 + %c = call float @cosf(float %y) #0 + %res = fadd float %s, %c + ret float %res +} + +; Multiple uses of sin and cos results +define float @sincos_multi_use(float %x) { +; CHECK-LABEL: @sincos_multi_use( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SIN]], [[COS]] +; CHECK-NEXT: [[RES:%.*]] = fadd float [[ADD]], [[MUL]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_multi_use( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[ADD:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: [[MUL:%.*]] = fmul float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[ADD]], [[MUL]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %s = call float @sinf(float %x) #0 + %c = call float @cosf(float %x) #0 + %add = fadd float %s, %c + %mul = fmul float %s, %c + %res = fadd float %add, %mul + ret float %res +} + +; Intrinsic sin + intrinsic cos - should combine +define float @sincos_intrinsic_f32(float %x) { +; CHECK-LABEL: @sincos_intrinsic_f32( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_intrinsic_f32( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %s = call float @llvm.sin.f32(float %x) + %c = call float @llvm.cos.f32(float %x) + %res = fadd float %s, %c + ret float %res +} + +; Mixed: libcall sin + intrinsic cos +define float @sincos_mixed_libcall_sin_intrinsic_cos(float %x) { +; CHECK-LABEL: @sincos_mixed_libcall_sin_intrinsic_cos( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_mixed_libcall_sin_intrinsic_cos( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %s = call float @sinf(float %x) #0 + %c = call float @llvm.cos.f32(float %x) + %res = fadd float %s, %c + ret float %res +} + +; Mixed: intrinsic sin + libcall cos +define float @sincos_mixed_intrinsic_sin_libcall_cos(float %x) { +; CHECK-LABEL: @sincos_mixed_intrinsic_sin_libcall_cos( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_mixed_intrinsic_sin_libcall_cos( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %s = call float @llvm.sin.f32(float %x) + %c = call float @cosf(float %x) #0 + %res = fadd float %s, %c + ret float %res +} + +; UnsafeFPShrink: sin(fpext float) -> fpext(sinf(float)) +; This should trigger optimizeUnaryDoubleFP before converting to intrinsic. +define float @sin_double_to_float_shrink(float %x) { +; CHECK-LABEL: @sin_double_to_float_shrink( +; CHECK-NEXT: [[EXT:%.*]] = fpext float [[X:%.*]] to double +; CHECK-NEXT: [[S:%.*]] = call double @llvm.sin.f64(double [[EXT]]) +; CHECK-NEXT: [[TRUNC:%.*]] = fptrunc double [[S]] to float +; CHECK-NEXT: ret float [[TRUNC]] +; +; CHECK-SHRINK-LABEL: @sin_double_to_float_shrink( +; CHECK-SHRINK-NEXT: [[SINF:%.*]] = call float @llvm.sin.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: ret float [[SINF]] +; + %ext = fpext float %x to double + %s = call double @sin(double %ext) #0 + %trunc = fptrunc double %s to float + ret float %trunc +} + +; UnsafeFPShrink: cos(fpext float) -> fpext(cosf(float)) +define float @cos_double_to_float_shrink(float %x) { +; CHECK-LABEL: @cos_double_to_float_shrink( +; CHECK-NEXT: [[EXT:%.*]] = fpext float [[X:%.*]] to double +; CHECK-NEXT: [[C:%.*]] = call double @llvm.cos.f64(double [[EXT]]) +; CHECK-NEXT: [[TRUNC:%.*]] = fptrunc double [[C]] to float +; CHECK-NEXT: ret float [[TRUNC]] +; +; CHECK-SHRINK-LABEL: @cos_double_to_float_shrink( +; CHECK-SHRINK-NEXT: [[COSF:%.*]] = call float @llvm.cos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: ret float [[COSF]] +; + %ext = fpext float %x to double + %c = call double @cos(double %ext) #0 + %trunc = fptrunc double %c to float + ret float %trunc +} + +; UnsafeFPShrink + sincos: sin(fpext float) + cos(fpext float) should +; first shrink to sinf/cosf, then combine into llvm.sincos.f32. +define { float, float } @sincos_double_to_float_shrink(float %x) { +; CHECK-LABEL: @sincos_double_to_float_shrink( +; CHECK-NEXT: [[EXT:%.*]] = fpext float [[X:%.*]] to double +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[EXT]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[ST:%.*]] = fptrunc double [[SIN]] to float +; CHECK-NEXT: [[CT:%.*]] = fptrunc double [[COS]] to float +; CHECK-NEXT: [[R0:%.*]] = insertvalue { float, float } poison, float [[ST]], 0 +; CHECK-NEXT: [[R1:%.*]] = insertvalue { float, float } [[R0]], float [[CT]], 1 +; CHECK-NEXT: ret { float, float } [[R1]] +; +; CHECK-SHRINK-LABEL: @sincos_double_to_float_shrink( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: ret { float, float } [[SINCOS]] +; + %ext = fpext float %x to double + %s = call double @sin(double %ext) #0 + %c = call double @cos(double %ext) #0 + %st = fptrunc double %s to float + %ct = fptrunc double %c to float + %r0 = insertvalue { float, float } poison, float %st, 0 + %r1 = insertvalue { float, float } %r0, float %ct, 1 + ret { float, float } %r1 +} + +; FMF flags should be intersected when combining sin and cos. +define float @sincos_fmf_intersect(float %x) { +; CHECK-LABEL: @sincos_fmf_intersect( +; CHECK-NEXT: [[SINCOS:%.*]] = call nnan ninf { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_fmf_intersect( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call nnan ninf { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %s = call nnan ninf nsz float @llvm.sin.f32(float %x) + %c = call nnan ninf arcp float @llvm.cos.f32(float %x) + %res = fadd float %s, %c + ret float %res +} + +; If one of the calls has no FMF, the combined call should have no FMF either. +define float @sincos_fmf_one_unset(float %x) { +; CHECK-LABEL: @sincos_fmf_one_unset( +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-NEXT: [[S:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[C:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd float [[S]], [[C]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_fmf_one_unset( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + %s = call fast float @llvm.sin.f32(float %x) + %c = call float @llvm.cos.f32(float %x) + %res = fadd float %s, %c + ret float %res +} + +; Vector sin+cos intrinsics with the same operand should be combined into a +; single vector sincos intrinsic. +define <4 x float> @sincos_v4f32(<4 x float> %x) { +; CHECK-LABEL: @sincos_v4f32( +; CHECK-NEXT: [[SINCOS:%.*]] = call { <4 x float>, <4 x float> } @llvm.sincos.v4f32(<4 x float> [[X:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd <4 x float> [[SIN]], [[COS]] +; CHECK-NEXT: ret <4 x float> [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_v4f32( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { <4 x float>, <4 x float> } @llvm.sincos.v4f32(<4 x float> [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd <4 x float> [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret <4 x float> [[RES]] +; + %s = call <4 x float> @llvm.sin.v4f32(<4 x float> %x) + %c = call <4 x float> @llvm.cos.v4f32(<4 x float> %x) + %res = fadd <4 x float> %s, %c + ret <4 x float> %res +} + +define <2 x double> @sincos_v2f64(<2 x double> %x) { +; CHECK-LABEL: @sincos_v2f64( +; CHECK-NEXT: [[SINCOS:%.*]] = call { <2 x double>, <2 x double> } @llvm.sincos.v2f64(<2 x double> [[X:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { <2 x double>, <2 x double> } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { <2 x double>, <2 x double> } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd <2 x double> [[SIN]], [[COS]] +; CHECK-NEXT: ret <2 x double> [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_v2f64( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { <2 x double>, <2 x double> } @llvm.sincos.v2f64(<2 x double> [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { <2 x double>, <2 x double> } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { <2 x double>, <2 x double> } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd <2 x double> [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret <2 x double> [[RES]] +; + %s = call <2 x double> @llvm.sin.v2f64(<2 x double> %x) + %c = call <2 x double> @llvm.cos.v2f64(<2 x double> %x) + %res = fadd <2 x double> %s, %c + ret <2 x double> %res +} + +; Same for scalable vectors. +define <vscale x 4 x float> @sincos_nxv4f32(<vscale x 4 x float> %x) { +; CHECK-LABEL: @sincos_nxv4f32( +; CHECK-NEXT: [[SINCOS:%.*]] = call { <vscale x 4 x float>, <vscale x 4 x float> } @llvm.sincos.nxv4f32(<vscale x 4 x float> [[X:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { <vscale x 4 x float>, <vscale x 4 x float> } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { <vscale x 4 x float>, <vscale x 4 x float> } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd <vscale x 4 x float> [[SIN]], [[COS]] +; CHECK-NEXT: ret <vscale x 4 x float> [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_nxv4f32( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { <vscale x 4 x float>, <vscale x 4 x float> } @llvm.sincos.nxv4f32(<vscale x 4 x float> [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { <vscale x 4 x float>, <vscale x 4 x float> } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { <vscale x 4 x float>, <vscale x 4 x float> } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd <vscale x 4 x float> [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret <vscale x 4 x float> [[RES]] +; + %s = call <vscale x 4 x float> @llvm.sin.nxv4f32(<vscale x 4 x float> %x) + %c = call <vscale x 4 x float> @llvm.cos.nxv4f32(<vscale x 4 x float> %x) + %res = fadd <vscale x 4 x float> %s, %c + ret <vscale x 4 x float> %res +} + +; FMF flags should still be intersected for vector sin/cos. +define <4 x float> @sincos_v4f32_fmf_intersect(<4 x float> %x) { +; CHECK-LABEL: @sincos_v4f32_fmf_intersect( +; CHECK-NEXT: [[SINCOS:%.*]] = call nnan ninf { <4 x float>, <4 x float> } @llvm.sincos.v4f32(<4 x float> [[X:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 1 +; CHECK-NEXT: [[RES:%.*]] = fadd <4 x float> [[SIN]], [[COS]] +; CHECK-NEXT: ret <4 x float> [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_v4f32_fmf_intersect( +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call nnan ninf { <4 x float>, <4 x float> } @llvm.sincos.v4f32(<4 x float> [[X:%.*]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { <4 x float>, <4 x float> } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd <4 x float> [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: ret <4 x float> [[RES]] +; + %s = call nnan ninf nsz <4 x float> @llvm.sin.v4f32(<4 x float> %x) + %c = call nnan ninf arcp <4 x float> @llvm.cos.v4f32(<4 x float> %x) + %res = fadd <4 x float> %s, %c + ret <4 x float> %res +} + +attributes #0 = { nounwind memory(none) } >From 941cc952f4278df479ef2c3978da753aed11b0c0 Mon Sep 17 00:00:00 2001 From: Kito Cheng <[email protected]> Date: Tue, 28 Apr 2026 19:28:43 +0800 Subject: [PATCH 2/3] fixup clang-hip-vega20 build bot issue --- .../InstCombine/InstCombineCalls.cpp | 12 +++-- llvm/test/Transforms/InstCombine/sincos.ll | 51 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index ec5deea9f454d..8a213794862b8 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1914,9 +1914,15 @@ static Value *foldSinAndCosToSinCos(IntrinsicInst *II, IRBuilderBase &B, // Insert sincos right after the argument definition. IRBuilderBase::InsertPointGuard Guard(B); - if (auto *ArgInst = dyn_cast<Instruction>(Arg)) - B.SetInsertPoint(ArgInst->getParent(), std::next(ArgInst->getIterator())); - else { + if (auto *ArgInst = dyn_cast<Instruction>(Arg)) { + BasicBlock *ArgBB = ArgInst->getParent(); + // Need skip whole PHIs if Arg is PHI to prevent insert in the middle + // of PHIs. + if (isa<PHINode>(ArgInst)) + B.SetInsertPoint(ArgBB, ArgBB->getFirstInsertionPt()); + else + B.SetInsertPoint(ArgBB, std::next(ArgInst->getIterator())); + } else { BasicBlock &EntryBB = II->getFunction()->getEntryBlock(); B.SetInsertPoint(&EntryBB, EntryBB.begin()); } diff --git a/llvm/test/Transforms/InstCombine/sincos.ll b/llvm/test/Transforms/InstCombine/sincos.ll index 31577c871d608..a1fd6074954d3 100644 --- a/llvm/test/Transforms/InstCombine/sincos.ll +++ b/llvm/test/Transforms/InstCombine/sincos.ll @@ -418,4 +418,55 @@ define <4 x float> @sincos_v4f32_fmf_intersect(<4 x float> %x) { ret <4 x float> %res } +; When the shared argument is a PHI but the block has more PHIs after it, +; the sincos call must be placed after all PHIs, not next to the argument. +; Otherwise it would be sandwiched between PHIs and produce malformed IR. +define float @sincos_arg_is_phi_with_following_phi(i1 %cond, float %a, float %b, float %c) { +; CHECK-LABEL: @sincos_arg_is_phi_with_following_phi( +; CHECK-NEXT: br i1 [[COND:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: br label [[MERGE:%.*]] +; CHECK: else: +; CHECK-NEXT: br label [[MERGE]] +; CHECK: merge: +; CHECK-NEXT: [[X:%.*]] = phi float [ [[A:%.*]], [[THEN]] ], [ [[B:%.*]], [[ELSE]] ] +; CHECK-NEXT: [[Y:%.*]] = phi float [ [[B]], [[THEN]] ], [ [[C:%.*]], [[ELSE]] ] +; CHECK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[SUM:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-NEXT: [[RES:%.*]] = fadd float [[SUM]], [[Y]] +; CHECK-NEXT: ret float [[RES]] +; +; CHECK-SHRINK-LABEL: @sincos_arg_is_phi_with_following_phi( +; CHECK-SHRINK-NEXT: br i1 [[COND:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK-SHRINK: then: +; CHECK-SHRINK-NEXT: br label [[MERGE:%.*]] +; CHECK-SHRINK: else: +; CHECK-SHRINK-NEXT: br label [[MERGE]] +; CHECK-SHRINK: merge: +; CHECK-SHRINK-NEXT: [[X:%.*]] = phi float [ [[A:%.*]], [[THEN]] ], [ [[B:%.*]], [[ELSE]] ] +; CHECK-SHRINK-NEXT: [[Y:%.*]] = phi float [ [[B]], [[THEN]] ], [ [[C:%.*]], [[ELSE]] ] +; CHECK-SHRINK-NEXT: [[SINCOS:%.*]] = call { float, float } @llvm.sincos.f32(float [[X]]) +; CHECK-SHRINK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-SHRINK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-SHRINK-NEXT: [[SUM:%.*]] = fadd float [[SIN]], [[COS]] +; CHECK-SHRINK-NEXT: [[RES:%.*]] = fadd float [[SUM]], [[Y]] +; CHECK-SHRINK-NEXT: ret float [[RES]] +; + br i1 %cond, label %then, label %else +then: + br label %merge +else: + br label %merge +merge: + %x = phi float [ %a, %then ], [ %b, %else ] + %y = phi float [ %b, %then ], [ %c, %else ] + %s = call float @llvm.sin.f32(float %x) + %c0 = call float @llvm.cos.f32(float %x) + %sum = fadd float %s, %c0 + %res = fadd float %sum, %y + ret float %res +} + attributes #0 = { nounwind memory(none) } >From 46a43aa18ea5656501ff0f8dd4cf91be6cf47b1b Mon Sep 17 00:00:00 2001 From: Kito Cheng <[email protected]> Date: Wed, 15 Jul 2026 10:45:26 +0800 Subject: [PATCH 3/3] fixup: update testcase --- .../Transforms/InstCombine/fdiv-cos-sin.ll | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll b/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll index 85c6f76de5335..2450f4b54dcab 100644 --- a/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll +++ b/llvm/test/Transforms/InstCombine/fdiv-cos-sin.ll @@ -3,8 +3,9 @@ define double @fdiv_cos_sin(double %a) { ; CHECK-LABEL: @fdiv_cos_sin( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret double [[DIV]] ; @@ -16,8 +17,9 @@ define double @fdiv_cos_sin(double %a) { define double @fdiv_strict_cos_strict_sin_reassoc(double %a) { ; CHECK-LABEL: @fdiv_strict_cos_strict_sin_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret double [[DIV]] ; @@ -29,8 +31,10 @@ define double @fdiv_strict_cos_strict_sin_reassoc(double %a) { define double @fdiv_reassoc_cos_strict_sin_strict(double %a, ptr dereferenceable(2) %dummy) { ; CHECK-LABEL: @fdiv_reassoc_cos_strict_sin_strict( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1:[0-9]+]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]] +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[COS]], [[SIN]] ; CHECK-NEXT: ret double [[DIV]] ; %1 = call double @llvm.cos.f64(double %a) @@ -41,8 +45,10 @@ define double @fdiv_reassoc_cos_strict_sin_strict(double %a, ptr dereferenceable define double @fdiv_reassoc_cos_reassoc_sin_strict(double %a) { ; CHECK-LABEL: @fdiv_reassoc_cos_reassoc_sin_strict( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]] +; CHECK-NEXT: [[SINCOS:%.*]] = call { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[COS]], [[SIN]] ; CHECK-NEXT: ret double [[DIV]] ; %1 = call reassoc double @llvm.cos.f64(double %a) @@ -53,8 +59,9 @@ define double @fdiv_reassoc_cos_reassoc_sin_strict(double %a) { define double @fdiv_cos_sin_reassoc_multiple_uses(double %a) { ; CHECK-LABEL: @fdiv_cos_sin_reassoc_multiple_uses( -; CHECK-NEXT: [[TMP1:%.*]] = call reassoc double @llvm.cos.f64(double [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { double, double } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use(double [[TMP2]]) ; CHECK-NEXT: ret double [[DIV]] @@ -68,8 +75,10 @@ define double @fdiv_cos_sin_reassoc_multiple_uses(double %a) { define double @fdiv_cos_sin_reassoc(double %a) { ; CHECK-LABEL: @fdiv_cos_sin_reassoc( -; CHECK-NEXT: [[TAN:%.*]] = call reassoc double @tan(double [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double 1.000000e+00, [[TAN]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { double, double } @llvm.sincos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { double, double } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { double, double } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[COS]], [[SIN]] ; CHECK-NEXT: ret double [[DIV]] ; %1 = call reassoc double @llvm.cos.f64(double %a) @@ -80,8 +89,9 @@ define double @fdiv_cos_sin_reassoc(double %a) { define half @fdiv_cosf16_sinf16_reassoc(half %a) { ; CHECK-LABEL: @fdiv_cosf16_sinf16_reassoc( -; CHECK-NEXT: [[TMP1:%.*]] = call reassoc half @llvm.cos.f16(half [[A:%.*]]) -; CHECK-NEXT: [[TMP2:%.*]] = call reassoc half @llvm.sin.f16(half [[A]]) +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { half, half } @llvm.sincos.f16(half [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { half, half } [[SINCOS]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { half, half } [[SINCOS]], 1 ; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc half [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret half [[DIV]] ; @@ -93,8 +103,10 @@ define half @fdiv_cosf16_sinf16_reassoc(half %a) { define float @fdiv_cosf_sinf_reassoc(float %a) { ; CHECK-LABEL: @fdiv_cosf_sinf_reassoc( -; CHECK-NEXT: [[TANF:%.*]] = call reassoc float @tanf(float [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc float 1.000000e+00, [[TANF]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { float, float } @llvm.sincos.f32(float [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { float, float } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { float, float } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc float [[COS]], [[SIN]] ; CHECK-NEXT: ret float [[DIV]] ; %1 = call reassoc float @llvm.cos.f32(float %a) @@ -105,8 +117,10 @@ define float @fdiv_cosf_sinf_reassoc(float %a) { define fp128 @fdiv_cosfp128_sinfp128_reassoc(fp128 %a) { ; CHECK-LABEL: @fdiv_cosfp128_sinfp128_reassoc( -; CHECK-NEXT: [[TANL:%.*]] = call reassoc fp128 @tanl(fp128 [[A:%.*]]) #[[ATTR1]] -; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc fp128 1.000000e+00, [[TANL]] +; CHECK-NEXT: [[SINCOS:%.*]] = call reassoc { fp128, fp128 } @llvm.sincos.f128(fp128 [[A:%.*]]) +; CHECK-NEXT: [[SIN:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 0 +; CHECK-NEXT: [[COS:%.*]] = extractvalue { fp128, fp128 } [[SINCOS]], 1 +; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc fp128 [[COS]], [[SIN]] ; CHECK-NEXT: ret fp128 [[DIV]] ; %1 = call reassoc fp128 @llvm.cos.fp128(fp128 %a) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
