Skip to content

Commit 313a33b

Browse files
authored
[InstCombine] Reduce nested logical operator if poison is implied (#86823)
Fixes #76623 Alive2 proof: https://alive2.llvm.org/ce/z/gX6znJ (I'm not sure how to write a proof for such transform, maybe there are mistakes) In most cases, `icmp(a, C1) && (other_cond && icmp(a, C2))` will be reduced to `icmp(a, C1) & (other_cond && icmp(a, C2))`, since latter icmp always implies the poison of the former. After reduction, it's easier to simplify the icmp chain. Similarly, this patch does the same thing for `(A && B) && C --> A && (B & C)`. Maybe we could constraint such reduction only on icmps if there is regression in benchmarks.
1 parent 3d985a6 commit 313a33b

File tree

3 files changed

+292
-0
lines changed

3 files changed

+292
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,6 +3091,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
30913091
return BinaryOperator::CreateOr(CondVal, FalseVal);
30923092
}
30933093

3094+
if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_One(), m_Value(B)))) &&
3095+
impliesPoison(FalseVal, B)) {
3096+
// (A || B) || C --> A || (B | C)
3097+
return replaceInstUsesWith(
3098+
SI, Builder.CreateLogicalOr(A, Builder.CreateOr(B, FalseVal)));
3099+
}
3100+
30943101
if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
30953102
if (auto *RHS = dyn_cast<FCmpInst>(FalseVal))
30963103
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ false,
@@ -3132,6 +3139,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
31323139
return BinaryOperator::CreateAnd(CondVal, TrueVal);
31333140
}
31343141

3142+
if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_Value(B), m_Zero()))) &&
3143+
impliesPoison(TrueVal, B)) {
3144+
// (A && B) && C --> A && (B & C)
3145+
return replaceInstUsesWith(
3146+
SI, Builder.CreateLogicalAnd(A, Builder.CreateAnd(B, TrueVal)));
3147+
}
3148+
31353149
if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
31363150
if (auto *RHS = dyn_cast<FCmpInst>(TrueVal))
31373151
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ true,

llvm/test/Transforms/InstCombine/and-or-icmps.ll

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3038,3 +3038,63 @@ define i32 @icmp_slt_0_or_icmp_add_1_sge_100_i32_fail(i32 %x) {
30383038
%D = or i32 %C, %B
30393039
ret i32 %D
30403040
}
3041+
3042+
define i1 @logical_and_icmps1(i32 %a, i1 %other_cond) {
3043+
; CHECK-LABEL: @logical_and_icmps1(
3044+
; CHECK-NEXT: entry:
3045+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[A:%.*]], 10086
3046+
; CHECK-NEXT: [[RET2:%.*]] = select i1 [[RET1:%.*]], i1 [[CMP3]], i1 false
3047+
; CHECK-NEXT: ret i1 [[RET2]]
3048+
;
3049+
entry:
3050+
%cmp1 = icmp sgt i32 %a, -1
3051+
%logical_and = select i1 %other_cond, i1 %cmp1, i1 false
3052+
%cmp2 = icmp slt i32 %a, 10086
3053+
%ret = select i1 %logical_and, i1 %cmp2, i1 false
3054+
ret i1 %ret
3055+
}
3056+
3057+
define i1 @logical_and_icmps2(i32 %a, i1 %other_cond) {
3058+
; CHECK-LABEL: @logical_and_icmps2(
3059+
; CHECK-NEXT: entry:
3060+
; CHECK-NEXT: ret i1 false
3061+
;
3062+
entry:
3063+
%cmp1 = icmp slt i32 %a, -1
3064+
%logical_and = select i1 %other_cond, i1 %cmp1, i1 false
3065+
%cmp2 = icmp eq i32 %a, 10086
3066+
%ret = select i1 %logical_and, i1 %cmp2, i1 false
3067+
ret i1 %ret
3068+
}
3069+
3070+
define <4 x i1> @logical_and_icmps_vec1(<4 x i32> %a, <4 x i1> %other_cond) {
3071+
; CHECK-LABEL: @logical_and_icmps_vec1(
3072+
; CHECK-NEXT: entry:
3073+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult <4 x i32> [[A:%.*]], <i32 10086, i32 10086, i32 10086, i32 10086>
3074+
; CHECK-NEXT: [[RET2:%.*]] = select <4 x i1> [[RET1:%.*]], <4 x i1> [[CMP3]], <4 x i1> zeroinitializer
3075+
; CHECK-NEXT: ret <4 x i1> [[RET2]]
3076+
;
3077+
entry:
3078+
%cmp1 = icmp sgt <4 x i32> %a, <i32 -1, i32 -1, i32 -1, i32 -1 >
3079+
%logical_and = select <4 x i1> %other_cond, <4 x i1> %cmp1, <4 x i1> zeroinitializer
3080+
%cmp2 = icmp slt <4 x i32> %a, <i32 10086, i32 10086, i32 10086, i32 10086 >
3081+
%ret = select <4 x i1> %logical_and, <4 x i1> %cmp2, <4 x i1> zeroinitializer
3082+
ret <4 x i1> %ret
3083+
}
3084+
3085+
define i1 @logical_and_icmps_fail1(i32 %a, i32 %b, i1 %other_cond) {
3086+
; CHECK-LABEL: @logical_and_icmps_fail1(
3087+
; CHECK-NEXT: entry:
3088+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A:%.*]], -1
3089+
; CHECK-NEXT: [[LOGICAL_AND:%.*]] = select i1 [[OTHER_COND:%.*]], i1 [[CMP1]], i1 false
3090+
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B:%.*]]
3091+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[LOGICAL_AND]], i1 [[CMP2]], i1 false
3092+
; CHECK-NEXT: ret i1 [[RET]]
3093+
;
3094+
entry:
3095+
%cmp1 = icmp sgt i32 %a, -1
3096+
%logical_and = select i1 %other_cond, i1 %cmp1, i1 false
3097+
%cmp2 = icmp slt i32 %a, %b
3098+
%ret = select i1 %logical_and, i1 %cmp2, i1 false
3099+
ret i1 %ret
3100+
}

llvm/test/Transforms/InstCombine/logical-select.ll

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,3 +1303,221 @@ define i1 @logical_or_and_with_common_not_op_variant5(i1 %a) {
13031303
%or = select i1 %a, i1 true, i1 %and
13041304
ret i1 %or
13051305
}
1306+
1307+
define i1 @reduce_logical_and1(i1 %a, i32 %b, i32 %c) {
1308+
; CHECK-LABEL: @reduce_logical_and1(
1309+
; CHECK-NEXT: bb:
1310+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1311+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1312+
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP1]], [[CMP]]
1313+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
1314+
; CHECK-NEXT: ret i1 [[AND2]]
1315+
;
1316+
bb:
1317+
%cmp = icmp slt i32 %b, 6
1318+
%cmp1 = icmp sgt i32 %c, %b
1319+
%and1 = select i1 %a, i1 %cmp1, i1 false
1320+
%and2 = select i1 %and1, i1 %cmp, i1 false
1321+
ret i1 %and2
1322+
}
1323+
1324+
define i1 @reduce_logical_and2(i1 %a, i1 %b, i1 %c) {
1325+
; CHECK-LABEL: @reduce_logical_and2(
1326+
; CHECK-NEXT: bb:
1327+
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
1328+
; CHECK-NEXT: [[B:%.*]] = and i1 [[TMP0]], [[B1:%.*]]
1329+
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 [[B]], i1 false
1330+
; CHECK-NEXT: ret i1 [[AND3]]
1331+
;
1332+
bb:
1333+
%or = xor i1 %c, %b
1334+
%and1 = select i1 %a, i1 %or, i1 false
1335+
%and2 = select i1 %and1, i1 %b, i1 false
1336+
ret i1 %and2
1337+
}
1338+
1339+
define i1 @reduce_logical_and3(i1 %a, i32 %b, i32 noundef %c) {
1340+
; CHECK-LABEL: @reduce_logical_and3(
1341+
; CHECK-NEXT: bb:
1342+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1343+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1344+
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP]], [[CMP1]]
1345+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
1346+
; CHECK-NEXT: ret i1 [[AND2]]
1347+
;
1348+
bb:
1349+
%cmp = icmp slt i32 %b, 6
1350+
%cmp1 = icmp sgt i32 %c, %b
1351+
%and1 = select i1 %a, i1 %cmp, i1 false
1352+
%and2 = select i1 %and1, i1 %cmp1, i1 false
1353+
ret i1 %and2
1354+
}
1355+
1356+
define i1 @reduce_logical_or1(i1 %a, i32 %b, i32 %c) {
1357+
; CHECK-LABEL: @reduce_logical_or1(
1358+
; CHECK-NEXT: bb:
1359+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1360+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1361+
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP1]], [[CMP]]
1362+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
1363+
; CHECK-NEXT: ret i1 [[AND2]]
1364+
;
1365+
bb:
1366+
%cmp = icmp slt i32 %b, 6
1367+
%cmp1 = icmp sgt i32 %c, %b
1368+
%and1 = select i1 %a, i1 true, i1 %cmp1
1369+
%and2 = select i1 %and1, i1 true, i1 %cmp
1370+
ret i1 %and2
1371+
}
1372+
1373+
define i1 @reduce_logical_or2(i1 %a, i1 %b, i1 %c) {
1374+
; CHECK-LABEL: @reduce_logical_or2(
1375+
; CHECK-NEXT: bb:
1376+
; CHECK-NEXT: [[B:%.*]] = or i1 [[C:%.*]], [[B1:%.*]]
1377+
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 true, i1 [[B]]
1378+
; CHECK-NEXT: ret i1 [[AND3]]
1379+
;
1380+
bb:
1381+
%or = xor i1 %c, %b
1382+
%and1 = select i1 %a, i1 true, i1 %or
1383+
%and2 = select i1 %and1, i1 true, i1 %b
1384+
ret i1 %and2
1385+
}
1386+
1387+
define i1 @reduce_logical_or3(i1 %a, i32 %b, i32 noundef %c) {
1388+
; CHECK-LABEL: @reduce_logical_or3(
1389+
; CHECK-NEXT: bb:
1390+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1391+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1392+
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP]], [[CMP1]]
1393+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
1394+
; CHECK-NEXT: ret i1 [[AND2]]
1395+
;
1396+
bb:
1397+
%cmp = icmp slt i32 %b, 6
1398+
%cmp1 = icmp sgt i32 %c, %b
1399+
%and1 = select i1 %a, i1 true, i1 %cmp
1400+
%and2 = select i1 %and1, i1 true, i1 %cmp1
1401+
ret i1 %and2
1402+
}
1403+
1404+
define i1 @reduce_logical_and_fail1(i1 %a, i32 %b, i32 %c) {
1405+
; CHECK-LABEL: @reduce_logical_and_fail1(
1406+
; CHECK-NEXT: bb:
1407+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1408+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1409+
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
1410+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
1411+
; CHECK-NEXT: ret i1 [[AND2]]
1412+
;
1413+
bb:
1414+
%cmp = icmp slt i32 %b, 6
1415+
%cmp1 = icmp sgt i32 %c, %b
1416+
%and1 = select i1 %a, i1 %cmp, i1 false
1417+
%and2 = select i1 %and1, i1 %cmp1, i1 false
1418+
ret i1 %and2
1419+
}
1420+
1421+
define i1 @reduce_logical_and_fail2(i1 %a, i32 %b, i32 %c) {
1422+
; CHECK-LABEL: @reduce_logical_and_fail2(
1423+
; CHECK-NEXT: bb:
1424+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1425+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
1426+
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
1427+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
1428+
; CHECK-NEXT: ret i1 [[AND2]]
1429+
;
1430+
bb:
1431+
%cmp = icmp slt i32 %b, 6
1432+
%cmp1 = icmp sgt i32 %c, 7
1433+
%and1 = select i1 %a, i1 %cmp, i1 false
1434+
%and2 = select i1 %and1, i1 %cmp1, i1 false
1435+
ret i1 %and2
1436+
}
1437+
1438+
define i1 @reduce_logical_or_fail1(i1 %a, i32 %b, i32 %c) {
1439+
; CHECK-LABEL: @reduce_logical_or_fail1(
1440+
; CHECK-NEXT: bb:
1441+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1442+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1443+
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
1444+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
1445+
; CHECK-NEXT: ret i1 [[AND2]]
1446+
;
1447+
bb:
1448+
%cmp = icmp slt i32 %b, 6
1449+
%cmp1 = icmp sgt i32 %c, %b
1450+
%and1 = select i1 %a, i1 true, i1 %cmp
1451+
%and2 = select i1 %and1, i1 true, i1 %cmp1
1452+
ret i1 %and2
1453+
}
1454+
1455+
define i1 @reduce_logical_or_fail2(i1 %a, i32 %b, i32 %c) {
1456+
; CHECK-LABEL: @reduce_logical_or_fail2(
1457+
; CHECK-NEXT: bb:
1458+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1459+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
1460+
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
1461+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
1462+
; CHECK-NEXT: ret i1 [[AND2]]
1463+
;
1464+
bb:
1465+
%cmp = icmp slt i32 %b, 6
1466+
%cmp1 = icmp sgt i32 %c, 7
1467+
%and1 = select i1 %a, i1 true, i1 %cmp
1468+
%and2 = select i1 %and1, i1 true, i1 %cmp1
1469+
ret i1 %and2
1470+
}
1471+
1472+
define i1 @reduce_logical_and_multiuse(i1 %a, i32 %b, i32 %c) {
1473+
; CHECK-LABEL: @reduce_logical_and_multiuse(
1474+
; CHECK-NEXT: bb:
1475+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1476+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1477+
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
1478+
; CHECK-NEXT: call void @use1(i1 [[AND1]])
1479+
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP]], i1 false
1480+
; CHECK-NEXT: ret i1 [[AND2]]
1481+
;
1482+
bb:
1483+
%cmp = icmp slt i32 %b, 6
1484+
%cmp1 = icmp sgt i32 %c, %b
1485+
%and1 = select i1 %a, i1 %cmp1, i1 false
1486+
call void @use1(i1 %and1)
1487+
%and2 = select i1 %and1, i1 %cmp, i1 false
1488+
ret i1 %and2
1489+
}
1490+
1491+
define i1 @reduce_bitwise_and1(i1 %a, i32 %b, i32 %c) {
1492+
; CHECK-LABEL: @reduce_bitwise_and1(
1493+
; CHECK-NEXT: bb:
1494+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1495+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1496+
; CHECK-NEXT: [[AND1:%.*]] = or i1 [[CMP1]], [[A:%.*]]
1497+
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[CMP]]
1498+
; CHECK-NEXT: ret i1 [[AND2]]
1499+
;
1500+
bb:
1501+
%cmp = icmp slt i32 %b, 6
1502+
%cmp1 = icmp sgt i32 %c, %b
1503+
%and1 = or i1 %a, %cmp1
1504+
%and2 = select i1 %and1, i1 %cmp, i1 false
1505+
ret i1 %and2
1506+
}
1507+
1508+
define i1 @reduce_bitwise_and2(i1 %a, i32 %b, i32 %c) {
1509+
; CHECK-LABEL: @reduce_bitwise_and2(
1510+
; CHECK-NEXT: bb:
1511+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
1512+
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
1513+
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
1514+
; CHECK-NEXT: [[AND2:%.*]] = or i1 [[AND1]], [[CMP]]
1515+
; CHECK-NEXT: ret i1 [[AND2]]
1516+
;
1517+
bb:
1518+
%cmp = icmp slt i32 %b, 6
1519+
%cmp1 = icmp sgt i32 %c, %b
1520+
%and1 = select i1 %a, i1 %cmp1, i1 false
1521+
%and2 = or i1 %and1, %cmp
1522+
ret i1 %and2
1523+
}

0 commit comments

Comments
 (0)