[llvm] [C API] Add getters and setters for fast-math flags on relevant instructions (PR #75123)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 12 04:10:04 PST 2023


https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/75123

>From 61664ad7a1c391f082b5456622002b1d6a0e698d Mon Sep 17 00:00:00 2001
From: Benji Smith <6193112+Benjins at users.noreply.github.com>
Date: Mon, 11 Dec 2023 18:02:40 -0500
Subject: [PATCH 1/3] [C API] Add getters and setters for fast-math flags on
 relevant instructions

These flags are usable on floating point arithmetic, as well as call, select,
and phi instructions whose resulting type is floating point, or a vector of,
or an array of, a valid type. Whether or not the flags are valid for a given
instruction can be checked with the new LLVMGetCanUseFastMathFlags function

These are exposed using a new LLVMFastMathFlags type, which is an alias for
unsigned. An anonymous enum defines the bit values for it

Tests are added in echo.ll for select/phil/call, and the floating point types
in the new float_ops.ll bindings test

Select and the floating point arithmetic instructions were not implemented in
llvm-c-test/echo.cpp, so they were added as well
---
 llvm/docs/ReleaseNotes.rst             |   4 +
 llvm/include/llvm-c/Core.h             |  46 ++++++++
 llvm/lib/IR/Core.cpp                   |  62 ++++++++++
 llvm/test/Bindings/llvm-c/echo.ll      |  35 ++++++
 llvm/test/Bindings/llvm-c/float_ops.ll | 155 +++++++++++++++++++++++++
 llvm/tools/llvm-c-test/echo.cpp        |  63 ++++++++++
 6 files changed, 365 insertions(+)
 create mode 100644 llvm/test/Bindings/llvm-c/float_ops.ll

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index d5c634d2f29af5..757c66b1d3df4b 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -226,6 +226,10 @@ Changes to the C API
   * ``LLVMGetOperandBundleArgAtIndex``
   * ``LLVMGetOperandBundleTag``
 
+* Added ``LLVMGetFastMathFlags`` and ``LLVMSetFastMathFlags`` for getting/setting
+  the fast-math flags of an instruction, as well as ``LLVMGetCanUseFastMathFlags``
+  for checking if an instruction can use such flags
+
 Changes to the CodeGen infrastructure
 -------------------------------------
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 7cb809d378c957..43a64378587df8 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -483,6 +483,26 @@ typedef enum {
 
 typedef unsigned LLVMAttributeIndex;
 
+enum {
+  LLVMFastMathAllowReassoc = (1 << 0),
+  LLVMFastMathNoNaNs = (1 << 1),
+  LLVMFastMathNoInfs = (1 << 2),
+  LLVMFastMathNoSignedZeros = (1 << 3),
+  LLVMFastMathAllowReciprocal = (1 << 4),
+  LLVMFastMathAllowContract = (1 << 5),
+  LLVMFastMathApproxFunc = (1 << 6),
+  LLVMFastMathNone = 0,
+  LLVMFastMathAll = -1,
+};
+
+/**
+ * Flags to indicate what fast-math-style optimizations are allowed
+ * on operations
+ *
+ * See https://llvm.org/docs/LangRef.html#fast-math-flags
+ */
+typedef unsigned LLVMFastMathFlags;
+
 /**
  * @}
  */
@@ -4075,6 +4095,32 @@ LLVMBool LLVMGetNNeg(LLVMValueRef NonNegInst);
  */
 void LLVMSetNNeg(LLVMValueRef NonNegInst, LLVMBool IsNonNeg);
 
+/**
+ * Get the flags for which fast-math-style optimizations are allowed for this
+ * value
+ *
+ * Only valid on floating point instructions
+ * @see LLVMGetCanUseFastMathFlags
+ */
+LLVMFastMathFlags LLVMGetFastMathFlags(LLVMValueRef FPMathInst);
+/**
+ * Sets the flags for which fast-math-style optimizations are allowed for this
+ * value
+ *
+ * Only valid on floating point instructions
+ * @see LLVMGetCanUseFastMathFlags
+ */
+void LLVMSetFastMathFlags(LLVMValueRef FPMathInst, LLVMFastMathFlags FMF);
+
+/**
+ * Check if a given value can potentially have fast math flags
+ *
+ * Will return true for floating point arithmetic instructions, and for select,
+ * phil, and call instructions whose type is a floating point type, or a vector
+ * or array thereof See https://llvm.org/docs/LangRef.html#fast-math-flags
+ */
+LLVMBool LLVMGetCanUseFastMathFlags(LLVMValueRef Inst);
+
 /**
  * Gets whether the instruction has the disjoint flag set.
  * Only valid for or instructions.
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 96629de8a7534e..dea6d551b19e87 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -3319,6 +3319,52 @@ void LLVMSetArgOperand(LLVMValueRef Funclet, unsigned i, LLVMValueRef value) {
 
 /*--.. Arithmetic ..........................................................--*/
 
+static FastMathFlags mapFromLLVMFastMathFlags(LLVMFastMathFlags FMF) {
+  FastMathFlags NewFMF;
+  // First, check if all bits are set
+  // If not, check each one explicitly
+  if (FMF == static_cast<LLVMFastMathFlags>(LLVMFastMathAll))
+    NewFMF.set();
+  else {
+    NewFMF.setAllowReassoc((FMF & LLVMFastMathAllowReassoc) != 0);
+    NewFMF.setNoNaNs((FMF & LLVMFastMathNoNaNs) != 0);
+    NewFMF.setNoInfs((FMF & LLVMFastMathNoInfs) != 0);
+    NewFMF.setNoSignedZeros((FMF & LLVMFastMathNoSignedZeros) != 0);
+    NewFMF.setAllowReciprocal((FMF & LLVMFastMathAllowReciprocal) != 0);
+    NewFMF.setAllowContract((FMF & LLVMFastMathAllowContract) != 0);
+    NewFMF.setApproxFunc((FMF & LLVMFastMathApproxFunc) != 0);
+  }
+
+  return NewFMF;
+}
+
+static LLVMFastMathFlags mapToLLVMFastMathFlags(FastMathFlags FMF) {
+
+  // First, check if all bits are set
+  // If not, check each one explicitly
+  if (FMF.isFast())
+    return LLVMFastMathAll;
+  else {
+    LLVMFastMathFlags NewFMF = LLVMFastMathNone;
+    if (FMF.allowReassoc())
+      NewFMF |= LLVMFastMathAllowReassoc;
+    if (FMF.noNaNs())
+      NewFMF |= LLVMFastMathNoNaNs;
+    if (FMF.noInfs())
+      NewFMF |= LLVMFastMathNoInfs;
+    if (FMF.noSignedZeros())
+      NewFMF |= LLVMFastMathNoSignedZeros;
+    if (FMF.allowReciprocal())
+      NewFMF |= LLVMFastMathAllowReciprocal;
+    if (FMF.allowContract())
+      NewFMF |= LLVMFastMathAllowContract;
+    if (FMF.approxFunc())
+      NewFMF |= LLVMFastMathApproxFunc;
+
+    return NewFMF;
+  }
+}
+
 LLVMValueRef LLVMBuildAdd(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS,
                           const char *Name) {
   return wrap(unwrap(B)->CreateAdd(unwrap(LHS), unwrap(RHS), Name));
@@ -3518,6 +3564,22 @@ void LLVMSetNNeg(LLVMValueRef NonNegInst, LLVMBool IsNonNeg) {
   cast<Instruction>(P)->setNonNeg(IsNonNeg);
 }
 
+LLVMFastMathFlags LLVMGetFastMathFlags(LLVMValueRef FPMathInst) {
+  Value *P = unwrap<Value>(FPMathInst);
+  FastMathFlags FMF = cast<Instruction>(P)->getFastMathFlags();
+  return mapToLLVMFastMathFlags(FMF);
+}
+
+void LLVMSetFastMathFlags(LLVMValueRef FPMathInst, LLVMFastMathFlags FMF) {
+  Value *P = unwrap<Value>(FPMathInst);
+  cast<Instruction>(P)->setFastMathFlags(mapFromLLVMFastMathFlags(FMF));
+}
+
+LLVMBool LLVMGetCanUseFastMathFlags(LLVMValueRef V) {
+  Value *Val = unwrap<Value>(V);
+  return isa<FPMathOperator>(Val);
+}
+
 LLVMBool LLVMGetIsDisjoint(LLVMValueRef Inst) {
   Value *P = unwrap<Value>(Inst);
   return cast<PossiblyDisjointInst>(P)->isDisjoint();
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index 2e195beebd7bb3..be0207599478b8 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -299,6 +299,41 @@ entry:
   ret void
 }
 
+define void @test_fast_math_flags(i1 %c, float %a, float %b) {
+entry:
+  %select.f.1 = select i1 %c, float %a, float %b
+  %select.f.2 = select nsz i1 %c, float %a, float %b
+  %select.f.3 = select fast i1 %c, float %a, float %b
+  %select.f.4 = select nnan arcp afn i1 %c, float %a, float %b
+
+  br i1 %c, label %choose_a, label %choose_b
+
+choose_a:
+  br label %final
+
+choose_b:
+  br label %final
+
+final:
+  %phi.f.1 = phi float  [ %a, %choose_a ], [ %b, %choose_b ]
+  %phi.f.2 = phi nsz float [ %a, %choose_a ], [ %b, %choose_b ]
+  %phi.f.3 = phi fast float [ %a, %choose_a ], [ %b, %choose_b ]
+  %phi.f.4 = phi nnan arcp afn float [ %a, %choose_a ], [ %b, %choose_b ]
+  ret void
+}
+
+define float @test_fast_math_flags_call_inner(float %a) {
+  ret float %a
+}
+
+define void @test_fast_math_flags_call_outer(float %a) {
+  %a.1 = call float @test_fast_math_flags_call_inner(float %a)
+  %a.2 = call nsz float @test_fast_math_flags_call_inner(float %a)
+  %a.3 = call fast float @test_fast_math_flags_call_inner(float %a)
+  %a.4 = call nnan arcp afn float @test_fast_math_flags_call_inner(float %a)
+  ret void
+}
+
 !llvm.dbg.cu = !{!0, !2}
 !llvm.module.flags = !{!3}
 
diff --git a/llvm/test/Bindings/llvm-c/float_ops.ll b/llvm/test/Bindings/llvm-c/float_ops.ll
new file mode 100644
index 00000000000000..e569ce26b85358
--- /dev/null
+++ b/llvm/test/Bindings/llvm-c/float_ops.ll
@@ -0,0 +1,155 @@
+; RUN: llvm-as < %s | llvm-dis > %t.orig
+; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo
+; RUN: diff -w %t.orig %t.echo
+;
+source_filename = "/test/Bindings/float_ops.ll"
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+
+define float @float_ops_f32(float %a, float %b) {
+  %1 = fneg float %a
+
+  %2 = fadd float %a, %b
+  %3 = fsub float %a, %b
+  %4 = fmul float %a, %b
+  %5 = fdiv float %a, %b
+  %6 = frem float %a, %b
+
+  ret float %1
+}
+
+define double @float_ops_f64(double %a, double %b) {
+  %1 = fneg double %a
+
+  %2 = fadd double %a, %b
+  %3 = fsub double %a, %b
+  %4 = fmul double %a, %b
+  %5 = fdiv double %a, %b
+  %6 = frem double %a, %b
+
+  ret double %1
+}
+
+define void @float_cmp_f32(float %a, float %b) {
+  %1  = fcmp oeq float %a, %b
+  %2  = fcmp ogt float %a, %b
+  %3  = fcmp olt float %a, %b
+  %4  = fcmp ole float %a, %b
+  %5  = fcmp one float %a, %b
+
+  %6  = fcmp ueq float %a, %b
+  %7  = fcmp ugt float %a, %b
+  %8  = fcmp ult float %a, %b
+  %9  = fcmp ule float %a, %b
+  %10 = fcmp une float %a, %b
+
+  %11 = fcmp ord float %a, %b
+  %12 = fcmp false float %a, %b
+  %13 = fcmp true float %a, %b
+
+  ret void
+}
+
+define void @float_cmp_f64(double %a, double %b) {
+  %1  = fcmp oeq double %a, %b
+  %2  = fcmp ogt double %a, %b
+  %3  = fcmp olt double %a, %b
+  %4  = fcmp ole double %a, %b
+  %5  = fcmp one double %a, %b
+
+  %6  = fcmp ueq double %a, %b
+  %7  = fcmp ugt double %a, %b
+  %8  = fcmp ult double %a, %b
+  %9  = fcmp ule double %a, %b
+  %10 = fcmp une double %a, %b
+
+  %11 = fcmp ord double %a, %b
+  %12 = fcmp false double %a, %b
+  %13 = fcmp true double %a, %b
+
+  ret void
+}
+
+define void @float_cmp_fast_f32(float %a, float %b) {
+  %1  = fcmp fast oeq float %a, %b
+  %2  = fcmp nsz ogt float %a, %b
+  %3  = fcmp nsz nnan olt float %a, %b
+  %4  = fcmp contract ole float %a, %b
+  %5  = fcmp nnan one float %a, %b
+
+  %6  = fcmp nnan ninf nsz ueq float %a, %b
+  %7  = fcmp arcp ugt float %a, %b
+  %8  = fcmp fast ult float %a, %b
+  %9  = fcmp fast ule float %a, %b
+  %10 = fcmp fast une float %a, %b
+
+  %11 = fcmp fast ord float %a, %b
+  %12 = fcmp nnan ninf false float %a, %b
+  %13 = fcmp nnan ninf true float %a, %b
+
+  ret void
+}
+
+define void @float_cmp_fast_f64(double %a, double %b) {
+  %1  = fcmp fast oeq double %a, %b
+  %2  = fcmp nsz ogt double %a, %b
+  %3  = fcmp nsz nnan olt double %a, %b
+  %4  = fcmp contract ole double %a, %b
+  %5  = fcmp nnan one double %a, %b
+
+  %6  = fcmp nnan ninf nsz ueq double %a, %b
+  %7  = fcmp arcp ugt double %a, %b
+  %8  = fcmp fast ult double %a, %b
+  %9  = fcmp fast ule double %a, %b
+  %10 = fcmp fast une double %a, %b
+
+  %11 = fcmp fast ord double %a, %b
+  %12 = fcmp nnan ninf false double %a, %b
+  %13 = fcmp nnan ninf true double %a, %b
+
+  ret void
+}
+
+define float @float_ops_fast_f32(float %a, float %b) {
+  %1 = fneg nnan float %a
+
+  %2 = fadd ninf float %a, %b
+  %3 = fsub nsz float %a, %b
+  %4 = fmul arcp float %a, %b
+  %5 = fdiv contract float %a, %b
+  %6 = frem afn float %a, %b
+
+  %7 = fadd reassoc float %a, %b
+  %8 = fadd reassoc float %7, %b
+
+  %9  = fadd fast float %a, %b
+  %10 = fadd nnan nsz float %a, %b
+  %11 = frem nnan nsz float %a, %b
+  %12 = fdiv nnan nsz arcp float %a, %b
+  %13 = fmul nnan nsz ninf contract float %a, %b
+
+  ret float %1
+}
+
+define double @float_ops_fast_f64(double %a, double %b) {
+  %1 = fneg nnan double %a
+
+  %2 = fadd ninf double %a, %b
+  %3 = fsub nsz double %a, %b
+  %4 = fmul arcp double %a, %b
+  %5 = fdiv contract double %a, %b
+  %6 = frem afn double %a, %b
+
+  %7 = fadd reassoc double %a, %b
+  %8 = fadd reassoc double %7, %b
+
+  %9  = fadd fast double %a, %b
+  %10 = fadd nnan nsz double %a, %b
+  %11 = frem nnan nsz double %a, %b
+  %12 = fdiv nnan nsz arcp double %a, %b
+  %13 = fmul nnan nsz ninf contract double %a, %b
+
+  ret double %1
+}
+
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index bfc14e85a12bff..84c39b06102f10 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -770,8 +770,19 @@ struct FunCloner {
         }
 
         LLVMAddIncoming(Dst, Values.data(), Blocks.data(), IncomingCount);
+        if (LLVMGetCanUseFastMathFlags(Src))
+          LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         return Dst;
       }
+      case LLVMSelect: {
+        LLVMValueRef If = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef Then = CloneValue(LLVMGetOperand(Src, 1));
+        LLVMValueRef Else = CloneValue(LLVMGetOperand(Src, 2));
+        Dst = LLVMBuildSelect(Builder, If, Then, Else, Name);
+        if (LLVMGetCanUseFastMathFlags(Src))
+          LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
       case LLVMCall: {
         SmallVector<LLVMValueRef, 8> Args;
         SmallVector<LLVMOperandBundleRef, 8> Bundles;
@@ -790,6 +801,9 @@ struct FunCloner {
                                               ArgCount, Bundles.data(),
                                               Bundles.size(), Name);
         LLVMSetTailCallKind(Dst, LLVMGetTailCallKind(Src));
+        if (LLVMGetCanUseFastMathFlags(Src))
+          LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+
         CloneAttrs(Src, Dst);
         for (auto Bundle : Bundles)
           LLVMDisposeOperandBundle(Bundle);
@@ -930,6 +944,55 @@ struct FunCloner {
         LLVMSetNNeg(Dst, NNeg);
         break;
       }
+      case LLVMFAdd: {
+        LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildFAdd(Builder, LHS, RHS, Name);
+        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
+      case LLVMFSub: {
+        LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildFSub(Builder, LHS, RHS, Name);
+        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
+      case LLVMFMul: {
+        LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildFMul(Builder, LHS, RHS, Name);
+        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
+      case LLVMFDiv: {
+        LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildFDiv(Builder, LHS, RHS, Name);
+        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
+      case LLVMFRem: {
+        LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildFRem(Builder, LHS, RHS, Name);
+        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
+      case LLVMFNeg: {
+        LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 0));
+        Dst = LLVMBuildFNeg(Builder, Val, Name);
+        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
+      case LLVMFCmp: {
+        LLVMRealPredicate Pred = LLVMGetFCmpPredicate(Src);
+        LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildFCmp(Builder, Pred, LHS, RHS, Name);
+        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+        break;
+      }
       default:
         break;
     }

>From fbe7de5a2c99a4bab08ce7df7ae99c902daaab70 Mon Sep 17 00:00:00 2001
From: Benji Smith <6193112+Benjins at users.noreply.github.com>
Date: Mon, 11 Dec 2023 20:10:24 -0500
Subject: [PATCH 2/3] Fix typo in docs for LLVMGetCanUseFastMathFlags

---
 llvm/include/llvm-c/Core.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 43a64378587df8..6b489487c44ac1 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -4116,7 +4116,7 @@ void LLVMSetFastMathFlags(LLVMValueRef FPMathInst, LLVMFastMathFlags FMF);
  * Check if a given value can potentially have fast math flags
  *
  * Will return true for floating point arithmetic instructions, and for select,
- * phil, and call instructions whose type is a floating point type, or a vector
+ * phi, and call instructions whose type is a floating point type, or a vector
  * or array thereof See https://llvm.org/docs/LangRef.html#fast-math-flags
  */
 LLVMBool LLVMGetCanUseFastMathFlags(LLVMValueRef Inst);

>From fcfcf6f3578afb356f9247ee3114f21ea8236bee Mon Sep 17 00:00:00 2001
From: Benji Smith <6193112+Benjins at users.noreply.github.com>
Date: Tue, 12 Dec 2023 06:56:32 -0500
Subject: [PATCH 3/3] Address PR feedback

---
 llvm/include/llvm-c/Core.h             | 20 +++++----
 llvm/lib/IR/Core.cpp                   | 59 ++++++++++----------------
 llvm/test/Bindings/llvm-c/float_ops.ll |  3 +-
 llvm/tools/llvm-c-test/echo.cpp        | 17 +++-----
 4 files changed, 42 insertions(+), 57 deletions(-)

diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 6b489487c44ac1..37347ca0370ce6 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -492,12 +492,15 @@ enum {
   LLVMFastMathAllowContract = (1 << 5),
   LLVMFastMathApproxFunc = (1 << 6),
   LLVMFastMathNone = 0,
-  LLVMFastMathAll = -1,
+  LLVMFastMathAll = LLVMFastMathAllowReassoc | LLVMFastMathNoNaNs |
+                    LLVMFastMathNoInfs | LLVMFastMathNoSignedZeros |
+                    LLVMFastMathAllowReciprocal | LLVMFastMathAllowContract |
+                    LLVMFastMathApproxFunc,
 };
 
 /**
  * Flags to indicate what fast-math-style optimizations are allowed
- * on operations
+ * on operations.
  *
  * See https://llvm.org/docs/LangRef.html#fast-math-flags
  */
@@ -4097,27 +4100,28 @@ void LLVMSetNNeg(LLVMValueRef NonNegInst, LLVMBool IsNonNeg);
 
 /**
  * Get the flags for which fast-math-style optimizations are allowed for this
- * value
+ * value.
  *
- * Only valid on floating point instructions
+ * Only valid on floating point instructions.
  * @see LLVMGetCanUseFastMathFlags
  */
 LLVMFastMathFlags LLVMGetFastMathFlags(LLVMValueRef FPMathInst);
+
 /**
  * Sets the flags for which fast-math-style optimizations are allowed for this
- * value
+ * value.
  *
- * Only valid on floating point instructions
+ * Only valid on floating point instructions.
  * @see LLVMGetCanUseFastMathFlags
  */
 void LLVMSetFastMathFlags(LLVMValueRef FPMathInst, LLVMFastMathFlags FMF);
 
 /**
- * Check if a given value can potentially have fast math flags
+ * Check if a given value can potentially have fast math flags.
  *
  * Will return true for floating point arithmetic instructions, and for select,
  * phi, and call instructions whose type is a floating point type, or a vector
- * or array thereof See https://llvm.org/docs/LangRef.html#fast-math-flags
+ * or array thereof. See https://llvm.org/docs/LangRef.html#fast-math-flags
  */
 LLVMBool LLVMGetCanUseFastMathFlags(LLVMValueRef Inst);
 
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index dea6d551b19e87..f8f60e06333639 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -3321,48 +3321,35 @@ void LLVMSetArgOperand(LLVMValueRef Funclet, unsigned i, LLVMValueRef value) {
 
 static FastMathFlags mapFromLLVMFastMathFlags(LLVMFastMathFlags FMF) {
   FastMathFlags NewFMF;
-  // First, check if all bits are set
-  // If not, check each one explicitly
-  if (FMF == static_cast<LLVMFastMathFlags>(LLVMFastMathAll))
-    NewFMF.set();
-  else {
-    NewFMF.setAllowReassoc((FMF & LLVMFastMathAllowReassoc) != 0);
-    NewFMF.setNoNaNs((FMF & LLVMFastMathNoNaNs) != 0);
-    NewFMF.setNoInfs((FMF & LLVMFastMathNoInfs) != 0);
-    NewFMF.setNoSignedZeros((FMF & LLVMFastMathNoSignedZeros) != 0);
-    NewFMF.setAllowReciprocal((FMF & LLVMFastMathAllowReciprocal) != 0);
-    NewFMF.setAllowContract((FMF & LLVMFastMathAllowContract) != 0);
-    NewFMF.setApproxFunc((FMF & LLVMFastMathApproxFunc) != 0);
-  }
+  NewFMF.setAllowReassoc((FMF & LLVMFastMathAllowReassoc) != 0);
+  NewFMF.setNoNaNs((FMF & LLVMFastMathNoNaNs) != 0);
+  NewFMF.setNoInfs((FMF & LLVMFastMathNoInfs) != 0);
+  NewFMF.setNoSignedZeros((FMF & LLVMFastMathNoSignedZeros) != 0);
+  NewFMF.setAllowReciprocal((FMF & LLVMFastMathAllowReciprocal) != 0);
+  NewFMF.setAllowContract((FMF & LLVMFastMathAllowContract) != 0);
+  NewFMF.setApproxFunc((FMF & LLVMFastMathApproxFunc) != 0);
 
   return NewFMF;
 }
 
 static LLVMFastMathFlags mapToLLVMFastMathFlags(FastMathFlags FMF) {
+  LLVMFastMathFlags NewFMF = LLVMFastMathNone;
+  if (FMF.allowReassoc())
+    NewFMF |= LLVMFastMathAllowReassoc;
+  if (FMF.noNaNs())
+    NewFMF |= LLVMFastMathNoNaNs;
+  if (FMF.noInfs())
+    NewFMF |= LLVMFastMathNoInfs;
+  if (FMF.noSignedZeros())
+    NewFMF |= LLVMFastMathNoSignedZeros;
+  if (FMF.allowReciprocal())
+    NewFMF |= LLVMFastMathAllowReciprocal;
+  if (FMF.allowContract())
+    NewFMF |= LLVMFastMathAllowContract;
+  if (FMF.approxFunc())
+    NewFMF |= LLVMFastMathApproxFunc;
 
-  // First, check if all bits are set
-  // If not, check each one explicitly
-  if (FMF.isFast())
-    return LLVMFastMathAll;
-  else {
-    LLVMFastMathFlags NewFMF = LLVMFastMathNone;
-    if (FMF.allowReassoc())
-      NewFMF |= LLVMFastMathAllowReassoc;
-    if (FMF.noNaNs())
-      NewFMF |= LLVMFastMathNoNaNs;
-    if (FMF.noInfs())
-      NewFMF |= LLVMFastMathNoInfs;
-    if (FMF.noSignedZeros())
-      NewFMF |= LLVMFastMathNoSignedZeros;
-    if (FMF.allowReciprocal())
-      NewFMF |= LLVMFastMathAllowReciprocal;
-    if (FMF.allowContract())
-      NewFMF |= LLVMFastMathAllowContract;
-    if (FMF.approxFunc())
-      NewFMF |= LLVMFastMathApproxFunc;
-
-    return NewFMF;
-  }
+  return NewFMF;
 }
 
 LLVMValueRef LLVMBuildAdd(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS,
diff --git a/llvm/test/Bindings/llvm-c/float_ops.ll b/llvm/test/Bindings/llvm-c/float_ops.ll
index e569ce26b85358..80475c3d53f133 100644
--- a/llvm/test/Bindings/llvm-c/float_ops.ll
+++ b/llvm/test/Bindings/llvm-c/float_ops.ll
@@ -4,7 +4,6 @@
 ;
 source_filename = "/test/Bindings/float_ops.ll"
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.11.0"
 
 
 define float @float_ops_f32(float %a, float %b) {
@@ -128,6 +127,7 @@ define float @float_ops_fast_f32(float %a, float %b) {
   %11 = frem nnan nsz float %a, %b
   %12 = fdiv nnan nsz arcp float %a, %b
   %13 = fmul nnan nsz ninf contract float %a, %b
+  %14 = fmul nnan nsz ninf arcp contract afn reassoc float %a, %b
 
   ret float %1
 }
@@ -149,6 +149,7 @@ define double @float_ops_fast_f64(double %a, double %b) {
   %11 = frem nnan nsz double %a, %b
   %12 = fdiv nnan nsz arcp double %a, %b
   %13 = fmul nnan nsz ninf contract double %a, %b
+  %14 = fmul nnan nsz ninf arcp contract afn reassoc double %a, %b
 
   ret double %1
 }
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 84c39b06102f10..b352de86d18530 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -770,6 +770,7 @@ struct FunCloner {
         }
 
         LLVMAddIncoming(Dst, Values.data(), Blocks.data(), IncomingCount);
+        // Copy fast math flags here since we return early
         if (LLVMGetCanUseFastMathFlags(Src))
           LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         return Dst;
@@ -779,8 +780,6 @@ struct FunCloner {
         LLVMValueRef Then = CloneValue(LLVMGetOperand(Src, 1));
         LLVMValueRef Else = CloneValue(LLVMGetOperand(Src, 2));
         Dst = LLVMBuildSelect(Builder, If, Then, Else, Name);
-        if (LLVMGetCanUseFastMathFlags(Src))
-          LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       case LLVMCall: {
@@ -801,9 +800,6 @@ struct FunCloner {
                                               ArgCount, Bundles.data(),
                                               Bundles.size(), Name);
         LLVMSetTailCallKind(Dst, LLVMGetTailCallKind(Src));
-        if (LLVMGetCanUseFastMathFlags(Src))
-          LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
-
         CloneAttrs(Src, Dst);
         for (auto Bundle : Bundles)
           LLVMDisposeOperandBundle(Bundle);
@@ -948,41 +944,35 @@ struct FunCloner {
         LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
         LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
         Dst = LLVMBuildFAdd(Builder, LHS, RHS, Name);
-        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       case LLVMFSub: {
         LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
         LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
         Dst = LLVMBuildFSub(Builder, LHS, RHS, Name);
-        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       case LLVMFMul: {
         LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
         LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
         Dst = LLVMBuildFMul(Builder, LHS, RHS, Name);
-        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       case LLVMFDiv: {
         LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
         LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
         Dst = LLVMBuildFDiv(Builder, LHS, RHS, Name);
-        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       case LLVMFRem: {
         LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
         LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
         Dst = LLVMBuildFRem(Builder, LHS, RHS, Name);
-        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       case LLVMFNeg: {
         LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 0));
         Dst = LLVMBuildFNeg(Builder, Val, Name);
-        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       case LLVMFCmp: {
@@ -990,7 +980,6 @@ struct FunCloner {
         LLVMValueRef LHS = CloneValue(LLVMGetOperand(Src, 0));
         LLVMValueRef RHS = CloneValue(LLVMGetOperand(Src, 1));
         Dst = LLVMBuildFCmp(Builder, Pred, LHS, RHS, Name);
-        LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
         break;
       }
       default:
@@ -1002,6 +991,10 @@ struct FunCloner {
       exit(-1);
     }
 
+    // Copy fast-math flags on instructions that support them
+    if (LLVMGetCanUseFastMathFlags(Src))
+      LLVMSetFastMathFlags(Dst, LLVMGetFastMathFlags(Src));
+
     auto Ctx = LLVMGetModuleContext(M);
     size_t NumMetadataEntries;
     auto *AllMetadata =



More information about the llvm-commits mailing list