diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst --- a/llvm/docs/GlobalISel/GenericOpcode.rst +++ b/llvm/docs/GlobalISel/GenericOpcode.rst @@ -301,6 +301,11 @@ Shift the bits of a scalar left or right inserting zeros (sign-bit for G_ASHR). +G_ROTR, G_ROTL +^^^^^^^^^^^^^^ + +Rotate the bits right (G_ROTR) or left (G_ROTL). + G_ICMP ^^^^^^ diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -1856,6 +1856,18 @@ return buildInstr(TargetOpcode::G_UBFX, {Dst}, {Src, LSB, Width}); } + /// Build and insert \p Dst = G_ROTR \p Src, \p Amt + MachineInstrBuilder buildRotateRight(const DstOp &Dst, const SrcOp &Src, + const SrcOp &Amt) { + return buildInstr(TargetOpcode::G_ROTR, {Dst}, {Src, Amt}); + } + + /// Build and insert \p Dst = G_ROTL \p Src, \p Amt + MachineInstrBuilder buildRotateLeft(const DstOp &Dst, const SrcOp &Src, + const SrcOp &Amt) { + return buildInstr(TargetOpcode::G_ROTL, {Dst}, {Src, Amt}); + } + virtual MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef DstOps, ArrayRef SrcOps, Optional Flags = None); diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -432,6 +432,12 @@ // Generic funnel right shift HANDLE_TARGET_OPCODE(G_FSHR) +// Generic right rotate +HANDLE_TARGET_OPCODE(G_ROTR) + +// Generic left rotate +HANDLE_TARGET_OPCODE(G_ROTL) + /// Generic integer-base comparison, also applicable to vectors of integers. HANDLE_TARGET_OPCODE(G_ICMP) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -362,6 +362,20 @@ let hasSideEffects = false; } +/// Rotate bits right. +def G_ROTR : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type1:$src2); + let hasSideEffects = false; +} + +/// Rotate bits left. +def G_ROTL : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type1:$src2); + let hasSideEffects = false; +} + // Generic integer comparison. def G_ICMP : GenericInstruction { let OutOperandList = (outs type0:$dst); diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td --- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -141,6 +141,8 @@ def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; +def : GINodeEquiv; +def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -1576,6 +1576,19 @@ } break; } + case TargetOpcode::G_ROTR: + case TargetOpcode::G_ROTL: { + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT Src1Ty = MRI->getType(MI->getOperand(1).getReg()); + LLT Src2Ty = MRI->getType(MI->getOperand(2).getReg()); + if (DstTy.isVector() != Src1Ty.isVector() || + Src1Ty.isVector() != Src2Ty.isVector()) { + report("Rotate requires operands to be either all scalars or all vectors", + MI); + break; + } + break; + } default: break; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -291,6 +291,12 @@ # DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} # 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_ROTR (opcode {{[0-9]+}}): 2 type indices, 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_ROTL (opcode {{[0-9]+}}): 2 type indices, 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_ICMP (opcode {{[0-9]+}}): 2 type indices, 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_g_rotr_rotl.mir b/llvm/test/MachineVerifier/test_g_rotr_rotl.mir new file mode 100644 --- /dev/null +++ b/llvm/test/MachineVerifier/test_g_rotr_rotl.mir @@ -0,0 +1,15 @@ +# RUN: not --crash llc -march=arm64 -verify-machineinstrs -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# REQUIRES: aarch64-registered-target +--- +name: test_uniform +body: | + bb.0: + %src:_(<2 x s64>) = G_IMPLICIT_DEF + %amt:_(s64) = G_IMPLICIT_DEF + + ; CHECK: Rotate requires operands to be either all scalars or all vectors + %rotr:_(<2 x s64>) = G_ROTR %src, %amt + + %src2:_(s64) = G_IMPLICIT_DEF + %amt2:_(s64) = G_IMPLICIT_DEF +...