r232971 - [CodeGen] Properly support the half FP type with non-native operations.

Ahmed Bougacha ahmed.bougacha at gmail.com
Mon Mar 23 10:54:16 PDT 2015


Author: ab
Date: Mon Mar 23 12:54:16 2015
New Revision: 232971

URL: http://llvm.org/viewvc/llvm-project?rev=232971&view=rev
Log:
[CodeGen] Properly support the half FP type with non-native operations.

On AArch64, the -fallow-half-args-and-returns option is the default.
With it, the half type is considered legal (rather than the i16 used
normally for __fp16), but no operation is, except conversions and
load/stores and such.

The previous behavior was tantamount to saying LangOpts.NativeHalfType
was implied by LangOpts.HalfArgsAndReturns, which isn't true.
Instead, teach the various parts of CodeGen that already know about
half (using the intrinsics or not) about this weird in-between case,
where the "half" type is legal, but operations on it aren't.

This is a smaller intermediate step to the end-goal of removing the
intrinsic, always using "half", and letting the backend legalize.

Builds on r232968.
rdar://20045970, rdar://17468714
Differential Revision: http://reviews.llvm.org/D8367

Modified:
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/test/CodeGen/fp16-ops.c

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=232971&r1=232970&r2=232971&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Mon Mar 23 12:54:16 2015
@@ -751,20 +751,29 @@ Value *ScalarExprEmitter::EmitScalarConv
 
   llvm::Type *DstTy = ConvertType(DstType);
 
-  // Cast from storage-only half FP using the special intrinsic.
-  if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
-      !CGF.getContext().getLangOpts().HalfArgsAndReturns) {
-    if (DstTy->isFloatingPointTy())
-      return Builder.CreateCall(
-          CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, DstTy), Src);
-
-    // If this isn't an FP->FP conversion, go through float.
-    Src = Builder.CreateCall(
-        CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
-                             CGF.CGM.FloatTy),
-        Src);
-    SrcType = CGF.getContext().FloatTy;
-    SrcTy = CGF.FloatTy;
+  // Cast from half through float if half isn't a native type.
+  if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+    // Cast to FP using the intrinsic if the half type itself isn't supported.
+    if (DstTy->isFloatingPointTy()) {
+      if (!CGF.getContext().getLangOpts().HalfArgsAndReturns)
+        return Builder.CreateCall(
+            CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, DstTy),
+            Src);
+    } else {
+      // Cast to other types through float, using either the intrinsic or FPExt,
+      // depending on whether the half type itself is supported
+      // (as opposed to operations on half, available with NativeHalfType).
+      if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+        Src = Builder.CreateCall(
+            CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
+                                 CGF.CGM.FloatTy),
+            Src);
+      } else {
+        Src = Builder.CreateFPExt(Src, CGF.CGM.FloatTy, "conv");
+      }
+      SrcType = CGF.getContext().FloatTy;
+      SrcTy = CGF.FloatTy;
+    }
   }
 
   // Ignore conversions like int -> uint.
@@ -823,12 +832,18 @@ Value *ScalarExprEmitter::EmitScalarConv
     EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType,
                              DstTy);
 
-  // Cast to half using the intrinsic if from FP type, through float otherwise.
-  if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
-      !CGF.getContext().getLangOpts().HalfArgsAndReturns) {
-    if (SrcTy->isFloatingPointTy())
-      return Builder.CreateCall(
-          CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, SrcTy), Src);
+  // Cast to half through float if half isn't a native type.
+  if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+    // Make sure we cast in a single step if from another FP type.
+    if (SrcTy->isFloatingPointTy()) {
+      // Use the intrinsic if the half type itself isn't supported
+      // (as opposed to operations on half, available with NativeHalfType).
+      if (!CGF.getContext().getLangOpts().HalfArgsAndReturns)
+        return Builder.CreateCall(
+            CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, SrcTy), Src);
+      // If the half type is supported, just use an fptrunc.
+      return Builder.CreateFPTrunc(Src, DstTy);
+    }
     DstTy = CGF.FloatTy;
   }
 
@@ -856,10 +871,14 @@ Value *ScalarExprEmitter::EmitScalarConv
   }
 
   if (DstTy != ResTy) {
-    assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
-    Res = Builder.CreateCall(
+    if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+      assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
+      Res = Builder.CreateCall(
         CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy),
         Res);
+    } else {
+      Res = Builder.CreateFPTrunc(Res, ResTy, "conv");
+    }
   }
 
   return Res;
@@ -1762,13 +1781,16 @@ ScalarExprEmitter::EmitScalarPrePostIncD
     // Add the inc/dec to the real part.
     llvm::Value *amt;
 
-    if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
-        !CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+    if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
       // Another special case: half FP increment should be done via float
-      value = Builder.CreateCall(
-          CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
-                               CGF.CGM.FloatTy),
-          input);
+      if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+        value = Builder.CreateCall(
+            CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
+                                 CGF.CGM.FloatTy),
+            input, "incdec.conv");
+      } else {
+        value = Builder.CreateFPExt(input, CGF.CGM.FloatTy, "incdec.conv");
+      }
     }
 
     if (value->getType()->isFloatTy())
@@ -1786,12 +1808,16 @@ ScalarExprEmitter::EmitScalarPrePostIncD
     }
     value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
 
-    if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
-        !CGF.getContext().getLangOpts().HalfArgsAndReturns)
-      value = Builder.CreateCall(
-          CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16,
-                               CGF.CGM.FloatTy),
-          value);
+    if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+      if (!CGF.getContext().getLangOpts().HalfArgsAndReturns) {
+        value = Builder.CreateCall(
+            CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16,
+                                 CGF.CGM.FloatTy),
+            value, "incdec.conv");
+      } else {
+        value = Builder.CreateFPTrunc(value, input->getType(), "incdec.conv");
+      }
+    }
 
   // Objective-C pointer types.
   } else {

Modified: cfe/trunk/test/CodeGen/fp16-ops.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/fp16-ops.c?rev=232971&r1=232970&r2=232971&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/fp16-ops.c (original)
+++ cfe/trunk/test/CodeGen/fp16-ops.c Mon Mar 23 12:54:16 2015
@@ -1,5 +1,8 @@
 // REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s --check-prefix=NOHALF --check-prefix=CHECK
+// RUN: %clang_cc1 -emit-llvm -o - -triple aarch64-none-linux-gnueabi %s | FileCheck %s --check-prefix=NOHALF --check-prefix=CHECK
+// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi -fallow-half-arguments-and-returns %s | FileCheck %s --check-prefix=HALF --check-prefix=CHECK
+// RUN: %clang_cc1 -emit-llvm -o - -triple aarch64-none-linux-gnueabi -fallow-half-arguments-and-returns %s | FileCheck %s --check-prefix=HALF --check-prefix=CHECK
 typedef unsigned cond_t;
 
 volatile cond_t test;
@@ -12,289 +15,300 @@ void foo(void) {
 
   // Check unary ops
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // NOHALF: [[F16TOF32:call float @llvm.convert.from.fp16.f32]]
+  // HALF: [[F16TOF32:fpext half]]
   // CHECK: fptoui float
   test = (h0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: uitofp i32
+  // NOHALF: [[F32TOF16:call i16 @llvm.convert.to.fp16.f32]]
+  // HALF: [[F32TOF16:fptrunc float]]
+  h0 = (test);
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp une float
   test = (!h1);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fsub float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // NOHALF: [[F32TOF16]]
+  // HALF: [[F32TOF16]]
   h1 = -h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F32TOF16]]
   h1 = +h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1++;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   ++h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   --h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1--;
 
   // Check binary ops with various operands
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fmul float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = h0 * h2;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F32TOF16]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fmul float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = h0 * (__fp16) -2.0f;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fmul float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = h0 * f2;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fmul float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = f0 * h2;
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fdiv float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (h0 / h2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fdiv float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (h0 / (__fp16) -2.0f);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fdiv float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (h0 / f2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fdiv float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (f0 / h2);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (h2 + h0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = ((__fp16)-2.0 + h0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (h2 + f0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (f2 + h0);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fsub float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (h2 - h0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fsub float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = ((__fp16)-2.0f - h0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fsub float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (h2 - f0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fsub float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h1 = (f2 - h0);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp olt
   test = (h2 < h0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fcmp olt
   test = (h2 < (__fp16)42.0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp olt
   test = (h2 < f0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp olt
   test = (f2 < h0);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp ogt
   test = (h0 > h2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fcmp ogt
   test = ((__fp16)42.0 > h2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp ogt
   test = (h0 > f2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp ogt
   test = (f0 > h2);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp ole
   test = (h2 <= h0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fcmp ole
   test = (h2 <= (__fp16)42.0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp ole
   test = (h2 <= f0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp ole
   test = (f2 <= h0);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp oge
   test = (h0 >= h2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fcmp oge
   test = (h0 >= (__fp16)-2.0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp oge
   test = (h0 >= f2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp oge
   test = (f0 >= h2);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp oeq
   test = (h1 == h2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fcmp oeq
   test = (h1 == (__fp16)1.0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp oeq
   test = (h1 == f1);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp oeq
   test = (f1 == h1);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp une
   test = (h1 != h2);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fcmp une
   test = (h1 != (__fp16)1.0);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp une
   test = (h1 != f1);
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp une
   test = (f1 != h1);
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fcmp une
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F32TOF16]]
   h1 = (h1 ? h2 : h0);
   // Check assignments (inc. compound)
   h0 = h1;
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // NOHALF: [[F32TOF16]]
+  // HALF: store {{.*}} half 0xHC000
   h0 = (__fp16)-2.0f;
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 = f0;
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 += h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fadd
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 += (__fp16)1.0f;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fadd
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 += f2;
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fsub
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 -= h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fsub
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 -= (__fp16)1.0;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fsub
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 -= f2;
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fmul
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 *= h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fmul
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 *= (__fp16)1.0;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fmul
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 *= f2;
 
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // CHECK: [[F16TOF32]]
   // CHECK: fdiv
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 /= h1;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
+  // NOHALF: [[F16TOF32]]
   // CHECK: fdiv
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 /= (__fp16)1.0;
-  // CHECK: call float @llvm.convert.from.fp16.f32(
+  // CHECK: [[F16TOF32]]
   // CHECK: fdiv
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(
+  // CHECK: [[F32TOF16]]
   h0 /= f2;
 
   // Check conversions to/from double
-  // CHECK: call i16 @llvm.convert.to.fp16.f64(
+  // NOHALF: call i16 @llvm.convert.to.fp16.f64(
+  // HALF: fptrunc double {{.*}} to half
   h0 = d0;
 
   // CHECK: [[MID:%.*]] = fptrunc double {{%.*}} to float
-  // CHECK: call i16 @llvm.convert.to.fp16.f32(float [[MID]])
+  // NOHALF: call i16 @llvm.convert.to.fp16.f32(float [[MID]])
+  // HALF: fptrunc float [[MID]] to half
   h0 = (float)d0;
 
-  // CHECK: call double @llvm.convert.from.fp16.f64(
+  // NOHALF: call double @llvm.convert.from.fp16.f64(
+  // HALF: fpext half {{.*}} to double
   d0 = h0;
 
-  // CHECK: [[MID:%.*]] = call float @llvm.convert.from.fp16.f32(
+  // NOHALF: [[MID:%.*]] = call float @llvm.convert.from.fp16.f32(
+  // HALF: [[MID:%.*]] = fpext half {{.*}} to float
   // CHECK: fpext float [[MID]] to double
   d0 = (float)h0;
 }





More information about the cfe-commits mailing list