asavonic updated this revision to Diff 348219.
asavonic added a comment.

- Disabled double or float return for x86 targets
- Refactored checks into a separate function.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D98895

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/TargetInfo.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Basic/TargetInfo.cpp
  clang/lib/Basic/Targets/X86.cpp
  clang/lib/Basic/Targets/X86.h
  clang/lib/Sema/SemaChecking.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/Sema/x86-no-x87.c

Index: clang/test/Sema/x86-no-x87.c
===================================================================
--- /dev/null
+++ clang/test/Sema/x86-no-x87.c
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -target-feature -x87
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple i686-linux-gnu -target-feature -x87 -DRET_ERROR
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-windows-msvc -target-feature -x87 -DNOERROR
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -DNOERROR
+
+#ifdef NOERROR
+// expected-no-diagnostics
+#endif
+
+typedef long double long_double;
+
+// Declaration is fine, unless it is called or defined.
+double decl(long_double x, long_double y);
+
+#ifndef NOERROR
+// expected-error@+3{{long double is not supported on this target}}
+// expected-error@+2{{long double is not supported on this target}}
+#endif
+double ld_args(long_double x, long_double y);
+
+long_double ld_ret(double x, double y);
+
+#ifdef RET_ERROR
+// expected-error@+4{{return value of type double is not supported on this target}}
+// expected-error@+2{{return value of type double is not supported on this target}}
+#endif
+double args(double x, double y) {
+  return ld_args(x, y);
+}
+
+#ifdef RET_ERROR
+// expected-error@+2{{return value of type double is not supported on this target}}
+#endif
+double ret1(double x, double y) {
+#ifndef NOERROR
+  // expected-error@+2{{long double is not supported on this target}}
+#endif
+  return ld_ret(x, y);
+}
+
+#ifdef RET_ERROR
+// expected-error@+2{{return value of type float is not supported on this target}}
+#endif
+const float ret2(float a, double b) {
+  return a * b;
+}
+
+#ifdef RET_ERROR
+// expected-error@+2{{return value of type double is not supported on this target}}
+#endif
+double binop(double x, double y) {
+#ifndef NOERROR
+  // expected-error@+2{{long double is not supported on this target}}
+#endif
+  double z = (long_double)x * (long_double)y;
+  return z;
+}
+
+void assign1(long_double *ret, double x) {
+#ifndef NOERROR
+  // expected-error@+2{{long double is not supported on this target}}
+#endif
+  *ret = x;
+}
+
+struct st_long_double {
+  long_double ld;
+};
+
+void assign2() {
+  struct st_long_double st;
+  st.ld = 0.42;
+}
+
+void assign3() {
+  struct st_long_double st;
+  st.ld = 42;
+}
+
+void assign4(double d) {
+  struct st_long_double st;
+#ifndef NOERROR
+  // expected-error@+2{{long double is not supported on this target}}
+#endif
+  st.ld = d;
+}
+
+void assign5() {
+#ifndef NOERROR
+  // expected-error@+2{{long double is not supported on this target}}
+#endif
+  long_double ld = 0.42;
+}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -14002,6 +14002,20 @@
     }
   }
 
+  // Allow assignment of a literal, because it compiles to just a
+  // store of a constant.
+  bool IsLiteralAssign = (Opc == BO_Assign) && (isa<FloatingLiteral>(RHSExpr) ||
+                                                isa<IntegerLiteral>(RHSExpr));
+
+  if (!IsLiteralAssign) {
+    if (CheckTargetTypeSupport(Context.getTargetInfo(), LHSExpr->getType(),
+                               OpLoc, /*IsReturnType=*/false) ||
+        CheckTargetTypeSupport(Context.getTargetInfo(), RHSExpr->getType(),
+                               OpLoc, /*IsReturnType=*/false)) {
+      return ExprError();
+    }
+  }
+
   switch (Opc) {
   case BO_Assign:
     ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@@ -14840,6 +14854,13 @@
   if (Opc != UO_AddrOf && Opc != UO_Deref)
     CheckArrayAccess(Input.get());
 
+  if (CheckTargetTypeSupport(Context.getTargetInfo(), resultType, OpLoc,
+                             /*IsReturnType=*/false) ||
+      CheckTargetTypeSupport(Context.getTargetInfo(), InputExpr->getType(),
+                             OpLoc, /*IsReturnType=*/false)) {
+    return ExprError();
+  }
+
   auto *UO =
       UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK, OK,
                             OpLoc, CanOverflow, CurFPFeatureOverrides());
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -7270,6 +7270,9 @@
     }
   }
 
+  CheckTargetTypeSupport(Context.getTargetInfo(), NewVD->getType(),
+                         NewVD->getLocation(), /*IsReturnType=*/false);
+
   // Handle attributes prior to checking for duplicates in MergeVarDecl
   ProcessDeclAttributes(S, NewVD, D);
 
@@ -14223,6 +14226,9 @@
   CheckParmsForFunctionDef(FD->parameters(),
                            /*CheckParameterNames=*/true);
 
+  CheckTargetTypeSupport(Context.getTargetInfo(), ResultType, FD->getLocation(),
+                         /*IsReturnType=*/true);
+
   // Add non-parameter declarations already in the function to the current
   // scope.
   if (FnBodyScope) {
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -4756,6 +4756,14 @@
   CheckAbsoluteValueFunction(TheCall, FDecl);
   CheckMaxUnsignedZero(TheCall, FDecl);
 
+  CheckTargetTypeSupport(Context.getTargetInfo(), Proto->getReturnType(),
+                         TheCall->getExprLoc(), /*IsReturnType=*/true);
+
+  for (ParmVarDecl *Param : FDecl->parameters()) {
+    CheckTargetTypeSupport(Context.getTargetInfo(), Param->getType(),
+                           Param->getLocation(), /*IsReturnType=*/false);
+  }
+
   if (getLangOpts().ObjC)
     DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
 
@@ -14189,6 +14197,11 @@
                                      RD, /*DeclIsField*/ false);
       }
     }
+
+    if (CheckTargetTypeSupport(Context.getTargetInfo(), Param->getType(),
+                               Param->getLocation(), /*IsReturnType=*/false)) {
+      HasInvalidParm = true;
+    }
   }
 
   return HasInvalidParm;
@@ -16361,3 +16374,23 @@
         }
       });
 }
+
+bool Sema::CheckTargetTypeSupport(const TargetInfo &TI, QualType Ty,
+                                  SourceLocation Loc, bool IsReturnType) {
+  QualType UnqualTy = Ty.getCanonicalType().getUnqualifiedType();
+  if (!TI.hasLongDoubleType() && UnqualTy == Context.LongDoubleTy) {
+    Diag(Loc, diag::err_type_unsupported) << "long double";
+    return true;
+  }
+
+  if (IsReturnType && !TI.hasFPReturn()) {
+    bool IsDouble = UnqualTy == Context.DoubleTy;
+    bool IsFloat = UnqualTy == Context.FloatTy;
+    if (IsDouble || IsFloat) {
+      Diag(Loc, diag::err_return_type_unsupported)
+          << (IsDouble ? "double" : "float");
+      return true;
+    }
+  }
+  return false;
+}
Index: clang/lib/Basic/Targets/X86.h
===================================================================
--- clang/lib/Basic/Targets/X86.h
+++ clang/lib/Basic/Targets/X86.h
@@ -140,6 +140,7 @@
   bool HasSERIALIZE = false;
   bool HasTSXLDTRK = false;
   bool HasUINTR = false;
+  bool HasX87 = false;
 
 protected:
   llvm::X86::CPUKind CPU = llvm::X86::CK_None;
Index: clang/lib/Basic/Targets/X86.cpp
===================================================================
--- clang/lib/Basic/Targets/X86.cpp
+++ clang/lib/Basic/Targets/X86.cpp
@@ -314,6 +314,8 @@
       HasTSXLDTRK = true;
     } else if (Feature == "+uintr") {
       HasUINTR = true;
+    } else if (Feature == "+x87") {
+      HasX87 = true;
     }
 
     X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
@@ -355,6 +357,14 @@
 
   SimdDefaultAlign =
       hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
+
+  if (!HasX87) {
+    if (LongDoubleFormat == &llvm::APFloat::x87DoubleExtended())
+      HasLongDouble = false;
+    if (getTriple().getArch() == llvm::Triple::x86)
+      HasFPReturn = false;
+  }
+
   return true;
 }
 
@@ -1004,6 +1014,7 @@
       .Case("x86", true)
       .Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
       .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
+      .Case("x87", HasX87)
       .Case("xop", XOPLevel >= XOP)
       .Case("xsave", HasXSAVE)
       .Case("xsavec", HasXSAVEC)
Index: clang/lib/Basic/TargetInfo.cpp
===================================================================
--- clang/lib/Basic/TargetInfo.cpp
+++ clang/lib/Basic/TargetInfo.cpp
@@ -36,6 +36,8 @@
   HasFloat128 = false;
   HasFloat16 = false;
   HasBFloat16 = false;
+  HasLongDouble = true;
+  HasFPReturn = true;
   HasStrictFP = false;
   PointerWidth = PointerAlign = 32;
   BoolWidth = BoolAlign = 8;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -12502,6 +12502,9 @@
 
   void checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall);
 
+  bool CheckTargetTypeSupport(const TargetInfo &TI, QualType Ty,
+                              SourceLocation Loc, bool IsReturnType);
+
   bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
                                     unsigned MaxWidth);
   bool CheckNeonBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
Index: clang/include/clang/Basic/TargetInfo.h
===================================================================
--- clang/include/clang/Basic/TargetInfo.h
+++ clang/include/clang/Basic/TargetInfo.h
@@ -200,6 +200,8 @@
   bool HasFloat128;
   bool HasFloat16;
   bool HasBFloat16;
+  bool HasLongDouble;
+  bool HasFPReturn;
   bool HasStrictFP;
 
   unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
@@ -593,6 +595,13 @@
   /// Determine whether the _BFloat16 type is supported on this target.
   virtual bool hasBFloat16Type() const { return HasBFloat16; }
 
+  /// Determine whether the long double type is supported on this target.
+  virtual bool hasLongDoubleType() const { return HasLongDouble; }
+
+  /// Determine whether return of a floating point value is supported
+  /// on this target.
+  virtual bool hasFPReturn() const { return HasFPReturn; }
+
   /// Determine whether constrained floating point is supported on this target.
   virtual bool hasStrictFP() const { return HasStrictFP; }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9782,6 +9782,8 @@
   "feature, not permitted in C++">;
 def err_type_unsupported : Error<
   "%0 is not supported on this target">;
+def err_return_type_unsupported : Error<
+  "return value of type %0 is not supported on this target">;
 def err_nsconsumed_attribute_mismatch : Error<
   "overriding method has mismatched ns_consumed attribute on its"
   " parameter">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to