[llvm] [TypePromotion] Drop invalid nsw from promoted trunc-to-i1 conditions (PR #223637)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 15 02:36:54 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Vito Kortbeek (vkortbeek-gf)

<details>
<summary>Changes</summary>

Fix a miscompile introduced in #<!-- -->216311. TypePromotion zero-extends the operand of a trunc to i1.  When doing so, drop nsw unless nuw is also set, as the original operand might be all ones.

Preserve nuw because it remains valid when zero-extending. Preserve nuw nsw as well, since it implies an all-zero operand when truncating to i1.

Alive2 proofs: https://alive2.llvm.org/ce/z/GHTZXg

---
Full diff: https://github.com/llvm/llvm-project/pull/223637.diff


2 Files Affected:

- (modified) llvm/lib/CodeGen/TypePromotion.cpp (+12-2) 
- (modified) llvm/test/Transforms/TypePromotion/ARM/casts.ll (+45) 


``````````diff
diff --git a/llvm/lib/CodeGen/TypePromotion.cpp b/llvm/lib/CodeGen/TypePromotion.cpp
index 59ea4281f6ee4..2736ff3f8a299 100644
--- a/llvm/lib/CodeGen/TypePromotion.cpp
+++ b/llvm/lib/CodeGen/TypePromotion.cpp
@@ -534,8 +534,18 @@ void IRPromoter::PromoteTree() {
       }
     }
 
-    // Mutate the result type, unless this is an icmp, switch, or trunc to i1.
-    if (!isa<ICmpInst>(I) && !isa<SwitchInst>(I) && !isTruncToI1(I)) {
+    // A trunc to i1 keeps its type while its operand is zero extended.
+    // Drop nsw if nuw is not also set since we might zero-extend an all-ones
+    // operand. nuw still holds, as does nuw nsw, which implies a zero operand.
+    if (isTruncToI1(I)) {
+      auto *Trunc = cast<TruncInst>(I);
+      if (!Trunc->hasNoUnsignedWrap())
+        Trunc->setHasNoSignedWrap(false);
+      continue;
+    }
+
+    // Mutate the result type, unless this is an icmp or switch.
+    if (!isa<ICmpInst>(I) && !isa<SwitchInst>(I)) {
       I->mutateType(ExtTy);
       Promoted.insert(I);
     }
diff --git a/llvm/test/Transforms/TypePromotion/ARM/casts.ll b/llvm/test/Transforms/TypePromotion/ARM/casts.ll
index eee8b4e3ccbe8..2556ae05c3c25 100644
--- a/llvm/test/Transforms/TypePromotion/ARM/casts.ll
+++ b/llvm/test/Transforms/TypePromotion/ARM/casts.ll
@@ -822,6 +822,51 @@ exit:
   ret i8 %next
 }
 
+define i1 @trunc_i1_nsw(i8 zeroext %a, i8 zeroext %b) {
+; CHECK-LABEL: @trunc_i1_nsw(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = zext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[B:%.*]] to i32
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    [[COND:%.*]] = trunc i32 [[OR]] to i1
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+entry:
+  %or = or i8 %a, %b
+  %cond = trunc nsw i8 %or to i1
+  ret i1 %cond
+}
+
+define i1 @trunc_i1_nuw(i8 zeroext %a, i8 zeroext %b) {
+; CHECK-LABEL: @trunc_i1_nuw(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = zext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[B:%.*]] to i32
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    [[COND:%.*]] = trunc nuw i32 [[OR]] to i1
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+entry:
+  %or = or i8 %a, %b
+  %cond = trunc nuw i8 %or to i1
+  ret i1 %cond
+}
+
+define i1 @trunc_i1_nuw_nsw(i8 zeroext %a, i8 zeroext %b) {
+; CHECK-LABEL: @trunc_i1_nuw_nsw(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = zext i8 [[A:%.*]] to i32
+; CHECK-NEXT:    [[TMP1:%.*]] = zext i8 [[B:%.*]] to i32
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    [[COND:%.*]] = trunc nuw nsw i32 [[OR]] to i1
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+entry:
+  %or = or i8 %a, %b
+  %cond = trunc nuw nsw i8 %or to i1
+  ret i1 %cond
+}
+
 define void @search_back_through_trunc(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) {
 ; CHECK-LABEL: @search_back_through_trunc(
 ; CHECK-NEXT:  entry:

``````````

</details>


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


More information about the llvm-commits mailing list