def err_omp_wrong_dependency_iterator_type : Error<
"expected an integer or a pointer type of the outer loop counter '%0' for non-rectangular nests">;
def err_target_unsupported_type
- : Error<"%0 requires %select{|%2 bit size}1 %3 type support, but target "
- "'%4' does not support it">;
+ : Error<"%0 requires %select{|%2 bit size}1 %3 %select{|return }4type support,"
+ " but target '%5' does not support it">;
def err_omp_lambda_capture_in_declare_target_not_to : Error<
"variable captured in declare target region must appear in a to clause">;
def err_omp_device_type_mismatch : Error<
bool HasFloat16;
bool HasBFloat16;
bool HasIbm128;
+ bool HasLongDouble;
+ bool HasFPReturn;
bool HasStrictFP;
unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
/// Determine whether the __ibm128 type is supported on this target.
virtual bool hasIbm128Type() const { return HasIbm128; }
+ /// 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; }
HasIbm128 = false;
HasFloat16 = false;
HasBFloat16 = false;
+ HasLongDouble = true;
+ HasFPReturn = true;
HasStrictFP = false;
PointerWidth = PointerAlign = 32;
BoolWidth = BoolAlign = 8;
HasUINTR = true;
} else if (Feature == "+crc32") {
HasCRC32 = true;
+ } else if (Feature == "+x87") {
+ HasX87 = true;
}
X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
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;
}
.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)
bool HasTSXLDTRK = false;
bool HasUINTR = false;
bool HasCRC32 = false;
+ bool HasX87 = false;
protected:
llvm::X86::CPUKind CPU = llvm::X86::CK_None;
}
void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
- if (!LangOpts.SYCLIsDevice && !(LangOpts.OpenMP && LangOpts.OpenMPIsDevice))
- return;
-
if (isUnevaluatedContext() || Ty.isNull())
return;
FunctionDecl *FD = isa<FunctionDecl>(C) ? cast<FunctionDecl>(C)
: dyn_cast_or_null<FunctionDecl>(D);
- auto CheckType = [&](QualType Ty) {
+ auto CheckDeviceType = [&](QualType Ty) {
if (Ty->isDependentType())
return;
else
PD << "expression";
targetDiag(Loc, PD, FD)
- << false /*show bit size*/ << 0 /*bitsize*/
+ << false /*show bit size*/ << 0 /*bitsize*/ << false /*return*/
<< Ty << Context.getTargetInfo().getTriple().str();
}
return;
if (targetDiag(Loc, PD, FD)
<< true /*show bit size*/
<< static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty
+ << false /*return*/ << Context.getTargetInfo().getTriple().str()) {
+ if (D)
+ D->setInvalidDecl();
+ }
+ if (D)
+ targetDiag(D->getLocation(), diag::note_defined_here, FD) << D;
+ }
+ };
+
+ auto CheckType = [&](QualType Ty, bool IsRetTy = false) {
+ if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice))
+ CheckDeviceType(Ty);
+
+ QualType UnqualTy = Ty.getCanonicalType().getUnqualifiedType();
+ const TargetInfo &TI = Context.getTargetInfo();
+ if (!TI.hasLongDoubleType() && UnqualTy == Context.LongDoubleTy) {
+ PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type);
+ if (D)
+ PD << D;
+ else
+ PD << "expression";
+
+ if (Diag(Loc, PD, FD)
+ << false /*show bit size*/ << 0 << Ty << false /*return*/
+ << Context.getTargetInfo().getTriple().str()) {
+ if (D)
+ D->setInvalidDecl();
+ }
+ if (D)
+ targetDiag(D->getLocation(), diag::note_defined_here, FD) << D;
+ }
+
+ bool IsDouble = UnqualTy == Context.DoubleTy;
+ bool IsFloat = UnqualTy == Context.FloatTy;
+ if (IsRetTy && !TI.hasFPReturn() && (IsDouble || IsFloat)) {
+ PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type);
+ if (D)
+ PD << D;
+ else
+ PD << "expression";
+
+ if (Diag(Loc, PD, FD)
+ << false /*show bit size*/ << 0 << Ty << true /*return*/
<< Context.getTargetInfo().getTriple().str()) {
if (D)
D->setInvalidDecl();
};
CheckType(Ty);
-
if (const auto *FPTy = dyn_cast<FunctionProtoType>(Ty)) {
for (const auto &ParamTy : FPTy->param_types())
CheckType(ParamTy);
- CheckType(FPTy->getReturnType());
+ CheckType(FPTy->getReturnType(), /*IsRetTy=*/true);
}
if (const auto *FNPTy = dyn_cast<FunctionNoProtoType>(Ty))
- CheckType(FNPTy->getReturnType());
+ CheckType(FNPTy->getReturnType(), /*IsRetTy=*/true);
}
/// Looks through the macro-expansion chain for the given
}
}
- checkTypeSupport(NewFD->getType(), D.getBeginLoc(), NewFD);
-
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
if (!NewFD->isInvalidDecl() && NewFD->isMain())
DeclsToCheckForDeferredDiags.insert(FD);
}
+ if (FD && !FD->isDeleted())
+ checkTypeSupport(FD->getType(), FD->getLocation(), FD);
+
return dcl;
}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple i686-linux-gnu -target-feature -x87 -DRET_ERROR
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple i686-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);
+
+template <typename T>
+T decl_ld_del(T);
+
+// No code is generated for deleted functions
+long_double decl_ld_del(long_double) = delete;
+double decl_ld_del(double) = delete;
+float decl_ld_del(float) = delete;
+
+#ifndef NOERROR
+// expected-error@+4{{'def' requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+// expected-note@+3{{'def' defined here}}
+// expected-note@+2{{'x' defined here}}
+#endif
+int def(long_double x) {
+#ifndef NOERROR
+// expected-error@+2{{'x' requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ return (int)x;
+}
+
+#ifndef NOERROR
+// expected-note@+3{{'ld_args' defined here}}
+// expected-note@+2{{'ld_args' defined here}}
+#endif
+int ld_args(long_double x, long_double y);
+
+int call1(float x, float y) {
+#ifndef NOERROR
+ // expected-error@+2 2{{'ld_args' requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ return ld_args(x, y);
+}
+
+#ifndef NOERROR
+// expected-note@+2{{'ld_ret' defined here}}
+#endif
+long_double ld_ret(double x, double y);
+
+int call2(float x, float y) {
+#ifndef NOERROR
+ // expected-error@+2{{'ld_ret' requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ return (int)ld_ret(x, y);
+}
+
+int binop(double x, double y) {
+#ifndef NOERROR
+ // expected-error@+2 2{{expression requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ double z = (long_double)x * (long_double)y;
+ return (int)z;
+}
+
+void assign1(long_double *ret, double x) {
+#ifndef NOERROR
+ // expected-error@+2{{expression requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ *ret = x;
+}
+
+struct st_long_double1 {
+#ifndef NOERROR
+ // expected-note@+2{{'ld' defined here}}
+#endif
+ long_double ld;
+};
+
+struct st_long_double2 {
+#ifndef NOERROR
+ // expected-note@+2{{'ld' defined here}}
+#endif
+ long_double ld;
+};
+
+struct st_long_double3 {
+#ifndef NOERROR
+ // expected-note@+2{{'ld' defined here}}
+#endif
+ long_double ld;
+};
+
+void assign2() {
+ struct st_long_double1 st;
+#ifndef NOERROR
+ // expected-error@+3{{expression requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+ // expected-error@+2{{'ld' requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ st.ld = 0.42;
+}
+
+void assign3() {
+ struct st_long_double2 st;
+#ifndef NOERROR
+ // expected-error@+3{{expression requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+ // expected-error@+2{{'ld' requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ st.ld = 42;
+}
+
+void assign4(double d) {
+ struct st_long_double3 st;
+#ifndef NOERROR
+ // expected-error@+3{{expression requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+ // expected-error@+2{{'ld' requires 'long_double' (aka 'long double') type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ st.ld = d;
+}
+
+void assign5() {
+ // unused variable declaration is fine
+ long_double ld = 0.42;
+}
+
+#ifndef NOERROR
+// expected-note@+3{{'d_ret1' defined here}}
+// expected-error@+2{{'d_ret1' requires 'double' return type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+double d_ret1(float x) {
+ return 0.0;
+}
+
+#ifndef NOERROR
+// expected-note@+2{{'d_ret2' defined here}}
+#endif
+double d_ret2(float x);
+
+int d_ret3(float x) {
+#ifndef NOERROR
+ // expected-error@+2{{'d_ret2' requires 'double' return type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ return (int)d_ret2(x);
+}
+
+#ifndef NOERROR
+// expected-note@+3{{'f_ret1' defined here}}
+// expected-error@+2{{'f_ret1' requires 'float' return type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+float f_ret1(float x) {
+ return 0.0f;
+}
+
+#ifndef NOERROR
+// expected-note@+2{{'f_ret2' defined here}}
+#endif
+float f_ret2(float x);
+
+int f_ret3(float x) {
+#ifndef NOERROR
+ // expected-error@+2{{'f_ret2' requires 'float' return type support, but target 'i686-unknown-linux-gnu' does not support it}}
+#endif
+ return (int)f_ret2(x);
+}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-linux-gnu -target-feature -x87
+// 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);
+
+template <typename T>
+T decl_ld_del(T);
+
+// No code is generated for deleted functions
+long_double decl_ld_del(long_double) = delete;
+double decl_ld_del(double) = delete;
+float decl_ld_del(float) = delete;
+
+#ifndef NOERROR
+// expected-error@+4{{'def' requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+// expected-note@+3{{'def' defined here}}
+// expected-note@+2{{'x' defined here}}
+#endif
+int def(long_double x) {
+#ifndef NOERROR
+// expected-error@+2{{'x' requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ return (int)x;
+}
+
+#ifndef NOERROR
+// expected-note@+3{{'ld_args' defined here}}
+// expected-note@+2{{'ld_args' defined here}}
+#endif
+int ld_args(long_double x, long_double y);
+
+int call1(float x, float y) {
+#ifndef NOERROR
+ // expected-error@+2 2{{'ld_args' requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ return ld_args(x, y);
+}
+
+#ifndef NOERROR
+// expected-note@+2{{'ld_ret' defined here}}
+#endif
+long_double ld_ret(double x, double y);
+
+int call2(float x, float y) {
+#ifndef NOERROR
+ // expected-error@+2{{'ld_ret' requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ return (int)ld_ret(x, y);
+}
+
+int binop(double x, double y) {
+#ifndef NOERROR
+ // expected-error@+2 2{{expression requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ double z = (long_double)x * (long_double)y;
+ return (int)z;
+}
+
+void assign1(long_double *ret, double x) {
+#ifndef NOERROR
+ // expected-error@+2{{expression requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ *ret = x;
+}
+
+struct st_long_double1 {
+#ifndef NOERROR
+ // expected-note@+2{{'ld' defined here}}
+#endif
+ long_double ld;
+};
+
+struct st_long_double2 {
+#ifndef NOERROR
+ // expected-note@+2{{'ld' defined here}}
+#endif
+ long_double ld;
+};
+
+struct st_long_double3 {
+#ifndef NOERROR
+ // expected-note@+2{{'ld' defined here}}
+#endif
+ long_double ld;
+};
+
+void assign2() {
+ struct st_long_double1 st;
+#ifndef NOERROR
+ // expected-error@+3{{expression requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+ // expected-error@+2{{'ld' requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ st.ld = 0.42;
+}
+
+void assign3() {
+ struct st_long_double2 st;
+#ifndef NOERROR
+ // expected-error@+3{{expression requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+ // expected-error@+2{{'ld' requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ st.ld = 42;
+}
+
+void assign4(double d) {
+ struct st_long_double3 st;
+#ifndef NOERROR
+ // expected-error@+3{{expression requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+ // expected-error@+2{{'ld' requires 'long_double' (aka 'long double') type support, but target 'x86_64-unknown-linux-gnu' does not support it}}
+#endif
+ st.ld = d;
+}
+
+void assign5() {
+ // unused variable declaration is fine
+ long_double ld = 0.42;
+}
+
+// Double and Float return type on x86_64 do not use x87 registers
+double d_ret1(float x) {
+ return 0.0;
+}
+
+double d_ret2(float x);
+
+int d_ret3(float x) {
+ return (int)d_ret2(x);
+}
+
+float f_ret1(float x) {
+ return 0.0f;
+}
+
+float f_ret2(float x);
+
+int f_ret3(float x) {
+ return (int)f_ret2(x);
+}
C.field1 = A;
}
+long double ld_func(long double arg);
+
void usage() {
// expected-note@+1 3{{'A' defined here}}
__float128 A;
float F2 = 0.1f;
// expected-error@+1 3{{expression requires 128 bit size '__float128' type support, but target 'spir64' does not support it}}
float F3 = ((__float128)F1 * (__float128)F2) / 2.0f;
+
+ // assume that long double is supported
+ float F4 = ld_func(F3);
};
// expected-note@+1 {{called by 'usage'}}