[llvm] r265262 - Mark some FP intrinsics as safe to speculatively execute

Peter Zotov via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 3 05:30:46 PDT 2016


Author: whitequark
Date: Sun Apr  3 07:30:46 2016
New Revision: 265262

URL: http://llvm.org/viewvc/llvm-project?rev=265262&view=rev
Log:
Mark some FP intrinsics as safe to speculatively execute

Floating point intrinsics in LLVM are generally not speculatively
executed, since most of them are defined to behave the same as libm
functions, which set errno.

However, the only error that can happen  when executing ceil, floor,
nearbyint, rint and round libm functions per POSIX.1-2001 is -ERANGE,
and that requires the maximum value of the exponent to be smaller
than  the number of mantissa bits, which is not the case with any of
the floating point types supported by LLVM.

The trunc and copysign functions never set errno per per POSIX.1-2001.

Differential Revision: http://reviews.llvm.org/D18643

Added:
    llvm/trunk/test/Transforms/LICM/hoist-round.ll
Modified:
    llvm/trunk/lib/Analysis/ValueTracking.cpp

Modified: llvm/trunk/lib/Analysis/ValueTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ValueTracking.cpp?rev=265262&r1=265261&r2=265262&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ValueTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/ValueTracking.cpp Sun Apr  3 07:30:46 2016
@@ -2989,17 +2989,29 @@ bool llvm::isSafeToSpeculativelyExecute(
       case Intrinsic::umul_with_overflow:
       case Intrinsic::usub_with_overflow:
         return true;
-      // Sqrt should be OK, since the llvm sqrt intrinsic isn't defined to set
-      // errno like libm sqrt would.
+      // These intrinsics are defined to have the same behavior as libm
+      // functions except for setting errno.
       case Intrinsic::sqrt:
       case Intrinsic::fma:
       case Intrinsic::fmuladd:
+        return true;
+      // These intrinsics are defined to have the same behavior as libm
+      // functions, and the corresponding libm functions never set errno.
+      case Intrinsic::trunc:
+      case Intrinsic::copysign:
       case Intrinsic::fabs:
       case Intrinsic::minnum:
       case Intrinsic::maxnum:
         return true;
-      // TODO: some fp intrinsics are marked as having the same error handling
-      // as libm. They're safe to speculate when they won't error.
+      // These intrinsics are defined to have the same behavior as libm
+      // functions, which never overflow when operating on the IEEE754 types
+      // that we support, and never set errno otherwise.
+      case Intrinsic::ceil:
+      case Intrinsic::floor:
+      case Intrinsic::nearbyint:
+      case Intrinsic::rint:
+      case Intrinsic::round:
+        return true;
       // TODO: are convert_{from,to}_fp16 safe?
       // TODO: can we list target-specific intrinsics here?
       default: break;

Added: llvm/trunk/test/Transforms/LICM/hoist-round.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LICM/hoist-round.ll?rev=265262&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/LICM/hoist-round.ll (added)
+++ llvm/trunk/test/Transforms/LICM/hoist-round.ll Sun Apr  3 07:30:46 2016
@@ -0,0 +1,61 @@
+; RUN: opt -S -licm < %s | FileCheck %s
+
+target datalayout = "E-m:e-p:32:32-i8:8:8-i16:16:16-i64:32:32-f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32"
+
+; This test verifies that ceil, floor, nearbyint, trunc, rint, round,
+; copysign, minnum, maxnum and fabs intrinsics are considered safe
+; to speculate.
+
+; CHECK-LABEL: @test
+; CHECK: call float @llvm.ceil.f32
+; CHECK: call float @llvm.floor.f32
+; CHECK: call float @llvm.nearbyint.f32
+; CHECK: call float @llvm.rint.f32
+; CHECK: call float @llvm.round.f32
+; CHECK: call float @llvm.trunc.f32
+; CHECK: call float @llvm.fabs.f32
+; CHECK: call float @llvm.copysign.f32
+; CHECK: call float @llvm.minnum.f32
+; CHECK: call float @llvm.maxnum.f32
+; CHECK: for.body:
+
+define void @test(float %arg1, float %arg2) {
+entry:
+  br label %for.head
+
+for.head:
+  %IND = phi i32 [ 0, %entry ], [ %IND.new, %for.body ]
+  %CMP = icmp slt i32 %IND, 10
+  br i1 %CMP, label %for.body, label %exit
+
+for.body:
+  %tmp.1 = call float @llvm.ceil.f32(float %arg1)
+  %tmp.2 = call float @llvm.floor.f32(float %tmp.1)
+  %tmp.3 = call float @llvm.nearbyint.f32(float %tmp.2)
+  %tmp.4 = call float @llvm.rint.f32(float %tmp.3)
+  %tmp.5 = call float @llvm.round.f32(float %tmp.4)
+  %tmp.6 = call float @llvm.trunc.f32(float %tmp.5)
+  %tmp.7 = call float @llvm.fabs.f32(float %tmp.6)
+  %tmp.8 = call float @llvm.copysign.f32(float %tmp.7, float %arg2)
+  %tmp.9 = call float @llvm.minnum.f32(float %tmp.8, float %arg2)
+  %tmp.10 = call float @llvm.maxnum.f32(float %tmp.9, float %arg2)
+  call void @consume(float %tmp.10)
+  %IND.new = add i32 %IND, 1
+  br label %for.head
+
+exit:
+  ret void
+}
+
+declare void @consume(float)
+
+declare float @llvm.ceil.f32(float)
+declare float @llvm.floor.f32(float)
+declare float @llvm.nearbyint.f32(float)
+declare float @llvm.rint.f32(float)
+declare float @llvm.round.f32(float)
+declare float @llvm.trunc.f32(float)
+declare float @llvm.fabs.f32(float)
+declare float @llvm.copysign.f32(float, float)
+declare float @llvm.minnum.f32(float, float)
+declare float @llvm.maxnum.f32(float, float)




More information about the llvm-commits mailing list