[llvm] [RISCV] Transform fcmp to is.fpclass (PR #120242)
Gergely Futo via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 17 07:02:55 PST 2024
https://github.com/futog created https://github.com/llvm/llvm-project/pull/120242
The `instcombine` pass transforms some `is.fpclass` intrinsics into `fcpm` calls. If a given floating point extension is not available (F/D/Zfinx/Zfinx/Zfh/Zfhmin), these `fcmp` calls are lowered to libcalls.
In these cases, custom lowering of the `is.fpclass` intrinsics in the back-end generates more efficient code.
In the `riscv-codegenprepare` pass, these `fcmp` calls are converted back to `is.fpclass` intrinsics.
>From 0dff7fbbad04e4d711c9beb84e227c81137f2c5d Mon Sep 17 00:00:00 2001
From: Gergely Futo <gergely.futo at hightec-rt.com>
Date: Mon, 16 Dec 2024 09:01:37 +0100
Subject: [PATCH] [RISCV] Transform fcmp to is.fpclass
The `instcombine` pass transforms some `is.fpclass` intrinsics into
`fcpm` calls. If a given floating point extension is not available
(F/D/Zfinx/Zfinx/Zfh/Zfhmin), these `fcmp` calls are lowered to libcalls.
In these cases, custom lowering of the `is.fpclass` intrinsics in the
back-end generates more efficient code.
In the `riscv-codegenprepare` pass, these `fcmp` calls are converted
back to `is.fpclass` intrinsics.
---
llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp | 39 +
llvm/test/CodeGen/RISCV/is-fpclass-f32.ll | 1097 +++++++++++++++++
llvm/test/CodeGen/RISCV/is-fpclass-f64.ll | 68 +
.../RISCV/riscv-codegenprepare-fpclass.ll | 307 +++++
4 files changed, 1511 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/is-fpclass-f32.ll
create mode 100644 llvm/test/CodeGen/RISCV/is-fpclass-f64.ll
create mode 100644 llvm/test/CodeGen/RISCV/riscv-codegenprepare-fpclass.ll
diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp
index 5be5345cca73a9..9bee2ff2590774 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPrepare.cpp
@@ -20,11 +20,13 @@
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
+#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;
@@ -58,6 +60,7 @@ class RISCVCodeGenPrepare : public FunctionPass,
bool visitAnd(BinaryOperator &BO);
bool visitIntrinsicInst(IntrinsicInst &I);
bool expandVPStrideLoad(IntrinsicInst &I);
+ bool visitFCmpInst(FCmpInst &I);
};
} // end anonymous namespace
@@ -196,6 +199,42 @@ bool RISCVCodeGenPrepare::expandVPStrideLoad(IntrinsicInst &II) {
return true;
}
+// The 'fcmp uno/ord/oeq/une/ueq/one/ogt/oge/olt/ole x, 0.0' instructions are
+// equivalent to an FP class test. If the fcmp instruction would be custom
+// lowered or lowered to a libcall, use the is.fpclass intrinsic instead, which
+// is lowered by the back-end without a libcall.
+//
+// This basically reverts the transformations of
+// InstCombinerImpl::foldIntrinsicIsFPClass.
+bool RISCVCodeGenPrepare::visitFCmpInst(FCmpInst &Fcmp) {
+ const auto *TLI = ST->getTargetLowering();
+ const EVT VT = TLI->getValueType(*DL, Fcmp.getOperand(0)->getType());
+ const int ISDOpcode = TLI->InstructionOpcodeToISD(Fcmp.getOpcode());
+
+ auto LegalizeTypeAction = TLI->getTypeAction(Fcmp.getContext(), VT);
+ auto OperationAction = TLI->getOperationAction(ISDOpcode, VT);
+ if ((LegalizeTypeAction != TargetLoweringBase::TypeSoftenFloat &&
+ LegalizeTypeAction != TargetLoweringBase::TypeSoftPromoteHalf) ||
+ OperationAction == TargetLowering::Custom)
+ return false;
+
+ auto [ClassVal, ClassTest] =
+ fcmpToClassTest(Fcmp.getPredicate(), *Fcmp.getParent()->getParent(),
+ Fcmp.getOperand(0), Fcmp.getOperand(1));
+
+ // FIXME: For some conditions (e.g ole, olt, oge, ogt) the output is quite
+ // verbose compared to the libcall. Should we do the tranformation
+ // only if we are optimizing for speed?
+ if (!ClassVal)
+ return false;
+
+ IRBuilder<> Builder(&Fcmp);
+ Value *IsFPClass = Builder.createIsFPClass(ClassVal, ClassTest);
+ Fcmp.replaceAllUsesWith(IsFPClass);
+ RecursivelyDeleteTriviallyDeadInstructions(&Fcmp);
+ return true;
+}
+
bool RISCVCodeGenPrepare::runOnFunction(Function &F) {
if (skipFunction(F))
return false;
diff --git a/llvm/test/CodeGen/RISCV/is-fpclass-f32.ll b/llvm/test/CodeGen/RISCV/is-fpclass-f32.ll
new file mode 100644
index 00000000000000..dd918ba7a1a8d7
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/is-fpclass-f32.ll
@@ -0,0 +1,1097 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs -target-abi=ilp32f < %s \
+; RUN: | FileCheck -check-prefix=RV32IF %s
+; RUN: llc -mtriple=riscv32 -mattr=+zfinx -verify-machineinstrs -target-abi=ilp32 < %s \
+; RUN: | FileCheck -check-prefix=RV32IZFINX %s
+; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs -target-abi=ilp32f < %s \
+; RUN: | FileCheck -check-prefix=RV32IF %s
+; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs -target-abi=lp64f < %s \
+; RUN: | FileCheck -check-prefix=RV64IF %s
+; RUN: llc -mtriple=riscv64 -mattr=+zfinx -verify-machineinstrs -target-abi=lp64 < %s \
+; RUN: | FileCheck -check-prefix=RV64IZFINX %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs -target-abi=lp64d < %s \
+; RUN: | FileCheck -check-prefix=RV64IF %s
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64I %s
+
+declare i1 @llvm.is.fpclass.f32(float, i32)
+
+define i1 @fpclass(float %x) {
+; RV32IF-LABEL: fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 927
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 927
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 927
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 927
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a1, a0, 1
+; RV32I-NEXT: lui a2, 2048
+; RV32I-NEXT: slti a0, a0, 0
+; RV32I-NEXT: lui a3, 522240
+; RV32I-NEXT: lui a4, 1046528
+; RV32I-NEXT: srli a1, a1, 1
+; RV32I-NEXT: addi a2, a2, -1
+; RV32I-NEXT: addi a5, a1, -1
+; RV32I-NEXT: sltu a2, a5, a2
+; RV32I-NEXT: xor a5, a1, a3
+; RV32I-NEXT: slt a3, a3, a1
+; RV32I-NEXT: add a4, a1, a4
+; RV32I-NEXT: seqz a1, a1
+; RV32I-NEXT: seqz a5, a5
+; RV32I-NEXT: srli a4, a4, 24
+; RV32I-NEXT: and a2, a2, a0
+; RV32I-NEXT: or a1, a1, a5
+; RV32I-NEXT: sltiu a4, a4, 127
+; RV32I-NEXT: or a1, a1, a2
+; RV32I-NEXT: or a1, a1, a3
+; RV32I-NEXT: and a0, a4, a0
+; RV32I-NEXT: or a0, a1, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a1, a0
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a2, 2048
+; RV64I-NEXT: lui a3, 522240
+; RV64I-NEXT: lui a4, 1046528
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: addiw a2, a2, -1
+; RV64I-NEXT: slti a1, a1, 0
+; RV64I-NEXT: addi a5, a0, -1
+; RV64I-NEXT: sltu a2, a5, a2
+; RV64I-NEXT: xor a5, a0, a3
+; RV64I-NEXT: slt a3, a3, a0
+; RV64I-NEXT: add a4, a0, a4
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: seqz a5, a5
+; RV64I-NEXT: srliw a4, a4, 24
+; RV64I-NEXT: and a2, a2, a1
+; RV64I-NEXT: or a0, a0, a5
+; RV64I-NEXT: sltiu a4, a4, 127
+; RV64I-NEXT: or a0, a0, a2
+; RV64I-NEXT: or a0, a0, a3
+; RV64I-NEXT: and a1, a4, a1
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: ret
+ %cmp = call i1 @llvm.is.fpclass.f32(float %x, i32 639)
+ ret i1 %cmp
+}
+
+define i1 @is_nan_fpclass(float %x) {
+; RV32IF-LABEL: is_nan_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 768
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_nan_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 768
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_nan_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 768
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_nan_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 768
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_nan_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: lui a1, 522240
+; RV32I-NEXT: slt a0, a1, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_nan_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: lui a1, 522240
+; RV64I-NEXT: slt a0, a1, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 3) ; nan
+ ret i1 %1
+}
+
+define i1 @is_qnan_fpclass(float %x) {
+; RV32IF-LABEL: is_qnan_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: srli a0, a0, 9
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_qnan_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: srli a0, a0, 9
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_qnan_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: srli a0, a0, 9
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_qnan_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: srli a0, a0, 9
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_qnan_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: lui a1, 523264
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: addi a1, a1, -1
+; RV32I-NEXT: slt a0, a1, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_qnan_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a1, 523264
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: addiw a1, a1, -1
+; RV64I-NEXT: slt a0, a1, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 2) ; qnan
+ ret i1 %1
+}
+
+define i1 @is_snan_fpclass(float %x) {
+; RV32IF-LABEL: is_snan_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: slli a0, a0, 23
+; RV32IF-NEXT: srli a0, a0, 31
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_snan_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: slli a0, a0, 23
+; RV32IZFINX-NEXT: srli a0, a0, 31
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_snan_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: slli a0, a0, 55
+; RV64IF-NEXT: srli a0, a0, 63
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_snan_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: slli a0, a0, 55
+; RV64IZFINX-NEXT: srli a0, a0, 63
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_snan_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: lui a1, 523264
+; RV32I-NEXT: lui a2, 522240
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: slt a1, a0, a1
+; RV32I-NEXT: slt a0, a2, a0
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_snan_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a1, 523264
+; RV64I-NEXT: lui a2, 522240
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: slt a1, a0, a1
+; RV64I-NEXT: slt a0, a2, a0
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 1) ; snan
+ ret i1 %1
+}
+
+define i1 @is_inf_fpclass(float %x) {
+; RV32IF-LABEL: is_inf_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 129
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_inf_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 129
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_inf_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 129
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_inf_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 129
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_inf_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: lui a1, 522240
+; RV32I-NEXT: xor a0, a0, a1
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_inf_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: lui a1, 522240
+; RV64I-NEXT: xor a0, a0, a1
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 516) ; 0x204 = "inf"
+ ret i1 %1
+}
+
+define i1 @is_posinf_fpclass(float %x) {
+; RV32IF-LABEL: is_posinf_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: slli a0, a0, 24
+; RV32IF-NEXT: srli a0, a0, 31
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_posinf_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: slli a0, a0, 24
+; RV32IZFINX-NEXT: srli a0, a0, 31
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_posinf_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: slli a0, a0, 56
+; RV64IF-NEXT: srli a0, a0, 63
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_posinf_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: slli a0, a0, 56
+; RV64IZFINX-NEXT: srli a0, a0, 63
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_posinf_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a1, 522240
+; RV32I-NEXT: xor a0, a0, a1
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_posinf_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a0, a0
+; RV64I-NEXT: lui a1, 522240
+; RV64I-NEXT: xor a0, a0, a1
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 512) ; 0x200 = "+inf"
+ ret i1 %1
+}
+
+define i1 @is_neginf_fpclass(float %x) {
+; RV32IF-LABEL: is_neginf_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 1
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_neginf_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 1
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_neginf_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 1
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_neginf_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 1
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_neginf_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: lui a1, 1046528
+; RV32I-NEXT: xor a0, a0, a1
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_neginf_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a0, a0
+; RV64I-NEXT: lui a1, 1046528
+; RV64I-NEXT: xor a0, a0, a1
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 4) ; "-inf"
+ ret i1 %1
+}
+
+define i1 @is_finite_fpclass(float %x) {
+; RV32IF-LABEL: is_finite_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 126
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_finite_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 126
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_finite_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 126
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_finite_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 126
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_finite_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: lui a1, 522240
+; RV32I-NEXT: slt a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_finite_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: lui a1, 522240
+; RV64I-NEXT: slt a0, a0, a1
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 504) ; 0x1f8 = "finite"
+ ret i1 %1
+}
+
+define i1 @is_posfinite_fpclass(float %x) {
+; RV32IF-LABEL: is_posfinite_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 112
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_posfinite_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 112
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_posfinite_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 112
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_posfinite_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 112
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_posfinite_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: srli a0, a0, 23
+; RV32I-NEXT: sltiu a0, a0, 255
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_posfinite_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: srliw a0, a0, 23
+; RV64I-NEXT: sltiu a0, a0, 255
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 448) ; 0x1c0 = "+finite"
+ ret i1 %1
+}
+
+define i1 @is_negfinite_fpclass(float %x) {
+; RV32IF-LABEL: is_negfinite_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 14
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_negfinite_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 14
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_negfinite_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 14
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_negfinite_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 14
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_negfinite_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a1, a0, 1
+; RV32I-NEXT: lui a2, 522240
+; RV32I-NEXT: srli a1, a1, 1
+; RV32I-NEXT: slt a1, a1, a2
+; RV32I-NEXT: slti a0, a0, 0
+; RV32I-NEXT: and a0, a1, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_negfinite_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a1, a0
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a2, 522240
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: slt a0, a0, a2
+; RV64I-NEXT: slti a1, a1, 0
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 56) ; 0x38 = "-finite"
+ ret i1 %1
+}
+
+define i1 @is_notfinite_fpclass(float %x) {
+; RV32IF-LABEL: is_notfinite_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 897
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_notfinite_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 897
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_notfinite_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 897
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_notfinite_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 897
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_notfinite_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: lui a1, 522240
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: addi a1, a1, -1
+; RV32I-NEXT: slt a0, a1, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_notfinite_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a1, 522240
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: addiw a1, a1, -1
+; RV64I-NEXT: slt a0, a1, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 519) ; ox207 = "inf|nan"
+ ret i1 %1
+}
+
+define i1 @is_zero_fpclass(float %x) {
+; RV32IF-LABEL: is_zero_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 24
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_zero_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 24
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_zero_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 24
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_zero_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 24
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_zero_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_zero_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 96) ; ox60 = "zero"
+ ret i1 %1
+}
+
+define i1 @is_notzero_fpclass(float %x) {
+; RV32IF-LABEL: is_notzero_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 999
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_notzero_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 999
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_notzero_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 999
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_notzero_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 999
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_notzero_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: snez a0, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_notzero_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: snez a0, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 927) ; ox39f = "~zero"
+ ret i1 %1
+}
+
+define i1 @is_zero_nan_fpclass(float %x) {
+; RV32IF-LABEL: is_zero_nan_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 792
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_zero_nan_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 792
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_zero_nan_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 792
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_zero_nan_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 792
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_zero_nan_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: lui a1, 522240
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: slt a1, a1, a0
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: or a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_zero_nan_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a1, 522240
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: slt a1, a1, a0
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 99) ; ox63 = "zero|nan"
+ ret i1 %1
+}
+
+define i1 @is_not_zero_nan_fpclass(float %x) {
+; RV32IF-LABEL: is_not_zero_nan_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 231
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_not_zero_nan_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 231
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_not_zero_nan_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 231
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_not_zero_nan_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 231
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_not_zero_nan_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a0, a0, 1
+; RV32I-NEXT: lui a1, 522240
+; RV32I-NEXT: srli a0, a0, 1
+; RV32I-NEXT: addi a1, a1, 1
+; RV32I-NEXT: slt a1, a0, a1
+; RV32I-NEXT: snez a0, a0
+; RV32I-NEXT: and a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_not_zero_nan_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a1, 522240
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: addiw a1, a1, 1
+; RV64I-NEXT: slt a1, a0, a1
+; RV64I-NEXT: snez a0, a0
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 924) ; ox39c = "~(zero|nan)"
+ ret i1 %1
+}
+
+define i1 @is_possubnormal_posnormal_posinf_fpclass(float %x) {
+; RV32IF-LABEL: is_possubnormal_posnormal_posinf_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 224
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_possubnormal_posnormal_posinf_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 224
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_possubnormal_posnormal_posinf_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 224
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_possubnormal_posnormal_posinf_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 224
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_possubnormal_posnormal_posinf_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi a1, a0, -1
+; RV32I-NEXT: lui a2, 2048
+; RV32I-NEXT: slli a3, a0, 1
+; RV32I-NEXT: addi a2, a2, -1
+; RV32I-NEXT: sltu a1, a1, a2
+; RV32I-NEXT: lui a2, 1046528
+; RV32I-NEXT: srli a3, a3, 1
+; RV32I-NEXT: add a2, a3, a2
+; RV32I-NEXT: lui a3, 522240
+; RV32I-NEXT: xor a3, a0, a3
+; RV32I-NEXT: slti a0, a0, 0
+; RV32I-NEXT: seqz a3, a3
+; RV32I-NEXT: or a1, a1, a3
+; RV32I-NEXT: srli a2, a2, 24
+; RV32I-NEXT: sltiu a2, a2, 127
+; RV32I-NEXT: xori a0, a0, 1
+; RV32I-NEXT: and a0, a2, a0
+; RV32I-NEXT: or a0, a1, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_possubnormal_posnormal_posinf_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a1, a0
+; RV64I-NEXT: addiw a2, a0, -1
+; RV64I-NEXT: lui a3, 2048
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: addiw a3, a3, -1
+; RV64I-NEXT: sltu a2, a2, a3
+; RV64I-NEXT: lui a3, 1046528
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: add a0, a0, a3
+; RV64I-NEXT: lui a3, 522240
+; RV64I-NEXT: xor a3, a1, a3
+; RV64I-NEXT: slti a1, a1, 0
+; RV64I-NEXT: seqz a3, a3
+; RV64I-NEXT: or a2, a2, a3
+; RV64I-NEXT: srliw a0, a0, 24
+; RV64I-NEXT: sltiu a0, a0, 127
+; RV64I-NEXT: xori a1, a1, 1
+; RV64I-NEXT: and a0, a0, a1
+; RV64I-NEXT: or a0, a2, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 896) ; ox380 = "+subnormal|+normal|+inf"
+ ret i1 %1
+}
+
+define i1 @is_positive_negzero_fpclass(float %x) {
+; RV32IF-LABEL: is_positive_negzero_fpclass:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 248
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_positive_negzero_fpclass:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 248
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_positive_negzero_fpclass:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 248
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_positive_negzero_fpclass:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 248
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_positive_negzero_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi a1, a0, -1
+; RV32I-NEXT: lui a2, 2048
+; RV32I-NEXT: lui a3, 522240
+; RV32I-NEXT: slli a4, a0, 1
+; RV32I-NEXT: addi a2, a2, -1
+; RV32I-NEXT: sltu a1, a1, a2
+; RV32I-NEXT: lui a2, 1046528
+; RV32I-NEXT: xor a3, a0, a3
+; RV32I-NEXT: slti a0, a0, 0
+; RV32I-NEXT: srli a4, a4, 1
+; RV32I-NEXT: seqz a3, a3
+; RV32I-NEXT: add a2, a4, a2
+; RV32I-NEXT: seqz a4, a4
+; RV32I-NEXT: or a3, a4, a3
+; RV32I-NEXT: srli a2, a2, 24
+; RV32I-NEXT: or a1, a3, a1
+; RV32I-NEXT: sltiu a2, a2, 127
+; RV32I-NEXT: xori a0, a0, 1
+; RV32I-NEXT: and a0, a2, a0
+; RV32I-NEXT: or a0, a1, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_positive_negzero_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a1, a0
+; RV64I-NEXT: addiw a2, a0, -1
+; RV64I-NEXT: lui a3, 2048
+; RV64I-NEXT: lui a4, 522240
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: addiw a3, a3, -1
+; RV64I-NEXT: sltu a2, a2, a3
+; RV64I-NEXT: lui a3, 1046528
+; RV64I-NEXT: xor a4, a1, a4
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: slti a1, a1, 0
+; RV64I-NEXT: seqz a4, a4
+; RV64I-NEXT: add a3, a0, a3
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: or a0, a0, a4
+; RV64I-NEXT: srliw a3, a3, 24
+; RV64I-NEXT: or a0, a0, a2
+; RV64I-NEXT: sltiu a2, a3, 127
+; RV64I-NEXT: xori a1, a1, 1
+; RV64I-NEXT: and a1, a2, a1
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 992) ; ox3e0 = "positive|-zero"
+ ret i1 %1
+}
+
+define i1 @is_negsubnormal_negnormal_neginf(float %x) {
+; RV32IF-LABEL: is_negsubnormal_negnormal_neginf:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 7
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_negsubnormal_negnormal_neginf:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 7
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_negsubnormal_negnormal_neginf:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 7
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_negsubnormal_negnormal_neginf:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 7
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_negsubnormal_negnormal_neginf:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a1, a0, 1
+; RV32I-NEXT: lui a2, 2048
+; RV32I-NEXT: slti a3, a0, 0
+; RV32I-NEXT: lui a4, 1046528
+; RV32I-NEXT: srli a1, a1, 1
+; RV32I-NEXT: addi a2, a2, -1
+; RV32I-NEXT: xor a0, a0, a4
+; RV32I-NEXT: add a4, a1, a4
+; RV32I-NEXT: addi a1, a1, -1
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: sltu a1, a1, a2
+; RV32I-NEXT: srli a4, a4, 24
+; RV32I-NEXT: and a1, a1, a3
+; RV32I-NEXT: sltiu a2, a4, 127
+; RV32I-NEXT: or a0, a1, a0
+; RV32I-NEXT: and a2, a2, a3
+; RV32I-NEXT: or a0, a0, a2
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_negsubnormal_negnormal_neginf:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a1, a0
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a2, 2048
+; RV64I-NEXT: lui a3, 1046528
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: addiw a2, a2, -1
+; RV64I-NEXT: slti a4, a1, 0
+; RV64I-NEXT: xor a1, a1, a3
+; RV64I-NEXT: add a3, a0, a3
+; RV64I-NEXT: addi a0, a0, -1
+; RV64I-NEXT: seqz a1, a1
+; RV64I-NEXT: sltu a0, a0, a2
+; RV64I-NEXT: srliw a2, a3, 24
+; RV64I-NEXT: and a0, a0, a4
+; RV64I-NEXT: sltiu a2, a2, 127
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: and a2, a2, a4
+; RV64I-NEXT: or a0, a0, a2
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 28) ; ox1c = "-subnormal|-normal|-inf"
+ ret i1 %1
+}
+
+define i1 @is_negative_poszero(float %x) {
+; RV32IF-LABEL: is_negative_poszero:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fclass.s a0, fa0
+; RV32IF-NEXT: andi a0, a0, 31
+; RV32IF-NEXT: snez a0, a0
+; RV32IF-NEXT: ret
+;
+; RV32IZFINX-LABEL: is_negative_poszero:
+; RV32IZFINX: # %bb.0:
+; RV32IZFINX-NEXT: fclass.s a0, a0
+; RV32IZFINX-NEXT: andi a0, a0, 31
+; RV32IZFINX-NEXT: snez a0, a0
+; RV32IZFINX-NEXT: ret
+;
+; RV64IF-LABEL: is_negative_poszero:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fclass.s a0, fa0
+; RV64IF-NEXT: andi a0, a0, 31
+; RV64IF-NEXT: snez a0, a0
+; RV64IF-NEXT: ret
+;
+; RV64IZFINX-LABEL: is_negative_poszero:
+; RV64IZFINX: # %bb.0:
+; RV64IZFINX-NEXT: fclass.s a0, a0
+; RV64IZFINX-NEXT: andi a0, a0, 31
+; RV64IZFINX-NEXT: snez a0, a0
+; RV64IZFINX-NEXT: ret
+;
+; RV32I-LABEL: is_negative_poszero:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a1, a0, 1
+; RV32I-NEXT: lui a2, 2048
+; RV32I-NEXT: slti a3, a0, 0
+; RV32I-NEXT: lui a4, 1046528
+; RV32I-NEXT: srli a1, a1, 1
+; RV32I-NEXT: addi a2, a2, -1
+; RV32I-NEXT: xor a0, a0, a4
+; RV32I-NEXT: addi a5, a1, -1
+; RV32I-NEXT: add a4, a1, a4
+; RV32I-NEXT: seqz a1, a1
+; RV32I-NEXT: seqz a0, a0
+; RV32I-NEXT: sltu a2, a5, a2
+; RV32I-NEXT: or a0, a1, a0
+; RV32I-NEXT: srli a4, a4, 24
+; RV32I-NEXT: and a2, a2, a3
+; RV32I-NEXT: sltiu a1, a4, 127
+; RV32I-NEXT: or a0, a0, a2
+; RV32I-NEXT: and a1, a1, a3
+; RV32I-NEXT: or a0, a0, a1
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: is_negative_poszero:
+; RV64I: # %bb.0:
+; RV64I-NEXT: sext.w a1, a0
+; RV64I-NEXT: slli a0, a0, 33
+; RV64I-NEXT: lui a2, 2048
+; RV64I-NEXT: lui a3, 1046528
+; RV64I-NEXT: srli a0, a0, 33
+; RV64I-NEXT: addiw a2, a2, -1
+; RV64I-NEXT: slti a4, a1, 0
+; RV64I-NEXT: xor a1, a1, a3
+; RV64I-NEXT: addi a5, a0, -1
+; RV64I-NEXT: add a3, a0, a3
+; RV64I-NEXT: seqz a0, a0
+; RV64I-NEXT: seqz a1, a1
+; RV64I-NEXT: sltu a2, a5, a2
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: srliw a1, a3, 24
+; RV64I-NEXT: and a2, a2, a4
+; RV64I-NEXT: sltiu a1, a1, 127
+; RV64I-NEXT: or a0, a0, a2
+; RV64I-NEXT: and a1, a1, a4
+; RV64I-NEXT: or a0, a0, a1
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f32(float %x, i32 124) ; ox1c = "negative|+zero"
+ ret i1 %1
+}
diff --git a/llvm/test/CodeGen/RISCV/is-fpclass-f64.ll b/llvm/test/CodeGen/RISCV/is-fpclass-f64.ll
new file mode 100644
index 00000000000000..8ce041eb3b6589
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/is-fpclass-f64.ll
@@ -0,0 +1,68 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs -target-abi=ilp32d < %s \
+; RUN: | FileCheck -check-prefixes=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs -target-abi=lp64d < %s \
+; RUN: | FileCheck -check-prefixes=RV64IFD %s
+; RUN: llc -mtriple=riscv32 -mattr=+zdinx -verify-machineinstrs -target-abi=ilp32 < %s \
+; RUN: | FileCheck -check-prefix=RV32IZFINXZDINX %s
+; RUN: llc -mtriple=riscv64 -mattr=+zdinx -verify-machineinstrs -target-abi=lp64 < %s\
+; RUN: | FileCheck -check-prefix=RV64IZFINXZDINX %s
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s | FileCheck -check-prefix=RV64I %s
+
+
+declare i1 @llvm.is.fpclass.f64(double, i32)
+
+define i1 @isnan_d_fpclass(double %x) {
+; RV32IFD-LABEL: isnan_d_fpclass:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fclass.d a0, fa0
+; RV32IFD-NEXT: andi a0, a0, 768
+; RV32IFD-NEXT: snez a0, a0
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: isnan_d_fpclass:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fclass.d a0, fa0
+; RV64IFD-NEXT: andi a0, a0, 768
+; RV64IFD-NEXT: snez a0, a0
+; RV64IFD-NEXT: ret
+;
+; RV32IZFINXZDINX-LABEL: isnan_d_fpclass:
+; RV32IZFINXZDINX: # %bb.0:
+; RV32IZFINXZDINX-NEXT: fclass.d a0, a0
+; RV32IZFINXZDINX-NEXT: andi a0, a0, 768
+; RV32IZFINXZDINX-NEXT: snez a0, a0
+; RV32IZFINXZDINX-NEXT: ret
+;
+; RV64IZFINXZDINX-LABEL: isnan_d_fpclass:
+; RV64IZFINXZDINX: # %bb.0:
+; RV64IZFINXZDINX-NEXT: fclass.d a0, a0
+; RV64IZFINXZDINX-NEXT: andi a0, a0, 768
+; RV64IZFINXZDINX-NEXT: snez a0, a0
+; RV64IZFINXZDINX-NEXT: ret
+;
+; RV32I-LABEL: isnan_d_fpclass:
+; RV32I: # %bb.0:
+; RV32I-NEXT: slli a1, a1, 1
+; RV32I-NEXT: srli a1, a1, 1
+; RV32I-NEXT: lui a2, 524032
+; RV32I-NEXT: beq a1, a2, .LBB0_2
+; RV32I-NEXT: # %bb.1:
+; RV32I-NEXT: slt a0, a2, a1
+; RV32I-NEXT: ret
+; RV32I-NEXT: .LBB0_2:
+; RV32I-NEXT: snez a0, a0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: isnan_d_fpclass:
+; RV64I: # %bb.0:
+; RV64I-NEXT: slli a0, a0, 1
+; RV64I-NEXT: li a1, 2047
+; RV64I-NEXT: srli a0, a0, 1
+; RV64I-NEXT: slli a1, a1, 52
+; RV64I-NEXT: slt a0, a1, a0
+; RV64I-NEXT: ret
+ %1 = call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; nan
+ ret i1 %1
+}
diff --git a/llvm/test/CodeGen/RISCV/riscv-codegenprepare-fpclass.ll b/llvm/test/CodeGen/RISCV/riscv-codegenprepare-fpclass.ll
new file mode 100644
index 00000000000000..d4728e6cf8a5e1
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/riscv-codegenprepare-fpclass.ll
@@ -0,0 +1,307 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -riscv-codegenprepare -S -mtriple=riscv32 -mattr=-f,-d < %s | FileCheck %s --check-prefixes=RV32I
+; RUN: opt -riscv-codegenprepare -S -mtriple=riscv32 -mattr=+f,-d < %s | FileCheck %s --check-prefixes=RV32IF
+; RUN: opt -riscv-codegenprepare -S -mtriple=riscv32 -mattr=+zfinx,-zdinx < %s | FileCheck %s --check-prefixes=RV32IZFINX
+
+; RUN: opt -riscv-codegenprepare -S -mtriple=riscv32 -mattr=+d < %s | FileCheck %s --check-prefixes=RV32ID
+; RUN: opt -riscv-codegenprepare -S -mtriple=riscv32 -mattr=+zdinx < %s | FileCheck %s --check-prefixes=RV32IZDINX
+
+define i1 @test_is_nan(double %arg) {
+; RV32I-LABEL: define i1 @test_is_nan(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 3)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_is_nan(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 3)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_is_nan(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 3)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_is_nan(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp uno double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_is_nan(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp uno double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp uno double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_not_is_nan(double %arg) {
+; RV32I-LABEL: define i1 @test_not_is_nan(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 1020)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_not_is_nan(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 1020)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_not_is_nan(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 1020)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_not_is_nan(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp ord double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_not_is_nan(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp ord double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp ord double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_is_zero(double %arg) {
+; RV32I-LABEL: define i1 @test_is_zero(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 96)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_is_zero(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 96)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_is_zero(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 96)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_is_zero(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp oeq double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_is_zero(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp oeq double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp oeq double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_not_is_zero(double %arg) {
+; RV32I-LABEL: define i1 @test_not_is_zero(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 927)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_not_is_zero(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 927)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_not_is_zero(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 927)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_not_is_zero(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp une double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_not_is_zero(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp une double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp une double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_is_zero_or_nan(double %arg) {
+; RV32I-LABEL: define i1 @test_is_zero_or_nan(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 99)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_is_zero_or_nan(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 99)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_is_zero_or_nan(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 99)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_is_zero_or_nan(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp ueq double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_is_zero_or_nan(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp ueq double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp ueq double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_not_is_zero_or_nan(double %arg) {
+; RV32I-LABEL: define i1 @test_not_is_zero_or_nan(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 924)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_not_is_zero_or_nan(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 924)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_not_is_zero_or_nan(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 924)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_not_is_zero_or_nan(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp one double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_not_is_zero_or_nan(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp one double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp one double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_is_possubnormal_or_posnormal_or_posinf(double %arg) {
+; RV32I-LABEL: define i1 @test_is_possubnormal_or_posnormal_or_posinf(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 896)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_is_possubnormal_or_posnormal_or_posinf(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 896)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_is_possubnormal_or_posnormal_or_posinf(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 896)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_is_possubnormal_or_posnormal_or_posinf(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp ogt double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_is_possubnormal_or_posnormal_or_posinf(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp ogt double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp ogt double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_is_positive_or_negzero(double %arg) {
+; RV32I-LABEL: define i1 @test_is_positive_or_negzero(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 992)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_is_positive_or_negzero(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 992)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_is_positive_or_negzero(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 992)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_is_positive_or_negzero(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp oge double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_is_positive_or_negzero(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp oge double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp oge double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_is_negsubnormal_or_negnormal_or_neginf(double %arg) {
+; RV32I-LABEL: define i1 @test_is_negsubnormal_or_negnormal_or_neginf(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 28)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_is_negsubnormal_or_negnormal_or_neginf(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 28)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_is_negsubnormal_or_negnormal_or_neginf(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 28)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_is_negsubnormal_or_negnormal_or_neginf(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp olt double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_is_negsubnormal_or_negnormal_or_neginf(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp olt double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp olt double %arg, 0.000000e+00
+ ret i1 %1
+}
+
+define i1 @test_is_negative_or_poszero(double %arg) {
+; RV32I-LABEL: define i1 @test_is_negative_or_poszero(
+; RV32I-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32I-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 124)
+; RV32I-NEXT: ret i1 [[TMP1]]
+;
+; RV32IF-LABEL: define i1 @test_is_negative_or_poszero(
+; RV32IF-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IF-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 124)
+; RV32IF-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZFINX-LABEL: define i1 @test_is_negative_or_poszero(
+; RV32IZFINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZFINX-NEXT: [[TMP1:%.*]] = call i1 @llvm.is.fpclass.f64(double [[ARG]], i32 124)
+; RV32IZFINX-NEXT: ret i1 [[TMP1]]
+;
+; RV32ID-LABEL: define i1 @test_is_negative_or_poszero(
+; RV32ID-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32ID-NEXT: [[TMP1:%.*]] = fcmp ole double [[ARG]], 0.000000e+00
+; RV32ID-NEXT: ret i1 [[TMP1]]
+;
+; RV32IZDINX-LABEL: define i1 @test_is_negative_or_poszero(
+; RV32IZDINX-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
+; RV32IZDINX-NEXT: [[TMP1:%.*]] = fcmp ole double [[ARG]], 0.000000e+00
+; RV32IZDINX-NEXT: ret i1 [[TMP1]]
+;
+ %1 = fcmp ole double %arg, 0.000000e+00
+ ret i1 %1
+}
More information about the llvm-commits
mailing list