================
@@ -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