]> granicus.if.org Git - clang/commitdiff
Annotate imprecise FP division with fpaccuracy metadata
authorPeter Collingbourne <peter@pcc.me.uk>
Thu, 27 Oct 2011 19:19:51 +0000 (19:19 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Thu, 27 Oct 2011 19:19:51 +0000 (19:19 +0000)
The OpenCL single precision division operation is only required to
be accurate to 2.5ulp.  Annotate the fdiv instruction with metadata
which signals to the backend that an imprecise divide instruction
may be used.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143136 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGenOpenCL/fpaccuracy.cl [new file with mode: 0644]

index bd4e553991b33ed0ffff5f09a34fb90f5beff6f1..9ad3ae8352eaee740c6d070d9296125030391d49 100644 (file)
@@ -23,6 +23,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/Frontend/CodeGenOptions.h"
 #include "llvm/Intrinsics.h"
+#include "llvm/LLVMContext.h"
 #include "llvm/Target/TargetData.h"
 using namespace clang;
 using namespace CodeGen;
@@ -2752,3 +2753,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
     return RValue::get(0);
   return ConvertTempToRValue(*this, E->getType(), OrigDest);
 }
+
+void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, unsigned AccuracyN,
+                                    unsigned AccuracyD) {
+  assert(Val->getType()->isFPOrFPVectorTy());
+  if (!AccuracyN || !isa<llvm::Instruction>(Val))
+    return;
+
+  llvm::Value *Vals[2];
+  Vals[0] = llvm::ConstantInt::get(Int32Ty, AccuracyN);
+  Vals[1] = llvm::ConstantInt::get(Int32Ty, AccuracyD);
+  llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(), Vals);
+
+  cast<llvm::Instruction>(Val)->setMetadata(llvm::LLVMContext::MD_fpaccuracy,
+                                            Node);
+}
index 582d1c45722195027ed8b1cb66ea00d0a98433b0..25b4a0a0e7719324eb872bbdaebcfd817df39076 100644 (file)
@@ -1772,8 +1772,18 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
       Builder.SetInsertPoint(DivCont);
     }
   }
-  if (Ops.LHS->getType()->isFPOrFPVectorTy())
-    return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
+  if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
+    llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
+    if (CGF.getContext().getLangOptions().OpenCL) {
+      // OpenCL 1.1 7.4: minimum accuracy of single precision / is 2.5ulp
+      llvm::Type *ValTy = Val->getType();
+      if (ValTy->isFloatTy() ||
+          (isa<llvm::VectorType>(ValTy) &&
+           cast<llvm::VectorType>(ValTy)->getElementType()->isFloatTy()))
+        CGF.SetFPAccuracy(Val, 5, 2);
+    }
+    return Val;
+  }
   else if (Ops.Ty->hasUnsignedIntegerRepresentation())
     return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div");
   else
index 858962d337be462fd9cbf48a434d859f569c3098..4940e21c8be064f3060bdc00712604c27c79f0c2 100644 (file)
@@ -2382,6 +2382,11 @@ public:
   /// a r-value suitable for passing the given parameter.
   void EmitDelegateCallArg(CallArgList &args, const VarDecl *param);
 
+  /// SetFPAccuracy - Set the minimum required accuracy of the given floating
+  /// point operation, expressed as the maximum relative error in ulp.
+  void SetFPAccuracy(llvm::Value *Val, unsigned AccuracyN,
+                     unsigned AccuracyD = 1);
+
 private:
   void EmitReturnOfRValue(RValue RV, QualType Ty);
 
diff --git a/test/CodeGenOpenCL/fpaccuracy.cl b/test/CodeGenOpenCL/fpaccuracy.cl
new file mode 100644 (file)
index 0000000..47fca69
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+typedef __attribute__(( ext_vector_type(4) )) float float4;
+
+float spscalardiv(float a, float b) {
+  // CHECK: @spscalardiv
+  // CHECK: fdiv{{.*}}, !fpaccuracy ![[MD:[0-9]+]]
+  return a / b;
+}
+
+float4 spvectordiv(float4 a, float4 b) {
+  // CHECK: @spvectordiv
+  // CHECK: fdiv{{.*}}, !fpaccuracy ![[MD]]
+  return a / b;
+}
+
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+
+double dpscalardiv(double a, double b) {
+  // CHECK: @dpscalardiv
+  // CHECK-NOT: !fpaccuracy
+  return a / b;
+}
+
+// CHECK: ![[MD]] = metadata !{i{{[0-9]+}} 5, i{{[0-9]+}} 2}