diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -488,6 +488,7 @@ BUILTIN(__builtin_isinf_sign, "i.", "FnctE") BUILTIN(__builtin_isnan, "i.", "FnctE") BUILTIN(__builtin_isnormal, "i.", "FnctE") +BUILTIN(__builtin_isfpclass, "iCi.", "nctE") // FP signbit builtins BUILTIN(__builtin_signbit, "i.", "Fnct") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3143,6 +3143,17 @@ return RValue::get(V); } + case Builtin::BI__builtin_isfpclass: { + Expr::EvalResult Result; + if (!E->getArg(0)->EvaluateAsInt(Result, CGM.getContext())) + break; + uint64_t Test = Result.Val.getInt().getLimitedValue(); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); + Value *V = EmitScalarExpr(E->getArg(1)); + return RValue::get(Builder.CreateZExt(Builder.createIsFPClass(V, Test), + ConvertType(E->getType()))); + } + case Builtin::BI__builtin_nondeterministic_value: { llvm::Type *Ty = ConvertType(E->getArg(0)->getType()); diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -63,6 +63,7 @@ P(isinf, (1.)); P(isinf_sign, (1.)); P(isnan, (1.)); + P(isfpclass, (1, 1.)); // Bitwise & Numeric Functions diff --git a/clang/test/CodeGen/isfpclass.c b/clang/test/CodeGen/isfpclass.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/isfpclass.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -O1 -emit-llvm %s -o - | FileCheck %s + +_Bool check_isfpclass_finite(float x) { + return __builtin_isfpclass(504 /*Finite*/, x); +} +// CHECK-LABEL: define {{.*}} i1 @check_isfpclass_finite( +// CHECK: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504) + +_Bool check_isfpclass_finite_strict(float x) { +#pragma STDC FENV_ACCESS ON + return __builtin_isfpclass(504 /*Finite*/, x); +} +// CHECK-LABEL: define {{.*}} i1 @check_isfpclass_finite_strict( +// CHECK: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 504) + +_Bool check_isfpclass_nan_f32(float x) { +#pragma STDC FENV_ACCESS ON + return __builtin_isfpclass(3 /*NaN*/, x); +} +// CHECK-LABEL: define {{.*}} i1 @check_isfpclass_nan_f32( +// CHECK: call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 3) + +_Bool check_isfpclass_nan_f64(double x) { +#pragma STDC FENV_ACCESS ON + return __builtin_isfpclass(3 /*NaN*/, x); +} +// CHECK-LABEL: define {{.*}} i1 @check_isfpclass_nan_f64( +// CHECK: call i1 @llvm.is.fpclass.f64(double {{.*}}, i32 3) diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h --- a/llvm/include/llvm/IR/IRBuilder.h +++ b/llvm/include/llvm/IR/IRBuilder.h @@ -2518,6 +2518,8 @@ unsigned Index, unsigned FieldIndex, MDNode *DbgInfo); + Value *createIsFPClass(Value *FPNum, unsigned Test); + private: /// Helper function that creates an assume intrinsic call that /// represents an alignment assumption on the provided pointer \p PtrValue diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp --- a/llvm/lib/IR/IRBuilder.cpp +++ b/llvm/lib/IR/IRBuilder.cpp @@ -1375,6 +1375,14 @@ return Fn; } +Value *IRBuilderBase::createIsFPClass(Value *FPNum, unsigned Test) { + auto TestV = llvm::ConstantInt::get(Type::getInt32Ty(Context), Test); + Module *M = BB->getParent()->getParent(); + Function *FnIsFPClass = + Intrinsic::getDeclaration(M, Intrinsic::is_fpclass, {FPNum->getType()}); + return CreateCall(FnIsFPClass, {FPNum, TestV}); +} + CallInst *IRBuilderBase::CreateAlignmentAssumptionHelper(const DataLayout &DL, Value *PtrValue, Value *AlignValue,