[PATCH] [ConstantFolding] Fix wrong folding of intrinsic 'convert.from.fp16'.

Andrea Di Biagio Andrea_DiBiagio at sn.scee.net
Thu May 14 07:57:14 PDT 2015


Hi hfinkel, majnemer,

This patch fixes a wrong constant folding of intrinsic 'convert.from.fp16'.

Function 'ConstantFoldScalarCall' (in ConstantFolding.cpp) works under the wrong assumption that a call to 'convert.from.fp16' always returns a value of type 'float'.

However, intrinsic 'convert.from.fp16' can be 'overloaded'; for example, we can use 'convert.from.fp16.fp64' to convert from half to double; etc.

Before this patch, the following example would have triggered an assertion failure in opt (with '-constprop'):
```
define double @foo() {
  entry:
  %0 = call double @llvm.convert.from.fp16.f64(i16 0)
  ret double %0
}
```
in Value.cpp:325: void llvm::Value::replaceAllUsesWith(llvm::Value*): Assertion `New->getType() == getType() && "replaceAllUses of value with new value of different type!" failed.

This patch fixes the problem in ConstantFolding.cpp. When folding a call to convert.from.fp16, we perform a different kind of conversion based on the call return type.

Added test 'Transform/ConstProp/convert-from-fp16.ll'.

Please let me know if ok to submit.

Thanks!
-Andrea

http://reviews.llvm.org/D9771

Files:
  lib/Analysis/ConstantFolding.cpp
  test/Transforms/ConstProp/convert-from-fp16.ll

Index: lib/Analysis/ConstantFolding.cpp
===================================================================
--- lib/Analysis/ConstantFolding.cpp
+++ lib/Analysis/ConstantFolding.cpp
@@ -1397,6 +1397,25 @@
   return APF.convertToDouble();
 }
 
+// Returns the floating point arithmetic semantic associated to type 'Ty'.
+// This helper function is used by 'ConstantFoldScalarCall' when
+// constant folding intrinsic calls to 'convert_from_fp16'.
+static const fltSemantics &getFloatingPointSemanticFromType(const Type *Ty) {
+  if (Ty->isHalfTy())
+    return APFloat::IEEEhalf;
+  else if (Ty->isFloatTy())
+    return APFloat::IEEEsingle;
+  else if (Ty->isDoubleTy())
+    return APFloat::IEEEdouble;
+  else if (Ty->isFP128Ty())
+    return APFloat::IEEEquad;
+  else if (Ty->isX86_FP80Ty())
+    return APFloat::x87DoubleExtended;
+  else if (Ty->isPPC_FP128Ty())
+    return APFloat::PPCDoubleDouble;
+  llvm_unreachable("Not a floating point type!");
+}
+
 static Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID,
                                         Type *Ty, ArrayRef<Constant *> Operands,
                                         const TargetLibraryInfo *TLI) {
@@ -1543,8 +1562,10 @@
         APFloat Val(APFloat::IEEEhalf, Op->getValue());
 
         bool lost = false;
+        
+        const fltSemantics &FPS = getFloatingPointSemanticFromType(Ty);
         APFloat::opStatus status =
-          Val.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &lost);
+          Val.convert(FPS, APFloat::rmNearestTiesToEven, &lost);
 
         // Conversion is always precise.
         (void)status;
Index: test/Transforms/ConstProp/convert-from-fp16.ll
===================================================================
--- test/Transforms/ConstProp/convert-from-fp16.ll
+++ test/Transforms/ConstProp/convert-from-fp16.ll
@@ -0,0 +1,45 @@
+; RUN: opt -constprop -S < %s | FileCheck %s
+
+; Verify that we don't crash with an assertion failure when constant folding
+; a call to intrinsic 'convert.from.fp16' if the return type is not 'float'.
+
+define float @fold_from_fp16_to_fp32() {
+; CHECK: ret float 0.000000e+00
+entry:
+  %0 = call float @llvm.convert.from.fp16.f32(i16 0)
+  ret float %0
+}
+
+define double @fold_from_fp16_to_fp64() {
+; CHECK: ret double 0.000000e+00
+entry:
+  %0 = call double @llvm.convert.from.fp16.f64(i16 0)
+  ret double %0
+}
+
+define x86_fp80 @fold_from_fp16_to_fp80() {
+; CHECK: ret x86_fp80 0xK00000000000000000000
+entry:
+  %0 = call x86_fp80 @llvm.convert.from.fp16.f80(i16 0)
+  ret x86_fp80 %0
+}
+
+define fp128 @fold_from_fp16_to_fp128() {
+; CHECK: ret fp128 0xL00000000000000000000000000000000
+entry:
+  %0 = call fp128 @llvm.convert.from.fp16.f128(i16 0)
+  ret fp128 %0
+}
+
+define ppc_fp128 @fold_from_fp16_to_ppcfp128() {
+; CHECK: ret ppc_fp128 0xM00000000000000000000000000000000
+entry:
+  %0 = call ppc_fp128 @llvm.convert.from.fp16.ppcf128(i16 0)
+  ret ppc_fp128 %0
+}
+
+declare float @llvm.convert.from.fp16.f32(i16)
+declare double @llvm.convert.from.fp16.f64(i16)
+declare x86_fp80 @llvm.convert.from.fp16.f80(i16)
+declare fp128 @llvm.convert.from.fp16.f128(i16)
+declare ppc_fp128 @llvm.convert.from.fp16.ppcf128(i16)

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D9771.25776.patch
Type: text/x-patch
Size: 3230 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150514/9bca9748/attachment.bin>


More information about the llvm-commits mailing list