Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[InstCombine] Update the select operand when the cond is trunc and has the nuw or nsw property. #105914

Merged
merged 3 commits into from
Aug 24, 2024

Conversation

c8ef
Copy link
Contributor

@c8ef c8ef commented Aug 24, 2024

This patch updates the select operand when the cond has the nuw or nsw property. Considering the semantics of the nuw and nsw flag, if there is no poison value in this expression, this code assumes that X can only be 0, 1 or -1.

close: #96765
alive2: https://alive2.llvm.org/ce/z/3n3n2Q

@c8ef c8ef requested a review from nikic as a code owner August 24, 2024 01:51
@llvmbot
Copy link
Member

llvmbot commented Aug 24, 2024

@llvm/pr-subscribers-llvm-transforms

Author: None (c8ef)

Changes

This patch adds a fold from select (trunc nuw X to i1), X, Y to select (trunc nuw X to i1), 1, Y. Considering the semantics of the nuw flag, if there is no poison value in this expression, this code assumes that X can only be 0 or 1.

Partially resolved: #96765


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

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp (+10)
  • (added) llvm/test/Transforms/InstCombine/fold-select-trunc-if-nuw.ll (+35)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 18ffc209f259e0..49582004d9a4f6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -4201,5 +4201,15 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
     }
   }
 
+  // select (trunc nuw X to i1), X, Y --> select (trunc nuw X to i1), 1, Y
+  if (auto *TI = dyn_cast<TruncInst>(CondVal)) {
+    Value *Trunc;
+    if (TI->hasNoUnsignedWrap() && match(CondVal, m_Trunc(m_Value(Trunc))) &&
+        match(TrueVal, m_Specific(Trunc))) {
+      return SelectInst::Create(
+          CondVal, ConstantInt::get(TrueVal->getType(), 1), FalseVal);
+    }
+  }
+
   return nullptr;
 }
diff --git a/llvm/test/Transforms/InstCombine/fold-select-trunc-if-nuw.ll b/llvm/test/Transforms/InstCombine/fold-select-trunc-if-nuw.ll
new file mode 100644
index 00000000000000..09fb2d77f9ef56
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/fold-select-trunc-if-nuw.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i8 @fold_select_trunc_if_nuw(i8 %x, i8 %y) {
+; CHECK-LABEL: @fold_select_trunc_if_nuw(
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nuw i8 [[X:%.*]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[TRUNC]], i8 1, i8 [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %trunc = trunc nuw i8 %x to i1
+  %ret = select i1 %trunc, i8 %x, i8 %y
+  ret i8 %ret
+}
+
+define i8 @fold_select_trunc_if_nuw_negative(i8 %x, i8 %y) {
+; CHECK-LABEL: @fold_select_trunc_if_nuw_negative(
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nsw i8 [[X:%.*]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[TRUNC]], i8 [[X]], i8 [[Y:%.*]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+  %trunc = trunc nsw i8 %x to i1
+  %ret = select i1 %trunc, i8 %x, i8 %y
+  ret i8 %ret
+}
+
+define <2 x i8> @fold_select_trunc_if_nuw_vector(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @fold_select_trunc_if_nuw_vector(
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nuw <2 x i8> [[X:%.*]] to <2 x i1>
+; CHECK-NEXT:    [[RET:%.*]] = select <2 x i1> [[TRUNC]], <2 x i8> <i8 1, i8 1>, <2 x i8> [[Y:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[RET]]
+;
+  %trunc = trunc nuw <2 x i8> %x to <2 x i1>
+  %ret = select <2 x i1> %trunc, <2 x i8> %x, <2 x i8> %y
+  ret <2 x i8> %ret
+}

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an alive2 proof to the patch description.

Note that the same transform also works for trunc nsw and -1, though that's probably less practically relevant.

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp Outdated Show resolved Hide resolved
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp Outdated Show resolved Hide resolved
@nikic
Copy link
Contributor

nikic commented Aug 24, 2024

Note that the same transform also works for trunc nsw and -1, though that's probably less practically relevant.

There's also the variant where the trunc operand is used in FalseVal rather than TrueVal. In that case we can replace with zero.

@nikic nikic requested a review from dtcxzyw August 24, 2024 07:20
@c8ef
Copy link
Contributor Author

c8ef commented Aug 24, 2024

Please add an alive2 proof to the patch description.

Note that the same transform also works for trunc nsw and -1, though that's probably less practically relevant.

Added all four transformations and relevant alive2 proof.

@c8ef c8ef changed the title [InstCombine] fold select (trunc nuw X to i1), X, Y to select (trunc nuw X to i1), 1, Y [InstCombine] Update the select operand when the cond has the nuw or nsw property. Aug 24, 2024
@c8ef c8ef changed the title [InstCombine] Update the select operand when the cond has the nuw or nsw property. [InstCombine] Update the select operand when the cond is trunc and has the nuw or nsw property. Aug 24, 2024
Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

This could be generalized using simplifyWithOpReplaced, but probably not worthwhile. The non-trunc variant of that is:

if (!isa<Constant>(CondVal) && SelType->isIntOrIntVectorTy() &&
CondType->isVectorTy() == SelType->isVectorTy()) {
if (Value *S = simplifyWithOpReplaced(TrueVal, CondVal,
ConstantInt::getTrue(CondType), SQ,
/* AllowRefinement */ true))
return replaceOperand(SI, 1, S);
if (Value *S = simplifyWithOpReplaced(FalseVal, CondVal,
ConstantInt::getFalse(CondType), SQ,
/* AllowRefinement */ true))
return replaceOperand(SI, 2, S);
}

@c8ef
Copy link
Contributor Author

c8ef commented Aug 24, 2024

Would it be better to place this transformation at

static Value *simplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
? If yes, I'd like to relocate the implementation there.

@nikic
Copy link
Contributor

nikic commented Aug 24, 2024

Would it be better to place this transformation at

static Value *simplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,

? If yes, I'd like to relocate the implementation there.

The transform can't go into InstSimplify because it modifies/creates an instruction.

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Aug 24, 2024
Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@dtcxzyw dtcxzyw merged commit 43c6fb2 into llvm:main Aug 24, 2024
8 checks passed
@c8ef c8ef deleted the trunc branch August 24, 2024 11:57
dmpolukhin pushed a commit to dmpolukhin/llvm-project that referenced this pull request Sep 2, 2024
…and has the `nuw` or `nsw` property. (llvm#105914)

This patch updates the select operand when the cond has the nuw or nsw
property. Considering the semantics of the nuw and nsw flag, if there is
no poison value in this expression, this code assumes that X can only be
0, 1 or -1.

close: llvm#96765
alive2: https://alive2.llvm.org/ce/z/3n3n2Q
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

trunc nuw x to i1 as branch/select cond implies x
4 participants