Skip to content

Commit 0823cb7

Browse files
authored
[InstCombine] Fold (X << Y) / (X << Z) -> 1 << Y >> Z (#68863)
Resolve #68857. Alive2 proofs: [Whole proofs](https://alive2.llvm.org/ce/z/A5b85F)
1 parent 2ef1587 commit 0823cb7

File tree

2 files changed

+277
-0
lines changed

2 files changed

+277
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,28 @@ static Instruction *foldIDivShl(BinaryOperator &I,
980980
Ret = BinaryOperator::CreateSDiv(X, Y);
981981
}
982982

983+
// If X << Y and X << Z does not overflow, then:
984+
// (X << Y) / (X << Z) -> (1 << Y) / (1 << Z) -> 1 << Y >> Z
985+
if (match(Op0, m_Shl(m_Value(X), m_Value(Y))) &&
986+
match(Op1, m_Shl(m_Specific(X), m_Value(Z)))) {
987+
auto *Shl0 = cast<OverflowingBinaryOperator>(Op0);
988+
auto *Shl1 = cast<OverflowingBinaryOperator>(Op1);
989+
990+
if (IsSigned ? (Shl0->hasNoSignedWrap() && Shl1->hasNoSignedWrap())
991+
: (Shl0->hasNoUnsignedWrap() && Shl1->hasNoUnsignedWrap())) {
992+
Constant *One = ConstantInt::get(X->getType(), 1);
993+
// Only preserve the nsw flag if dividend has nsw
994+
// or divisor has nsw and operator is sdiv.
995+
Value *Dividend = Builder.CreateShl(
996+
One, Y, "shl.dividend",
997+
/*HasNUW*/ true,
998+
/*HasNSW*/
999+
IsSigned ? (Shl0->hasNoUnsignedWrap() || Shl1->hasNoUnsignedWrap())
1000+
: Shl0->hasNoSignedWrap());
1001+
Ret = BinaryOperator::CreateLShr(Dividend, Z);
1002+
}
1003+
}
1004+
9831005
if (!Ret)
9841006
return nullptr;
9851007

llvm/test/Transforms/InstCombine/div-shift.ll

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
33

44
declare void @use(i8)
5+
declare void @use32(i32)
56

67
declare i8 @llvm.umin.i8(i8, i8)
78
declare i8 @llvm.umax.i8(i8, i8)
@@ -1025,3 +1026,257 @@ define i8 @udiv_shl_no_overflow(i8 %x, i8 %y) {
10251026
%mul = udiv i8 %x, %min
10261027
ret i8 %mul
10271028
}
1029+
1030+
; (X<<Y) / (X<<Z) -> 1 << Y >> Z
1031+
1032+
define i32 @sdiv_shl_pair_const(i32 %a) {
1033+
; CHECK-LABEL: @sdiv_shl_pair_const(
1034+
; CHECK-NEXT: entry:
1035+
; CHECK-NEXT: ret i32 2
1036+
;
1037+
entry:
1038+
%lhs = shl nsw i32 %a, 2
1039+
%rhs = shl nsw i32 %a, 1
1040+
%div = sdiv i32 %lhs, %rhs
1041+
ret i32 %div
1042+
}
1043+
1044+
define i32 @udiv_shl_pair_const(i32 %a) {
1045+
; CHECK-LABEL: @udiv_shl_pair_const(
1046+
; CHECK-NEXT: entry:
1047+
; CHECK-NEXT: ret i32 2
1048+
;
1049+
entry:
1050+
%lhs = shl nuw i32 %a, 2
1051+
%rhs = shl nuw i32 %a, 1
1052+
%div = udiv i32 %lhs, %rhs
1053+
ret i32 %div
1054+
}
1055+
1056+
define i32 @sdiv_shl_pair1(i32 %a, i32 %x, i32 %y) {
1057+
; CHECK-LABEL: @sdiv_shl_pair1(
1058+
; CHECK-NEXT: entry:
1059+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw nsw i32 1, [[X:%.*]]
1060+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y:%.*]]
1061+
; CHECK-NEXT: ret i32 [[DIV]]
1062+
;
1063+
entry:
1064+
%lhs = shl nsw i32 %a, %x
1065+
%rhs = shl nuw nsw i32 %a, %y
1066+
%div = sdiv i32 %lhs, %rhs
1067+
ret i32 %div
1068+
}
1069+
1070+
define i32 @sdiv_shl_pair2(i32 %a, i32 %x, i32 %y) {
1071+
; CHECK-LABEL: @sdiv_shl_pair2(
1072+
; CHECK-NEXT: entry:
1073+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw nsw i32 1, [[X:%.*]]
1074+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y:%.*]]
1075+
; CHECK-NEXT: ret i32 [[DIV]]
1076+
;
1077+
entry:
1078+
%lhs = shl nuw nsw i32 %a, %x
1079+
%rhs = shl nsw i32 %a, %y
1080+
%div = sdiv i32 %lhs, %rhs
1081+
ret i32 %div
1082+
}
1083+
1084+
define i32 @sdiv_shl_pair3(i32 %a, i32 %x, i32 %y) {
1085+
; CHECK-LABEL: @sdiv_shl_pair3(
1086+
; CHECK-NEXT: entry:
1087+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw i32 1, [[X:%.*]]
1088+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y:%.*]]
1089+
; CHECK-NEXT: ret i32 [[DIV]]
1090+
;
1091+
entry:
1092+
%lhs = shl nsw i32 %a, %x
1093+
%rhs = shl nsw i32 %a, %y
1094+
%div = sdiv i32 %lhs, %rhs
1095+
ret i32 %div
1096+
}
1097+
1098+
define i32 @sdiv_shl_no_pair_fail(i32 %a, i32 %b, i32 %x, i32 %y) {
1099+
; CHECK-LABEL: @sdiv_shl_no_pair_fail(
1100+
; CHECK-NEXT: entry:
1101+
; CHECK-NEXT: [[LHS:%.*]] = shl nuw nsw i32 [[A:%.*]], [[X:%.*]]
1102+
; CHECK-NEXT: [[RHS:%.*]] = shl nuw i32 [[B:%.*]], [[Y:%.*]]
1103+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[LHS]], [[RHS]]
1104+
; CHECK-NEXT: ret i32 [[DIV]]
1105+
;
1106+
entry:
1107+
%lhs = shl nuw nsw i32 %a, %x
1108+
%rhs = shl nuw i32 %b, %y
1109+
%div = sdiv i32 %lhs, %rhs
1110+
ret i32 %div
1111+
}
1112+
1113+
define i32 @udiv_shl_pair1(i32 %a, i32 %x, i32 %y) {
1114+
; CHECK-LABEL: @udiv_shl_pair1(
1115+
; CHECK-NEXT: entry:
1116+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw i32 1, [[X:%.*]]
1117+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y:%.*]]
1118+
; CHECK-NEXT: ret i32 [[DIV]]
1119+
;
1120+
entry:
1121+
%lhs = shl nuw i32 %a, %x
1122+
%rhs = shl nuw i32 %a, %y
1123+
%div = udiv i32 %lhs, %rhs
1124+
ret i32 %div
1125+
}
1126+
1127+
define i32 @udiv_shl_pair2(i32 %a, i32 %x, i32 %y) {
1128+
; CHECK-LABEL: @udiv_shl_pair2(
1129+
; CHECK-NEXT: entry:
1130+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw nsw i32 1, [[X:%.*]]
1131+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y:%.*]]
1132+
; CHECK-NEXT: ret i32 [[DIV]]
1133+
;
1134+
entry:
1135+
%lhs = shl nuw nsw i32 %a, %x
1136+
%rhs = shl nuw i32 %a, %y
1137+
%div = udiv i32 %lhs, %rhs
1138+
ret i32 %div
1139+
}
1140+
1141+
define i32 @udiv_shl_pair3(i32 %a, i32 %x, i32 %y) {
1142+
; CHECK-LABEL: @udiv_shl_pair3(
1143+
; CHECK-NEXT: entry:
1144+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw i32 1, [[X:%.*]]
1145+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y:%.*]]
1146+
; CHECK-NEXT: ret i32 [[DIV]]
1147+
;
1148+
entry:
1149+
%lhs = shl nuw i32 %a, %x
1150+
%rhs = shl nuw nsw i32 %a, %y
1151+
%div = udiv i32 %lhs, %rhs
1152+
ret i32 %div
1153+
}
1154+
1155+
define i32 @sdiv_shl_pair_overflow_fail1(i32 %a, i32 %x, i32 %y) {
1156+
; CHECK-LABEL: @sdiv_shl_pair_overflow_fail1(
1157+
; CHECK-NEXT: entry:
1158+
; CHECK-NEXT: [[LHS:%.*]] = shl i32 [[A:%.*]], [[X:%.*]]
1159+
; CHECK-NEXT: [[RHS:%.*]] = shl nsw i32 [[A]], [[Y:%.*]]
1160+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[LHS]], [[RHS]]
1161+
; CHECK-NEXT: ret i32 [[DIV]]
1162+
;
1163+
entry:
1164+
%lhs = shl i32 %a, %x
1165+
%rhs = shl nsw i32 %a, %y
1166+
%div = sdiv i32 %lhs, %rhs
1167+
ret i32 %div
1168+
}
1169+
1170+
define i32 @sdiv_shl_pair_overflow_fail2(i32 %a, i32 %x, i32 %y) {
1171+
; CHECK-LABEL: @sdiv_shl_pair_overflow_fail2(
1172+
; CHECK-NEXT: entry:
1173+
; CHECK-NEXT: [[LHS:%.*]] = shl nsw i32 [[A:%.*]], [[X:%.*]]
1174+
; CHECK-NEXT: [[RHS:%.*]] = shl nuw i32 [[A]], [[Y:%.*]]
1175+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[LHS]], [[RHS]]
1176+
; CHECK-NEXT: ret i32 [[DIV]]
1177+
;
1178+
entry:
1179+
%lhs = shl nsw i32 %a, %x
1180+
%rhs = shl nuw i32 %a, %y
1181+
%div = sdiv i32 %lhs, %rhs
1182+
ret i32 %div
1183+
}
1184+
1185+
define i32 @udiv_shl_pair_overflow_fail1(i32 %a, i32 %x, i32 %y) {
1186+
; CHECK-LABEL: @udiv_shl_pair_overflow_fail1(
1187+
; CHECK-NEXT: entry:
1188+
; CHECK-NEXT: [[LHS:%.*]] = shl nsw i32 [[A:%.*]], [[X:%.*]]
1189+
; CHECK-NEXT: [[RHS:%.*]] = shl nuw i32 [[A]], [[Y:%.*]]
1190+
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[LHS]], [[RHS]]
1191+
; CHECK-NEXT: ret i32 [[DIV]]
1192+
;
1193+
entry:
1194+
%lhs = shl nsw i32 %a, %x
1195+
%rhs = shl nuw i32 %a, %y
1196+
%div = udiv i32 %lhs, %rhs
1197+
ret i32 %div
1198+
}
1199+
1200+
define i32 @udiv_shl_pair_overflow_fail2(i32 %a, i32 %x, i32 %y) {
1201+
; CHECK-LABEL: @udiv_shl_pair_overflow_fail2(
1202+
; CHECK-NEXT: entry:
1203+
; CHECK-NEXT: [[LHS:%.*]] = shl nsw i32 [[A:%.*]], [[X:%.*]]
1204+
; CHECK-NEXT: [[RHS:%.*]] = shl i32 [[A]], [[Y:%.*]]
1205+
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[LHS]], [[RHS]]
1206+
; CHECK-NEXT: ret i32 [[DIV]]
1207+
;
1208+
entry:
1209+
%lhs = shl nsw i32 %a, %x
1210+
%rhs = shl i32 %a, %y
1211+
%div = udiv i32 %lhs, %rhs
1212+
ret i32 %div
1213+
}
1214+
1215+
define i32 @udiv_shl_pair_overflow_fail3(i32 %a, i32 %x, i32 %y) {
1216+
; CHECK-LABEL: @udiv_shl_pair_overflow_fail3(
1217+
; CHECK-NEXT: entry:
1218+
; CHECK-NEXT: [[LHS:%.*]] = shl nuw nsw i32 [[A:%.*]], [[X:%.*]]
1219+
; CHECK-NEXT: [[RHS:%.*]] = shl i32 [[A]], [[Y:%.*]]
1220+
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[LHS]], [[RHS]]
1221+
; CHECK-NEXT: ret i32 [[DIV]]
1222+
;
1223+
entry:
1224+
%lhs = shl nuw nsw i32 %a, %x
1225+
%rhs = shl i32 %a, %y
1226+
%div = udiv i32 %lhs, %rhs
1227+
ret i32 %div
1228+
}
1229+
1230+
define i32 @sdiv_shl_pair_multiuse1(i32 %a, i32 %x, i32 %y) {
1231+
; CHECK-LABEL: @sdiv_shl_pair_multiuse1(
1232+
; CHECK-NEXT: entry:
1233+
; CHECK-NEXT: [[LHS:%.*]] = shl nuw nsw i32 [[A:%.*]], [[X:%.*]]
1234+
; CHECK-NEXT: call void @use32(i32 [[LHS]])
1235+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw nsw i32 1, [[X]]
1236+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y:%.*]]
1237+
; CHECK-NEXT: ret i32 [[DIV]]
1238+
;
1239+
entry:
1240+
%lhs = shl nuw nsw i32 %a, %x
1241+
call void @use32(i32 %lhs)
1242+
%rhs = shl nsw i32 %a, %y
1243+
%div = sdiv i32 %lhs, %rhs
1244+
ret i32 %div
1245+
}
1246+
1247+
define i32 @sdiv_shl_pair_multiuse2(i32 %a, i32 %x, i32 %y) {
1248+
; CHECK-LABEL: @sdiv_shl_pair_multiuse2(
1249+
; CHECK-NEXT: entry:
1250+
; CHECK-NEXT: [[RHS:%.*]] = shl nsw i32 [[A:%.*]], [[Y:%.*]]
1251+
; CHECK-NEXT: call void @use32(i32 [[RHS]])
1252+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw nsw i32 1, [[X:%.*]]
1253+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y]]
1254+
; CHECK-NEXT: ret i32 [[DIV]]
1255+
;
1256+
entry:
1257+
%lhs = shl nuw nsw i32 %a, %x
1258+
%rhs = shl nsw i32 %a, %y
1259+
call void @use32(i32 %rhs)
1260+
%div = sdiv i32 %lhs, %rhs
1261+
ret i32 %div
1262+
}
1263+
1264+
define i32 @sdiv_shl_pair_multiuse3(i32 %a, i32 %x, i32 %y) {
1265+
; CHECK-LABEL: @sdiv_shl_pair_multiuse3(
1266+
; CHECK-NEXT: entry:
1267+
; CHECK-NEXT: [[LHS:%.*]] = shl nuw nsw i32 [[A:%.*]], [[X:%.*]]
1268+
; CHECK-NEXT: [[RHS:%.*]] = shl nsw i32 [[A]], [[Y:%.*]]
1269+
; CHECK-NEXT: call void @use32(i32 [[LHS]])
1270+
; CHECK-NEXT: call void @use32(i32 [[RHS]])
1271+
; CHECK-NEXT: [[SHL_DIVIDEND:%.*]] = shl nuw nsw i32 1, [[X]]
1272+
; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[SHL_DIVIDEND]], [[Y]]
1273+
; CHECK-NEXT: ret i32 [[DIV]]
1274+
;
1275+
entry:
1276+
%lhs = shl nuw nsw i32 %a, %x
1277+
%rhs = shl nsw i32 %a, %y
1278+
call void @use32(i32 %lhs)
1279+
call void @use32(i32 %rhs)
1280+
%div = sdiv i32 %lhs, %rhs
1281+
ret i32 %div
1282+
}

0 commit comments

Comments
 (0)