Skip to content

Commit f37ab15

Browse files
[InstCombine] Infer exact for lshr by cttz (#136696)
Infer the 'exact' flag on an 'lshr' or 'ashr' instruction when the shift amount is computed via a 'cttz' intrinsic on the same operand. Proof: https://alive2.llvm.org/ce/z/CQR2PG Fixes #131444.
1 parent 30bedb3 commit f37ab15

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,12 @@ static bool setShiftFlags(BinaryOperator &I, const SimplifyQuery &Q) {
994994
I.setIsExact();
995995
return true;
996996
}
997+
// Infer 'exact' flag if shift amount is cttz(x) on the same operand.
998+
if (match(I.getOperand(1), m_Intrinsic<Intrinsic::cttz>(
999+
m_Specific(I.getOperand(0)), m_Value()))) {
1000+
I.setIsExact();
1001+
return true;
1002+
}
9971003
}
9981004

9991005
// Compute what we know about shift count.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
3+
4+
declare i32 @llvm.cttz.i32(i32, i1)
5+
6+
define i32 @test_cttz_lshr(i32 %x) {
7+
; CHECK-LABEL: define i32 @test_cttz_lshr(
8+
; CHECK-SAME: i32 [[X:%.*]]) {
9+
; CHECK-NEXT: [[CTTZ:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
10+
; CHECK-NEXT: [[SH:%.*]] = lshr exact i32 [[X]], [[CTTZ]]
11+
; CHECK-NEXT: ret i32 [[SH]]
12+
;
13+
%cttz = call i32 @llvm.cttz.i32(i32 %x, i1 false)
14+
%sh = lshr i32 %x, %cttz
15+
ret i32 %sh
16+
}
17+
18+
define i32 @test_cttz_ashr(i32 %x) {
19+
; CHECK-LABEL: define i32 @test_cttz_ashr(
20+
; CHECK-SAME: i32 [[X:%.*]]) {
21+
; CHECK-NEXT: [[CTTZ:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
22+
; CHECK-NEXT: [[SH:%.*]] = ashr exact i32 [[X]], [[CTTZ]]
23+
; CHECK-NEXT: ret i32 [[SH]]
24+
;
25+
%cttz = call i32 @llvm.cttz.i32(i32 %x, i1 true)
26+
%sh = ashr i32 %x, %cttz
27+
ret i32 %sh
28+
}
29+
30+
define i32 @test_cttz_diff_operand(i32 %x, i32 %y) {
31+
; CHECK-LABEL: define i32 @test_cttz_diff_operand(
32+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
33+
; CHECK-NEXT: [[CTTZ:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[Y]], i1 true)
34+
; CHECK-NEXT: [[SH:%.*]] = lshr i32 [[X]], [[CTTZ]]
35+
; CHECK-NEXT: ret i32 [[SH]]
36+
;
37+
%cttz = call i32 @llvm.cttz.i32(i32 %y, i1 true)
38+
%sh = lshr i32 %x, %cttz
39+
ret i32 %sh
40+
}
41+

llvm/test/Transforms/InstCombine/select.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -2736,7 +2736,7 @@ define i32 @pr47322_more_poisonous_replacement(i32 %arg) {
27362736
; CHECK-LABEL: @pr47322_more_poisonous_replacement(
27372737
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[ARG:%.*]], 0
27382738
; CHECK-NEXT: [[TRAILING:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[ARG]], i1 true)
2739-
; CHECK-NEXT: [[SHIFTED:%.*]] = lshr i32 [[ARG]], [[TRAILING]]
2739+
; CHECK-NEXT: [[SHIFTED:%.*]] = lshr exact i32 [[ARG]], [[TRAILING]]
27402740
; CHECK-NEXT: [[R1_SROA_0_1:%.*]] = select i1 [[CMP]], i32 0, i32 [[SHIFTED]]
27412741
; CHECK-NEXT: ret i32 [[R1_SROA_0_1]]
27422742
;

0 commit comments

Comments
 (0)