Index: llvm/include/llvm/Analysis/InstructionSimplify.h =================================================================== --- llvm/include/llvm/Analysis/InstructionSimplify.h +++ llvm/include/llvm/Analysis/InstructionSimplify.h @@ -294,8 +294,8 @@ /// See if V simplifies when its operand Op is replaced with RepOp. If not, /// return null. -/// AllowRefinement specifies whether the simplification can be a refinement, -/// or whether it needs to be strictly identical. +/// AllowRefinement specifies whether the simplification can be a refinement +/// (e.g. 0 instead of poison), or whether it needs to be strictly identical. Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, const SimplifyQuery &Q, bool AllowRefinement); Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -3936,18 +3936,33 @@ transform(I->operands(), NewOps.begin(), [&](Value *V) { return V == Op ? RepOp : V; }); - // Consider: - // %cmp = icmp eq i32 %x, 2147483647 - // %add = add nsw i32 %x, 1 - // %sel = select i1 %cmp, i32 -2147483648, i32 %add - // - // We can't replace %sel with %add unless we strip away the flags (which will - // be done in InstCombine). - // TODO: This is unsound, because it only catches some forms of refinement. - if (!AllowRefinement && canCreatePoison(cast(I))) - return nullptr; + if (!AllowRefinement) { + // General InstSimplify functions may refine the result, e.g. by returning + // a constant for a potentially poison value. To avoid this, implement only + // a few non-refining but profitable transforms here. + + if (auto *BO = dyn_cast(I)) { + unsigned Opcode = BO->getOpcode(); + // id op x -> x, x op id -> x + if (NewOps[0] == ConstantExpr::getBinOpIdentity(Opcode, I->getType())) + return NewOps[1]; + if (NewOps[1] == ConstantExpr::getBinOpIdentity(Opcode, I->getType(), + /* RHS */ true)) + return NewOps[0]; + + // x & x -> x, x | x -> x + if ((Opcode == Instruction::And || Opcode == Instruction::Or) && + NewOps[0] == NewOps[1]) + return NewOps[0]; + } - if (MaxRecurse) { + if (auto *GEP = dyn_cast(I)) { + // getelementptr x, 0 -> x + if (NewOps.size() == 2 && match(NewOps[1], m_Zero()) && + !GEP->isInBounds()) + return NewOps[0]; + } + } else if (MaxRecurse) { // The simplification queries below may return the original value. Consider: // %div = udiv i32 %arg, %arg2 // %mul = mul nsw i32 %div, %arg2 @@ -3986,6 +4001,18 @@ return nullptr; } + // Consider: + // %cmp = icmp eq i32 %x, 2147483647 + // %add = add nsw i32 %x, 1 + // %sel = select i1 %cmp, i32 -2147483648, i32 %add + // + // We can't replace %sel with %add unless we strip away the flags (which + // will be done in InstCombine). + // TODO: This may be unsound, because it only catches some forms of + // refinement. + if (!AllowRefinement && canCreatePoison(cast(I))) + return nullptr; + if (CmpInst *C = dyn_cast(I)) return ConstantFoldCompareInstOperands(C->getPredicate(), ConstOps[0], ConstOps[1], Q.DL, Q.TLI); Index: llvm/test/Transforms/InstCombine/minmax-fold.ll =================================================================== --- llvm/test/Transforms/InstCombine/minmax-fold.ll +++ llvm/test/Transforms/InstCombine/minmax-fold.ll @@ -1080,7 +1080,7 @@ define i37 @add_umax_simplify(i37 %x) { ; CHECK-LABEL: @add_umax_simplify( -; CHECK-NEXT: [[A:%.*]] = add i37 [[X:%.*]], 42 +; CHECK-NEXT: [[A:%.*]] = add nuw i37 [[X:%.*]], 42 ; CHECK-NEXT: ret i37 [[A]] ; %a = add nuw i37 %x, 42 Index: llvm/test/Transforms/InstCombine/select.ll =================================================================== --- llvm/test/Transforms/InstCombine/select.ll +++ llvm/test/Transforms/InstCombine/select.ll @@ -902,7 +902,9 @@ define i32 @test57(i32 %x, i32 %y) { ; CHECK-LABEL: @test57( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: ret i32 [[AND]] +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X]], 0 +; CHECK-NEXT: [[DOTAND:%.*]] = select i1 [[TOBOOL]], i32 0, i32 [[AND]] +; CHECK-NEXT: ret i32 [[DOTAND]] ; %and = and i32 %x, %y %tobool = icmp eq i32 %x, 0 @@ -2680,7 +2682,7 @@ define i32 @pr47322_more_poisonous_replacement(i32 %arg) { ; CHECK-LABEL: @pr47322_more_poisonous_replacement( ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[ARG:%.*]], 0 -; CHECK-NEXT: [[TRAILING:%.*]] = call i32 @llvm.cttz.i32(i32 [[ARG]], i1 immarg true), [[RNG0:!range !.*]] +; CHECK-NEXT: [[TRAILING:%.*]] = call i32 @llvm.cttz.i32(i32 [[ARG]], i1 immarg true), !range [[RNG0:![0-9]+]] ; CHECK-NEXT: [[SHIFTED:%.*]] = lshr i32 [[ARG]], [[TRAILING]] ; CHECK-NEXT: [[R1_SROA_0_1:%.*]] = select i1 [[CMP]], i32 0, i32 [[SHIFTED]] ; CHECK-NEXT: ret i32 [[R1_SROA_0_1]] Index: llvm/test/Transforms/InstSimplify/pr49495.ll =================================================================== --- llvm/test/Transforms/InstSimplify/pr49495.ll +++ llvm/test/Transforms/InstSimplify/pr49495.ll @@ -4,9 +4,11 @@ ; The first comparison (a != b) should not be dropped define i1 @test1(i8* %a, i8* %b) { ; CHECK-LABEL: @test1( -; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds i8, i8* [[A:%.*]], i64 -1 -; CHECK-NEXT: [[COND2:%.*]] = icmp ugt i8* [[A2]], [[B:%.*]] -; CHECK-NEXT: ret i1 [[COND2]] +; CHECK-NEXT: [[COND1:%.*]] = icmp ne i8* [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds i8, i8* [[A]], i64 -1 +; CHECK-NEXT: [[COND2:%.*]] = icmp ugt i8* [[A2]], [[B]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND1]], i1 [[COND2]], i1 false +; CHECK-NEXT: ret i1 [[RES]] ; %cond1 = icmp ne i8* %a, %b %a2 = getelementptr inbounds i8, i8* %a, i64 -1 @@ -18,9 +20,11 @@ ; The first comparison (a != b) should not be dropped define i1 @test2(i32 %a, i32 %b) { ; CHECK-LABEL: @test2( -; CHECK-NEXT: [[A2:%.*]] = add nuw i32 [[A:%.*]], 1 -; CHECK-NEXT: [[COND2:%.*]] = icmp ult i32 [[A2]], [[B:%.*]] -; CHECK-NEXT: ret i1 [[COND2]] +; CHECK-NEXT: [[COND1:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[A2:%.*]] = add nuw i32 [[A]], 1 +; CHECK-NEXT: [[COND2:%.*]] = icmp ult i32 [[A2]], [[B]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND1]], i1 [[COND2]], i1 false +; CHECK-NEXT: ret i1 [[RES]] ; %cond1 = icmp ne i32 %a, %b %a2 = add nuw i32 %a, 1