================
@@ -2714,12 +2714,440 @@ 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`: Set the sign bit to zero.
+ if (BaseName == "fabsl") {
+ 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`: Take the magnitude from the first operand and the sign bit
+ // from the second one.
+ if (BaseName == "copysignl") {
+ 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;
+ }
+
+ // `signbit`: Take the sign bit and normalize it to boolean.
+ if (Name == "__builtin_signbit" || BaseName == "signbitl") {
+ if (!E->getArg(0)->getType()->isSpecificBuiltinType(
+ BuiltinType::LongDouble))
+ return false;
+ llvm::Value *V = EmitScalarExpr(E->getArg(0));
+ llvm::Value *Sign =
+ Builder.CreateTrunc(Builder.CreateLShr(V, 79), Builder.getInt1Ty());
+ Result = RValue::get(Builder.CreateZExt(Sign, ConvertType(E->getType())));
+ return true;
+ }
+
+ // `__builtin_isnan`: Check if the value is a NaN. An unnormal or pseudo
+ // denormal image is undefined behavior, since it will never be produced in a
+ // constant expression.
+ if (Name == "__builtin_isnan") {
+ if (!E->getArg(0)->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));
----------------
lhmouse wrote:
Fixed in 29da274f4cd33a80e943a3f0316fc5ecda624e7e.
https://github.com/llvm/llvm-project/pull/237057
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits