[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 14:04:06 PDT 2026


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

>From 56f60c2be46b7add005014bb34041c92c3076f7d 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 1/4] [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.
---
 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
+}

>From 2b8d94370ee3f1d4a3c861944ef31b16bdcd373e Mon Sep 17 00:00:00 2001
From: Byeongjee Kang <byeongjee.kang at gmail.com>
Date: Tue, 5 May 2026 16:29:19 -0400
Subject: [PATCH 2/4] fixup! [MSP430] Compute c+1 at the operand bit width in
 EmitCMP

---
 llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll b/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
index 5f3f3ecf20700..b1876e348b054 100644
--- a/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
+++ b/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
@@ -8,9 +8,6 @@
 ; 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

>From d744fa3cd4154df682c923051c2ca8c5a0cf7400 Mon Sep 17 00:00:00 2001
From: Byeongjee Kang <byeongjee.kang at gmail.com>
Date: Tue, 5 May 2026 16:31:45 -0400
Subject: [PATCH 3/4] fixup! [MSP430] Compute c+1 at the operand bit width in
 EmitCMP

---
 llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll | 69 +++++++++++++++-----
 1 file changed, 53 insertions(+), 16 deletions(-)

diff --git a/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll b/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
index b1876e348b054..5ba3b5759d6a4 100644
--- a/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
+++ b/llvm/test/CodeGen/MSP430/cmp-imm-high-bit.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc -mtriple=msp430 < %s | FileCheck %s
 
 ; Regression tests for EmitCMP folding of LHS constants whose i16 high bit is
@@ -8,46 +9,74 @@
 ; isUIntN(16, val) assertion in the APInt constructor for any constant with
 ; bit 15 set.
 
-; 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 {
+; CHECK-LABEL: cmp_ule_high_bit:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    cmp #-32767, r12
+; CHECK-NEXT:    mov #1, r12
+; CHECK-NEXT:    bic r2, r12
+; CHECK-NEXT:    ret
   %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 {
+; CHECK-LABEL: cmp_ugt_high_bit:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    cmp #-32767, r12
+; CHECK-NEXT:    mov r2, r12
+; CHECK-NEXT:    and #1, r12
+; CHECK-NEXT:    ret
   %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 {
+; CHECK-LABEL: cmp_sle_neg_high_bit:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    mov #1, r12
+; CHECK-NEXT:    cmp #-32766, r13
+; CHECK-NEXT:    jl .LBB2_2
+; CHECK-NEXT:  ; %bb.1:
+; CHECK-NEXT:    clr r12
+; CHECK-NEXT:  .LBB2_2:
+; CHECK-NEXT:    ret
   %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 {
+; CHECK-LABEL: cmp_sgt_neg_high_bit:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    mov #1, r12
+; CHECK-NEXT:    cmp #-32766, r13
+; CHECK-NEXT:    jge .LBB3_2
+; CHECK-NEXT:  ; %bb.1:
+; CHECK-NEXT:    clr r12
+; CHECK-NEXT:  .LBB3_2:
+; CHECK-NEXT:    ret
   %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 {
+; CHECK-LABEL: br_ule_high_bit:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    cmp #-32767, r12
+; CHECK-NEXT:    jhs .LBB4_2
+; CHECK-NEXT:  ; %bb.1: ; %yes
+; CHECK-NEXT:    mov #1, r12
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  .LBB4_2: ; %no
+; CHECK-NEXT:    clr r12
+; CHECK-NEXT:    ret
   %t = icmp ule i16 %a, 32768
   br i1 %t, label %yes, label %no
 yes:
@@ -56,9 +85,17 @@ 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 {
+; CHECK-LABEL: br_sle_neg_high_bit:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    cmp #-32766, r12
+; CHECK-NEXT:    jge .LBB5_2
+; CHECK-NEXT:  ; %bb.1: ; %yes
+; CHECK-NEXT:    mov #1, r12
+; CHECK-NEXT:    ret
+; CHECK-NEXT:  .LBB5_2: ; %no
+; CHECK-NEXT:    clr r12
+; CHECK-NEXT:    ret
   %t = icmp sle i16 %a, -32767
   br i1 %t, label %yes, label %no
 yes:

>From 7c43170a2714d809388c9bb0276f38166fb0b63e Mon Sep 17 00:00:00 2001
From: Byeongjee Kang <byeongjee.kang at gmail.com>
Date: Tue, 5 May 2026 17:02:58 -0400
Subject: [PATCH 4/4] fixup! [MSP430] Compute c+1 at the operand bit width in
 EmitCMP

---
 llvm/lib/Target/MSP430/MSP430ISelLowering.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
index 218c79b283c27..abae461cb4492 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->getAPIntValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getSignedConstant(C->getSExtValue() + 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->getAPIntValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getSignedConstant(C->getSExtValue() + 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->getAPIntValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getSignedConstant(C->getSExtValue() + 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->getAPIntValue() + 1, dl, C->getValueType(0));
+      RHS = DAG.getSignedConstant(C->getSExtValue() + 1, dl, C->getValueType(0));
       TCC = MSP430CC::COND_GE;
       break;
     }



More information about the llvm-commits mailing list