[llvm-branch-commits] [llvm] release/23.x: [MIPS] Fix GP-relative selection after select/add combine (#215414) (PR #220795)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Sep 2 21:02:24 PDT 2026


https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/220795

Backport c5b1e01ed897f417c370a225c6cdaaa14a1c142d

Requested by: @brad0

>From a48be23922e6a98849c8c081375e038c6892ae91 Mon Sep 17 00:00:00 2001
From: david04g <85910051+david04g at users.noreply.github.com>
Date: Wed, 2 Sep 2026 20:54:03 -0700
Subject: [PATCH] [MIPS] Fix GP-relative selection after select/add combine
 (#215414)

## Summary

- Rewrite `$gp + select(...)` before MIPS instruction selection when a
select
  arm contains a GP-relative relocation.
- Keep each `MipsISD::GPRel` attached to a selectable add operation.
- Add MIPS32 regression coverage and update the resulting MIPS64 checks.

## Background

The generic DAG combiner can transform:

    select C, (add $gp, %gp_rel(A)), (add $gp, %gp_rel(B))

into:

    add $gp, (select C, %gp_rel(A), %gp_rel(B))

This leaves `MipsISD::GPRel` as a standalone value, which MIPS
instruction
selection cannot match. The new MIPS DAG-to-DAG preprocessing step
restores
the distributive form before selection.

This follows the MIPS-local fixup direction discussed in #212163 and
avoids
introducing a target-independent hook.

## Testing

- Built `llc` on current `upstream/main`.
- Ran the exact MIPS32 static `-mgpopt -mattr=+noabicalls` reproducer.
- Ran:
  - `llvm/test/CodeGen/Mips/cmov.ll`
  - `llvm/test/CodeGen/Mips/llvm-ir/select-globaladdr.ll`
- Ran `check-llvm-codegen-mips`:
  - 1040 discovered
  - 1033 passed
  - 3 unsupported
  - 4 expected failures
  - 0 unexpected failures

Fixes #212057

AI disclosure: I used OpenAI Codex to help with issue analysis, patch
development/review, and local validation. I personally reviewed and
understand the final code, tests, and PR description and take
responsibility
for the contribution.

(cherry picked from commit c5b1e01ed897f417c370a225c6cdaaa14a1c142d)
---
 llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp     | 49 +++++++++++++++++++
 llvm/lib/Target/Mips/MipsISelDAGToDAG.h       |  2 +
 llvm/test/CodeGen/Mips/cmov.ll                |  6 +++
 .../CodeGen/Mips/llvm-ir/select-globaladdr.ll |  7 ++-
 4 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
index 36706243232c0..4e90d78048199 100644
--- a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
@@ -224,6 +224,55 @@ bool MipsDAGToDAGISel::selectVecAddAsVecSubIfProfitable(SDNode *Node) {
   return true;
 }
 
+void MipsDAGToDAGISel::PreprocessISelDAG() {
+  // The generic DAG combiner folds
+  //
+  //   select C, (add $gp, %gp_rel(A)), (add $gp, %gp_rel(B))
+  //
+  // into
+  //
+  //   add $gp, (select C, %gp_rel(A), %gp_rel(B)).
+  //
+  // A GP-relative relocation is only selectable as an operand of the add.
+  // Restore the original form before instruction selection so the relocation
+  // is never selected on its own.
+  bool MadeChange = false;
+  for (SDNode &Node : llvm::make_early_inc_range(CurDAG->allnodes())) {
+    if (Node.getOpcode() != ISD::ADD)
+      continue;
+
+    SDValue Base = Node.getOperand(0);
+    SDValue Sel = Node.getOperand(1);
+    if (Base.getOpcode() == ISD::SELECT)
+      std::swap(Base, Sel);
+
+    const auto *BaseReg = dyn_cast<RegisterSDNode>(Base);
+    if (!BaseReg ||
+        (BaseReg->getReg() != Mips::GP && BaseReg->getReg() != Mips::GP_64) ||
+        Sel.getOpcode() != ISD::SELECT)
+      continue;
+
+    SDValue TrueValue = Sel.getOperand(1);
+    SDValue FalseValue = Sel.getOperand(2);
+    if (TrueValue.getOpcode() != MipsISD::GPRel &&
+        FalseValue.getOpcode() != MipsISD::GPRel)
+      continue;
+
+    SDLoc DL(&Node);
+    EVT VT = Node.getValueType(0);
+    SDNodeFlags Flags = Node.getFlags();
+    TrueValue = CurDAG->getNode(ISD::ADD, DL, VT, Base, TrueValue, Flags);
+    FalseValue = CurDAG->getNode(ISD::ADD, DL, VT, Base, FalseValue, Flags);
+    SDValue NewSel =
+        CurDAG->getSelect(DL, VT, Sel.getOperand(0), TrueValue, FalseValue);
+    CurDAG->ReplaceAllUsesOfValueWith(SDValue(&Node, 0), NewSel);
+    MadeChange = true;
+  }
+
+  if (MadeChange)
+    CurDAG->RemoveDeadNodes();
+}
+
 /// Select instructions not customized! Used for
 /// expanded, promoted and normal instructions
 void MipsDAGToDAGISel::Select(SDNode *Node) {
diff --git a/llvm/lib/Target/Mips/MipsISelDAGToDAG.h b/llvm/lib/Target/Mips/MipsISelDAGToDAG.h
index f19d72d94f806..1c90835526e43 100644
--- a/llvm/lib/Target/Mips/MipsISelDAGToDAG.h
+++ b/llvm/lib/Target/Mips/MipsISelDAGToDAG.h
@@ -124,6 +124,8 @@ class MipsDAGToDAGISel : public SelectionDAGISel {
   /// add X, <-1, -1...> --> sub X, <1, 1...>
   bool selectVecAddAsVecSubIfProfitable(SDNode *Node);
 
+  void PreprocessISelDAG() override;
+
   void Select(SDNode *N) override;
 
   virtual bool trySelect(SDNode *Node) = 0;
diff --git a/llvm/test/CodeGen/Mips/cmov.ll b/llvm/test/CodeGen/Mips/cmov.ll
index ee60b353b86b6..fba0526e7f5bc 100644
--- a/llvm/test/CodeGen/Mips/cmov.ll
+++ b/llvm/test/CodeGen/Mips/cmov.ll
@@ -5,6 +5,7 @@
 ; RUN: llc -mtriple=mips64el -mcpu=mips4                  -relocation-model=pic < %s | FileCheck %s -check-prefixes=ALL,64-CMOV
 ; RUN: llc -mtriple=mips64el -mcpu=mips64                 -relocation-model=pic < %s | FileCheck %s -check-prefixes=ALL,64-CMOV
 ; RUN: llc -mtriple=mips64el -mcpu=mips64r6               -relocation-model=pic < %s | FileCheck %s -check-prefixes=ALL,64-CMP
+; RUN: llc -mtriple=mips -mcpu=mips32 -relocation-model=static -mgpopt -mattr=+noabicalls < %s | FileCheck %s -check-prefix=GPREL
 
 @i1 = global [3 x i32] [i32 1, i32 2, i32 3], align 4
 @i3 = common global ptr null, align 4
@@ -51,6 +52,11 @@ entry:
 
 ; ALL-LABEL: cmov2:
 
+; GPREL-LABEL: cmov2:
+; GPREL-DAG:   addiu $[[D:[0-9]+]], $gp, %gp_rel(d)
+; GPREL-DAG:   addiu $[[C:[0-9]+]], $gp, %gp_rel(c)
+; GPREL:       movn $[[D]], $[[C]], $4
+
 ; 32-CMOV-DAG:  addiu $[[R1:[0-9]+]], ${{[0-9]+}}, %got(d)
 ; 32-CMOV-DAG:  addiu $[[R0:[0-9]+]], ${{[0-9]+}}, %got(c)
 ; 32-CMOV-DAG:  movn  $[[R1]], $[[R0]], $4
diff --git a/llvm/test/CodeGen/Mips/llvm-ir/select-globaladdr.ll b/llvm/test/CodeGen/Mips/llvm-ir/select-globaladdr.ll
index 7e6a6b0dbcecd..a43525f4e2bbe 100644
--- a/llvm/test/CodeGen/Mips/llvm-ir/select-globaladdr.ll
+++ b/llvm/test/CodeGen/Mips/llvm-ir/select-globaladdr.ll
@@ -10,11 +10,10 @@ define ptr @tst_select_ptr_ptr(i1 %tobool.not) {
 ; MIPS64:       # %bb.0: # %entry
 ; MIPS64-NEXT:    sll $1, $4, 0
 ; MIPS64-NEXT:    andi $1, $1, 1
-; MIPS64-NEXT:    daddiu $2, $zero, %gp_rel(.str)
-; MIPS64-NEXT:    daddiu $3, $zero, %gp_rel(.str.1)
-; MIPS64-NEXT:    movn $2, $3, $1
+; MIPS64-NEXT:    daddiu $2, $gp, %gp_rel(.str)
+; MIPS64-NEXT:    daddiu $3, $gp, %gp_rel(.str.1)
 ; MIPS64-NEXT:    jr $ra
-; MIPS64-NEXT:    daddu $2, $gp, $2
+; MIPS64-NEXT:    movn $2, $3, $1
 entry:
   %cond = select i1 %tobool.not, ptr @.str.1, ptr @.str
   ret ptr %cond



More information about the llvm-branch-commits mailing list