From 0a2b1ba33ae6dcaedb81417f7c4cc714f72a5968 Mon Sep 17 00:00:00 2001 From: Jessica Paquette Date: Tue, 17 Aug 2021 09:45:23 -0700 Subject: [PATCH] [GlobalISel] Add G_ISNAN Add a generic opcode equivalent to the `llvm.isnan` intrinsic + MachineVerifier support for it. We need an opcode here because we may want target-specific lowering later on. Differential Revision: https://reviews.llvm.org/D108222 --- llvm/docs/GlobalISel/GenericOpcode.rst | 11 ++++++++++ llvm/include/llvm/Support/TargetOpcodes.def | 4 +++- llvm/include/llvm/Target/GenericOpcodes.td | 7 ++++++ llvm/lib/CodeGen/MachineVerifier.cpp | 19 +++++++++++++++++ llvm/test/MachineVerifier/test_g_isnan.mir | 33 +++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 llvm/test/MachineVerifier/test_g_isnan.mir diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst index 5f1ac06..4abe069 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 fbe0d1a..6ba679b 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 e3e1d5f..4d0b91e 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 2b980ec..0c49504 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 0000000..94bc93b --- /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 -- 2.7.4