[InstCombine] Extend stacksave/restore elimination

Previously, InstCombine detected a pair of llvm.stacksave/stackrestore
instructions that are adjacent modulo debug instructions in order to
eliminate the llvm.stackrestore. This precludes situations where
intervening instructions (e.g. loads) preclude the llvm.stacksave and
llvm.stackrestore from becoming adjacent. This commit extends the logic
and allows for eliminating the llvm.stackrestore when the range of
instructions between them does not include any alloca or side-effect
causing instructions.

Signed-off-by: Itay Bookstein <itay.bookstein@nextsilicon.com>

Reviewed By: lebedev.ri

Differential Revision: https://reviews.llvm.org/D113105
This commit is contained in:
Itay Bookstein 2021-11-03 15:08:06 +02:00
parent fe7491d32f
commit f9059efa0d
2 changed files with 60 additions and 6 deletions

View File

@ -1802,14 +1802,40 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
return ClassifyResult::None;
};
// If the save is right next to the restore, remove the restore. This can
// happen when variable allocas are DCE'd.
// If the stacksave and the stackrestore are in the same BB, and there is
// no intervening call, alloca, or stackrestore of a different stacksave,
// remove the restore. This can happen when variable allocas are DCE'd.
if (IntrinsicInst *SS = dyn_cast<IntrinsicInst>(II->getArgOperand(0))) {
if (SS->getIntrinsicID() == Intrinsic::stacksave) {
// Skip over debug info.
if (SS->getNextNonDebugInstruction() == II) {
return eraseInstFromFunction(CI);
if (SS->getIntrinsicID() == Intrinsic::stacksave &&
SS->getParent() == II->getParent()) {
BasicBlock::iterator BI(SS);
bool CannotRemove = false;
for (++BI; &*BI != II; ++BI) {
switch (Classify(&*BI)) {
case ClassifyResult::None:
// So far so good, look at next instructions.
break;
case ClassifyResult::StackRestore:
// If we found an intervening stackrestore for a different
// stacksave, we can't remove the stackrestore. Otherwise, continue.
if (cast<IntrinsicInst>(*BI).getArgOperand(0) != SS)
CannotRemove = true;
break;
case ClassifyResult::Alloca:
case ClassifyResult::CallWithSideEffects:
// If we found an alloca, a non-intrinsic call, or an intrinsic
// call with side effects, we can't remove the stackrestore.
CannotRemove = true;
break;
}
if (CannotRemove)
break;
}
if (!CannotRemove)
return eraseInstFromFunction(CI);
}
}

View File

@ -110,3 +110,31 @@ return:
; CHECK: call void @llvm.stackrestore(i8* %save1)
; CHECK: br i1 %done, label %loop, label %return
; CHECK: ret void
define i32 @test4(i32 %m, i32* %a, i32* %b) {
entry:
br label %for.body
for.body:
%x.012 = phi i32 [ 0, %entry ], [ %add2, %for.body ]
%i.011 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%0 = call i8* @llvm.stacksave()
%load1 = load i32, i32* %a, align 4
%mul1 = mul nsw i32 %load1, %m
%add1 = add nsw i32 %mul1, %x.012
call void @llvm.stackrestore(i8* %0)
%load2 = load i32, i32* %b, align 4
%mul2 = mul nsw i32 %load2, %m
%add2 = add nsw i32 %mul2, %add1
call void @llvm.stackrestore(i8* %0)
%inc = add nuw nsw i32 %i.011, 1
%exitcond.not = icmp eq i32 %inc, 100
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
for.cond.cleanup:
ret i32 %add2
}
; CHECK-LABEL: define i32 @test4(
; CHECK-NOT: call void @llvm.stackrestore
; CHECK: ret i32 %add2