mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
[IR] Consider non-willreturn as side effect (PR50511)
This adjusts mayHaveSideEffect() to return true for !willReturn() instructions. Just like other side-effects, non-willreturn calls (aka "divergence") cannot be removed and cannot be reordered relative to other side effects. This fixes a number of bugs where non-willreturn calls are either incorrectly dropped or moved. In particular, it also fixes the last open problem in https://bugs.llvm.org/show_bug.cgi?id=50511. I performed a cursory review of all current mayHaveSideEffect() uses, which convinced me that these are indeed the desired default semantics. Places that do not want to consider non-willreturn as a sideeffect generally do not want mayHaveSideEffect() semantics at all. I identified two such cases, which are addressed by D106591 and D106742. Finally, there is a use in SCEV for which we don't really have an appropriate API right now -- what it wants is basically "would this be considered forward progress". I've just spelled out the previous semantics there. Differential Revision: https://reviews.llvm.org/D106749
This commit is contained in:
parent
9ae7d5aa56
commit
bab200ac44
@ -627,11 +627,16 @@ public:
|
||||
|
||||
/// Return true if the instruction may have side effects.
|
||||
///
|
||||
/// Side effects are:
|
||||
/// * Writing to memory.
|
||||
/// * Unwinding.
|
||||
/// * Not returning (e.g. an infinite loop).
|
||||
///
|
||||
/// Note that this does not consider malloc and alloca to have side
|
||||
/// effects because the newly allocated memory is completely invisible to
|
||||
/// instructions which don't use the returned value. For cases where this
|
||||
/// matters, isSafeToSpeculativelyExecute may be more appropriate.
|
||||
bool mayHaveSideEffects() const { return mayWriteToMemory() || mayThrow(); }
|
||||
bool mayHaveSideEffects() const;
|
||||
|
||||
/// Return true if the instruction can be removed if the result is unused.
|
||||
///
|
||||
|
@ -80,7 +80,7 @@ void DemandedBitsWrapperPass::print(raw_ostream &OS, const Module *M) const {
|
||||
|
||||
static bool isAlwaysLive(Instruction *I) {
|
||||
return I->isTerminator() || isa<DbgInfoIntrinsic>(I) || I->isEHPad() ||
|
||||
I->mayHaveSideEffects() || !I->willReturn();
|
||||
I->mayHaveSideEffects();
|
||||
}
|
||||
|
||||
void DemandedBits::determineLiveOperandBits(
|
||||
|
@ -6677,7 +6677,7 @@ ScalarEvolution::getLoopProperties(const Loop *L) {
|
||||
if (auto *SI = dyn_cast<StoreInst>(I))
|
||||
return !SI->isSimple();
|
||||
|
||||
return I->mayHaveSideEffects();
|
||||
return I->mayThrow() || I->mayWriteToMemory();
|
||||
};
|
||||
|
||||
LoopProperties LP = {/* HasNoAbnormalExits */ true,
|
||||
|
@ -663,6 +663,10 @@ bool Instruction::mayThrow() const {
|
||||
return isa<ResumeInst>(this);
|
||||
}
|
||||
|
||||
bool Instruction::mayHaveSideEffects() const {
|
||||
return mayWriteToMemory() || mayThrow() || !willReturn();
|
||||
}
|
||||
|
||||
bool Instruction::isSafeToRemove() const {
|
||||
return (!isa<CallInst>(this) || !this->mayHaveSideEffects()) &&
|
||||
!this->isTerminator();
|
||||
|
@ -326,7 +326,7 @@ void AggressiveDeadCodeElimination::initialize() {
|
||||
|
||||
bool AggressiveDeadCodeElimination::isAlwaysLive(Instruction &I) {
|
||||
// TODO -- use llvm::isInstructionTriviallyDead
|
||||
if (I.isEHPad() || I.mayHaveSideEffects() || !I.willReturn()) {
|
||||
if (I.isEHPad() || I.mayHaveSideEffects()) {
|
||||
// Skip any value profile instrumentation calls if they are
|
||||
// instrumenting constants.
|
||||
if (isInstrumentsConstant(I))
|
||||
|
@ -979,16 +979,16 @@ try.cont:
|
||||
ret void
|
||||
}
|
||||
|
||||
; TODO: Should not get sunk.
|
||||
define i32 @not_willreturn(i8* %p) {
|
||||
; CHECK-LABEL: @not_willreturn(
|
||||
; CHECK-NEXT: [[X:%.*]] = call i32 @getv() #[[ATTR5:[0-9]+]]
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: store volatile i8 0, i8* [[P:%.*]], align 1
|
||||
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[OUT:%.*]]
|
||||
; CHECK: out:
|
||||
; CHECK-NEXT: [[X_LE:%.*]] = call i32 @getv() #[[ATTR5:[0-9]+]]
|
||||
; CHECK-NEXT: ret i32 [[X_LE]]
|
||||
; CHECK-NEXT: [[X_LCSSA:%.*]] = phi i32 [ [[X]], [[LOOP]] ]
|
||||
; CHECK-NEXT: ret i32 [[X_LCSSA]]
|
||||
;
|
||||
br label %loop
|
||||
|
||||
|
@ -395,11 +395,16 @@ exit:
|
||||
}
|
||||
|
||||
; Inner infinite loop hidden behind a call.
|
||||
; TODO: Loop should not get deleted.
|
||||
define void @not_willreturn() {
|
||||
; CHECK-LABEL: @not_willreturn(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
||||
; CHECK-NEXT: call void @sideeffect() #[[ATTR2:[0-9]+]]
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[IV]], 100
|
||||
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
@ -34,9 +34,9 @@ define i32 @test_1() {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; TODO: Call should not get dropped.
|
||||
define i32 @test_not_willreturn() {
|
||||
; CHECK-LABEL: @test_not_willreturn(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call [[EMPTY:%.*]] @has_side_effects() #[[ATTR1:[0-9]+]]
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
%1 = call %empty @has_side_effects() nounwind readonly
|
||||
|
Loading…
Reference in New Issue
Block a user