[llvm] [InstCombine] Simplify the overflow result of `umulov X, X` (PR #80796)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 5 20:10:39 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Yingwei Zheng (dtcxzyw)
<details>
<summary>Changes</summary>
This patch does the following folds if only the overflow result is used:
```
extractvalue (umul.with.overflow iN X, X), 1 -> icmp ugt X, 2^(N/2)-1
```
Alive2: https://alive2.llvm.org/ce/z/a8yPC6
---
Full diff: https://github.com/llvm/llvm-project/pull/80796.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+11)
- (added) llvm/test/Transforms/InstCombine/umulo-square.ll (+72)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index dd168917f4dc9..4e88a5cc535b1 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3459,6 +3459,17 @@ InstCombinerImpl::foldExtractOfOverflowIntrinsic(ExtractValueInst &EV) {
WO->getLHS()->getType()->isIntOrIntVectorTy(1))
return BinaryOperator::CreateAnd(WO->getLHS(), WO->getRHS());
+ // extractvalue (umul_with_overflow X, X), 1 -> X u> 2^(N/2)-1
+ if (OvID == Intrinsic::umul_with_overflow && WO->getLHS() == WO->getRHS()) {
+ unsigned BitWidth = WO->getLHS()->getType()->getScalarSizeInBits();
+ // Only handle even bitwidths for performance reasons.
+ if (BitWidth % 2 == 0)
+ return new ICmpInst(
+ ICmpInst::ICMP_UGT, WO->getLHS(),
+ ConstantInt::get(WO->getLHS()->getType(),
+ APInt::getLowBitsSet(BitWidth, BitWidth / 2)));
+ }
+
// If only the overflow result is used, and the right hand side is a
// constant (or constant splat), we can remove the intrinsic by directly
// checking for overflow.
diff --git a/llvm/test/Transforms/InstCombine/umulo-square.ll b/llvm/test/Transforms/InstCombine/umulo-square.ll
new file mode 100644
index 0000000000000..838ebc35875b2
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/umulo-square.ll
@@ -0,0 +1,72 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -passes=instcombine -S %s | FileCheck %s
+
+define i1 @umulov_square_i32(i32 %x) {
+; CHECK-LABEL: define i1 @umulov_square_i32(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[RES:%.*]] = icmp ugt i32 [[X]], 65535
+; CHECK-NEXT: ret i1 [[RES]]
+;
+ %ret = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %x)
+ %res = extractvalue {i32, i1} %ret, 1
+ ret i1 %res
+}
+
+define i1 @umulov_square_i16(i16 %x) {
+; CHECK-LABEL: define i1 @umulov_square_i16(
+; CHECK-SAME: i16 [[X:%.*]]) {
+; CHECK-NEXT: [[RES:%.*]] = icmp ugt i16 [[X]], 255
+; CHECK-NEXT: ret i1 [[RES]]
+;
+ %ret = call {i16, i1} @llvm.umul.with.overflow.i16(i16 %x, i16 %x)
+ %res = extractvalue {i16, i1} %ret, 1
+ ret i1 %res
+}
+
+; Negative tests
+
+define i1 @umulov_square_i13(i13 %x) {
+; CHECK-LABEL: define i1 @umulov_square_i13(
+; CHECK-SAME: i13 [[X:%.*]]) {
+; CHECK-NEXT: [[RET:%.*]] = call { i13, i1 } @llvm.umul.with.overflow.i13(i13 [[X]], i13 [[X]])
+; CHECK-NEXT: [[RES:%.*]] = extractvalue { i13, i1 } [[RET]], 1
+; CHECK-NEXT: ret i1 [[RES]]
+;
+ %ret = call {i13, i1} @llvm.umul.with.overflow.i13(i13 %x, i13 %x)
+ %res = extractvalue {i13, i1} %ret, 1
+ ret i1 %res
+}
+
+define i1 @umulov_square_i32_multiuse(i32 %x) {
+; CHECK-LABEL: define i1 @umulov_square_i32_multiuse(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[RET:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[X]], i32 [[X]])
+; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[RET]], 1
+; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i32, i1 } [[RET]], 0
+; CHECK-NEXT: call void @use(i32 [[VAL]])
+; CHECK-NEXT: ret i1 [[RES]]
+;
+ %ret = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %x)
+ %res = extractvalue {i32, i1} %ret, 1
+ %val = extractvalue {i32, i1} %ret, 0
+ call void @use(i32 %val)
+ ret i1 %res
+}
+
+define i1 @smulov_square_i32(i32 %x) {
+; CHECK-LABEL: define i1 @smulov_square_i32(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[RET:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[X]], i32 [[X]])
+; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[RET]], 1
+; CHECK-NEXT: ret i1 [[RES]]
+;
+ %ret = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 %x)
+ %res = extractvalue {i32, i1} %ret, 1
+ ret i1 %res
+}
+
+declare {i32, i1} @llvm.umul.with.overflow.i32(i32, i32)
+declare {i32, i1} @llvm.smul.with.overflow.i32(i32, i32)
+declare {i16, i1} @llvm.umul.with.overflow.i16(i16, i16)
+declare {i13, i1} @llvm.umul.with.overflow.i13(i13, i13)
+declare void @use(i32)
``````````
</details>
https://github.com/llvm/llvm-project/pull/80796
More information about the llvm-commits
mailing list