[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