mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
MaterializeLoopScopes: drop pass
Drop the `MaterializeLoopScopes` pass after the re-design the loop matching stage to work entirely on `clift`, without the need to insert a `scope_closer` edge to guide the emission. Simultaneously, drop the DAGify `Head` metadata insertion, since it will not be checked anymore during the `MaterializeLoopScopes` pass.
This commit is contained in:
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
class MaterializeLoopScopes : public llvm::FunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
public:
|
||||
MaterializeLoopScopes() : llvm::FunctionPass(ID) {}
|
||||
|
||||
bool runOnFunction(llvm::Function &F) override;
|
||||
|
||||
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override;
|
||||
};
|
||||
@@ -21,7 +21,6 @@ revng_add_analyses_library_internal(
|
||||
GenericRegionPass.cpp
|
||||
InlineDispatcherSwitch.cpp
|
||||
InlineDivergentScopesPass.cpp
|
||||
MaterializeLoopScopes.cpp
|
||||
MaterializeTrivialGotoPass.cpp
|
||||
MetaRegion.cpp
|
||||
PromoteCallNoReturn.cpp
|
||||
|
||||
@@ -21,19 +21,6 @@ using namespace llvm;
|
||||
// Debug logger
|
||||
static Logger<> Log("dagify");
|
||||
|
||||
/// Helper function used to insert on the `Head` node the metadata that will be
|
||||
/// later checked for consistency
|
||||
static void insertHeadMD(BasicBlock *Head) {
|
||||
|
||||
// We attach a metadata to the terminator instruction of the `Head`
|
||||
// block. Later on, we will check during `MaterializeLoopScopes` that
|
||||
// the `Head` block of each `GenericRegion` will be the same
|
||||
Instruction *HeadTerminator = Head->getTerminator();
|
||||
QuickMetadata QMD(getContext(HeadTerminator));
|
||||
auto *HeadMD = QMD.tuple();
|
||||
HeadTerminator->setMetadata("genericregion-head", HeadMD);
|
||||
}
|
||||
|
||||
class DAGifyPassImpl {
|
||||
Function &F;
|
||||
const ScopeGraphBuilder SGBuilder;
|
||||
@@ -155,12 +142,9 @@ public:
|
||||
RegionNodes.insert(RegionNode);
|
||||
}
|
||||
|
||||
// Mark the `Head` block with the custom named metadata
|
||||
// 1. Process the retreating edges of the `GenericRegion`
|
||||
BasicBlock *Head = Region->getHead();
|
||||
revng_assert(Head);
|
||||
insertHeadMD(Head);
|
||||
|
||||
// 1. Process the retreating edges of the `GenericRegion`
|
||||
using GT = GraphTraits<BasicBlock *>;
|
||||
auto Retreatings = getBackedgesWhiteList<BasicBlock *, GT>(Head,
|
||||
RegionNodes);
|
||||
|
||||
@@ -1,395 +0,0 @@
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Support/GenericDomTree.h"
|
||||
|
||||
#include "revng/RestructureCFG/GenericRegionInfo.h"
|
||||
#include "revng/RestructureCFG/MaterializeLoopScopes.h"
|
||||
#include "revng/RestructureCFG/ScopeGraphAlgorithms.h"
|
||||
#include "revng/RestructureCFG/ScopeGraphGraphTraits.h"
|
||||
#include "revng/RestructureCFG/ScopeGraphUtils.h"
|
||||
#include "revng/Support/Assert.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// Debug logger
|
||||
static Logger<> Log("materialize-loop-scopes");
|
||||
|
||||
/// Helper function which inserts the `scope_closer` edge representing the
|
||||
/// `MaterializeLoopScope` operation result
|
||||
static void addScopeCloser(const ScopeGraphBuilder &SGBuilder,
|
||||
BasicBlock *Head,
|
||||
BasicBlock *UniqueSuccessor) {
|
||||
|
||||
// We split the `Head` block in order to insert a `scope_start`, so that we
|
||||
// can insert the `scope_closer` between `scope_start` and the elected
|
||||
// `UniqueSuccessor` materializing the `scope` corresponding to the loop body
|
||||
Instruction *HeadTerminator = Head->getTerminator();
|
||||
BasicBlock *LoopStart = Head->splitBasicBlock(HeadTerminator, "loop_start");
|
||||
|
||||
// Log the `UniqueSuccessor` to which we are inserting the `scope_closer` to
|
||||
revng_log(Log,
|
||||
"The elected unique successor is block:"
|
||||
<< UniqueSuccessor->getName() << "\n");
|
||||
|
||||
// We insert the `scope_closer` edge from the `Head` to the `UniqueSuccessor`
|
||||
SGBuilder.addScopeCloser(Head, UniqueSuccessor);
|
||||
}
|
||||
|
||||
/// Helper function used to verify that the elected `Head` contains the metadata
|
||||
/// attached during the `DAGify` pass
|
||||
static void verifyHeadMD(BasicBlock *Head) {
|
||||
|
||||
// We check that each `Head` block has a metadata attached during the
|
||||
// `DAGify` pass
|
||||
Instruction *HeadTerminator = Head->getTerminator();
|
||||
auto *MD = HeadTerminator->getMetadata("genericregion-head");
|
||||
|
||||
// We must find the metadata by design
|
||||
revng_assert(MD);
|
||||
auto *Tuple = dyn_cast_or_null<MDTuple>(MD);
|
||||
revng_assert(Tuple);
|
||||
}
|
||||
|
||||
/// Helper to obtain the immediate postdominator `BasicBlock`, if present
|
||||
static BasicBlock *
|
||||
getImmediatePostDominator(BasicBlock *N,
|
||||
PostDomTreeOnView<BasicBlock, Scope> &PostDomTree) {
|
||||
auto *Node = PostDomTree.getNode(N)->getIDom();
|
||||
if (Node) {
|
||||
return Node->getBlock();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to populate the sets of exiting and successor candidates
|
||||
static void
|
||||
collectExitBlocks(GenericRegion<BasicBlock *> *Region,
|
||||
std::set<BasicBlock *> &ExitingBlocks,
|
||||
std::set<BasicBlock *> &UniqueSuccessorCandidates) {
|
||||
for (auto *RegionNode : Region->blocks()) {
|
||||
SmallSetVector<BasicBlock *, 2>
|
||||
Successors = getScopeGraphSuccessors(RegionNode);
|
||||
for (BasicBlock *Successor : Successors) {
|
||||
if (not Region->containsBlock(Successor)) {
|
||||
|
||||
// We collect the `Successor`s of the `GenericRegion`
|
||||
UniqueSuccessorCandidates.insert(Successor);
|
||||
|
||||
// We collect all the blocks from which there is a exiting edge
|
||||
// from the `GenericRegion`
|
||||
ExitingBlocks.insert(RegionNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function used to create the `Footer` block, which will become the
|
||||
/// unique successor of the `GenericRegion`, and to divert the exiting edges to
|
||||
/// such block
|
||||
static BasicBlock *
|
||||
enforceFooterSuccessor(GenericRegion<BasicBlock *> *Region,
|
||||
std::set<BasicBlock *> &ExitingBlocks,
|
||||
std::set<BasicBlock *> &UniqueSuccessorCandidates) {
|
||||
|
||||
revng_assert(ExitingBlocks.size() == 1);
|
||||
BasicBlock *UniqueExitingBlock = *ExitingBlocks.begin();
|
||||
|
||||
llvm::SmallSet<BasicBlock *, 4> InternalSuccessors;
|
||||
SmallSetVector<BasicBlock *, 2>
|
||||
Successors = getScopeGraphSuccessors(UniqueExitingBlock);
|
||||
for (BasicBlock *Successor : Successors) {
|
||||
if (Region->containsBlock(Successor)) {
|
||||
InternalSuccessors.insert(Successor);
|
||||
}
|
||||
}
|
||||
|
||||
auto *ExitingBlockTerminator = UniqueExitingBlock->getTerminator();
|
||||
|
||||
// We clone the original `Terminator` in the `footer` block
|
||||
LLVMContext &Context = getContext(UniqueExitingBlock);
|
||||
Function *F = UniqueExitingBlock->getParent();
|
||||
BasicBlock *Footer = BasicBlock::Create(Context, "footer", F);
|
||||
Instruction *FooterTerminator = ExitingBlockTerminator->clone();
|
||||
IRBuilder<> FooterBuilder(Footer);
|
||||
FooterBuilder.Insert(FooterTerminator);
|
||||
|
||||
// We divert the edges exiting from the `GenericRegion` to the
|
||||
// `Footer` block
|
||||
replaceSuccessors(ExitingBlockTerminator, UniqueSuccessorCandidates, Footer);
|
||||
|
||||
// In the `Footer`, we need to remove all the edges not going to the
|
||||
// `GenericRegion` successors
|
||||
for (BasicBlock *InternalSuccessor : InternalSuccessors) {
|
||||
simplifyTerminator(Footer, InternalSuccessor);
|
||||
}
|
||||
|
||||
return Footer;
|
||||
}
|
||||
|
||||
/// Helper function used to check for the preconditions needed on the
|
||||
/// predecessors of the candidate immediate post dominator `UniqueSuccessor`.
|
||||
/// Specifically, we check that all the predecessors are either in the current
|
||||
/// `GenericRegion` or in the parent one.
|
||||
static bool
|
||||
checkPredecessorsCondition(GenericRegion<BasicBlock *> *Region,
|
||||
GenericRegion<BasicBlock *> *ParentRegion,
|
||||
BasicBlock *UniqueSuccessor) {
|
||||
// Check that `UniqueSuccessor` belong to `ParentRegion`
|
||||
if (not ParentRegion->containsBlock(UniqueSuccessor)) {
|
||||
|
||||
// Log the motivation for the exclusion of the `UniqueSuccessor`
|
||||
// candidate
|
||||
revng_log(Log,
|
||||
"Candidate unique successor " << UniqueSuccessor->getName()
|
||||
<< " is not in the parent region, "
|
||||
"and needs to be "
|
||||
"discarded");
|
||||
|
||||
// If the identified `UniqueSuccessor` is not in the parent
|
||||
// `GenericRegion`, we signal this fact
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that all the predecessors of the candidate `UniqueSuccessor`
|
||||
// are either in the `GenericRegion` under analysis or in its parent
|
||||
// `GenericRegion`
|
||||
SmallSetVector<BasicBlock *, 2>
|
||||
Predecessors = getScopeGraphPredecessors(UniqueSuccessor);
|
||||
for (BasicBlock *Predecessor : Predecessors) {
|
||||
if ((not Region->containsBlock(Predecessor))
|
||||
or (not ParentRegion->containsBlock(Predecessor))) {
|
||||
|
||||
// Log the motivation for the exclusion of the `UniqueSuccessor`
|
||||
// candidate
|
||||
revng_log(Log,
|
||||
"Candidate unique successor " << UniqueSuccessor->getName()
|
||||
<< " has not compatible "
|
||||
"predecessors, and needs to "
|
||||
"be discarded");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Helper function used to check for the preconditions needed on the
|
||||
/// predecessors of the candidate immediate post dominator `UniqueSuccessor`.
|
||||
/// Specifically, we check that all the predecessors are dominated by the elect
|
||||
/// entry of the `GenericRegion` (the `Head`).
|
||||
static bool checkPredecessorsDominance(BasicBlock *Head,
|
||||
BasicBlock *UniqueSuccessor) {
|
||||
DomTreeOnView<BasicBlock, Scope> DomTree;
|
||||
Function *F = Head->getParent();
|
||||
DomTree.recalculate(*F);
|
||||
|
||||
// Check that all the predecessors are either dominated by the entry
|
||||
// node of the loop
|
||||
SmallSetVector<BasicBlock *, 2>
|
||||
Predecessors = getScopeGraphPredecessors(UniqueSuccessor);
|
||||
for (BasicBlock *Predecessor : Predecessors) {
|
||||
if (not DomTree.dominates(Head, Predecessor)) {
|
||||
|
||||
// Log the motivation for the exclusion of the `UniqueSuccessor`
|
||||
// candidate
|
||||
revng_log(Log,
|
||||
"Candidate unique successor " << UniqueSuccessor->getName()
|
||||
<< " has not compatible "
|
||||
"predecessors, and needs to "
|
||||
"be discarded");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::optional<BasicBlock *>
|
||||
tryEnforceUniqueSuccessor(GenericRegion<BasicBlock *> *Region) {
|
||||
|
||||
// Collect the exiting blocks and the `SuccessorCandidates` of the
|
||||
// `GenericRegion`
|
||||
std::set<BasicBlock *> ExitingBlocks;
|
||||
std::set<BasicBlock *> UniqueSuccessorCandidates;
|
||||
collectExitBlocks(Region, ExitingBlocks, UniqueSuccessorCandidates);
|
||||
|
||||
std::optional<BasicBlock *> UniqueSuccessor;
|
||||
|
||||
// A. We iterate over all the successors blocks of each node in the
|
||||
// `GenericRegion`. If there is a unique candidate successor, we can
|
||||
// elect such block as `UniqueSuccessor`..
|
||||
|
||||
// If the loop has a single clearly identified successor, we can proceed
|
||||
// with the insertion of the `scope_closer` to the `UniqueSuccessor`
|
||||
if (UniqueSuccessorCandidates.size() == 1) {
|
||||
UniqueSuccessor = *UniqueSuccessorCandidates.begin();
|
||||
|
||||
return UniqueSuccessor;
|
||||
}
|
||||
|
||||
// B. If the `GenericRegion` has a single block with exiting edges, we
|
||||
// insert a `footer` block grouping such exiting edges, and we insert
|
||||
// a `scope_closer` to it
|
||||
if (ExitingBlocks.size() == 1 and UniqueSuccessorCandidates.size() > 1) {
|
||||
BasicBlock *Footer = enforceFooterSuccessor(Region,
|
||||
ExitingBlocks,
|
||||
UniqueSuccessorCandidates);
|
||||
|
||||
return Footer;
|
||||
}
|
||||
|
||||
// C. If we did not elect the `UniqueSuccessor` in the previous stages,
|
||||
// we try to navigate up in the post dominator tree until we find the
|
||||
// first immediate post dominator block which is outside the current
|
||||
// `GenericRegion.
|
||||
revng_assert(not UniqueSuccessor);
|
||||
BasicBlock *Head = Region->getHead();
|
||||
Function *F = Head->getParent();
|
||||
PostDomTreeOnView<BasicBlock, Scope> PostDomTree;
|
||||
PostDomTree.recalculate(*F);
|
||||
BasicBlock *Candidate = Head;
|
||||
while ((Candidate = getImmediatePostDominator(Candidate, PostDomTree))) {
|
||||
if (not Region->containsBlock(Candidate)) {
|
||||
|
||||
// Here we have identified the first node outside the
|
||||
// `GenericRegion` which postdominates the entry node. This node
|
||||
// will be our candidate for becoming the exit node of the
|
||||
// `GenericRegion`.
|
||||
UniqueSuccessor = Candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We did not find a `UniqueSuccessor`
|
||||
if (not UniqueSuccessor) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// We admit the election of a immediate post dominator block as the
|
||||
// `UniqueSuccessor` of a `GenericRegion` only if both the following
|
||||
// properties hold:
|
||||
// 1: The candidate block must be in the direct parent of the
|
||||
// `GenericRegion`.
|
||||
// 2: All the incoming edges into the `UniqueSuccessor` block
|
||||
// originate either from blocks in the `GenericRegion` under
|
||||
// analysis (edges exiting the `GenericRegion`) or in its parent.
|
||||
auto *ParentRegion = Region->getParent();
|
||||
|
||||
// We may not have a `ParentRegion`, in that case the `GenericRegion` we
|
||||
// are analyzing is at the first level in the `RegionTree`, and the
|
||||
// following check is not needed
|
||||
if (ParentRegion) {
|
||||
|
||||
// If the preconditions are not satisfied, we cannot identify the
|
||||
// `UniqueSuccessor`
|
||||
if (not checkPredecessorsCondition(Region,
|
||||
ParentRegion,
|
||||
*UniqueSuccessor)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
// We now check that all the predecessors of the candidate immediate
|
||||
// post dominator block `UniqueSuccessor` are dominated by the `Head`,
|
||||
// which is another precondition for the election of the
|
||||
// `UniqueSuccessor` of the `GenericRegion`
|
||||
if (not checkPredecessorsDominance(Head, *UniqueSuccessor)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// If we reach this point, it means that all the preconditions are
|
||||
// satisfied, and that we can elect the `UniqueSuccessor`
|
||||
return UniqueSuccessor;
|
||||
}
|
||||
|
||||
/// Implementation class used to run the `MaterializeLoopScopes`
|
||||
/// transformation
|
||||
class MaterializeLoopScopesImpl {
|
||||
Function &F;
|
||||
ScopeGraphBuilder SGBuilder;
|
||||
|
||||
public:
|
||||
MaterializeLoopScopesImpl(Function &F) : F(F), SGBuilder(&F) {}
|
||||
|
||||
public:
|
||||
bool run() {
|
||||
|
||||
// We instantiate and run the `GenericRegionInfo` analysis on the raw CFG,
|
||||
// and not on the `ScopeGraph`. This is done because the current pass runs
|
||||
// after `DAGify`, which disrupts the loops on the `ScopeGraph`.
|
||||
// Under the assumption that the successor order of each `BasicBlock` is not
|
||||
// modified between `DAGify` and `MaterializeLoopScopes`, we have the
|
||||
// guarantee that the `GenericRegionInfo` computed remains equivalent.
|
||||
GenericRegionInfo<Function *> RegionInfo;
|
||||
RegionInfo.compute(&F);
|
||||
|
||||
// We keep a boolean variable to track whether the `Function` was modified
|
||||
bool FunctionModified = false;
|
||||
|
||||
// We iterate over all the `GenericRegion`s that were found
|
||||
for (auto &TopLevelRegion : RegionInfo.top_level_regions()) {
|
||||
for (auto *Region : post_order(&TopLevelRegion)) {
|
||||
|
||||
// Retrieve the elected `Head` of the `GenericRegion`
|
||||
BasicBlock *Head = Region->getHead();
|
||||
revng_log(Log, "Elected head is: " << Head->getName() << "\n");
|
||||
|
||||
// Verify that the `Head` is the same one elected during the `DAGify`
|
||||
// pass
|
||||
verifyHeadMD(Head);
|
||||
|
||||
// 1. Try to find a `UniqueSuccessor` candidate
|
||||
std::optional<BasicBlock *>
|
||||
UniqueSuccessor = tryEnforceUniqueSuccessor(Region);
|
||||
|
||||
// 2. Enforce the single successor, if found, by adding a `scope_closer`
|
||||
// to it, for the `GenericRegion`
|
||||
if (UniqueSuccessor) {
|
||||
|
||||
// We mark the current `Function` as modified
|
||||
FunctionModified = true;
|
||||
|
||||
// We insert the `scope_closer` to `UniqueSuccessor`
|
||||
addScopeCloser(SGBuilder, Head, *UniqueSuccessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FunctionModified;
|
||||
}
|
||||
};
|
||||
|
||||
char MaterializeLoopScopes::ID = 0;
|
||||
static constexpr const char *Flag = "materialize-loop-scopes";
|
||||
using Reg = llvm::RegisterPass<MaterializeLoopScopes>;
|
||||
static Reg X(Flag, "Perform the materialization of loop scopes transformation");
|
||||
|
||||
bool MaterializeLoopScopes::runOnFunction(llvm::Function &F) {
|
||||
|
||||
// Instantiate and call the `Impl` class
|
||||
MaterializeLoopScopesImpl MLoopScopesImpl(F);
|
||||
bool FunctionModified = MLoopScopesImpl.run();
|
||||
|
||||
// This pass may transform the CFG by transforming some edges into `goto`
|
||||
// edges, and by adding some `scope_closer` edges on the `ScopeGraph`
|
||||
return FunctionModified;
|
||||
}
|
||||
|
||||
void MaterializeLoopScopes::getAnalysisUsage(llvm::AnalysisUsage &AU) const {
|
||||
// This pass does not preserve the CFG
|
||||
}
|
||||
@@ -686,7 +686,6 @@ Branches:
|
||||
- inline-divergent-scopes
|
||||
- enforce-single-exit
|
||||
- materialize-trivial-goto
|
||||
- materialize-loop-scopes
|
||||
- select-scope
|
||||
- inline-divergent-scopes
|
||||
- enforce-single-exit
|
||||
|
||||
@@ -302,7 +302,7 @@ block_h:
|
||||
; CHECK: block_a:
|
||||
; CHECK-NEXT: br i1 %a, label %block_b, label %block_h
|
||||
; CHECK: block_b:
|
||||
; CHECK-NEXT: br label %block_c, !genericregion-head !2
|
||||
; CHECK-NEXT: br label %block_c
|
||||
; CHECK: block_c:
|
||||
; CHECK-NEXT: br i1 %a, label %block_d, label %block_e
|
||||
; CHECK: block_d:
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
;
|
||||
; This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
;
|
||||
|
||||
; RUN: %revngopt %s -materialize-loop-scopes -S -o - | FileCheck %s
|
||||
|
||||
; function tags metadata needed for all the tests
|
||||
declare !revng.tags !0 void @scope_closer(ptr)
|
||||
declare !revng.tags !1 void @goto_block()
|
||||
!0 = !{!"marker", !"scope-closer"}
|
||||
!1 = !{!"marker", !"goto-block"}
|
||||
!2 = !{}
|
||||
|
||||
; MLoopScopes on not dagified loop with single successor
|
||||
|
||||
define void @f(i1 noundef %a) {
|
||||
|
||||
block_a:
|
||||
br label %block_b
|
||||
|
||||
block_b:
|
||||
br label %block_c, !genericregion-head !2
|
||||
|
||||
block_c:
|
||||
br label %block_d
|
||||
|
||||
block_d:
|
||||
br i1 %a, label %block_b, label %block_e
|
||||
|
||||
block_e:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @f(i1 noundef %a)
|
||||
; CHECK: block_a:
|
||||
; CHECK-NEXT: br label %block_b
|
||||
; CHECK: block_b:
|
||||
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@f, %block_e))
|
||||
; CHECK-NEXT: br label %loop_start
|
||||
; CHECK: loop_start:
|
||||
; CHECK-NEXT: br label %block_c, !genericregion-head !2
|
||||
; CHECK: block_c:
|
||||
; CHECK-NEXT: br label %block_d
|
||||
; CHECK: block_d:
|
||||
; CHECK-NEXT: br i1 %a, label %block_b, label %block_e
|
||||
; CHECK: block_e:
|
||||
; CHECK-NEXT: ret void
|
||||
|
||||
; MLoopScopes on dagified loop with single successor
|
||||
|
||||
define void @g(i1 noundef %a) {
|
||||
|
||||
block_a:
|
||||
br label %block_b
|
||||
|
||||
block_b:
|
||||
br label %block_c, !genericregion-head !2
|
||||
|
||||
block_c:
|
||||
br label %block_d
|
||||
|
||||
block_d:
|
||||
br i1 %a, label %goto_block_b, label %block_e
|
||||
|
||||
goto_block_b:
|
||||
call void @scope_closer(ptr blockaddress(@g, %block_e))
|
||||
call void @goto_block()
|
||||
br label %block_b
|
||||
|
||||
block_e:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @g(i1 noundef %a)
|
||||
; CHECK: block_a:
|
||||
; CHECK-NEXT: br label %block_b
|
||||
; CHECK: block_b:
|
||||
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@g, %block_e))
|
||||
; CHECK-NEXT: br label %loop_start
|
||||
; CHECK: loop_start:
|
||||
; CHECK-NEXT: br label %block_c, !genericregion-head !2
|
||||
; CHECK: block_c:
|
||||
; CHECK-NEXT: br label %block_d
|
||||
; CHECK: block_d:
|
||||
; CHECK-NEXT: br i1 %a, label %goto_block_b, label %block_e
|
||||
; CHECK: goto_block_b:
|
||||
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@g, %block_e))
|
||||
; CHECK-NEXT: call void @goto_block()
|
||||
; CHECK-NEXT: br label %block_b
|
||||
; CHECK: block_e:
|
||||
; CHECK-NEXT: ret void
|
||||
|
||||
; MLoopScopes on not dagified loop with multiple successors, footer insertion
|
||||
|
||||
define void @h(i32 noundef %a) {
|
||||
|
||||
block_a:
|
||||
br label %block_b
|
||||
|
||||
block_b:
|
||||
switch i32 %a, label %block_e [
|
||||
i32 0, label %block_f
|
||||
i32 1, label %block_c
|
||||
], !genericregion-head !2
|
||||
|
||||
block_c:
|
||||
br label %block_d
|
||||
|
||||
block_d:
|
||||
br label %block_b
|
||||
|
||||
block_e:
|
||||
br label %block_g
|
||||
|
||||
block_f:
|
||||
br label %block_g
|
||||
|
||||
block_g:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @h(i32 noundef %a)
|
||||
; CHECK: block_a:
|
||||
; CHECK-NEXT: br label %block_b
|
||||
; CHECK: block_b:
|
||||
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@h, %footer))
|
||||
; CHECK-NEXT: br label %loop_start
|
||||
; CHECK: loop_start:
|
||||
; CHECK-NEXT: switch i32 %a, label %footer [
|
||||
; CHECK-NEXT: i32 0, label %footer
|
||||
; CHECK-NEXT: i32 1, label %block_c
|
||||
; CHECK-NEXT: ], !genericregion-head !2
|
||||
; CHECK: block_c:
|
||||
; CHECK-NEXT: br label %block_d
|
||||
; CHECK: block_d:
|
||||
; CHECK-NEXT: br label %block_b
|
||||
; CHECK: block_e:
|
||||
; CHECK-NEXT: br label %block_g
|
||||
; CHECK: block_f:
|
||||
; CHECK-NEXT: br label %block_g
|
||||
; CHECK: block_g:
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: footer:
|
||||
; CHECK-NEXT: switch i32 %a, label %block_e [
|
||||
; CHECK-NEXT: i32 0, label %block_f
|
||||
; CHECK-NEXT: ], !genericregion-head !2
|
||||
|
||||
; MLoopScopes on dagified loop with multiple successors, no footer is inserted
|
||||
|
||||
define void @i(i32 noundef %a) {
|
||||
block_a:
|
||||
br label %block_b
|
||||
|
||||
block_b:
|
||||
switch i32 %a, label %block_b_ids [
|
||||
i32 0, label %block_b_ids
|
||||
i32 1, label %block_c
|
||||
], !genericregion-head !2
|
||||
|
||||
block_c:
|
||||
br label %block_d
|
||||
|
||||
block_d:
|
||||
br label %goto_block_b
|
||||
|
||||
block_e:
|
||||
br label %block_g
|
||||
|
||||
block_f:
|
||||
br label %block_g
|
||||
|
||||
block_g:
|
||||
ret void
|
||||
|
||||
goto_block_b:
|
||||
call void @goto_block()
|
||||
call void @scope_closer(ptr blockaddress(@i, %block_b_ids))
|
||||
br label %block_b
|
||||
|
||||
block_b_ids:
|
||||
switch i32 %a, label %block_e [
|
||||
i32 0, label %block_f
|
||||
]
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @i(i32 noundef %a)
|
||||
; CHECK: block_a:
|
||||
; CHECK-NEXT: br label %block_b
|
||||
; CHECK: block_b:
|
||||
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@i, %block_b_ids))
|
||||
; CHECK-NEXT: br label %loop_start
|
||||
; CHECK: loop_start:
|
||||
; CHECK-NEXT: switch i32 %a, label %block_b_ids [
|
||||
; CHECK-NEXT: i32 0, label %block_b_ids
|
||||
; CHECK-NEXT: i32 1, label %block_c
|
||||
; CHECK-NEXT: ], !genericregion-head !2
|
||||
; CHECK: block_c:
|
||||
; CHECK-NEXT: br label %block_d
|
||||
; CHECK: block_d:
|
||||
; CHECK-NEXT: br label %goto_block_b
|
||||
; CHECK: block_e:
|
||||
; CHECK-NEXT: br label %block_g
|
||||
; CHECK: block_f:
|
||||
; CHECK-NEXT: br label %block_g
|
||||
; CHECK: block_g:
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: goto_block_b:
|
||||
; CHECK-NEXT: call void @goto_block()
|
||||
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@i, %block_b_ids))
|
||||
; CHECK-NEXT: br label %block_b
|
||||
; CHECK: block_b_ids:
|
||||
; CHECK-NEXT: switch i32 %a, label %block_e [
|
||||
; CHECK-NEXT: i32 0, label %block_f
|
||||
; CHECK-NEXT: ]
|
||||
Reference in New Issue
Block a user