[llvm] [GlobalISel] Add G_ABDS and G_ABDU instructions (PR #118122)

Thorsten Schütt via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 29 11:21:16 PST 2024


https://github.com/tschuett created https://github.com/llvm/llvm-project/pull/118122

Fixes https://github.com/llvm/llvm-project/issues/118085

The DAG has the same instructions: the signed and unsigned absulute difference of it's input. For AArch64, they map to uabd and sabd for Neon and SVE. The SVE instructions will require custom patterns.

/// i.e trunc(abs(sext(Op0) - sext(Op1))) becomes abds(Op0, Op1) 
///  or trunc(abs(zext(Op0) - zext(Op1))) becomes abdu(Op0, Op1)

For GlobalISel, we are going to write the combines in MIR patterns.

see:
llvm/test/CodeGen/AArch64/abd-combine.ll

>From 9f929ff523b3b608d3629737ddf1c4a85b04db56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= <schuett at gmail.com>
Date: Fri, 29 Nov 2024 20:18:39 +0100
Subject: [PATCH] [GlobalISel] Add G_ABDS and G_ABDU instructions

Fixes https://github.com/llvm/llvm-project/issues/118085

The DAG has the same instructions: the signed and unsigned absulute
difference of it's input. For AArch64, they map to uabd and sabd for
Neon and SVE. The SVE instructions will require custom patterns.

/// i.e trunc(abs(sext(Op0) - sext(Op1))) becomes abds(Op0, Op1)
///  or trunc(abs(zext(Op0) - zext(Op1))) becomes abdu(Op0, Op1)

For GlobalISel, we are going to write the combines in MIR patterns.

see:
llvm/test/CodeGen/AArch64/abd-combine.ll
---
 llvm/docs/GlobalISel/GenericOpcode.rst        |  7 ++++
 .../CodeGen/GlobalISel/MachineIRBuilder.h     | 28 +++++++++++++++
 llvm/include/llvm/Support/TargetOpcodes.def   |  6 ++++
 llvm/include/llvm/Target/GenericOpcodes.td    | 14 ++++++++
 llvm/lib/CodeGen/MachineVerifier.cpp          | 35 +++++++++++++++++++
 .../GlobalISel/legalizer-info-validation.mir  |  8 +++++
 .../GlobalISel/legalizer-info-validation.mir  |  8 +++++
 llvm/test/MachineVerifier/test_abd_su.mir     | 35 +++++++++++++++++++
 8 files changed, 141 insertions(+)
 create mode 100644 llvm/test/MachineVerifier/test_abd_su.mir

diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst
index 076dc7fa93e565..718f99373d28c1 100644
--- a/llvm/docs/GlobalISel/GenericOpcode.rst
+++ b/llvm/docs/GlobalISel/GenericOpcode.rst
@@ -474,6 +474,13 @@ undefined.
   %2:_(s33) = G_CTLZ_ZERO_UNDEF %1
   %2:_(s33) = G_CTTZ_ZERO_UNDEF %1
 
+Compute the absolute difference (signed and unsigned), e.g. abs(x-y).
+
+.. code-block:: none
+
+  %0:_(s33) = G_ABDS %2, %3
+  %1:_(s33) = G_ABDU %4, %5
+
 Floating Point Operations
 -------------------------
 
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index 3516065f9b6cb3..8c1f5e0f4135cb 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -1767,6 +1767,34 @@ class MachineIRBuilder {
     return buildInstr(TargetOpcode::G_MUL, {Dst}, {Src0, Src1}, Flags);
   }
 
+  /// Build and insert \p Res = G_ABDS \p Op0, \p Op1
+  ///
+  /// G_ABDS return the signed absolute difference of \p Op0 and \p Op1.
+  ///
+  /// \pre setBasicBlock or setMI must have been called.
+  /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers
+  ///      with the same (scalar or vector) type).
+  ///
+  /// \return a MachineInstrBuilder for the newly created instruction.
+  MachineInstrBuilder buildAbds(const DstOp &Dst, const SrcOp &Src0,
+                                const SrcOp &Src1) {
+    return buildInstr(TargetOpcode::G_ABDS, {Dst}, {Src0, Src1});
+  }
+
+  /// Build and insert \p Res = G_ABDU \p Op0, \p Op1
+  ///
+  /// G_ABDS return the unsigned absolute difference of \p Op0 and \p Op1.
+  ///
+  /// \pre setBasicBlock or setMI must have been called.
+  /// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers
+  ///      with the same (scalar or vector) type).
+  ///
+  /// \return a MachineInstrBuilder for the newly created instruction.
+  MachineInstrBuilder buildAbdu(const DstOp &Dst, const SrcOp &Src0,
+                                const SrcOp &Src1) {
+    return buildInstr(TargetOpcode::G_ABDU, {Dst}, {Src0, Src1});
+  }
+
   MachineInstrBuilder buildUMulH(const DstOp &Dst, const SrcOp &Src0,
                                  const SrcOp &Src1,
                                  std::optional<unsigned> Flags = std::nullopt) {
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index 17987935ed3cf4..5ef3707b81fe91 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -289,6 +289,12 @@ HANDLE_TARGET_OPCODE(G_OR)
 /// Generic bitwise exclusive-or instruction.
 HANDLE_TARGET_OPCODE(G_XOR)
 
+/// Generic absolute difference signed instruction.
+HANDLE_TARGET_OPCODE(G_ABDS)
+
+/// Generic absolute difference unsigned instruction.
+HANDLE_TARGET_OPCODE(G_ABDU)
+
 
 HANDLE_TARGET_OPCODE(G_IMPLICIT_DEF)
 
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index 60606db078b374..ab18bfa6b0f8bf 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -386,6 +386,20 @@ def G_ASHR : GenericInstruction {
   let hasSideEffects = false;
 }
 
+// Generic absolute difference signed.
+def G_ABDS : GenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src1, type0:$src2);
+  let hasSideEffects = false;
+}
+
+// Generic absolute difference unsigned.
+def G_ABDU : GenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src1, type0:$src2);
+  let hasSideEffects = false;
+}
+
 /// Funnel 'double' shifts take 3 operands, 2 inputs and the shift amount.
 /// fshl(X,Y,Z): (X << (Z % bitwidth)) | (Y >> (bitwidth - (Z % bitwidth)))
 def G_FSHL : GenericInstruction {
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index b08a93ae9a6d58..7f02637dfde1a3 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -1585,6 +1585,41 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
 
     break;
   }
+  case TargetOpcode::G_ABDS:
+  case TargetOpcode::G_ABDU: {
+    LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+    LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
+    LLT SrcTy2 = MRI->getType(MI->getOperand(2).getReg());
+
+    if (SrcTy.isPointerOrPointerVector() || SrcTy2.isPointerOrPointerVector()) {
+      report("Generic abds/abdu does not support pointers as operands", MI);
+      break;
+    }
+
+    if (DstTy.isPointerOrPointerVector()) {
+      report("Generic abds/abdu does not support pointers as a result", MI);
+      break;
+    }
+
+    if ((DstTy.isVector() != SrcTy.isVector()) ||
+        (DstTy.isVector() &&
+         DstTy.getElementCount() != SrcTy.getElementCount())) {
+      report("Generic vector abds/abdu must preserve number of lanes", MI);
+      break;
+    }
+
+    if (SrcTy != SrcTy2) {
+      report("Generic abds/abdu must have same input types", MI);
+      break;
+    }
+
+    if (DstTy != SrcTy) {
+      report("Generic abds/abdu must have same input and output types", MI);
+      break;
+    }
+
+    break;
+  }
   case TargetOpcode::G_SCMP:
   case TargetOpcode::G_UCMP: {
     LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index d35bface7cb48b..7c9c958b5a8189 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -70,6 +70,14 @@
 # DEBUG-NEXT: .. the first uncovered type index: 1, OK
 # DEBUG-NEXT: .. the first uncovered imm index: 0, OK
 #
+# DEBUG-NEXT: G_ABDS (opcode 65): 1 type index, 0 imm indices
+# DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined
+#
+# DEBUG-NEXT:G_ABDU (opcode 66): 1 type index, 0 imm indices
+# DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined
+#
 # DEBUG-NEXT: G_IMPLICIT_DEF (opcode {{[0-9]+}}): 1 type index, 0 imm indices
 # DEBUG-NEXT: .. the first uncovered type index: {{[0-9]+}}, OK
 # DEBUG-NEXT: .. the first uncovered imm index: {{[0-9]+}}, OK
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
index 719ea38cbb9c52..e2ba4f4b7651d3 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
@@ -73,6 +73,14 @@
 # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 #
+# DEBUG-NEXT: G_ABDS (opcode 65): 1 type index, 0 imm indices
+# DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined
+#
+# DEBUG-NEXT:G_ABDU (opcode 66): 1 type index, 0 imm indices
+# DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined
+#
 # DEBUG-NEXT: G_IMPLICIT_DEF (opcode {{[0-9]+}}): 1 type index, 0 imm indices
 # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
diff --git a/llvm/test/MachineVerifier/test_abd_su.mir b/llvm/test/MachineVerifier/test_abd_su.mir
new file mode 100644
index 00000000000000..d8347ff3e5a519
--- /dev/null
+++ b/llvm/test/MachineVerifier/test_abd_su.mir
@@ -0,0 +1,35 @@
+# RUN: not --crash llc -verify-machineinstrs -mtriple=arm64 -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# REQUIRES: aarch64-registered-target
+
+---
+name:            g_abd_su
+body: |
+  bb.0:
+
+    %2:_(p0) = G_IMPLICIT_DEF
+    %3:_(p0) = G_IMPLICIT_DEF
+    ; CHECK: Generic abds/abdu does not support pointers as operands
+    %4:_(s1) = G_ABDS %2, %3
+
+    %12:_(s64) = G_IMPLICIT_DEF
+    %13:_(s64) = G_IMPLICIT_DEF
+    ; CHECK: Generic abds/abdu does not support pointers as a result
+    %14:_(p0) = G_ABDS %12, %13
+
+    %23:_(<2 x s32>) = G_IMPLICIT_DEF
+    %24:_(<2 x s32>) = G_IMPLICIT_DEF
+    ; CHECK: Generic vector abds/abdu must preserve number of lanes
+    %5:_(s1) = G_ABDU  %23, %24
+
+    %15:_(s32) = G_CONSTANT i32 0
+    %16:_(s64) = G_CONSTANT i64 2
+    ; CHECK: Generic abds/abdu must have same input types
+    %17:_(s1) = G_ABDU %15, %16
+
+    %18:_(s64) = G_CONSTANT i64 0
+    %19:_(s64) = G_CONSTANT i64 2
+    ; CHECK: Generic abds/abdu must have same input and output types
+    %20:_(s1) = G_ABDU %18, %19
+
+...
+



More information about the llvm-commits mailing list