llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

x86_64-w64-mingw32 uses the x87 format for `long double`, while
arm64ec-w64-mingw32 uses binary64, so data containing `long double`
cannot be shared with x64 code.

Accept -mlong-double-{64,80,128} for arm64ec-w64-mingw32. The default
remains binary64.

* -mlong-double-128 uses binary128, as AArch64 Linux does.
* -mlong-double-80 gives `long double` the x86-64 layout (size 16,
  alignment 16) for struct layout and global initializers. As the
  AArch64 backend does not support x86_fp80, report an error in CodeGen
  when a `long double` value is used or appears in an emitted function
  signature. Unused inline functions, e.g. in &lt;cmath&gt;, are not
  diagnosed. `long double` is not an HFA base type, so a struct
  containing it is passed in general-purpose registers.

LLM-aided

---
Full diff: https://github.com/llvm/llvm-project/pull/237827.diff


10 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticCommonKinds.td (+2) 
- (modified) clang/lib/CodeGen/CGExprComplex.cpp (+6) 
- (modified) clang/lib/CodeGen/CGExprScalar.cpp (+3) 
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+27-1) 
- (modified) clang/lib/CodeGen/CodeGenModule.h (+10) 
- (modified) clang/lib/CodeGen/Targets/AArch64.cpp (+4-1) 
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+3) 
- (added) clang/test/CodeGen/arm64ec-long-double-error.cpp (+47) 
- (added) clang/test/CodeGen/arm64ec-long-double.c (+41) 
- (added) clang/test/Driver/arm64ec-long-double.c (+11) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td 
b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 986acebce22e55..9161870a1c35fd 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -369,6 +369,8 @@ def warn_target_unrecognized_env : Warning<
   InGroup<InvalidCommandLineArgument>;
 def err_target_unsupported_abi_with_fpu : Error<
   "'%0' ABI is not supported with FPU">;
+def err_storage_only_long_double : Error<
+  "x87 'long double' values are not supported on target '%0'">;
 
 def err_ppc_impossible_musttail: Error<
   "'musttail' attribute for this call is impossible because %select{"
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp 
b/clang/lib/CodeGen/CGExprComplex.cpp
index 30d693fb371cb6..0d9d1751a2775c 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -94,6 +94,12 @@ class ComplexExprEmitter
 
   ComplexPairTy Visit(Expr *E) {
     ApplyDebugLocation DL(CGF, E);
+    if (CGF.CGM.hasStorageOnlyLongDouble() &&
+        CGF.CGM.diagnoseLongDoubleType(E->getType(), E->getExprLoc())) {
+      auto *Poison = llvm::PoisonValue::get(
+          CGF.ConvertType(CGF.getContext().LongDoubleTy));
+      return ComplexPairTy(Poison, Poison);
+    }
     return StmtVisitor<ComplexExprEmitter, ComplexPairTy>::Visit(E);
   }
 
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 0e2e29f0745d27..28c4c642430ca6 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -498,6 +498,9 @@ class ScalarExprEmitter
 
   Value *Visit(Expr *E) {
     ApplyDebugLocation DL(CGF, E);
+    if (CGF.CGM.hasStorageOnlyLongDouble() &&
+        CGF.CGM.diagnoseLongDoubleType(E->getType(), E->getExprLoc()))
+      return llvm::PoisonValue::get(ConvertType(E->getType()));
     return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
   }
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index ce084487a69820..a0719c318f6829 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -556,7 +556,10 @@ CodeGenModule::CodeGenModule(ASTContext &C,
       Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
       VMContext(M.getContext()), VTables(*this), StackHandler(diags),
       SanitizerMD(new SanitizerMetadata(*this)),
-      AtomicOpts(Target.getAtomicOpts()) {
+      AtomicOpts(Target.getAtomicOpts()),
+      HasStorageOnlyLongDouble(&Target.getLongDoubleFormat() ==
+                                   &llvm::APFloat::x87DoubleExtended() &&
+                               !Target.getTriple().isX86()) {
 
   AbiMapper = std::make_unique<QualTypeMapper>(C, M.getDataLayout(), AbiAlloc);
   AbiReverseMapper = std::make_unique<llvm::abi::IRTypeMapper>(
@@ -2964,10 +2967,33 @@ void 
CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,
 
     Error(Loc, "__vectorcall calling convention is not currently supported");
   }
+  if (HasStorageOnlyLongDouble) {
+    SourceLocation Loc;
+    if (const Decl *D = GD.getDecl())
+      Loc = D->getLocation();
+    if (!diagnoseLongDoubleType(Info.getReturnType(), Loc))
+      for (const CGFunctionInfoArgInfo &Arg : Info.arguments())
+        if (diagnoseLongDoubleType(Arg.type, Loc))
+          break;
+  }
   F->setAttributes(PAL);
   F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
 }
 
+bool CodeGenModule::diagnoseLongDoubleType(QualType Ty, SourceLocation Loc) {
+  if (const auto *AT = Ty->getAs<AtomicType>())
+    Ty = AT->getValueType();
+  if (const auto *CT = Ty->getAs<ComplexType>())
+    Ty = CT->getElementType();
+  else if (const auto *VT = Ty->getAs<VectorType>())
+    Ty = VT->getElementType();
+  if (!Ty->isSpecificBuiltinType(BuiltinType::LongDouble))
+    return false;
+  getDiags().Report(Loc, diag::err_storage_only_long_double)
+      << getTriple().str();
+  return true;
+}
+
 static void removeImageAccessQualifier(std::string& TyName) {
   std::string ReadOnlyQual("__read_only");
   std::string::size_type ReadOnlyPos = TyName.find(ReadOnlyQual);
diff --git a/clang/lib/CodeGen/CodeGenModule.h 
b/clang/lib/CodeGen/CodeGenModule.h
index e2bd6bc4701fda..9c9f95511cd13f 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -722,6 +722,10 @@ class CodeGenModule : public CodeGenTypeCache {
 
   AtomicOptions AtomicOpts;
 
+  // 'long double' has the x87 format on a target that cannot compute with it,
+  // e.g. ARM64EC with -mlong-double-80; only its layout is supported.
+  bool HasStorageOnlyLongDouble;
+
   // A set of functions which should be hot-patched; see
   // -fms-hotpatch-functions-file (and -list). This will nearly always be 
empty.
   // The list is sorted for binary-searching.
@@ -748,6 +752,12 @@ class CodeGenModule : public CodeGenTypeCache {
   /// Set the current Atomic options.
   void setAtomicOpts(AtomicOptions AO) { AtomicOpts = AO; }
 
+  bool hasStorageOnlyLongDouble() const { return HasStorageOnlyLongDouble; }
+
+  /// If \p Ty contains a storage-only 'long double' value, report an error at
+  /// \p Loc and return true.
+  bool diagnoseLongDoubleType(QualType Ty, SourceLocation Loc);
+
   /// Return true if we should emit location information for expressions.
   bool getExpressionLocationsEnabled() const;
 
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp 
b/clang/lib/CodeGen/Targets/AArch64.cpp
index e493f717af581d..85ca8888dbde0d 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -690,8 +690,11 @@ bool 
AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
   // but with the difference that any floating-point type is allowed,
   // including __fp16.
   if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+    // AArch64 cannot lower x86_fp80; pass an x87 'long double' in GPRs.
     if (BT->isFloatingPoint())
-      return true;
+      return BT->getKind() != BuiltinType::LongDouble ||
+             &getTarget().getLongDoubleFormat() !=
+                 &llvm::APFloat::x87DoubleExtended();
   } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
     if (auto Kind = VT->getVectorKind();
         Kind == VectorKind::SveFixedLengthData ||
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 61a81f33ab22dd..d0f04781338b6e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6347,6 +6347,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
     else if (TC.getTriple().isPPC() &&
              (A->getOption().getID() != options::OPT_mlong_double_80))
       A->render(Args, CmdArgs);
+    else if (TC.getTriple().isWindowsArm64EC() &&
+             TC.getTriple().isWindowsGNUEnvironment())
+      A->render(Args, CmdArgs);
     else
       D.Diag(diag::err_drv_unsupported_opt_for_target)
           << A->getAsString(Args) << TripleStr;
diff --git a/clang/test/CodeGen/arm64ec-long-double-error.cpp 
b/clang/test/CodeGen/arm64ec-long-double-error.cpp
new file mode 100644
index 00000000000000..065de7a8fece0e
--- /dev/null
+++ b/clang/test/CodeGen/arm64ec-long-double-error.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple arm64ec-w64-windows-gnu -mlong-double-80 -std=c++17 
-emit-llvm-only -verify=use %s
+// RUN: %clang_cc1 -triple arm64ec-w64-windows-gnu -mlong-double-80 -std=c++17 
-emit-llvm-only -verify=ret -DRET %s
+// RUN: %clang_cc1 -triple arm64ec-w64-windows-gnu -mlong-double-80 -std=c++17 
-emit-llvm-only -verify=param -DPARAM %s
+// RUN: %clang_cc1 -triple arm64ec-w64-windows-gnu -mlong-double-128 
-std=c++17 -emit-llvm-only -verify=ld128 %s
+
+// ld128-no-diagnostics
+
+// Unused inline definitions, such as those in <cmath>, are not emitted.
+inline long double unused_fabs(long double x) { return __builtin_fabsl(x); }
+
+long double g = 1.5L;
+struct S { long double x; } gs = {2.5L};
+
+// Only the layout is needed here.
+static_assert(sizeof(long double) == 16 && alignof(long double) == 16);
+long double *addr() { return &g; }
+void copy(S *d) { *d = gs; }
+void pass(S s) {}
+
+#if RET
+// An address-taken declaration needs an ARM64EC exit thunk.
+// ret-error@+1 {{x87 'long double' values are not supported on target 
'arm64ec-w64-windows-gnu'}}
+long double ret();
+void *take() { return (void *)&ret; }
+#elif PARAM
+// param-error@+1 {{x87 'long double' values are not supported}}
+void param(long double) {}
+#else
+typedef long double v2ld __attribute__((vector_size(32)));
+
+void use(double d, _Complex long double *c, _Atomic long double *a, v2ld *v) {
+  // use-error@+1 {{x87 'long double' values are not supported}}
+  d = g;
+  // use-error@+1 {{x87 'long double' values are not supported}}
+  gs.x = d;
+  // use-error@+1 2 {{x87 'long double' values are not supported}}
+  d = g < gs.x;
+  // use-error@+1 {{x87 'long double' values are not supported}}
+  d = __real__ *c;
+  // use-error@+1 {{x87 'long double' values are not supported}}
+  *a += 1;
+  // use-error@+1 {{x87 'long double' values are not supported}}
+  *v = *v + *v;
+  // use-error@+1 {{x87 'long double' values are not supported}}
+  unused_fabs(0);
+}
+#endif
diff --git a/clang/test/CodeGen/arm64ec-long-double.c 
b/clang/test/CodeGen/arm64ec-long-double.c
new file mode 100644
index 00000000000000..85982c5024e308
--- /dev/null
+++ b/clang/test/CodeGen/arm64ec-long-double.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple arm64ec-w64-windows-gnu -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=CHECK,LD64
+// RUN: %clang_cc1 -triple arm64ec-w64-windows-gnu -mlong-double-80 -emit-llvm 
-o - %s | FileCheck %s --check-prefixes=CHECK,LD80
+// RUN: %clang_cc1 -triple arm64ec-w64-windows-gnu -mlong-double-128 
-emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LD128
+
+// -mlong-double-80 gives 'long double' the layout of x86_64-w64-mingw32 so 
that
+// data can be shared with x64 code, but values cannot be computed with.
+
+int ld_size = sizeof(long double);
+int ld_align = _Alignof(long double);
+// LD64:  @ld_size = dso_local global i32 8
+// LD64:  @ld_align = dso_local global i32 8
+// LD80:  @ld_size = dso_local global i32 16
+// LD80:  @ld_align = dso_local global i32 16
+// LD128: @ld_size = dso_local global i32 16
+// LD128: @ld_align = dso_local global i32 16
+
+// LD64:  @g = dso_local global double 1.500000e+00, align 8
+// LD80:  @g = dso_local global x86_fp80 1.500000e+00, align 16
+// LD128: @g = dso_local global fp128 1.500000e+00, align 16
+long double g = 1.5L;
+
+struct S {
+  long double x;
+};
+// LD64:  @gs = dso_local global %struct.S { double 2.500000e+00 }, align 8
+// LD80:  @gs = dso_local global %struct.S { x86_fp80 2.500000e+00 }, align 16
+// LD128: @gs = dso_local global %struct.S { fp128 2.500000e+00 }, align 16
+struct S gs = {2.5L};
+
+// The x87 format is not a homogeneous floating-point aggregate base type.
+// LD64:  define {{.*}}void @pass_struct([1 x double] %s.coerce)
+// LD80:  define {{.*}}void @pass_struct(i128 %s.coerce)
+// LD128: define {{.*}}void @pass_struct([1 x fp128] %s.coerce)
+void pass_struct(struct S s) {}
+
+// CHECK-LABEL: define {{.*}}void @copy(
+// LD80:          call void @llvm.memcpy.p0.p0.i64(ptr align 16 %{{.*}}, ptr 
align 16 %{{.*}}, i64 16, i1 false)
+void copy(struct S *d, struct S *s) { *d = *s; }
+
+// CHECK-LABEL: define {{.*}}ptr @addr(
+long double *addr(void) { return &g; }
diff --git a/clang/test/Driver/arm64ec-long-double.c 
b/clang/test/Driver/arm64ec-long-double.c
new file mode 100644
index 00000000000000..3f30ff374deaf9
--- /dev/null
+++ b/clang/test/Driver/arm64ec-long-double.c
@@ -0,0 +1,11 @@
+// RUN: %clang -### --target=arm64ec-w64-mingw32 -mlong-double-64 -c %s 2>&1 | 
FileCheck %s --check-prefix=LD64
+// RUN: %clang -### --target=arm64ec-w64-mingw32 -mlong-double-80 -c %s 2>&1 | 
FileCheck %s --check-prefix=LD80
+// RUN: %clang -### --target=arm64ec-w64-mingw32 -mlong-double-128 -c %s 2>&1 
| FileCheck %s --check-prefix=LD128
+// RUN: not %clang -### --target=arm64ec-pc-windows-msvc -mlong-double-80 -c 
%s 2>&1 | FileCheck %s --check-prefix=MSVC
+// RUN: not %clang -### --target=aarch64-w64-mingw32 -mlong-double-80 -c %s 
2>&1 | FileCheck %s --check-prefix=AARCH64
+
+// LD64: "-mlong-double-64"
+// LD80: "-mlong-double-80"
+// LD128: "-mlong-double-128"
+// MSVC: error: unsupported option '-mlong-double-80' for target 
'arm64ec-pc-windows-msvc{{.*}}'
+// AARCH64: error: unsupported option '-mlong-double-80' for target 
'aarch64-w64-windows-gnu'

``````````

</details>


https://github.com/llvm/llvm-project/pull/237827
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to