Skip to content

Reland "[InstSimplify] Add basic constant folding for llvm.sincos" #119192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 9, 2024

Conversation

MacDue
Copy link
Member

@MacDue MacDue commented Dec 9, 2024

This calls into the existing constant folding for llvm.sin and llvm.cos, which currently does not fold for any non-finite values, so most tests are negative tests at the moment.

Note: The constant folding does not consider the afn fast-math flag and will produce the same result regardless of if the flag is set.

This is a reland of #114527 that updates the syntax of one of the tests from: <float 1.000000e+00, float 1.000000e+00> to splat (float 1.000000e+00).

This calls into the existing constant folding for `llvm.sin` and
`llvm.cos`, which currently does not fold for any non-finite values,
so most tests are negative tests.
@MacDue MacDue added the skip-precommit-approval PR for CI feedback, not intended for review label Dec 9, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 9, 2024

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: Benjamin Maxwell (MacDue)

Changes

This calls into the existing constant folding for llvm.sin and llvm.cos, which currently does not fold for any non-finite values, so most tests are negative tests at the moment.

Note: The constant folding does not consider the afn fast-math flag and will produce the same result regardless of if the flag is set.

This is a reland of #114527 that updates the syntax of one of the tests from: &lt;float 1.000000e+00, float 1.000000e+00&gt; to splat (float 1.000000e+00).


Full diff: https://github.com/llvm/llvm-project/pull/119192.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ConstantFolding.cpp (+35)
  • (added) llvm/test/Transforms/InstSimplify/sincos.ll (+148)
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index efbccee76f2c51..0233d31459062d 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1632,6 +1632,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
   case Intrinsic::sqrt:
   case Intrinsic::sin:
   case Intrinsic::cos:
+  case Intrinsic::sincos:
   case Intrinsic::pow:
   case Intrinsic::powi:
   case Intrinsic::ldexp:
@@ -3534,6 +3535,40 @@ ConstantFoldStructCall(StringRef Name, Intrinsic::ID IntrinsicID,
       return nullptr;
     return ConstantStruct::get(StTy, Result0, Result1);
   }
+  case Intrinsic::sincos: {
+    Type *Ty = StTy->getContainedType(0);
+    Type *TyScalar = Ty->getScalarType();
+
+    auto ConstantFoldScalarSincosCall =
+        [&](Constant *Op) -> std::pair<Constant *, Constant *> {
+      Constant *SinResult =
+          ConstantFoldScalarCall(Name, Intrinsic::sin, TyScalar, Op, TLI, Call);
+      Constant *CosResult =
+          ConstantFoldScalarCall(Name, Intrinsic::cos, TyScalar, Op, TLI, Call);
+      return std::make_pair(SinResult, CosResult);
+    };
+
+    if (auto *FVTy = dyn_cast<FixedVectorType>(Ty)) {
+      SmallVector<Constant *> SinResults(FVTy->getNumElements());
+      SmallVector<Constant *> CosResults(FVTy->getNumElements());
+
+      for (unsigned I = 0, E = FVTy->getNumElements(); I != E; ++I) {
+        Constant *Lane = Operands[0]->getAggregateElement(I);
+        std::tie(SinResults[I], CosResults[I]) =
+            ConstantFoldScalarSincosCall(Lane);
+        if (!SinResults[I] || !CosResults[I])
+          return nullptr;
+      }
+
+      return ConstantStruct::get(StTy, ConstantVector::get(SinResults),
+                                 ConstantVector::get(CosResults));
+    }
+
+    auto [SinResult, CosResult] = ConstantFoldScalarSincosCall(Operands[0]);
+    if (!SinResult || !CosResult)
+      return nullptr;
+    return ConstantStruct::get(StTy, SinResult, CosResult);
+  }
   default:
     // TODO: Constant folding of vector intrinsics that fall through here does
     // not work (e.g. overflow intrinsics)
diff --git a/llvm/test/Transforms/InstSimplify/sincos.ll b/llvm/test/Transforms/InstSimplify/sincos.ll
new file mode 100644
index 00000000000000..e0f81ee45af056
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/sincos.ll
@@ -0,0 +1,148 @@
+; RUN: opt -S -passes=instsimplify %s | FileCheck %s
+
+define { float, float } @sincos_zero() {
+; CHECK-LABEL: define { float, float } @sincos_zero() {
+; CHECK-NEXT:    ret { float, float } { float 0.000000e+00, float 1.000000e+00 }
+;
+  %ret = call { float, float } @llvm.sincos.f32(float zeroinitializer)
+  ret { float, float } %ret
+}
+
+define { float, float } @sincos_neg_zero() {
+; CHECK-LABEL: define { float, float } @sincos_neg_zero() {
+; CHECK-NEXT:    ret { float, float } { float -0.000000e+00, float 1.000000e+00 }
+;
+  %ret = call { float, float } @llvm.sincos.f32(float -0.0)
+  ret { float, float } %ret
+}
+
+define { float, float } @sincos_one() {
+; CHECK-LABEL: define { float, float } @sincos_one() {
+; CHECK-NEXT:    ret { float, float } { float [[$SIN_ONE:.+]], float [[$COS_ONE:.+]] }
+;
+  %ret = call { float, float } @llvm.sincos.f32(float 1.0)
+  ret { float, float } %ret
+}
+
+define { float, float } @sincos_two() {
+; CHECK-LABEL: define { float, float } @sincos_two() {
+; CHECK-NEXT:    ret { float, float } { float [[$SIN_TWO:.+]], float [[$COS_TWO:.+]] }
+;
+  %ret = call { float, float } @llvm.sincos.f32(float 2.0)
+  ret { float, float } %ret
+}
+
+define { <2 x float>, <2 x float> } @sincos_vector() {
+; CHECK-LABEL: define { <2 x float>, <2 x float> } @sincos_vector() {
+; CHECK-NEXT:    ret { <2 x float>, <2 x float> } { <2 x float> <float [[$SIN_ONE]], float [[$SIN_TWO]]>, <2 x float> <float [[$COS_ONE]], float [[$COS_TWO]]> }
+;
+  %ret = call { <2 x float>, <2 x float> } @llvm.sincos.v2f32(<2 x float> <float 1.0, float 2.0>)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @sincos_zero_vector() {
+; CHECK-LABEL: define { <2 x float>, <2 x float> } @sincos_zero_vector() {
+; CHECK-NEXT:    ret { <2 x float>, <2 x float> } { <2 x float> zeroinitializer, <2 x float> splat (float 1.000000e+00) }
+;
+  %ret = call { <2 x float>, <2 x float> } @llvm.sincos.v2f32(<2 x float> zeroinitializer)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { float, float } @sincos_poison() {
+; CHECK-LABEL: define { float, float } @sincos_poison() {
+; CHECK-NEXT:    [[RET:%.*]] = call { float, float } @llvm.sincos.f32(float poison)
+; CHECK-NEXT:    ret { float, float } [[RET]]
+;
+  %ret = call { float, float } @llvm.sincos.f32(float poison)
+  ret { float, float } %ret
+}
+
+define { <2 x float>, <2 x float> } @sincos_poison_vector() {
+; CHECK-LABEL: define { <2 x float>, <2 x float> } @sincos_poison_vector() {
+; CHECK-NEXT:    [[RET:%.*]] = call { <2 x float>, <2 x float> } @llvm.sincos.v2f32(<2 x float> poison)
+; CHECK-NEXT:    ret { <2 x float>, <2 x float> } [[RET]]
+;
+  %ret = call { <2 x float>, <2 x float> } @llvm.sincos.v2f32(<2 x float> poison)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <vscale x 2 x float>, <vscale x 2 x float> } @sincos_poison_scalable_vector() {
+; CHECK-LABEL: define { <vscale x 2 x float>, <vscale x 2 x float> } @sincos_poison_scalable_vector() {
+; CHECK-NEXT:    [[RET:%.*]] = call { <vscale x 2 x float>, <vscale x 2 x float> } @llvm.sincos.nxv2f32(<vscale x 2 x float> poison)
+; CHECK-NEXT:    ret { <vscale x 2 x float>, <vscale x 2 x float> } [[RET]]
+;
+  %ret = call { <vscale x 2 x float>, <vscale x 2 x float> } @llvm.sincos.nxv2f32(<vscale x 2 x float> poison)
+  ret { <vscale x 2 x float>, <vscale x 2 x float> } %ret
+}
+
+define { float, float } @sincos_undef() {
+; CHECK-LABEL: define { float, float } @sincos_undef() {
+; CHECK-NEXT:    [[RET:%.*]] = call { float, float } @llvm.sincos.f32(float undef)
+; CHECK-NEXT:    ret { float, float } [[RET]]
+;
+  %ret = call { float, float } @llvm.sincos.f32(float undef)
+  ret { float, float } %ret
+}
+
+define { <2 x float>, <2 x float> } @sincos_undef_vector() {
+; CHECK-LABEL: define { <2 x float>, <2 x float> } @sincos_undef_vector() {
+; CHECK-NEXT:    [[RET:%.*]] = call { <2 x float>, <2 x float> } @llvm.sincos.v2f32(<2 x float> undef)
+; CHECK-NEXT:    ret { <2 x float>, <2 x float> } [[RET]]
+;
+  %ret = call { <2 x float>, <2 x float> } @llvm.sincos.v2f32(<2 x float> undef)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <vscale x 2 x float>, <vscale x 2 x float> } @sincos_undef_scalable_vector() {
+; CHECK-LABEL: define { <vscale x 2 x float>, <vscale x 2 x float> } @sincos_undef_scalable_vector() {
+; CHECK-NEXT:    [[RET:%.*]] = call { <vscale x 2 x float>, <vscale x 2 x float> } @llvm.sincos.nxv2f32(<vscale x 2 x float> undef)
+; CHECK-NEXT:    ret { <vscale x 2 x float>, <vscale x 2 x float> } [[RET]]
+;
+  %ret = call { <vscale x 2 x float>, <vscale x 2 x float> } @llvm.sincos.nxv2f32(<vscale x 2 x float> undef)
+  ret { <vscale x 2 x float>, <vscale x 2 x float> } %ret
+}
+
+define { <vscale x 2 x float>, <vscale x 2 x float> } @sincos_zero_scalable_vector() {
+; CHECK-LABEL: define { <vscale x 2 x float>, <vscale x 2 x float> } @sincos_zero_scalable_vector() {
+; CHECK-NEXT:    [[RET:%.*]] = call { <vscale x 2 x float>, <vscale x 2 x float> } @llvm.sincos.nxv2f32(<vscale x 2 x float> zeroinitializer)
+; CHECK-NEXT:    ret { <vscale x 2 x float>, <vscale x 2 x float> } [[RET]]
+;
+  %ret = call { <vscale x 2 x float>, <vscale x 2 x float> } @llvm.sincos.nxv2f32(<vscale x 2 x float> zeroinitializer)
+  ret { <vscale x 2 x float>, <vscale x 2 x float> } %ret
+}
+
+define { float, float } @sincos_inf() {
+; CHECK-LABEL: define { float, float } @sincos_inf() {
+; CHECK-NEXT:    [[RET:%.*]] = call { float, float } @llvm.sincos.f32(float 0x7FF0000000000000)
+; CHECK-NEXT:    ret { float, float } [[RET]]
+;
+  %ret = call { float, float } @llvm.sincos.f32(float 0x7FF0000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @sincos_neginf() {
+; CHECK-LABEL: define { float, float } @sincos_neginf() {
+; CHECK-NEXT:    [[RET:%.*]] = call { float, float } @llvm.sincos.f32(float 0xFFF0000000000000)
+; CHECK-NEXT:    ret { float, float } [[RET]]
+;
+  %ret = call { float, float } @llvm.sincos.f32(float 0xFFF0000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @sincos_qnan() {
+; CHECK-LABEL: define { float, float } @sincos_qnan() {
+; CHECK-NEXT:    [[RET:%.*]] = call { float, float } @llvm.sincos.f32(float 0x7FF8000000000000)
+; CHECK-NEXT:    ret { float, float } [[RET]]
+;
+  %ret = call { float, float } @llvm.sincos.f32(float 0x7FF8000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @sincos_snan() {
+; CHECK-LABEL: define { float, float } @sincos_snan() {
+; CHECK-NEXT:    [[RET:%.*]] = call { float, float } @llvm.sincos.f32(float 0x7FF0000020000000)
+; CHECK-NEXT:    ret { float, float } [[RET]]
+;
+  %ret = call { float, float } @llvm.sincos.f32(float bitcast (i32 2139095041 to float))
+  ret { float, float } %ret
+}

@MacDue MacDue merged commit 24561f4 into llvm:main Dec 9, 2024
13 checks passed
@MacDue MacDue deleted the sincos_const_fold_reland branch December 9, 2024 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants