diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst index 076dc7fa93e56..718f99373d28c 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 3516065f9b6cb..fac7fa6417265 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_ABDU 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 Flags = std::nullopt) { diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index 17987935ed3cf..5ef3707b81fe9 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 60606db078b37..c8f91cd0de597 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -386,6 +386,22 @@ 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; + let isCommutable = true; +} + +// Generic absolute difference unsigned. +def G_ABDU : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = false; + let isCommutable = true; +} + /// 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 b08a93ae9a6d5..8e64e4055665c 100644 --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -1585,6 +1585,31 @@ 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 ((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 d35bface7cb48..7c9c958b5a818 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 719ea38cbb9c5..e2ba4f4b7651d 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 0000000000000..4f9272f238a7d --- /dev/null +++ b/llvm/test/MachineVerifier/test_abd_su.mir @@ -0,0 +1,33 @@ +# 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 + %4:_(s1) = G_ABDS %2, %3 + + %12:_(s64) = G_IMPLICIT_DEF + %13:_(s64) = G_IMPLICIT_DEF + %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 + +... + diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td index 7dbaf4390c0f7..ffefaba284299 100644 --- a/llvm/test/TableGen/GlobalISelEmitter.td +++ b/llvm/test/TableGen/GlobalISelEmitter.td @@ -513,7 +513,7 @@ def : Pat<(frag GPR32:$src1, complex:$src2, complex:$src3), // R00O-NEXT: GIM_Reject, // R00O: // Label [[DEFAULT_NUM]]: @[[DEFAULT]] // R00O-NEXT: GIM_Reject, -// R00O-NEXT: }; // Size: 1832 bytes +// R00O-NEXT: }; // Size: 1840 bytes def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4), [(set GPR32:$dst,