[llvm] [SLP] Make getSameOpcode support interchangeable instructions. (PR #127450)

Han-Kuan Chen via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 20 23:54:01 PST 2025


================
@@ -810,6 +810,207 @@ static std::optional<unsigned> getExtractIndex(Instruction *E) {
 
 namespace {
 
+/// Base class for representing instructions that can be interchanged with other
+/// equivalent forms. For example, multiplication by a power of 2 can be
+/// interchanged with a left shift.
+///
+/// Derived classes implement specific interchange patterns by overriding the
+/// virtual methods to define their interchange logic.
+///
+/// The class maintains a reference to the main instruction (MainOp) and
+/// provides methods to:
+/// - Check if another instruction is interchangeable (isSame)
+/// - Get the opcode for the interchangeable form
+/// (getInterchangeableInstructionOpcode)
+/// - Get the operands for the interchangeable form
+/// (getInterchangeableInstructionOps)
+class InterchangeableInstruction {
+protected:
+  Instruction *const MainOp;
+
+  /// Return non nullptr if the right operand of I is ConstantInt.
+  static ConstantInt *isBinOpWithConstantInt(Instruction *I) {
+    Constant *C;
+    if (!match(I, m_BinOp(m_Value(), m_Constant(C))))
+      return nullptr;
+    if (auto *CI = dyn_cast<ConstantInt>(C)) {
+      return CI;
+    } else if (auto *CDV = dyn_cast<ConstantDataVector>(C)) {
+      if (auto *CI = dyn_cast_if_present<ConstantInt>(CDV->getSplatValue()))
+        return CI;
+    }
+    return nullptr;
+  }
+
+public:
+  InterchangeableInstruction(Instruction *MainOp) : MainOp(MainOp) {}
+  virtual bool isSame(Instruction *I) {
----------------
HanKuanChen wrote:

Probably cannot. I expected to add other class here. For example,
```
define void @test(<16 x i8> %81, ptr %output) {
entry:
  %shuffle.i = shufflevector <16 x i8> %81, <16 x i8> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
  %shuffle.i109 = shufflevector <16 x i8> %81, <16 x i8> poison, <8 x i32> <i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
  %vmovl.i108 = zext <8 x i8> %shuffle.i to <8 x i16>
  %vmovl.i = zext <8 x i8> %shuffle.i109 to <8 x i16>
  %vext = shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
  %vext20 = shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9>
  %vext29 = shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10>
  %gep0 = getelementptr inbounds i16, ptr %output, i64 0
  %gep1 = getelementptr inbounds i16, ptr %output, i64 8
  %gep2 = getelementptr inbounds i16, ptr %output, i64 16
  %gep3 = getelementptr inbounds i16, ptr %output, i64 24
  store <8 x i16> %vext, ptr %gep0, align 4
  store <8 x i16> %vmovl.i108, ptr %gep1, align 4
  store <8 x i16> %vext20, ptr %gep2, align 4
  store <8 x i16> %vext29, ptr %gep3, align 4
  ret void
}
```
zext and shufflevector are interchangeable. `%vmovl.i108` can be `shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>`.
```
  %vmovl.i108 = shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
  %vext = shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>
  %vext20 = shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9>
  %vext29 = shufflevector <8 x i16> %vmovl.i108, <8 x i16> %vmovl.i, <8 x i32> <i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10>
```
virtual can help me do that.

https://github.com/llvm/llvm-project/pull/127450


More information about the llvm-commits mailing list