diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3525,6 +3525,45 @@ return NV; } + // Try to push freeze through instructions that propagate but don't produce + // poison as far as possible. If operand of freeze follows three conditions + // 1) one-use, 2) does not produce poison and 3) has all but one + // guaranteed-non-poison operands then push the freeze through to the one + // operand that is not guaranteed non poison. The actual transform is as + // follows. + // Op1 = ... ; ; Op1 can be posion + // Op0 = Inst(Op1, NonPoisonOps...) ; Op0 has only one use and only have + // ; single guaranteed-non-poison operands + // ... = Freeze(Op0) + // => + // Op1 = ... + // Op1.fr = Freeze(Op1) + // ... = Inst(Op1.fr, NonPoisonOps...) + if (auto *Inst = dyn_cast(Op0)) { + Value *NotGuaranteedNonPoisonOperand; + unsigned NumGuaranteedNonPoisonOperand = 0; + for (Use &U : Inst->operands()) { + if (isGuaranteedNotToBeUndefOrPoison(U.get())) + NumGuaranteedNonPoisonOperand++; + else + NotGuaranteedNonPoisonOperand = U.get(); + } + + if (Inst->hasOneUse() && !canCreateUndefOrPoison(dyn_cast(Op0)) && + NumGuaranteedNonPoisonOperand == + dyn_cast(Op0)->getNumOperands() - 1) { + if (Instruction *Op1 = + dyn_cast(NotGuaranteedNonPoisonOperand)) { + auto &U = *Op1->use_begin(); + auto *FI = new FreezeInst(Op1, Op1->getName() + ".fr"); + + replaceUse(U, FI); + FI->insertBefore(Inst); + return replaceInstUsesWith(I, Op0); + } + } + } + if (match(Op0, m_Undef())) { // If I is freeze(undef), see its uses and fold it to the best constant. // - or: pick -1 diff --git a/llvm/test/Transforms/InstCombine/freeze.ll b/llvm/test/Transforms/InstCombine/freeze.ll --- a/llvm/test/Transforms/InstCombine/freeze.ll +++ b/llvm/test/Transforms/InstCombine/freeze.ll @@ -86,3 +86,35 @@ call void @use_i32_i1(i32 %a, i1 %b) ret void } + +; Move the freeze forward to prevent poison from spreading. + +define i32 @early_freeze_test1(i32 %x, i32 %y) { +; CHECK-LABEL: @early_freeze_test1( +; CHECK-NEXT: [[V1:%.*]] = add i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]] +; CHECK-NEXT: [[V2:%.*]] = shl i32 [[V1_FR]], 1 +; CHECK-NEXT: [[V3:%.*]] = and i32 [[V2]], 2 +; CHECK-NEXT: ret i32 [[V3]] +; + %v1 = add i32 %x, %y + %v2 = shl i32 %v1, 1 + %v3 = and i32 %v2, 2 + %v3.fr = freeze i32 %v3 + ret i32 %v3.fr +} + +define i1 @early_freeze_test2(i32* %ptr) { +; CHECK-LABEL: @early_freeze_test2( +; CHECK-NEXT: [[V1:%.*]] = load i32, i32* [[PTR:%.*]], align 4 +; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]] +; CHECK-NEXT: [[V2:%.*]] = and i32 [[V1_FR]], 1 +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[V2]], 0 +; CHECK-NEXT: ret i1 [[COND]] +; + %v1 = load i32, i32* %ptr + %v2 = and i32 %v1, 1 + %cond = icmp eq i32 %v2, 0 + %cond.fr = freeze i1 %cond + ret i1 %cond.fr +}