@@ -29,6 +29,16 @@ using namespace clang;
2929using namespace clang ::CIRGen;
3030using namespace llvm ;
3131
32+ static mlir::Value tryUseTestFPKind (CIRGenFunction &cgf, unsigned BuiltinID,
33+ mlir::Value V) {
34+ if (cgf.getBuilder ().getIsFPConstrained () &&
35+ cgf.getBuilder ().getDefaultConstrainedExcept () != cir::fp::ebIgnore) {
36+ if (mlir::Value Result = cgf.getTargetHooks ().testFPKind (
37+ V, BuiltinID, cgf.getBuilder (), cgf.cgm ))
38+ return Result;
39+ }
40+ return nullptr ;
41+ }
3242static RValue emitLibraryCall (CIRGenFunction &cgf, const FunctionDecl *fd,
3343 const CallExpr *e, mlir::Operation *calleeValue) {
3444 CIRGenCallee callee = CIRGenCallee::forDirect (calleeValue, GlobalDecl (fd));
@@ -515,14 +525,117 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
515525 cir::PrefetchOp::create (builder, loc, address, locality, isWrite);
516526 return RValue::get (nullptr );
517527 }
528+ // From https://clang.llvm.org/docs/LanguageExtensions.html#builtin-isfpclass
529+ // :
530+ //
531+ // The `__builtin_isfpclass()` builtin is a generalization of functions
532+ // isnan, isinf, isfinite and some others defined by the C standard. It tests
533+ // if the floating-point value, specified by the first argument, falls into
534+ // any of data classes, specified by the second argument.
535+ case Builtin::BI__builtin_isnan: {
536+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
537+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
538+ if (mlir::Value result = tryUseTestFPKind (*this , builtinID, v))
539+ return RValue::get (result);
540+ mlir::Location loc = getLoc (e->getBeginLoc ());
541+ // FIXME: We should use builder.createZExt once createZExt is available.
542+ return RValue::get (builder.createZExtOrBitCast (
543+ loc, builder.createIsFPClass (loc, v, FPClassTest::fcNan),
544+ convertType (e->getType ())));
545+ }
546+
547+ case Builtin::BI__builtin_issignaling: {
548+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
549+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
550+ mlir::Location loc = getLoc (e->getBeginLoc ());
551+ // FIXME: We should use builder.createZExt once createZExt is available.
552+ return RValue::get (builder.createZExtOrBitCast (
553+ loc, builder.createIsFPClass (loc, v, FPClassTest::fcSNan),
554+ convertType (e->getType ())));
555+ }
556+
557+ case Builtin::BI__builtin_isinf: {
558+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
559+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
560+ if (mlir::Value result = tryUseTestFPKind (*this , builtinID, v))
561+ return RValue::get (result);
562+ mlir::Location loc = getLoc (e->getBeginLoc ());
563+ // FIXME: We should use builder.createZExt once createZExt is available.
564+ return RValue::get (builder.createZExtOrBitCast (
565+ loc, builder.createIsFPClass (loc, v, FPClassTest::fcInf),
566+ convertType (e->getType ())));
567+ }
568+
569+ case Builtin::BIfinite:
570+ case Builtin::BI__finite:
571+ case Builtin::BIfinitef:
572+ case Builtin::BI__finitef:
573+ case Builtin::BIfinitel:
574+ case Builtin::BI__finitel:
575+ case Builtin::BI__builtin_isfinite: {
576+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
577+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
578+ if (mlir::Value result = tryUseTestFPKind (*this , builtinID, v))
579+ return RValue::get (result);
580+ mlir::Location loc = getLoc (e->getBeginLoc ());
581+ // FIXME: We should use builder.createZExt once createZExt is available.
582+ return RValue::get (builder.createZExtOrBitCast (
583+ loc, builder.createIsFPClass (loc, v, FPClassTest::fcFinite),
584+ convertType (e->getType ())));
585+ }
586+
587+ case Builtin::BI__builtin_isnormal: {
588+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
589+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
590+ mlir::Location loc = getLoc (e->getBeginLoc ());
591+ // FIXME: We should use builder.createZExt once createZExt is available.
592+ return RValue::get (builder.createZExtOrBitCast (
593+ loc, builder.createIsFPClass (loc, v, FPClassTest::fcNormal),
594+ convertType (e->getType ())));
595+ }
596+
597+ case Builtin::BI__builtin_issubnormal: {
598+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
599+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
600+ mlir::Location loc = getLoc (e->getBeginLoc ());
601+ // FIXME: We should use builder.createZExt once createZExt is available.
602+ return RValue::get (builder.createZExtOrBitCast (
603+ loc, builder.createIsFPClass (loc, v, FPClassTest::fcSubnormal),
604+ convertType (e->getType ())));
605+ }
606+
607+ case Builtin::BI__builtin_iszero: {
608+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
609+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
610+ mlir::Location loc = getLoc (e->getBeginLoc ());
611+ // FIXME: We should use builder.createZExt once createZExt is available.
612+ return RValue::get (builder.createZExtOrBitCast (
613+ loc, builder.createIsFPClass (loc, v, FPClassTest::fcZero),
614+ convertType (e->getType ())));
615+ }
616+ case Builtin::BI__builtin_isfpclass: {
617+ Expr::EvalResult result;
618+ if (!e->getArg (1 )->EvaluateAsInt (result, cgm.getASTContext ()))
619+ break ;
620+
621+ CIRGenFunction::CIRGenFPOptionsRAII fpOptsRaii (*this , e);
622+ mlir::Value v = emitScalarExpr (e->getArg (0 ));
623+ uint64_t test = result.Val .getInt ().getLimitedValue ();
624+ mlir::Location loc = getLoc (e->getBeginLoc ());
625+ //
626+ // // FIXME: We should use builder.createZExt once createZExt is available.
627+ return RValue::get (builder.createZExtOrBitCast (
628+ loc, builder.createIsFPClass (loc, v, test), convertType (e->getType ())));
629+ }
518630 }
519631
520632 // If this is an alias for a lib function (e.g. __builtin_sin), emit
521633 // the call using the normal call path, but using the unmangled
522634 // version of the function name.
523- if (getContext ().BuiltinInfo .isLibFunction (builtinID))
635+ if (getContext ().BuiltinInfo .isLibFunction (builtinID)) {
524636 return emitLibraryCall (*this , fd, e,
525637 cgm.getBuiltinLibFunction (fd, builtinID));
638+ }
526639
527640 // Some target-specific builtins can have aggregate return values, e.g.
528641 // __builtin_arm_mve_vld2q_u32. So if the result is an aggregate, force
0 commit comments