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/2] 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/2] 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) }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to