[llvm] [AMDGPU] Account for existing SDWA selections (PR #123221)

Frederik Harwath via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 6 03:59:32 PST 2025


================
@@ -108,6 +111,42 @@ class SDWAOperand {
   MachineOperand *getReplacedOperand() const { return Replaced; }
   MachineInstr *getParentInst() const { return Target->getParent(); }
 
+  /// Combine an SDWA instruction's existing SDWA selection \p
+  /// ExistingSel with the SDWA selection \p OpSel of its operand. If
+  /// the selections are compatible, return the combined selection,
+  /// otherwise return a nullopt. For example, if we have ExistingSel
+  /// = BYTE_0 Sel and FoldedSel WORD_1 Sel:
+  ///     BYTE_0 Sel (WORD_1 Sel (%X)) -> BYTE_2 Sel (%X)
+  std::optional<SdwaSel> combineSdwaSel(SdwaSel ExistingSel,
----------------
frederik-h wrote:

We could split of an `areSelectionsCompatible` predicate from this function and use it to check whether or not this function will be successful before we call it instead of using the `std::optional`. But considering the way in which `SDWASrcOperand::convertToSDWA` determines `SrcSel`, I don't see how we could move this check much above the current place at which we invoke `combineSdwaSel` in this function. Perhaps placing it above the `V_MAC` handling would work. And I am not sure if splitting the function would really improve readability. Here's how the function would roughly look like (still using the `std::optional` which I had not yet removed): 
```
diff --git a/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp b/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp
index 39fe65e7c375..d87072ea88eb 100644
--- a/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp
@@ -111,31 +111,33 @@ public:
   MachineOperand *getReplacedOperand() const { return Replaced; }
   MachineInstr *getParentInst() const { return Target->getParent(); }

+  bool compatibleSelections(SdwaSel ExistingSel, SdwaSel OperandSel) {
+    return ExistingSel == SdwaSel::DWORD || OperandSel == ExistingSel ||
+           (ExistingSel != SdwaSel::WORD_1 && ExistingSel != SdwaSel::BYTE_2 &&
+            ExistingSel != SdwaSel::BYTE_3 &&
+            (OperandSel == SdwaSel::WORD_0 || OperandSel == SdwaSel::WORD_1));
+  }
+
   /// Combine an SDWA instruction's existing SDWA selection \p
   /// ExistingSel with the SDWA selection \p OpSel of its operand. If
   /// the selections are compatible, return the combined selection,
   /// otherwise return a nullopt. For example, if we have ExistingSel
-  /// = BYTE_0 Sel and FoldedSel WORD_1 Sel:
+  /// = BYTE_0 Sel and OperandSel WORD_1 Sel:
   ///     BYTE_0 Sel (WORD_1 Sel (%X)) -> BYTE_2 Sel (%X)
   std::optional<SdwaSel> combineSdwaSel(SdwaSel ExistingSel,
                                         SdwaSel OperandSel) {
-    if (ExistingSel == SdwaSel::DWORD)
-      return OperandSel;
-
-    if (OperandSel == SdwaSel::DWORD)
-      return ExistingSel;
-
-    if (ExistingSel == SdwaSel::WORD_1 || ExistingSel == SdwaSel::BYTE_2 ||
-        ExistingSel == SdwaSel::BYTE_3)
+    if (!compatibleSelections(ExistingSel, OperandSel))
       return {};

-    if (ExistingSel == OperandSel)
-      return ExistingSel;
+    if (ExistingSel == SdwaSel::DWORD)
+      return OperandSel;

-    if (OperandSel == SdwaSel::WORD_0)
+    if (OperandSel == ExistingSel ||
+       OperandSel == SdwaSel::DWORD ||
+       OperandSel == SdwaSel::WORD_0)
       return ExistingSel;

-    if (OperandSel == SdwaSel::WORD_1) {
+        if (OperandSel == SdwaSel::WORD_1) {
       if (ExistingSel == SdwaSel::BYTE_0)
         return SdwaSel::BYTE_2;
       if (ExistingSel == SdwaSel::BYTE_1)
@@ -143,8 +145,7 @@ public:
       if (ExistingSel == SdwaSel::WORD_0)
         return SdwaSel::WORD_1;
     }
-
-    return {};
+    llvm_unreachable("Unreachable");
   }

   MachineRegisterInfo *getMRI() const {
``` 

Do you think this is preferable to the current approach?

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


More information about the llvm-commits mailing list