[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