@@ -1121,7 +1121,7 @@ static const unsigned MaxDepth = 6;
1121
1121
// actual instructions, otherwise return a non-null dummy value. Return nullptr
1122
1122
// on failure.
1123
1123
static Value *takeLog2 (IRBuilderBase &Builder, Value *Op, unsigned Depth,
1124
- bool DoFold) {
1124
+ bool AssumeNonZero, bool DoFold) {
1125
1125
auto IfFold = [DoFold](function_ref<Value *()> Fn) {
1126
1126
if (!DoFold)
1127
1127
return reinterpret_cast <Value *>(-1 );
@@ -1147,37 +1147,48 @@ static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth,
1147
1147
// FIXME: Require one use?
1148
1148
Value *X, *Y;
1149
1149
if (match (Op, m_ZExt (m_Value (X))))
1150
- if (Value *LogX = takeLog2 (Builder, X, Depth, DoFold))
1150
+ if (Value *LogX = takeLog2 (Builder, X, Depth, AssumeNonZero, DoFold))
1151
1151
return IfFold ([&]() { return Builder.CreateZExt (LogX, Op->getType ()); });
1152
1152
1153
1153
// log2(X << Y) -> log2(X) + Y
1154
1154
// FIXME: Require one use unless X is 1?
1155
- if (match (Op, m_Shl (m_Value (X), m_Value (Y))))
1156
- if (Value *LogX = takeLog2 (Builder, X, Depth, DoFold))
1157
- return IfFold ([&]() { return Builder.CreateAdd (LogX, Y); });
1155
+ if (match (Op, m_Shl (m_Value (X), m_Value (Y)))) {
1156
+ auto *BO = cast<OverflowingBinaryOperator>(Op);
1157
+ // nuw will be set if the `shl` is trivially non-zero.
1158
+ if (AssumeNonZero || BO->hasNoUnsignedWrap () || BO->hasNoSignedWrap ())
1159
+ if (Value *LogX = takeLog2 (Builder, X, Depth, AssumeNonZero, DoFold))
1160
+ return IfFold ([&]() { return Builder.CreateAdd (LogX, Y); });
1161
+ }
1158
1162
1159
1163
// log2(Cond ? X : Y) -> Cond ? log2(X) : log2(Y)
1160
1164
// FIXME: missed optimization: if one of the hands of select is/contains
1161
1165
// undef, just directly pick the other one.
1162
1166
// FIXME: can both hands contain undef?
1163
1167
// FIXME: Require one use?
1164
1168
if (SelectInst *SI = dyn_cast<SelectInst>(Op))
1165
- if (Value *LogX = takeLog2 (Builder, SI->getOperand (1 ), Depth, DoFold))
1166
- if (Value *LogY = takeLog2 (Builder, SI->getOperand (2 ), Depth, DoFold))
1169
+ if (Value *LogX = takeLog2 (Builder, SI->getOperand (1 ), Depth,
1170
+ AssumeNonZero, DoFold))
1171
+ if (Value *LogY = takeLog2 (Builder, SI->getOperand (2 ), Depth,
1172
+ AssumeNonZero, DoFold))
1167
1173
return IfFold ([&]() {
1168
1174
return Builder.CreateSelect (SI->getOperand (0 ), LogX, LogY);
1169
1175
});
1170
1176
1171
1177
// log2(umin(X, Y)) -> umin(log2(X), log2(Y))
1172
1178
// log2(umax(X, Y)) -> umax(log2(X), log2(Y))
1173
1179
auto *MinMax = dyn_cast<MinMaxIntrinsic>(Op);
1174
- if (MinMax && MinMax->hasOneUse () && !MinMax->isSigned ())
1175
- if (Value *LogX = takeLog2 (Builder, MinMax->getLHS (), Depth, DoFold))
1176
- if (Value *LogY = takeLog2 (Builder, MinMax->getRHS (), Depth, DoFold))
1180
+ if (MinMax && MinMax->hasOneUse () && !MinMax->isSigned ()) {
1181
+ // Use AssumeNonZero as false here. Otherwise we can hit case where
1182
+ // log2(umax(X, Y)) != umax(log2(X), log2(Y)) (because overflow).
1183
+ if (Value *LogX = takeLog2 (Builder, MinMax->getLHS (), Depth,
1184
+ /* AssumeNonZero*/ false , DoFold))
1185
+ if (Value *LogY = takeLog2 (Builder, MinMax->getRHS (), Depth,
1186
+ /* AssumeNonZero*/ false , DoFold))
1177
1187
return IfFold ([&]() {
1178
- return Builder.CreateBinaryIntrinsic (
1179
- MinMax-> getIntrinsicID (), LogX, LogY);
1188
+ return Builder.CreateBinaryIntrinsic (MinMax-> getIntrinsicID (), LogX,
1189
+ LogY);
1180
1190
});
1191
+ }
1181
1192
1182
1193
return nullptr ;
1183
1194
}
@@ -1297,8 +1308,10 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
1297
1308
}
1298
1309
1299
1310
// Op1 udiv Op2 -> Op1 lshr log2(Op2), if log2() folds away.
1300
- if (takeLog2 (Builder, Op1, /* Depth*/ 0 , /* DoFold*/ false )) {
1301
- Value *Res = takeLog2 (Builder, Op1, /* Depth*/ 0 , /* DoFold*/ true );
1311
+ if (takeLog2 (Builder, Op1, /* Depth*/ 0 , /* AssumeNonZero*/ true ,
1312
+ /* DoFold*/ false )) {
1313
+ Value *Res = takeLog2 (Builder, Op1, /* Depth*/ 0 ,
1314
+ /* AssumeNonZero*/ true , /* DoFold*/ true );
1302
1315
return replaceInstUsesWith (
1303
1316
I, Builder.CreateLShr (Op0, Res, I.getName (), I.isExact ()));
1304
1317
}
0 commit comments