zahiraam updated this revision to Diff 437191.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113107/new/

https://reviews.llvm.org/D113107

Files:
  clang/docs/LanguageExtensions.rst
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/TargetInfo.h
  clang/lib/Basic/Targets/X86.cpp
  clang/lib/Basic/Targets/X86.h
  clang/lib/CodeGen/CGExprComplex.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/test/CodeGen/X86/Float16-arithmetic.c
  clang/test/CodeGen/X86/Float16-complex.c
  clang/test/CodeGen/X86/avx512fp16-complex.c
  clang/test/Sema/Float16.c
  clang/test/Sema/conversion-target-dep.c
  clang/test/SemaCXX/Float16.cpp

Index: clang/test/SemaCXX/Float16.cpp
===================================================================
--- clang/test/SemaCXX/Float16.cpp
+++ clang/test/SemaCXX/Float16.cpp
@@ -1,18 +1,10 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-pc %s
-// RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s -DHAVE
-// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s -DHAVE
-// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s -DHAVE
+// RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s
 
-#ifdef HAVE
 // expected-no-diagnostics
-#endif // HAVE
 
-#ifndef HAVE
-// expected-error@+2{{_Float16 is not supported on this target}}
-#endif // !HAVE
 _Float16 f;
 
-#ifndef HAVE
-// expected-error@+2{{invalid suffix 'F16' on floating constant}}
-#endif // !HAVE
 const auto g = 1.1F16;
Index: clang/test/Sema/conversion-target-dep.c
===================================================================
--- clang/test/Sema/conversion-target-dep.c
+++ clang/test/Sema/conversion-target-dep.c
@@ -6,7 +6,7 @@
 
 long double ld;
 double d;
-_Float16 f16; // x86-error {{_Float16 is not supported on this target}}
+_Float16 f16;
 
 int main(void) {
   ld = d; // x86-warning {{implicit conversion increases floating-point precision: 'double' to 'long double'}}
Index: clang/test/Sema/Float16.c
===================================================================
--- clang/test/Sema/Float16.c
+++ clang/test/Sema/Float16.c
@@ -1,18 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-pc %s
-// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-pc -target-feature +avx512fp16 %s -DHAVE
-// RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s -DHAVE
-// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s -DHAVE
-// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s -DHAVE
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-pc -target-feature +avx512fp16 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s
 
-#ifndef HAVE
-// expected-error@+2{{_Float16 is not supported on this target}}
-#endif // HAVE
-_Float16 f;
-
-#ifdef HAVE
 _Complex _Float16 a;
 void builtin_complex(void) {
   _Float16 a = 0;
   (void)__builtin_complex(a, a); // expected-error {{'_Complex _Float16' is invalid}}
 }
-#endif
+
Index: clang/test/CodeGen/X86/Float16-complex.c
===================================================================
--- clang/test/CodeGen/X86/Float16-complex.c
+++ clang/test/CodeGen/X86/Float16-complex.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -target-feature +avx512fp16 -o - | FileCheck %s --check-prefix=X86
+// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s --check-prefixes=X86-PROM
 
 _Float16 _Complex add_half_rr(_Float16 a, _Float16 b) {
   // X86-LABEL: @add_half_rr(
@@ -85,7 +86,29 @@
   return a * b;
 }
 _Float16 _Complex mul_half_cc(_Float16 _Complex a, _Float16 _Complex b) {
-  // X86-LABEL: @mul_half_cc(
+  // CHECK: @mul_half_cc(
+
+  // X86-PROM: fpext half {{.*}} to float
+  // X86-PROM: fpext half {{.*}} to float
+  // X86-PROM: fpext half {{.*}} to float
+  // X86-PROM: fpext half {{.*}} to float
+  // X86-PROM: %[[AC:[^ ]+]] = fmul float
+  // X86-PROM: %[[BD:[^ ]+]] = fmul float
+  // X86-PROM: %[[AD:[^ ]+]] = fmul float
+  // X86-PROM: %[[BC:[^ ]+]] = fmul float
+  // X86-PROM: %[[RR:[^ ]+]] = fsub float
+  // X86-PROM: %[[RI:[^ ]+]] = fadd float
+  // X86-PROM: fcmp uno float %[[RR]]
+  // X86-PROM: fcmp uno float %[[RI]]
+  // X86-PROM: call <2 x float> @__mulsc3(
+  // X86-PROM: fptrunc float {{.*}} to half
+  // X86-PROM: fptrunc float {{.*}} to half
+  // X86-PROM: %[[RETR:[^ ]+]] = getelementptr inbounds { half, half }
+  // X86-PROM: %[[RETI:[^ ]+]] = getelementptr inbounds { half, half }
+  // X86-PROM: store half {{.*}}, ptr %[[RETR]]
+  // X86-PROM: store half {{.*}}, ptr %[[RETI]]
+  // X86-PROM: load <2 x half>, ptr {{.*}}
+
   // X86: %[[AC:[^ ]+]] = fmul
   // X86: %[[BD:[^ ]+]] = fmul
   // X86: %[[AD:[^ ]+]] = fmul
@@ -98,7 +121,8 @@
   // X86: fcmp uno half %[[RR]]
   // X86: fcmp uno half %[[RI]]
   // X86: call {{.*}} @__mulhc3(
-  // X86: ret
+
+  // CHECK: ret
   return a * b;
 }
 
@@ -118,10 +142,32 @@
   return a / b;
 }
 _Float16 _Complex div_half_rc(_Float16 a, _Float16 _Complex b) {
-  // X86-LABEL: @div_half_rc(
+  // CHECK: @div_half_rc(
   // X86-NOT: fdiv
   // X86: call {{.*}} @__divhc3(
-  // X86: ret
+
+  // X86-PROM: load half
+  // X86-PROM: fpext half {{.*}} to float
+  // X86-PROM: getelementptr inbounds { half, half }
+  // X86-PROM: load half
+  // X86-PROM: getelementptr inbounds { half, half }
+  // X86-PROM: load half
+  // X86-PROM: fpext half {{.*}} to float
+  // X86-PROM: fpext half {{.*}} to float
+  // X86-PROM: call {{.*}} @__divsc3(
+  // X86-PROM: getelementptr inbounds { float, float }
+  // X86-PROM: load float
+  // X86-PROM: getelementptr inbounds { float, float }
+  // X86-PROM: load float
+  // X86-PROM: fptrunc float {{.*}} to half
+  // X86-PROM: fptrunc float {{.*}} to half
+  // X86-PROM: getelementptr inbounds { half, half }
+  // X86-PROM: getelementptr inbounds { half, half }
+  // X86-PROM: store half {{.*}}
+  // X86-PROM: store half {{.*}}
+
+  // CHECK: ret
+
   return a / b;
 }
 _Float16 _Complex div_half_cc(_Float16 _Complex a, _Float16 _Complex b) {
Index: clang/test/CodeGen/X86/Float16-arithmetic.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/X86/Float16-arithmetic.c
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -triple  x86_64-unknown-unknown \
+// RUN: -emit-llvm -o - %s  | FileCheck %s --check-prefixes=CHECK
+
+_Float16 add1(_Float16 a, _Float16 b) {
+  // CHECK-LABEL: define {{.*}} half @add1
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fadd float {{.*}}, {{.*}}
+  // CHECK: fptrunc float {{.*}} to half
+  // CHECK: ret half
+  return a + b;
+}
+
+_Float16 add2(_Float16 a, _Float16 b, _Float16 c) {
+  // CHECK-LABEL: define dso_local half @add2
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fadd float {{.*}}, {{.*}}
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fadd float {{.*}}, {{.*}}
+  // CHECK: fptrunc float {{.*}} to half
+  // CHECK: ret half
+  return a + b + c;
+}
+
+_Float16 div(_Float16 a, _Float16 b) {
+  // CHECK-LABEL: define dso_local half @div
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fdiv float {{.*}}, {{.*}}
+  // CHECK: fptrunc float {{.*}} to half
+  // CHECK: ret half
+  return a / b;
+}
+
+_Float16 mul(_Float16 a, _Float16 b) {
+  // CHECK-LABEL: define dso_local half @mul
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: load half, ptr{{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fmul float {{.*}}, {{.*}}
+  // CHECK: fptrunc float {{.*}} to half
+  // CHECK: ret half
+  return a * b;
+}
+
+_Float16 add_and_mul1(_Float16 a, _Float16 b, _Float16 c, _Float16 d) {
+  // CHECK-LABEL: define dso_local half @add_and_mul1
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fmul float {{.*}}, {{.*}}
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fmul float {{.*}}, {{.*}}
+  // CHECK: fadd float {{.*}}, {{.*}}
+  // CHECK: fptrunc float {{.*}} to half
+  // CHECK: ret half
+  return a * b + c * d;
+} 
+
+_Float16 add_and_mul2(_Float16 a, _Float16 b, _Float16 c, _Float16 d) {
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: alloca half
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}
+  // CHECK: store half {{.*}}, ptr {{.*}}, align 2
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: load half, ptr {{.*}}, align 2
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fmul float 6.000000e+00, {{.*}}
+  // CHECK: fsub float {{.*}}, {{.*}}
+  // CHECK: load half, ptr {{.*}}
+  // CHECK: fpext half {{.*}} to float
+  // CHECK: fadd float {{.*}}, {{.*}}
+  // CHECK: fptrunc float {{.*}} to half
+  // CHECK: ret half {{.*}}
+  return (a - 6*b)+c;
+}
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4407,6 +4407,11 @@
   /// EmitLoadOfComplex - Load a complex number from the specified l-value.
   ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc);
 
+  ComplexPairTy EmitPromotedComplexExpr(ComplexPairTy Src, QualType SrcTy,
+                                       llvm::Type *DstTy, SourceLocation Loc);
+  ComplexPairTy EmitPromotedScalarExpr(llvm::Value *Src, QualType SrcTy,
+                                       llvm::Type *DstType, SourceLocation Loc);
+
   Address emitAddrOfRealComponent(Address complex, QualType complexType);
   Address emitAddrOfImagComponent(Address complex, QualType complexType);
 
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -218,6 +218,7 @@
   CGBuilderTy &Builder;
   bool IgnoreResultAssign;
   llvm::LLVMContext &VMContext;
+
 public:
 
   ScalarExprEmitter(CodeGenFunction &cgf, bool ira=false)
@@ -791,7 +792,10 @@
   // Helper functions for fixed point binary operations.
   Value *EmitFixedPointBinOp(const BinOpInfo &Ops);
 
-  BinOpInfo EmitBinOps(const BinaryOperator *E);
+  BinOpInfo EmitBinOps(const BinaryOperator *E,
+                       QualType PromotionTy = QualType());
+  Value *EmitPromoted(const Expr *E);
+
   LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
                             Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
                                   Value *&Result);
@@ -799,10 +803,24 @@
   Value *EmitCompoundAssign(const CompoundAssignOperator *E,
                             Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
 
+  QualType getPromotionType(const Expr *E) {
+    if (E->getType()->isFloat16Type()) {
+      if (CGF.getTarget().ShouldEmitWithExcessPrecision())
+        return CGF.getContext().FloatTy;
+    }
+    return QualType();
+  }
+
   // Binary operators and binary compound assignment operators.
 #define HANDLEBINOP(OP) \
   Value *VisitBin ## OP(const BinaryOperator *E) {                         \
-    return Emit ## OP(EmitBinOps(E));                                      \
+    QualType promotionTy = getPromotionType(E);                            \
+    auto result = Emit##OP(EmitBinOps(E, promotionTy));                    \
+    if (result)                                                            \
+      if (!promotionTy.isNull())                                           \
+      result = Builder.CreateFPTrunc(result, ConvertType(E->getType()),    \
+                                     "unpromotion");                       \
+    return result;                                                         \
   }                                                                        \
   Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) {       \
     return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP);          \
@@ -1312,7 +1330,6 @@
     return EmitConversionToBool(Src, SrcType);
 
   llvm::Type *DstTy = ConvertType(DstType);
-
   // 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.
@@ -3050,12 +3067,56 @@
 //                           Binary Operators
 //===----------------------------------------------------------------------===//
 
-BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
+#define HANDLESCLRPROMOTION(OP, CLASS)                                        \
+  return Emit##OP(EmitBinOps(dyn_cast<BinaryOperator>(E->IgnoreParens()),     \
+                             getPromotionType(E)));
+
+Value *ScalarExprEmitter::EmitPromoted(const Expr *E) {
+  if (auto *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens())) {
+    switch (BinOp->getOpcode()) {
+    case BO_Add:
+      HANDLESCLRPROMOTION(Add, BinaryOperator);
+    case BO_Sub:
+      HANDLESCLRPROMOTION(Sub, BinaryOperator);
+    case BO_Mul:
+      HANDLESCLRPROMOTION(Mul, BinaryOperator);
+    case BO_Div:
+      HANDLESCLRPROMOTION(Div, BinaryOperator);
+    default:
+      return Visit(const_cast<Expr *>(E));
+    }
+  } else if (auto *UnOp = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+    switch (UnOp->getOpcode()) {
+    case UO_Minus:
+      HANDLESCLRPROMOTION(Sub, BinaryOperator);
+    default:
+      return Visit(const_cast<Expr *>(E));
+    }
+  }
+  else
+    return Visit(const_cast<Expr *>(E));
+}
+#undef HANDLESCLRPROMOTION
+
+BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E, QualType PromotionType) {
   TestAndClearIgnoreResultAssign();
   BinOpInfo Result;
-  Result.LHS = Visit(E->getLHS());
-  Result.RHS = Visit(E->getRHS());
-  Result.Ty  = E->getType();
+  if (!PromotionType.isNull()) {
+    Result.LHS =
+        EmitScalarCast(EmitPromoted(E->getLHS()), E->getType(), E->getType(),
+                       ConvertType(E->getType()), ConvertType(PromotionType),
+                       ScalarConversionOpts());
+    Result.RHS =
+        EmitScalarCast(EmitPromoted(E->getRHS()), E->getType(), E->getType(),
+                       ConvertType(E->getType()), ConvertType(PromotionType),
+                       ScalarConversionOpts());
+    Result.Ty = PromotionType;
+  }
+  else {
+    Result.LHS = Visit(E->getLHS());
+    Result.RHS = Visit(E->getRHS());
+    Result.Ty  = E->getType();
+  }
   Result.Opcode = E->getOpcode();
   Result.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts());
   Result.E = E;
Index: clang/lib/CodeGen/CGExprComplex.cpp
===================================================================
--- clang/lib/CodeGen/CGExprComplex.cpp
+++ clang/lib/CodeGen/CGExprComplex.cpp
@@ -68,6 +68,17 @@
     return I;
   }
 
+  QualType getPromotionType(const Expr *E) {
+    if (E->getType()->isComplexType()) {
+      QualType ElementType =
+          E->getType()->castAs<ComplexType>()->getElementType();
+      if (ElementType->isFloat16Type())
+        if (CGF.getTarget().ShouldEmitWithExcessPrecision())
+          return CGF.getContext().getComplexType(CGF.getContext().FloatTy);
+    }
+    return QualType();
+  }
+
   /// EmitLoadOfLValue - Given an expression with complex type that represents a
   /// value l-value, this method emits the address of the l-value, then loads
   /// and returns the result.
@@ -253,7 +264,9 @@
     QualType Ty;  // Computation Type.
   };
 
-  BinOpInfo EmitBinOps(const BinaryOperator *E);
+  BinOpInfo EmitBinOps(const BinaryOperator *E,
+                       QualType PromotionTy = QualType());
+  ComplexPairTy EmitPromoted(const Expr *E);
   LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
                                   ComplexPairTy (ComplexExprEmitter::*Func)
                                   (const BinOpInfo &),
@@ -876,21 +889,124 @@
   return ComplexPairTy(DSTr, DSTi);
 }
 
+#define HANDLECMPLXPROMOTION(OP, CLASS)                                        \
+  return Emit##OP(EmitBinOps(dyn_cast<BinaryOperator>(E->IgnoreParens()),      \
+                             getPromotionType(E)));
+
+ComplexPairTy ComplexExprEmitter::EmitPromoted(const Expr *E) {
+  if (auto *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens())) {
+    switch (BinOp->getOpcode()) {
+    case BO_Add:
+      HANDLECMPLXPROMOTION(BinAdd, BinaryOperator);
+    case BO_Sub:
+      HANDLECMPLXPROMOTION(BinSub, BinaryOperator);
+    case BO_Mul:
+      HANDLECMPLXPROMOTION(BinMul, BinaryOperator);
+    case BO_Div:
+      HANDLECMPLXPROMOTION(BinDiv, BinaryOperator);
+    default:
+      return Visit(const_cast<Expr *>(E));
+    }
+  } else if (auto *UnOp = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+    switch (UnOp->getOpcode()) {
+    case UO_Minus:
+      HANDLECMPLXPROMOTION(BinSub, BinaryOperator);
+    default:
+      return Visit(const_cast<Expr *>(E));
+    }
+  } else
+    return Visit(const_cast<Expr *>(E));
+}
+#undef HANDLECMPLXPROMOTION
+
+ComplexPairTy CodeGenFunction::EmitPromotedScalarExpr(
+    llvm::Value *Src, QualType SrcTy, llvm::Type *DstType, SourceLocation Loc) {
+  llvm::Type *SrcElementTy;
+  llvm::Type *DstElementTy;
+  DstElementTy = DstType;
+  SrcElementTy = Src->getType();
+  ComplexPairTy Res;
+  if (DstElementTy->getTypeID() < SrcElementTy->getTypeID())
+    assert("We are not expecting to land here, since we are promoting to a "
+           "larger type size");
+  else
+    Res.first = Builder.CreateFPExt(Src, DstType, "conv");
+  return Res;
+}
+
+ComplexPairTy CodeGenFunction::EmitPromotedComplexExpr(ComplexPairTy Src,
+                                                       QualType SrcTy,
+                                                       llvm::Type *DstType,
+                                                       SourceLocation Loc) {
+  llvm::Type *SrcElementTy;
+  llvm::Type *DstElementTy;
+  DstElementTy = DstType;
+  SrcElementTy = Src.first->getType();
+  llvm::Value *RealExt;
+  llvm::Value *ImgExt;
+  if (DstElementTy->getTypeID() < SrcElementTy->getTypeID())
+    assert("We are not expecting to land here, since we are promoting to a "
+           "larger type size");
+  else {
+    RealExt = Builder.CreateFPExt(Src.first, DstType, "conv");
+    ImgExt = Builder.CreateFPExt(Src.second, DstType, "conv");
+    Src.first = RealExt;
+    Src.second = ImgExt;
+  }
+  return Src;
+}
+
 ComplexExprEmitter::BinOpInfo
-ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
+ComplexExprEmitter::EmitBinOps(const BinaryOperator *E,
+                               QualType PromotionType) {
   TestAndClearIgnoreReal();
   TestAndClearIgnoreImag();
   BinOpInfo Ops;
-  if (E->getLHS()->getType()->isRealFloatingType())
-    Ops.LHS = ComplexPairTy(CGF.EmitScalarExpr(E->getLHS()), nullptr);
-  else
-    Ops.LHS = Visit(E->getLHS());
-  if (E->getRHS()->getType()->isRealFloatingType())
-    Ops.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
-  else
-    Ops.RHS = Visit(E->getRHS());
 
-  Ops.Ty = E->getType();
+  if (E->getLHS()->getType()->isRealFloatingType()) {
+    if (!PromotionType.isNull()) {
+      Ops.LHS = CGF.EmitPromotedScalarExpr(
+          CGF.EmitScalarExpr(E->getLHS()),
+          E->getType(), CGF.ConvertType(
+                 PromotionType->castAs<ComplexType>()->getElementType()),
+                E->getExprLoc());
+    } else {
+      Ops.LHS = ComplexPairTy(CGF.EmitScalarExpr(E->getLHS()), nullptr);
+    }
+  } else {
+    if (!PromotionType.isNull()) {
+      PromotionType->isComplexType();
+      Ops.LHS = CGF.EmitPromotedComplexExpr(
+          Visit(E->getLHS()), E->getType(),
+          CGF.ConvertType(PromotionType->castAs<ComplexType>()->getElementType()),
+          E->getExprLoc());
+    }
+    else
+      Ops.LHS = Visit(E->getLHS());
+  }
+  if (E->getRHS()->getType()->isRealFloatingType()) {
+    if (!PromotionType.isNull()) {
+      Ops.RHS = CGF.EmitPromotedScalarExpr(
+          CGF.EmitScalarExpr(E->getRHS()), E->getType(),
+                CGF.ConvertType(
+                    PromotionType->castAs<ComplexType>()->getElementType()), E->getExprLoc());
+    } else {
+      Ops.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
+    }
+  } else {
+    if (!PromotionType.isNull())
+      Ops.RHS = CGF.EmitPromotedComplexExpr(
+          Visit(E->getRHS()), E->getType(),
+          CGF.ConvertType(
+              PromotionType->castAs<ComplexType>()->getElementType()),
+          E->getExprLoc());
+    else
+      Ops.RHS = Visit(E->getRHS());
+  }
+  if (!PromotionType.isNull())
+    Ops.Ty = PromotionType;
+  else
+    Ops.Ty = E->getType();
   return Ops;
 }
 
@@ -1131,7 +1247,17 @@
   assert(E && getComplexType(E->getType()) &&
          "Invalid complex expression to emit");
   ComplexExprEmitter Emitter(*this);
-  ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
+  ComplexPairTy Val = Emitter.EmitPromoted(E);
+  if (!Emitter.getPromotionType(E).isNull()) {
+    Val.first = Builder.CreateFPTrunc(
+        Val.first,
+        ConvertType(dyn_cast<ComplexType>(E->getType())->getElementType()),
+                                      "unpromotion");
+    Val.second = Builder.CreateFPTrunc(
+        Val.second,
+        ConvertType(dyn_cast<ComplexType>(E->getType())->getElementType()),
+                                       "unpromotion");
+  }
   Emitter.EmitStoreOfComplex(Val, dest, isInit);
 }
 
Index: clang/lib/Basic/Targets/X86.h
===================================================================
--- clang/lib/Basic/Targets/X86.h
+++ clang/lib/Basic/Targets/X86.h
@@ -286,6 +286,10 @@
     return false;
   }
 
+  bool ShouldEmitWithExcessPrecision() const {
+    return HasFloat16 && !hasLegalHalfType();
+  }
+
   void getTargetDefines(const LangOptions &Opts,
                         MacroBuilder &Builder) const override;
 
Index: clang/lib/Basic/Targets/X86.cpp
===================================================================
--- clang/lib/Basic/Targets/X86.cpp
+++ clang/lib/Basic/Targets/X86.cpp
@@ -240,6 +240,7 @@
     } else if (Feature == "+avx512fp16") {
       HasAVX512FP16 = true;
       HasFloat16 = true;
+      HasLegalHalfType = true;
     } else if (Feature == "+avx512pf") {
       HasAVX512PF = true;
     } else if (Feature == "+avx512dq") {
@@ -369,6 +370,8 @@
                          .Default(NoXOP);
     XOPLevel = std::max(XOPLevel, XLevel);
   }
+  // Turn on _float16 for x86 (feature sse2)
+  HasFloat16 = SSELevel >= SSE2;
 
   // LLVM doesn't have a separate switch for fpmath, so only accept it if it
   // matches the selected sse level.
Index: clang/include/clang/Basic/TargetInfo.h
===================================================================
--- clang/include/clang/Basic/TargetInfo.h
+++ clang/include/clang/Basic/TargetInfo.h
@@ -905,6 +905,10 @@
     return true;
   }
 
+  virtual bool ShouldEmitWithExcessPrecision() const {
+    return false;
+  }
+
   /// Specify if mangling based on address space map should be used or
   /// not for language specific address spaces
   bool useAddressSpaceMapMangling() const {
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -488,6 +488,9 @@
 DWARF Support in Clang
 ----------------------
 
+- Support for ``AVX512-FP16`` instructions has been added.
+- Support for ``_Float16`` type has been added.
+
 Arm and AArch64 Support in Clang
 --------------------------------
 
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -743,7 +743,7 @@
 * 64-bit ARM (AArch64)
 * AMDGPU
 * SPIR
-* X86 (Only available under feature AVX512-FP16)
+* X86 (Enabled with feature SSE2 and up)
 
 ``_Float16`` will be supported on more targets as they define ABIs for it.
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to