[llvm] [MSP430] Compute c+1 at the operand bit width in EmitCMP (PR #195892)

Byeongjee Kang via llvm-commits llvm-commits at lists.llvm.org
Tue May 5 10:52:59 PDT 2026


https://github.com/byeongjee created https://github.com/llvm/llvm-project/pull/195892

 EmitCMP folds `c CMP rhs` into `rhs CMP' c+1` for four condition codes.
  The `c+1` must wrap modulo the i16 operand width, but the current code
  does `C->getSExtValue() + 1` — sign-extending to int64_t and adding there
  loses the bit width. For constants with bit 15 set the result carries
  bits above bit 15 and violates the contract of
  `getConstant(uint64_t, ..., MVT::i16)`: the `isUIntN` assertion fires
  under `LLVM_ENABLE_ASSERTIONS`, and the resulting APInt has non-zero
  bits past its declared width otherwise.

  Switching to `C->getAPIntValue() + 1` keeps the arithmetic at the
  constant's natural width with modular overflow. Mirrors the recent
  AMDGPU fix in 4f0b96f643d3.

  ## Reproducer (assertions build)
  ```c++
  echo 'define i16 @f(i16 %a) { %t = icmp ugt i16 %a, 32768
    %r = zext i1 %t to i16
    ret i16 %r }' | llc -mtriple=msp430
  # Assertion failed: (llvm::isUIntN(BitWidth, val) ...), APInt.h

>From 11aa08942290f9c89b8a924df8d776014ff88b9f Mon Sep 17 00:00:00 2001
From: Byeongjee Kang <byeongjee.kang at gmail.com>
Date: Tue, 5 May 2026 13:48:07 -0400
Subject: [PATCH] [MSP430] Compute c+1 at the operand bit width in EmitCMP
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

EmitCMP folds `c CMP rhs` into `rhs CMP' c+1` for four condition codes.
`c+1` must wrap modulo the i16 operand width, but the current code does
`C->getSExtValue() + 1` — sign-extending to int64_t and adding there
loses the bit width. For constants with bit 15 set, the result has bits
above bit 15 and violates the contract of `getConstant(uint64_t, ...,
MVT::i16)`.

Use `C->getAPIntValue() + 1` to keep the arithmetic at the natural
width. Mirrors AMDGPU's 4f0b96f643d3. Adds a regression test.
---
 llvm/lib/Target/MSP430/MSP430ISelLowering.cpp |  8 +--
 llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll  | 71 +++++++++++++++++++
 2 files changed, 75 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll

diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
index e118169377fe2..218c79b283c27 100644
--- a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
+++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
@@ -889,7 +889,7 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
     // fold constant into instruction.
     if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
       LHS = RHS;
-      RHS = DAG.getConstant(C->getSExtValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getConstant(C->getAPIntValue() + 1, dl, C->getValueType(0));
       TCC = MSP430CC::COND_LO;
       break;
     }
@@ -903,7 +903,7 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
     // fold constant into instruction.
     if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
       LHS = RHS;
-      RHS = DAG.getConstant(C->getSExtValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getConstant(C->getAPIntValue() + 1, dl, C->getValueType(0));
       TCC = MSP430CC::COND_HS;
       break;
     }
@@ -917,7 +917,7 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
     // fold constant into instruction.
     if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
       LHS = RHS;
-      RHS = DAG.getConstant(C->getSExtValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getConstant(C->getAPIntValue() + 1, dl, C->getValueType(0));
       TCC = MSP430CC::COND_L;
       break;
     }
@@ -931,7 +931,7 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
     // fold constant into instruction.
     if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
       LHS = RHS;
-      RHS = DAG.getConstant(C->getSExtValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getConstant(C->getAPIntValue() + 1, dl, C->getValueType(0));
       TCC = MSP430CC::COND_GE;
       break;
     }
diff --git a/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll b/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
new file mode 100644
index 0000000000000..5f3f3ecf20700
--- /dev/null
+++ b/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
@@ -0,0 +1,71 @@
+; RUN: llc -mtriple=msp430 < %s | FileCheck %s
+
+; Regression tests for EmitCMP folding of LHS constants whose i16 high bit is
+; set. These exercise the four EmitCMP branches that turn `c CMP rhs` into
+; `rhs CMP' c+1`. The constant addition must use APInt arithmetic at the
+; original bit width; computing it via getSExtValue() and then handing the
+; resulting int64_t to getConstant(uint64_t, ..., MVT::i16) trips the
+; isUIntN(16, val) assertion in the APInt constructor for any constant with
+; bit 15 set.
+
+target datalayout = "e-p:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:16:32"
+target triple = "msp430-generic-generic"
+
+; CHECK-LABEL: cmp_ule_high_bit:
+; Folded into `rhs u< 0x8001` (c = 0x8000, c+1 = 0x8001 = -32767 signed).
+; CHECK: cmp #-32767, r12
+define i16 @cmp_ule_high_bit(i16 %a) nounwind {
+  %t = icmp ule i16 %a, 32768
+  %r = zext i1 %t to i16
+  ret i16 %r
+}
+
+; CHECK-LABEL: cmp_ugt_high_bit:
+; Folded into `rhs u>= 0x8001`.
+; CHECK: cmp #-32767, r12
+define i16 @cmp_ugt_high_bit(i16 %a) nounwind {
+  %t = icmp ugt i16 %a, 32768
+  %r = zext i1 %t to i16
+  ret i16 %r
+}
+
+; CHECK-LABEL: cmp_sle_neg_high_bit:
+; Folded into `rhs s< -32766` (c = -32767, c+1 = -32766).
+; CHECK: cmp #-32766,
+define i16 @cmp_sle_neg_high_bit(i16 %a) nounwind {
+  %t = icmp sle i16 %a, -32767
+  %r = zext i1 %t to i16
+  ret i16 %r
+}
+
+; CHECK-LABEL: cmp_sgt_neg_high_bit:
+; Folded into `rhs s>= -32766`.
+; CHECK: cmp #-32766,
+define i16 @cmp_sgt_neg_high_bit(i16 %a) nounwind {
+  %t = icmp sgt i16 %a, -32767
+  %r = zext i1 %t to i16
+  ret i16 %r
+}
+
+; The br_cc path goes through the same EmitCMP helper.
+; CHECK-LABEL: br_ule_high_bit:
+; CHECK: cmp #-32767, r12
+define i16 @br_ule_high_bit(i16 %a) nounwind {
+  %t = icmp ule i16 %a, 32768
+  br i1 %t, label %yes, label %no
+yes:
+  ret i16 1
+no:
+  ret i16 0
+}
+
+; CHECK-LABEL: br_sle_neg_high_bit:
+; CHECK: cmp #-32766, r12
+define i16 @br_sle_neg_high_bit(i16 %a) nounwind {
+  %t = icmp sle i16 %a, -32767
+  br i1 %t, label %yes, label %no
+yes:
+  ret i16 1
+no:
+  ret i16 0
+}



More information about the llvm-commits mailing list