Skip to content

Commit e6d2bb0

Browse files
authored
[InstCombine] Simplifiy (-x * y * -x) into (x * y * x) (llvm#72953)
fix llvm#72259 proof: https://alive2.llvm.org/ce/z/HsrmTC
1 parent c4ff0a6 commit e6d2bb0

File tree

3 files changed

+182
-3
lines changed

3 files changed

+182
-3
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,13 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
350350
if (match(&I, m_c_Mul(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))
351351
return BinaryOperator::CreateNeg(Builder.CreateMul(X, Y));
352352

353+
// (-X * Y) * -X --> (X * Y) * X
354+
// (-X << Y) * -X --> (X << Y) * X
355+
if (match(Op1, m_Neg(m_Value(X)))) {
356+
if (Value *NegOp0 = Negator::Negate(false, /*IsNSW*/ false, Op0, *this))
357+
return BinaryOperator::CreateMul(NegOp0, X);
358+
}
359+
353360
// (X / Y) * Y = X - (X % Y)
354361
// (X / Y) * -Y = (X % Y) - X
355362
{

llvm/test/Transforms/InstCombine/mul-inseltpoison.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -672,9 +672,8 @@ define <2 x i32> @test_mul_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
672672

673673
define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
674674
; CHECK-LABEL: @test_mul_canonicalize_multiple_uses(
675-
; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]]
676-
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[NEG]], [[Y:%.*]]
677-
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL]], [[NEG]]
675+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
676+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
678677
; CHECK-NEXT: ret i32 [[MUL2]]
679678
;
680679
%neg = sub i32 0, %x

llvm/test/Transforms/InstCombine/mul.ll

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,17 +1255,190 @@ define <2 x i32> @test_mul_canonicalize_vec(<2 x i32> %x, <2 x i32> %y) {
12551255

12561256
define i32 @test_mul_canonicalize_multiple_uses(i32 %x, i32 %y) {
12571257
; CHECK-LABEL: @test_mul_canonicalize_multiple_uses(
1258+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
1259+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
1260+
; CHECK-NEXT: ret i32 [[MUL2]]
1261+
;
1262+
%neg = sub i32 0, %x
1263+
%mul = mul i32 %neg, %y
1264+
%mul2 = mul i32 %mul, %neg
1265+
ret i32 %mul2
1266+
}
1267+
1268+
define i32 @mul_nsw_mul_nsw_neg(i32 %x, i32 %y) {
1269+
; CHECK-LABEL: @mul_nsw_mul_nsw_neg(
1270+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
1271+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
1272+
; CHECK-NEXT: ret i32 [[MUL2]]
1273+
;
1274+
%neg = sub i32 0, %x
1275+
%mul = mul nsw i32 %neg, %y
1276+
%mul2 = mul nsw i32 %mul, %neg
1277+
ret i32 %mul2
1278+
}
1279+
1280+
define i32 @mul_mul_nsw_neg(i32 %x,i32 %y) {
1281+
; CHECK-LABEL: @mul_mul_nsw_neg(
1282+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
1283+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
1284+
; CHECK-NEXT: ret i32 [[MUL2]]
1285+
;
1286+
%neg = sub i32 0, %x
1287+
%mul = mul nsw i32 %neg, %y
1288+
%mul2 = mul i32 %mul, %neg
1289+
ret i32 %mul2
1290+
}
1291+
1292+
define i32 @mul_nsw_mul_neg(i32 %x,i32 %y) {
1293+
; CHECK-LABEL: @mul_nsw_mul_neg(
1294+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
1295+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
1296+
; CHECK-NEXT: ret i32 [[MUL2]]
1297+
;
1298+
%neg = sub i32 0, %x
1299+
%mul = mul i32 %neg, %y
1300+
%mul2 = mul nsw i32 %mul, %neg
1301+
ret i32 %mul2
1302+
}
1303+
1304+
define i32 @mul_nsw_mul_neg_onearg(i32 %x) {
1305+
; CHECK-LABEL: @mul_nsw_mul_neg_onearg(
1306+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[X]]
1307+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
1308+
; CHECK-NEXT: ret i32 [[MUL2]]
1309+
;
1310+
%neg = sub i32 0, %x
1311+
%mul = mul i32 %neg, %x
1312+
%mul2 = mul nsw i32 %mul, %neg
1313+
ret i32 %mul2
1314+
}
1315+
1316+
define i8 @mul_mul_nsw_neg_onearg(i8 %x) {
1317+
; CHECK-LABEL: @mul_mul_nsw_neg_onearg(
1318+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i8 [[X:%.*]], [[X]]
1319+
; CHECK-NEXT: [[MUL2:%.*]] = mul i8 [[MUL_NEG]], [[X]]
1320+
; CHECK-NEXT: ret i8 [[MUL2]]
1321+
;
1322+
%neg = sub i8 0, %x
1323+
%mul = mul nsw i8 %neg, %x
1324+
%mul2 = mul i8 %mul, %neg
1325+
ret i8 %mul2
1326+
}
1327+
1328+
define i32 @mul_nsw_mul_nsw_neg_onearg(i32 %x) {
1329+
; CHECK-LABEL: @mul_nsw_mul_nsw_neg_onearg(
1330+
; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i32 [[X:%.*]], [[X]]
1331+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL_NEG]], [[X]]
1332+
; CHECK-NEXT: ret i32 [[MUL2]]
1333+
;
1334+
%neg = sub i32 0, %x
1335+
%mul = mul nsw i32 %neg, %x
1336+
%mul2 = mul nsw i32 %mul, %neg
1337+
ret i32 %mul2
1338+
}
1339+
1340+
define i32 @mul_nsw_shl_nsw_neg(i32 %x, i32 %y) {
1341+
; CHECK-LABEL: @mul_nsw_shl_nsw_neg(
1342+
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]]
1343+
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[SHL_NEG]], [[X]]
1344+
; CHECK-NEXT: ret i32 [[MUL]]
1345+
;
1346+
%neg = sub i32 0, %x
1347+
%shl = shl nsw i32 %neg, %y
1348+
%mul = mul nsw i32 %shl, %neg
1349+
ret i32 %mul
1350+
}
1351+
1352+
define i32 @mul_shl_nsw_neg(i32 %x,i32 %y) {
1353+
; CHECK-LABEL: @mul_shl_nsw_neg(
1354+
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]]
1355+
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[SHL_NEG]], [[X]]
1356+
; CHECK-NEXT: ret i32 [[MUL]]
1357+
;
1358+
%neg = sub i32 0, %x
1359+
%shl = shl nsw i32 %neg, %y
1360+
%mul = mul i32 %shl, %neg
1361+
ret i32 %mul
1362+
}
1363+
1364+
define i32 @mul_nsw_shl_neg(i32 %x,i32 %y) {
1365+
; CHECK-LABEL: @mul_nsw_shl_neg(
1366+
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i32 [[X:%.*]], [[Y:%.*]]
1367+
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[SHL_NEG]], [[X]]
1368+
; CHECK-NEXT: ret i32 [[MUL]]
1369+
;
1370+
%neg = sub i32 0, %x
1371+
%shl = shl i32 %neg, %y
1372+
%mul = mul nsw i32 %shl, %neg
1373+
ret i32 %mul
1374+
}
1375+
1376+
define i32 @mul_nsw_shl_neg_onearg(i32 %x) {
1377+
; CHECK-LABEL: @mul_nsw_shl_neg_onearg(
1378+
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i32 [[X:%.*]], [[X]]
1379+
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[SHL_NEG]], [[X]]
1380+
; CHECK-NEXT: ret i32 [[MUL]]
1381+
;
1382+
%neg = sub i32 0, %x
1383+
%shl = shl i32 %neg, %x
1384+
%mul = mul nsw i32 %shl, %neg
1385+
ret i32 %mul
1386+
}
1387+
1388+
define i8 @mul_shl_nsw_neg_onearg(i8 %x) {
1389+
; CHECK-LABEL: @mul_shl_nsw_neg_onearg(
1390+
; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i8 [[X:%.*]], [[X]]
1391+
; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[SHL_NEG]], [[X]]
1392+
; CHECK-NEXT: ret i8 [[MUL]]
1393+
;
1394+
%neg = sub i8 0, %x
1395+
%shl = shl nsw i8 %neg, %x
1396+
%mul = mul i8 %shl, %neg
1397+
ret i8 %mul
1398+
}
1399+
1400+
define i32 @mul_nsw_shl_nsw_neg_onearg(i32 %x) {
1401+
; CHECK-LABEL: @mul_nsw_shl_nsw_neg_onearg(
1402+
; CHECK-NEXT: [[SHL_NEG:%.*]] = mul i32 [[X:%.*]], [[X]]
1403+
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[SHL_NEG]], [[X]]
1404+
; CHECK-NEXT: ret i32 [[MUL]]
1405+
;
1406+
%neg = sub i32 0, %x
1407+
%shl = mul nsw i32 %neg, %x
1408+
%mul = mul nsw i32 %shl, %neg
1409+
ret i32 %mul
1410+
}
1411+
1412+
define i32 @mul_use_mul_neg(i32 %x,i32 %y) {
1413+
; CHECK-LABEL: @mul_use_mul_neg(
12581414
; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]]
12591415
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[NEG]], [[Y:%.*]]
1416+
; CHECK-NEXT: call void @use32(i32 [[MUL]])
12601417
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[MUL]], [[NEG]]
12611418
; CHECK-NEXT: ret i32 [[MUL2]]
12621419
;
12631420
%neg = sub i32 0, %x
12641421
%mul = mul i32 %neg, %y
1422+
call void @use32(i32 %mul)
12651423
%mul2 = mul i32 %mul, %neg
12661424
ret i32 %mul2
12671425
}
12681426

1427+
define i32 @mul_shl_use_mul_neg(i32 %x,i32 %y) {
1428+
; CHECK-LABEL: @mul_shl_use_mul_neg(
1429+
; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]]
1430+
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[NEG]], [[Y:%.*]]
1431+
; CHECK-NEXT: call void @use32(i32 [[SHL]])
1432+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 [[SHL]], [[NEG]]
1433+
; CHECK-NEXT: ret i32 [[MUL2]]
1434+
;
1435+
%neg = sub i32 0, %x
1436+
%shl = shl i32 %neg, %y
1437+
call void @use32(i32 %shl)
1438+
%mul2 = mul i32 %shl, %neg
1439+
ret i32 %mul2
1440+
}
1441+
12691442
@X = global i32 5
12701443

12711444
define i64 @test_mul_canonicalize_neg_is_not_undone(i64 %L1) {

0 commit comments

Comments
 (0)