[InstCombine] fix miscompile from urem/udiv transform with constant expression

The isa<Constant> check could misfire on an instruction with 2 constant
operands. This bug was introduced with bb789381fc (D36988).

See issue #56810 for a C source example that exposed the bug.
This commit is contained in:
Sanjay Patel
2022-07-29 17:02:47 -04:00
parent e637feee80
commit d4940c0f3d
2 changed files with 14 additions and 9 deletions

View File

@@ -1008,8 +1008,7 @@ static Instruction *narrowUDivURem(BinaryOperator &I,
}
Constant *C;
if ((match(N, m_OneUse(m_ZExt(m_Value(X)))) && match(D, m_Constant(C))) ||
(match(D, m_OneUse(m_ZExt(m_Value(X)))) && match(N, m_Constant(C)))) {
if (match(N, m_OneUse(m_ZExt(m_Value(X)))) && match(D, m_Constant(C))) {
// If the constant is the same in the smaller type, use the narrow version.
Constant *TruncC = ConstantExpr::getTrunc(C, X->getType());
if (ConstantExpr::getZExt(TruncC, Ty) != C)
@@ -1017,11 +1016,17 @@ static Instruction *narrowUDivURem(BinaryOperator &I,
// udiv (zext X), C --> zext (udiv X, C')
// urem (zext X), C --> zext (urem X, C')
return new ZExtInst(Builder.CreateBinOp(Opcode, X, TruncC), Ty);
}
if (match(D, m_OneUse(m_ZExt(m_Value(X)))) && match(N, m_Constant(C))) {
// If the constant is the same in the smaller type, use the narrow version.
Constant *TruncC = ConstantExpr::getTrunc(C, X->getType());
if (ConstantExpr::getZExt(TruncC, Ty) != C)
return nullptr;
// udiv C, (zext X) --> zext (udiv C', X)
// urem C, (zext X) --> zext (urem C', X)
Value *NarrowOp = isa<Constant>(D) ? Builder.CreateBinOp(Opcode, X, TruncC)
: Builder.CreateBinOp(Opcode, TruncC, X);
return new ZExtInst(NarrowOp, Ty);
return new ZExtInst(Builder.CreateBinOp(Opcode, TruncC, X), Ty);
}
return nullptr;

View File

@@ -287,13 +287,13 @@ define i32 @udiv_constexpr(i8 %a) {
ret i32 %d
}
; FIXME: This is a miscompile (minimal form of PR56810)
; minimal form of PR56810
@g1 = external global [1 x i8]
define i32 @udiv_const_constexpr(i8 %a) {
; CHECK-LABEL: @udiv_const_constexpr(
; CHECK-NEXT: [[TMP1:%.*]] = udiv i8 ptrtoint ([1 x i8]* @g1 to i8), 42
; CHECK-NEXT: [[TMP1:%.*]] = udiv i8 42, ptrtoint ([1 x i8]* @g1 to i8)
; CHECK-NEXT: [[D:%.*]] = zext i8 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[D]]
;
@@ -301,13 +301,13 @@ define i32 @udiv_const_constexpr(i8 %a) {
ret i32 %d
}
; FIXME: This is a miscompile (minimal form of PR56810)
; minimal form of PR56810
@g2 = external global [1 x i8]
define i32 @urem_const_constexpr(i8 %a) {
; CHECK-LABEL: @urem_const_constexpr(
; CHECK-NEXT: [[TMP1:%.*]] = urem i8 ptrtoint ([1 x i8]* @g2 to i8), 42
; CHECK-NEXT: [[TMP1:%.*]] = urem i8 42, ptrtoint ([1 x i8]* @g2 to i8)
; CHECK-NEXT: [[D:%.*]] = zext i8 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[D]]
;