================
@@ -2714,12 +2714,481 @@ static void ClearPadding(CodeGenFunction &CGF, Address 
Src,
   }
 }
 
+/// Lower builtins that operate on ARM64EC's software x87 long double.  The
+/// ones that are required to be exact (fabs, copysign, signbit, isnan, isinf,
+/// isfinite, isnormal, fpclassify) are implemented with integer operations on
+/// the image itself; everything else is evaluated in `double` exactly like the
+/// C library does for its own long double entry points.  Return false when the
+/// builtin does not involve such a value.
+bool CodeGenFunction::EmitSoftX87LongDoubleBuiltin(unsigned BuiltinID,
+                                                   const CallExpr *E,
+                                                   RValue &Result) {
+  // The 'nan' and 'inf' families produce a `long double`, so they do not
+  // consume one but do need the integer image constructed below: they are the
+  // only builtins that yield a constant.  Match the bare name, since some of
+  // them are also reachable with a `__builtin_` prefix.
+  std::string Name = getContext().BuiltinInfo.getName(BuiltinID);
+  StringRef BaseName = Name;
+  BaseName.consume_front("__builtin_");
+  bool ProducesLongDouble = false;
+  for (const char *Str : {"nanl", "nansl", "infl", "huge_vall"})
+    ProducesLongDouble |= BaseName == Str;
+
+  // Everything below rewrites a call into its binary64 equivalent, which only
+  // makes sense when a `long double` is *consumed*.
+  bool ConsumesLongDouble = false;
+  for (const Expr *Arg : E->arguments()) {
+    QualType Ty = Arg->getType();
+    if (const auto *CTy = Ty->getAs<ComplexType>())
+      Ty = CTy->getElementType();
+    ConsumesLongDouble |= Ty->isSpecificBuiltinType(BuiltinType::LongDouble);
+  }
+
+  if (!ProducesLongDouble && !ConsumesLongDouble)
+    return false;
+
+  // `fabsl` and `__builtin_elementwise_abs` both set the sign bit to zero.
+  // The latter has no library spelling, so it is matched by its full name; a
+  // vector operand is rejected before it gets here.
+  if (BaseName == "fabsl" || Name == "__builtin_elementwise_abs") {
+    if (!E->getType()->isSpecificBuiltinType(BuiltinType::LongDouble))
+      return false;
+    llvm::Value *V = EmitScalarExpr(E->getArg(0));
+    llvm::Constant *MagnitudeMask = llvm::ConstantInt::get(
+        V->getType(), ~llvm::APInt::getOneBitSet(128, 79));
+    Result = RValue::get(Builder.CreateAnd(V, MagnitudeMask));
+    return true;
+  }
+
+  // `copysignl` and `__builtin_elementwise_copysign` both take the magnitude
+  // from the first operand and the sign bit from the second one.  The latter
+  // has no library spelling, so it is matched by its full name.
+  if (BaseName == "copysignl" || Name == "__builtin_elementwise_copysign") {
+    if (!E->getType()->isSpecificBuiltinType(BuiltinType::LongDouble))
+      return false;
+    llvm::Value *X = EmitScalarExpr(E->getArg(0));
+    llvm::Value *Y = EmitScalarExpr(E->getArg(1));
+    llvm::Constant *MagnitudeMask = llvm::ConstantInt::get(
+        X->getType(), ~llvm::APInt::getOneBitSet(128, 79));
+    llvm::Value *Magnitude = Builder.CreateAnd(X, MagnitudeMask);
+    llvm::Value *Sign = Builder.CreateAnd(Y, Builder.CreateNot(MagnitudeMask));
+    Result = RValue::get(Builder.CreateOr(Magnitude, Sign));
+    return true;
+  }
+
+  // `__builtin_canonicalizel`: Clear the padding bits and give a pseudo
+  // denormal, that is, a zero exponent with the integer bit set, the exponent
+  // one that spells the same number in the normal form.  This is what the x87
+  // does with an image that is loaded and stored again.
+  if (Name == "__builtin_canonicalizel") {
+    if (!E->getType()->isSpecificBuiltinType(BuiltinType::LongDouble))
+      return false;
+    llvm::Value *V = EmitScalarExpr(E->getArg(0));
+    llvm::Type *ImageTy = V->getType();
+    llvm::Constant *Zero = llvm::ConstantInt::get(ImageTy, 0);
+    llvm::Constant *ExponentMask =
+        llvm::ConstantInt::get(ImageTy, llvm::APInt(128, 0x7fffull) << 64);
+    llvm::Constant *IntegerBit =
+        llvm::ConstantInt::get(ImageTy, llvm::APInt::getOneBitSet(128, 63));
+    llvm::Constant *ExponentOne =
+        llvm::ConstantInt::get(ImageTy, llvm::APInt::getOneBitSet(128, 64));
+    llvm::Constant *ImageMask =
+        llvm::ConstantInt::get(ImageTy, llvm::APInt::getLowBitsSet(128, 80));
+    llvm::Value *IsPseudoDenormal = Builder.CreateAnd(
+        Builder.CreateICmpEQ(Builder.CreateAnd(V, ExponentMask), Zero),
+        Builder.CreateICmpNE(Builder.CreateAnd(V, IntegerBit), Zero));
+    llvm::Value *Normalized = Builder.CreateSelect(
+        IsPseudoDenormal, Builder.CreateOr(V, ExponentOne), V);
+    Result = RValue::get(Builder.CreateAnd(Normalized, ImageMask));
----------------
lhmouse wrote:

Fixed 1d0485c3f9b57283c69d201bf568f508617163e1. Also verified on x86-physical 
64 that the behavior matches.

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

Reply via email to