mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
[PM/LoopUnswitch] Detect irreducible control flow within loops and skip unswitching non-trivial edges.
Summary: This fixes the bug pointed out in review with non-trivial unswitching. This also provides a basis that should make it pretty easy to finish fleshing out a routine to scan an entire function body for irreducible control flow, but this patch remains minimal for disabling loop unswitch. Reviewers: sanjoy, fedor.sergeev Subscribers: mcrosier, hiraditya, llvm-commits Differential Revision: https://reviews.llvm.org/D45754 llvm-svn: 330357
This commit is contained in:
parent
52289d96c4
commit
a806fbf4b8
@ -17,9 +17,11 @@
|
|||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/Twine.h"
|
#include "llvm/ADT/Twine.h"
|
||||||
#include "llvm/Analysis/AssumptionCache.h"
|
#include "llvm/Analysis/AssumptionCache.h"
|
||||||
|
#include "llvm/Analysis/CFG.h"
|
||||||
#include "llvm/Analysis/CodeMetrics.h"
|
#include "llvm/Analysis/CodeMetrics.h"
|
||||||
#include "llvm/Analysis/LoopAnalysisManager.h"
|
#include "llvm/Analysis/LoopAnalysisManager.h"
|
||||||
#include "llvm/Analysis/LoopInfo.h"
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
|
#include "llvm/Analysis/LoopIterator.h"
|
||||||
#include "llvm/Analysis/LoopPass.h"
|
#include "llvm/Analysis/LoopPass.h"
|
||||||
#include "llvm/IR/BasicBlock.h"
|
#include "llvm/IR/BasicBlock.h"
|
||||||
#include "llvm/IR/Constant.h"
|
#include "llvm/IR/Constant.h"
|
||||||
@ -1938,6 +1940,17 @@ unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI, AssumptionCache &AC,
|
|||||||
if (UnswitchCandidates.empty())
|
if (UnswitchCandidates.empty())
|
||||||
return Changed;
|
return Changed;
|
||||||
|
|
||||||
|
// Check if there are irreducible CFG cycles in this loop. If so, we cannot
|
||||||
|
// easily unswitch non-trivial edges out of the loop. Doing so might turn the
|
||||||
|
// irreducible control flow into reducible control flow and introduce new
|
||||||
|
// loops "out of thin air". If we ever discover important use cases for doing
|
||||||
|
// this, we can add support to loop unswitch, but it is a lot of complexity
|
||||||
|
// for what seems little or no real world benifit.
|
||||||
|
LoopBlocksRPO RPOT(&L);
|
||||||
|
RPOT.perform(&LI);
|
||||||
|
if (containsIrreducibleCFG<const BasicBlock *>(RPOT, LI))
|
||||||
|
return Changed;
|
||||||
|
|
||||||
DEBUG(dbgs() << "Considering " << UnswitchCandidates.size()
|
DEBUG(dbgs() << "Considering " << UnswitchCandidates.size()
|
||||||
<< " non-trivial loop invariant conditions for unswitching.\n");
|
<< " non-trivial loop invariant conditions for unswitching.\n");
|
||||||
|
|
||||||
|
@ -2350,3 +2350,33 @@ loop_exit:
|
|||||||
; CHECK-NEXT: %[[LCSSA:.*]] = phi i32 [ %[[V]], %loop_begin ]
|
; CHECK-NEXT: %[[LCSSA:.*]] = phi i32 [ %[[V]], %loop_begin ]
|
||||||
; CHECK-NEXT: ret i32 %[[LCSSA]]
|
; CHECK-NEXT: ret i32 %[[LCSSA]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; Negative test: we do not switch when the loop contains unstructured control
|
||||||
|
; flows as it would significantly complicate the process as novel loops might
|
||||||
|
; be formed, etc.
|
||||||
|
define void @test_no_unswitch_unstructured_cfg(i1* %ptr, i1 %cond) {
|
||||||
|
; CHECK-LABEL: @test_no_unswitch_unstructured_cfg(
|
||||||
|
entry:
|
||||||
|
br label %loop_begin
|
||||||
|
|
||||||
|
loop_begin:
|
||||||
|
br i1 %cond, label %loop_left, label %loop_right
|
||||||
|
|
||||||
|
loop_left:
|
||||||
|
%v1 = load i1, i1* %ptr
|
||||||
|
br i1 %v1, label %loop_right, label %loop_merge
|
||||||
|
|
||||||
|
loop_right:
|
||||||
|
%v2 = load i1, i1* %ptr
|
||||||
|
br i1 %v2, label %loop_left, label %loop_merge
|
||||||
|
|
||||||
|
loop_merge:
|
||||||
|
%v3 = load i1, i1* %ptr
|
||||||
|
br i1 %v3, label %loop_latch, label %loop_exit
|
||||||
|
|
||||||
|
loop_latch:
|
||||||
|
br label %loop_begin
|
||||||
|
|
||||||
|
loop_exit:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user