[llvm] [Mips] Fix cttz.i32 fails to lower on mips16 (PR #179633)

via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 4 01:48:32 PST 2026


https://github.com/yingopq created https://github.com/llvm/llvm-project/pull/179633

MIPS16 cannot handle constant pools created by CTTZ table lookup expansion. This causes "Cannot select" errors when trying to select MipsISD::Lo nodes for constant pool addresses.

The fix adds a virtual method `canUseConstantPoolForCTTZ()` to TargetLowering. MIPS16 overrides this to return false, using ISD::CTPOP.

Fix #61055.

>From 7d2f56e4c2b2a7977776119e16cb1746634b8397 Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Wed, 4 Feb 2026 17:34:44 +0800
Subject: [PATCH] [Mips] Fix cttz.i32 fails to lower on mips16

MIPS16 cannot handle constant pools created by CTTZ table lookup
expansion. This causes "Cannot select" errors when trying to select
MipsISD::Lo nodes for constant pool addresses.

The fix adds a virtual method `canUseConstantPoolForCTTZ()` to
TargetLowering. MIPS16 overrides this to return false, using ISD::CTPOP.

Fix #61055.
---
 llvm/include/llvm/CodeGen/TargetLowering.h    |  3 +
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |  3 +-
 llvm/lib/Target/Mips/MipsISelLowering.cpp     |  5 ++
 llvm/lib/Target/Mips/MipsISelLowering.h       |  1 +
 .../Mips/GlobalISel/llvm-ir/cttz-mips16.ll    | 61 +++++++++++++++++++
 5 files changed, 72 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/cttz-mips16.ll

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index ada4ffd3bcc89..27954affe7b61 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -727,6 +727,9 @@ class LLVM_ABI TargetLoweringBase {
     return false;
   }
 
+  /// Return true if constant pool can be used for CTTZ expansion.
+  virtual bool canUseConstantPoolForCTTZ() const { return true; }
+
   /// Return true if ctlz instruction is fast.
   virtual bool isCtlzFast() const {
     return false;
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index a10b93063dc27..2c02e761b1b03 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -9691,8 +9691,9 @@ SDValue TargetLowering::expandCTTZ(SDNode *Node, SelectionDAG &DAG) const {
 
   // Emit Table Lookup if ISD::CTPOP used in the fallback path below is going
   // to be expanded or converted to a libcall.
+  const TargetLowering &TLI = DAG.getTargetLoweringInfo();
   if (!VT.isVector() && !isOperationLegalOrCustomOrPromote(ISD::CTPOP, VT) &&
-      !isOperationLegal(ISD::CTLZ, VT))
+      !isOperationLegal(ISD::CTLZ, VT) && TLI.canUseConstantPoolForCTTZ())
     if (SDValue V = CTTZTableLookup(Node, DAG, dl, VT, Op, NumBitsPerElt))
       return V;
 
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index f7e2825edcc5d..d92b70633fb94 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -1190,6 +1190,11 @@ bool MipsTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const {
   return Subtarget.hasMips32();
 }
 
+bool MipsTargetLowering::canUseConstantPoolForCTTZ() const {
+  // MIPS16 cannot use constant pools for CTTZ expansion.
+  return !Subtarget.inMips16Mode();
+}
+
 bool MipsTargetLowering::hasBitTest(SDValue X, SDValue Y) const {
   // We can use ANDI+SLTIU as a bit test. Y contains the bit position.
   // For MIPSR2 or later, we may be able to use the `ext` instruction or its
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index 806fb59f5ff3e..17fd4db0ba152 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -81,6 +81,7 @@ class TargetRegisterClass;
 
     bool isCheapToSpeculateCttz(Type *Ty) const override;
     bool isCheapToSpeculateCtlz(Type *Ty) const override;
+    bool canUseConstantPoolForCTTZ() const override;
     bool hasBitTest(SDValue X, SDValue Y) const override;
     bool shouldFoldConstantShiftPairToMask(const SDNode *N) const override;
 
diff --git a/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/cttz-mips16.ll b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/cttz-mips16.ll
new file mode 100644
index 0000000000000..7dbb4fc567a8b
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/cttz-mips16.ll
@@ -0,0 +1,61 @@
+; RUN: llc -mtriple=mipsel-linux-gnu -mcpu=mips32 -mattr=+mips16 -verify-machineinstrs < %s | FileCheck %s -check-prefixes=MIPS16
+
+define i32 @cttz_i32(i32 %a) {
+; MIPS16-LABEL: cttz_i32:
+; MIPS16:       # %bb.0: # %entry
+; MIPS16-NEXT:    not $2, $4
+; MIPS16-NEXT:	  addiu $4, -1	# 16 bit inst
+; MIPS16-NEXT:	  and $4, $2
+; MIPS16-NEXT:	  srl $2, $4, 1
+; MIPS16-NEXT:	  lw $3, $CPI0_0	# 16 bit inst
+; MIPS16-NEXT:	  and $3, $2
+; MIPS16-NEXT:	  subu $2, $4, $3
+; MIPS16-NEXT:	  lw $3, $CPI0_1	# 16 bit inst
+; MIPS16-NEXT:	  srl $4, $2, 2
+; MIPS16-NEXT:	  and $2, $3
+; MIPS16-NEXT:	  and $4, $3
+; MIPS16-NEXT:	  addu $2, $2, $4
+; MIPS16-NEXT:	  srl $3, $2, 4
+; MIPS16-NEXT:	  addu $2, $2, $3
+; MIPS16-NEXT:	  lw $3, $CPI0_2	# 16 bit inst
+; MIPS16-NEXT:	  and $3, $2
+; MIPS16-NEXT:	  lw $2, $CPI0_3	# 16 bit inst
+; MIPS16-NEXT:	  mult $3, $2
+; MIPS16-NEXT:	  mflo $2
+; MIPS16-NEXT:	  srl $2, $2, 24
+; MIPS16-NEXT:	  jrc $ra
+
+entry:
+  %0 = call i32 @llvm.cttz.i32(i32 %a, i1 false)
+  ret i32 %0
+}
+declare i32 @llvm.cttz.i32(i32, i1 immarg)
+
+define i64 @cttz_i64(i64  %a) {
+; MIPS16-LABEL: cttz_i64:
+; MIPS16:       # %bb.1: # %entry
+; MIPS16-NEXT:    not $4, $5
+; MIPS16-NEXT:	  addiu	$5, -1	# 16 bit inst
+; MIPS16-NEXT:	  and $5, $4
+; MIPS16-NEXT:	  srl $4, $5, 1
+; MIPS16-NEXT:	  and $4, $7
+; MIPS16-NEXT:	  subu $4, $5, $4
+; MIPS16-NEXT:	  srl $5, $4, 2
+; MIPS16-NEXT:	  and $4, $6
+; MIPS16-NEXT:	  and $5, $6
+; MIPS16-NEXT:	  addu $4, $4, $5
+; MIPS16-NEXT:	  srl $5, $4, 4
+; MIPS16-NEXT:	  addu $4, $4, $5
+; MIPS16-NEXT:	  and $4, $3
+; MIPS16-NEXT:	  mult $4, $2
+; MIPS16-NEXT:	  mflo $2
+; MIPS16-NEXT:	  srl $2, $2, 24
+; MIPS16-NEXT:	  addiu	$2, 32	# 16 bit inst
+; MIPS16-NEXT:	  li $3, 0
+; MIPS16-NEXT:	  jrc $ra
+
+entry:
+  %0 = call i64 @llvm.cttz.i64(i64 %a, i1 false)
+  ret i64 %0
+}
+declare i64 @llvm.cttz.i64(i64, i1 immarg)



More information about the llvm-commits mailing list