[llvm] [InstCombine] Preserve no-wrap flags in BitwiseOp(trunc(A), trunc(B)) fold. (PR #219567)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 28 13:00:05 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Andreas Jonson (andjo403)
<details>
<summary>Changes</summary>
proof: https://alive2.llvm.org/ce/z/BP5VSQ
---
Full diff: https://github.com/llvm/llvm-project/pull/219567.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+12-1)
- (modified) llvm/test/Transforms/InstCombine/and-xor-or.ll (+195)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 9e9ebfe5c5e90..054161d4481ff 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1911,7 +1911,18 @@ Instruction *InstCombinerImpl::foldCastedBitwiseLogic(BinaryOperator &I) {
if (shouldOptimizeCast(Cast0) && shouldOptimizeCast(Cast1)) {
Value *NewOp = Builder.CreateBinOp(LogicOpc, Cast0Src, Cast1Src,
I.getName());
- return CastInst::Create(CastOpcode, NewOp, DestTy);
+ auto *NewCast = CastInst::Create(CastOpcode, NewOp, DestTy);
+ if (auto *NewTrunc = dyn_cast<TruncInst>(NewCast)) {
+ auto *Trunc0 = cast<TruncInst>(Cast0);
+ auto *Trunc1 = cast<TruncInst>(Cast1);
+ NewTrunc->setHasNoUnsignedWrap(
+ LogicOpc == Instruction::And
+ ? Trunc0->hasNoUnsignedWrap() || Trunc1->hasNoUnsignedWrap()
+ : Trunc0->hasNoUnsignedWrap() && Trunc1->hasNoUnsignedWrap());
+ NewTrunc->setHasNoSignedWrap(Trunc0->hasNoSignedWrap() &&
+ Trunc1->hasNoSignedWrap());
+ }
+ return NewCast;
}
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/and-xor-or.ll b/llvm/test/Transforms/InstCombine/and-xor-or.ll
index 3bb1056c72025..1750aea8e1eaa 100644
--- a/llvm/test/Transforms/InstCombine/and-xor-or.ll
+++ b/llvm/test/Transforms/InstCombine/and-xor-or.ll
@@ -4247,6 +4247,201 @@ define i32 @trunc_trunc_xor_uses(i65 %x, i65 %y) {
ret i32 %r
}
+define i8 @trunc_nuw_trunc_nuw_xor(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nuw_trunc_nuw_xor
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = xor i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nuw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nuw i16 %x to i8
+ %sy = trunc nuw i16 %y to i8
+ %r = xor i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @trunc_nsw_trunc_nsw_xor(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nsw_trunc_nsw_xor
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = xor i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nsw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc nsw i16 %y to i8
+ %r = xor i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @neg_trunc_nsw_trunc_nuw_xor(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@neg_trunc_nsw_trunc_nuw_xor
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = xor i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc nuw i16 %y to i8
+ %r = xor i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @neg_trunc_nuw_trunc_xor(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@neg_trunc_nuw_trunc_xor
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = xor i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nuw i16 %x to i8
+ %sy = trunc i16 %y to i8
+ %r = xor i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @neg_trunc_nsw_trunc_xor(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@neg_trunc_nsw_trunc_xor
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = xor i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc i16 %y to i8
+ %r = xor i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @trunc_nuw_trunc_nuw_or(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nuw_trunc_nuw_or
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = or i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nuw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nuw i16 %x to i8
+ %sy = trunc nuw i16 %y to i8
+ %r = or i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @trunc_nsw_trunc_nsw_or(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nsw_trunc_nsw_or
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = or i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nsw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc nsw i16 %y to i8
+ %r = or i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @neg_trunc_nsw_trunc_nuw_or(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@neg_trunc_nsw_trunc_nuw_or
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = or i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc nuw i16 %y to i8
+ %r = or i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @neg_trunc_nuw_trunc_or(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@neg_trunc_nuw_trunc_or
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = or i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nuw i16 %x to i8
+ %sy = trunc i16 %y to i8
+ %r = or i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @neg_trunc_nsw_trunc_or(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@neg_trunc_nsw_trunc_or
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = or i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc i16 %y to i8
+ %r = or i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @trunc_nuw_trunc_nuw_and(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nuw_trunc_nuw_and
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = and i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nuw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nuw i16 %x to i8
+ %sy = trunc nuw i16 %y to i8
+ %r = and i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @trunc_nsw_trunc_nsw_and(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nsw_trunc_nsw_and
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = and i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nsw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc nsw i16 %y to i8
+ %r = and i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @trunc_nsw_trunc_nuw_and(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nsw_trunc_nuw_and
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = and i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nuw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc nuw i16 %y to i8
+ %r = and i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @trunc_nuw_trunc_and(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@trunc_nuw_trunc_and
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = and i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc nuw i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nuw i16 %x to i8
+ %sy = trunc i16 %y to i8
+ %r = and i8 %sx, %sy
+ ret i8 %r
+}
+
+define i8 @neg_trunc_nsw_trunc_and(i16 %x, i16 %y) {
+; CHECK-LABEL: define {{[^@]+}}@neg_trunc_nsw_trunc_and
+; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) {
+; CHECK-NEXT: [[R1:%.*]] = and i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = trunc i16 [[R1]] to i8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sx = trunc nsw i16 %x to i8
+ %sy = trunc i16 %y to i8
+ %r = and i8 %sx, %sy
+ ret i8 %r
+}
+
define i16 @and_zext_zext(i8 %x, i4 %y) {
; CHECK-LABEL: define {{[^@]+}}@and_zext_zext
; CHECK-SAME: (i8 [[X:%.*]], i4 [[Y:%.*]]) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/219567
More information about the llvm-commits
mailing list