[GlobalISel] Add G_ISNAN
authorJessica Paquette <jpaquette@apple.com>
Tue, 17 Aug 2021 16:45:23 +0000 (09:45 -0700)
committerJessica Paquette <jpaquette@apple.com>
Wed, 18 Aug 2021 17:42:05 +0000 (10:42 -0700)
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
llvm/include/llvm/Support/TargetOpcodes.def
llvm/include/llvm/Target/GenericOpcodes.td
llvm/lib/CodeGen/MachineVerifier.cpp
llvm/test/MachineVerifier/test_g_isnan.mir [new file with mode: 0644]

index 5f1ac06..4abe069 100644 (file)
@@ -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
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
index fbe0d1a..6ba679b 100644 (file)
@@ -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.
index e3e1d5f..4d0b91e 100644 (file)
@@ -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.
 //------------------------------------------------------------------------------
index 2b980ec..0c49504 100644 (file)
@@ -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 (file)
index 0000000..94bc93b
--- /dev/null
@@ -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