[cfe-commits] RFC: Half floating point support

John McCall rjmccall at apple.com
Tue Oct 4 16:02:30 PDT 2011


diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 0954e20..5364e1a 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1201,9 +1201,22 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
   case CK_IntegralCast:
   case CK_IntegralToFloating:
   case CK_FloatingToIntegral:
-  case CK_FloatingCast:
     return EmitScalarConversion(Visit(E), E->getType(), DestTy);
-
+  case CK_FloatingCast: {
+    // Floating casts might be a bit special: if we're doing casts to / from half
+    // FP, we should go via special intrinsics.
+    llvm::Value *V = Visit(E);
+    QualType SrcTy = E->getType();
+
+    if (DestTy->isHalfType()) {
+      V = EmitScalarConversion(V, SrcTy, CGF.getContext().FloatTy);
+      return Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), V);
+    } else if (SrcTy->isHalfType()) {
+      V = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), V);
+      return EmitScalarConversion(V, CGF.getContext().FloatTy, DestTy);
+    } else
+      return EmitScalarConversion(V, SrcTy, DestTy);
+  }

This needs to happen in EmitScalarConversion to get compound assignments working correctly.

diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index a1105d2..19ffcb7 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -185,6 +185,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
     case BuiltinType::ULong:
     case BuiltinType::LongLong:
     case BuiltinType::ULongLong:
+    case BuiltinType::Half:
     case BuiltinType::Float:
     case BuiltinType::Double:
     case BuiltinType::LongDouble:

The RTTI for 'half' is not, in fact, in the standard library.

diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d0a3f6b..a6b5901 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -378,12 +378,19 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
   // C99 6.3.2.1p2:
   //   If the lvalue has qualified type, the value has the unqualified
   //   version of the type of the lvalue; otherwise, the value has the
-  //   type of the lvalue.    
+  //   type of the lvalue.
   if (T.hasQualifiers())
     T = T.getUnqualifiedType();
-  
-  return Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
-                                        E, 0, VK_RValue));
+
+  ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
+                                                  E, 0, VK_RValue));
+
+  // Half FP is a bit different: it's a storage-only type, meaning that lvalue
+  // to rvalue conversion also yields an implicit cast to float.
+  if (T->isHalfType())
+    return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast);
+
+  return Res;
 }
 
I think this should be modeled as a promotion and performed during
UsualUnaryConversions, not during DefaultLvalueConversion.

@@ -8170,6 +8177,12 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
                                                 Opc == UO_PostInc,
                                                 Opc == UO_PreInc ||
                                                 Opc == UO_PreDec);
+    // Half FP is a bit different: it's a storage-only type, meaning that any
+    // "use" of it should involve promotion to float.
+    if (resultType->isHalfType()) {
+      Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast);
+      resultType = Context.FloatTy;
+    }

As Eli mentioned, this is wrong.

@@ -3910,6 +3910,24 @@ InitializationSequence::InitializationSequence(Sema &S,
     }
     
     AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+  } else if (SourceType->isHalfType() && ICS.isStandard() &&
+             ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
+    // Convert to rvalue doint promotion to float first.
+    ImplicitConversionSequence LvalueICS;
+    LvalueICS.setStandard();
+    LvalueICS.Standard.setAsIdentityConversion();
+    LvalueICS.Standard.setAllToTypes(Context.FloatTy);
+    LvalueICS.Standard.setToType(0, ICS.Standard.getToType(0));
+    LvalueICS.Standard.First = ICS.Standard.First;
+    LvalueICS.Standard.Second = ICK_Floating_Promotion;
+
+    AddConversionSequenceStep(LvalueICS, Context.FloatTy);
+
+    // Now perform any other conversion remaining.
+    ICS.Standard.setFromType(Context.FloatTy);
+    ICS.Standard.First = ICK_Identity;
+    ICS.Standard.setToType(0, Context.FloatTy);
+    AddConversionSequenceStep(ICS, Entity.getType());

This should be modeled in the standard-conversion logic.

+
+      // Half can be promoted to float.
+      if (FromBuiltin->getKind() == BuiltinType::Half &&
+          ToBuiltin->getKind() == BuiltinType::Float)
+        return true;

Half can also be promoted to double.

+  // Half FP is a bit different: it's a storage-only type, meaning that any
+  // "use" of it should involve promotion to float.
+  if (From->getType()->isHalfType())
+    From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).take();
+

This clearly doesn't belong here.

John.



More information about the cfe-commits mailing list