diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst index 5f1ac067d9f90a..4abe069b10e7a0 100644 --- a/llvm/docs/GlobalISel/GenericOpcode.rst +++ b/llvm/docs/GlobalISel/GenericOpcode.rst @@ -629,6 +629,17 @@ G_VECREDUCE_FMAX, G_VECREDUCE_FMIN FMIN/FMAX nodes can have flags, for NaN/NoNaN variants. +G_ISNAN +^^^^^^^ + +GlobalISel-equivalent of the '``llvm.isnan``' intrinsic. + +Returns a 1-bit scalar or vector of 1-bit scalar values. The result's contents +represent whether or not the source value is NaN. + +.. code-block:: none + + %is_nan:_(s1) = G_ISNAN %check_me_for_nan Integer/bitwise reductions ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index fbe0d1a55bfca1..6ba679b3d2a779 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -769,10 +769,12 @@ HANDLE_TARGET_OPCODE(G_VECREDUCE_UMIN) HANDLE_TARGET_OPCODE(G_SBFX) HANDLE_TARGET_OPCODE(G_UBFX) +HANDLE_TARGET_OPCODE(G_ISNAN) + /// Marker for the end of the generic opcode. /// This is used to check if an opcode is in the range of the /// generic opcodes. -HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_UBFX) +HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_ISNAN) /// BUILTIN_OP_END - This must be the last enum value in this list. /// The target-specific post-isel opcode values start here. diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index e3e1d5fc3c6555..4d0b91e3b6be22 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -225,6 +225,13 @@ def G_FREEZE : GenericInstruction { let hasSideEffects = false; } +// Generic opcode equivalent to the llvm.isnan intrinsic. +def G_ISNAN: GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type1:$src); + let hasSideEffects = false; +} + //------------------------------------------------------------------------------ // Binary ops. //------------------------------------------------------------------------------ diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp index 2b980ecb0236ad..0c495043c2cd7f 100644 --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -947,6 +947,25 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) { // Verify properties of various specific instruction types unsigned Opc = MI->getOpcode(); switch (Opc) { + case TargetOpcode::G_ISNAN: { + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT SrcTy = MRI->getType(MI->getOperand(1).getReg()); + LLT S1 = DstTy.isVector() ? DstTy.getElementType() : DstTy; + if (S1 != LLT::scalar(1)) { + report("Destination must be a 1-bit scalar or vector of 1-bit elements", + MI); + break; + } + + // Disallow pointers. + LLT SrcOrElt = SrcTy.isVector() ? SrcTy.getElementType() : SrcTy; + if (!SrcOrElt.isScalar()) { + report("Source must be a scalar or vector of scalars", MI); + break; + } + verifyVectorElementMatch(DstTy, SrcTy, MI); + break; + } case TargetOpcode::G_ASSERT_SEXT: case TargetOpcode::G_ASSERT_ZEXT: { std::string OpcName = diff --git a/llvm/test/MachineVerifier/test_g_isnan.mir b/llvm/test/MachineVerifier/test_g_isnan.mir new file mode 100644 index 00000000000000..94bc93b6719051 --- /dev/null +++ b/llvm/test/MachineVerifier/test_g_isnan.mir @@ -0,0 +1,33 @@ +# REQUIRES: aarch64-registered-target +# RUN: not --crash llc -verify-machineinstrs -mtriple aarch64 -run-pass none -o /dev/null %s 2>&1 | FileCheck %s + +name: test +body: | + bb.0: + liveins: $x0 + %s64:_(s64) = COPY $x0 + %v4s16:_(<4 x s16>) = COPY $x0 + + ; CHECK: *** Bad machine code: Destination must be a 1-bit scalar or vector of 1-bit elements *** + ; CHECK: instruction: %isnan1:_(s64) = G_ISNAN %s64:_(s64) + %isnan1:_(s64) = G_ISNAN %s64 + + ; CHECK: *** Bad machine code: operand types must be all-vector or all-scalar *** + ; CHECK: instruction: %isnan2:_(<2 x s1>) = G_ISNAN %s64:_(s64) + %isnan2:_(<2 x s1>) = G_ISNAN %s64 + + ; CHECK: *** Bad machine code: operand types must preserve number of vector elements *** + ; CHECK: instruction: %isnan3:_(<2 x s1>) = G_ISNAN %v4s16:_(<4 x s16>) + %isnan3:_(<2 x s1>) = G_ISNAN %v4s16 + + ; CHECK: *** Bad machine code: operand types must be all-vector or all-scalar *** + ; CHECK: instruction: %isnan4:_(s1) = G_ISNAN %v4s16:_(<4 x s16>) + %isnan4:_(s1) = G_ISNAN %v4s16 + + ; CHECK: *** Bad machine code: Destination must be a 1-bit scalar or vector of 1-bit elements *** + ; CHECK: instruction: %isnan5:_(p0) = G_ISNAN %s64:_(s64) + %isnan5:_(p0) = G_ISNAN %s64 + + ; CHECK: *** Bad machine code: Destination must be a 1-bit scalar or vector of 1-bit elements *** + ; CHECK: instruction: %isnan6:_(<4 x p0>) = G_ISNAN %v4s16:_(<4 x s16>) + %isnan6:_(<4 x p0>) = G_ISNAN %v4s16