File: CrossingAnalysis.cpp

package info (click to toggle)
intel-graphics-compiler 1.0.12504.6-1%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 83,912 kB
  • sloc: cpp: 910,147; lisp: 202,655; ansic: 15,197; python: 4,025; yacc: 2,241; lex: 1,570; pascal: 244; sh: 104; makefile: 25
file content (208 lines) | stat: -rw-r--r-- 7,045 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*========================== begin_copyright_notice ============================

Copyright (C) 2021 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

//===- CoroFrame.cpp - Builds and manipulates coroutine frame -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
///
/// Adapted from CoroFrame.cpp, this provides a utility to determine whether
/// a given value is live across some "suspend point" (e.g., barrier, TraceRay).
///
/// As a precondition, the function should first split each of the suspend
/// points into their own basic blocks (via splitAround()) to aid the analysis.
///
//===----------------------------------------------------------------------===//

#include "CrossingAnalysis.h"
#include "debug/Dump.hpp"
#include "common/LLVMWarningsPush.hpp"
#include <llvm/ADT/SmallVector.h>
#include <llvm/IR/Function.h>
#include "common/LLVMWarningsPop.hpp"

using namespace llvm;
using namespace IGC;

// Splits the block at a particular instruction unless it is the first
// instruction in the block with a single predecessor.
static BasicBlock* splitBlockIfNotFirst(Instruction* I, const Twine& Name) {
    auto* BB = I->getParent();
    if (&BB->front() == I) {
        if (BB->getSinglePredecessor()) {
            BB->setName(Name);
            return BB;
        }
    }
    return BB->splitBasicBlock(I, Name);
}

namespace IGC {

void splitAround(llvm::Instruction* I, const llvm::Twine& Name)
{
    splitBlockIfNotFirst(I, Name);
    if (I->getNextNode())
    {   //if I is terminator, we cannot split it further
        splitBlockIfNotFirst(I->getNextNode(), "After" + Name);
    }
}

} // namespace IGC

iterator_range<succ_iterator> SuspendCrossingInfo::successors(BlockData const& BD) const {
    BasicBlock* BB = Mapping.indexToBlock((unsigned)(&BD - &Block[0]));
    return llvm::successors(BB);
}

SuspendCrossingInfo::BlockData& SuspendCrossingInfo::getBlockData(BasicBlock* BB) {
    return Block[Mapping.blockToIndex(BB)];
}

LLVM_DUMP_METHOD void SuspendCrossingInfo::print(
    raw_ostream& OS, StringRef Label, BitVector const& BV) const {
    OS << Label << ":";
    for (size_t I = 0, N = BV.size(); I < N; ++I)
        if (BV[I])
            OS << " " << Mapping.indexToBlock(I)->getName();
    OS << "\n";
}

LLVM_DUMP_METHOD void SuspendCrossingInfo::print(raw_ostream& OS) const {
    for (size_t I = 0, N = Block.size(); I < N; ++I) {
        BasicBlock* const B = Mapping.indexToBlock(I);
        OS << B->getName() << ":\n";
        print(OS, "   Consumes", Block[I].Consumes);
        print(OS, "      Kills", Block[I].Kills);
    }
    OS << "\n";
}

LLVM_DUMP_METHOD void SuspendCrossingInfo::dump() const
{
    print(outs());
}

// Used for dumping into a file with a fixed name while running in debugger
LLVM_DUMP_METHOD void SuspendCrossingInfo::dumpToFile(const CodeGenContext *Ctx) const
{
    using namespace Debug;

    auto name =
        DumpName(IGC::Debug::GetShaderOutputName())
        .Hash(Ctx->hash)
        .Type(Ctx->type)
        .Pass("WIAnalysis")
        .Extension("txt");
    print(Dump(name, DumpType::DBG_MSG_TEXT).stream());
}

SuspendCrossingInfo::SuspendCrossingInfo(
    Function& F, const std::vector<Instruction*>& SuspendPoints)
    : Mapping(F) {
    const size_t N = Mapping.size();
    Block.resize(N);

    // Initialize every block so that it consumes itself
    for (size_t I = 0; I < N; ++I) {
        auto& B = Block[I];
        B.Consumes.resize(N);
        B.Kills.resize(N);
        B.Consumes.set(I);
    }

    // Mark all suspend blocks and indicate that they kill everything they
    // consume.
    auto markSuspendBlock = [&](Instruction* BarrierInst) {
        BasicBlock* SuspendBlock = BarrierInst->getParent();
        auto& B = getBlockData(SuspendBlock);
        B.Suspend = true;
        B.Kills |= B.Consumes;
    };

    for (auto *SP : SuspendPoints) {
        markSuspendBlock(SP);
    }

    // Iterate propagating consumes and kills until they stop changing.
    bool Changed;
    do {
        Changed = false;
        for (size_t I = 0; I < N; ++I) {
            auto& B = Block[I];
            for (BasicBlock* SI : successors(B)) {
                auto SuccNo = Mapping.blockToIndex(SI);

                // Saved Consumes and Kills bitsets so that it is easy to see
                // if anything changed after propagation.
                auto& S = Block[SuccNo];
                auto SavedConsumes = S.Consumes;
                auto SavedKills = S.Kills;

                // Propagate Kills and Consumes from block B into its successor S.
                S.Consumes |= B.Consumes;
                S.Kills |= B.Kills;

                // If block B is a suspend block, it should propagate kills into the
                // its successor for every block B consumes.
                if (B.Suspend) {
                    S.Kills |= B.Consumes;
                }
                if (S.Suspend) {
                    // If block S is a suspend block, it should kill all of the blocks it
                    // consumes.
                    S.Kills |= S.Consumes;
                }
                else {
                    // This is reached when S block is not Suspend and it
                    // needs to make sure that it is not in the kill set.
                    S.Kills.reset(SuccNo);
                }

                // See if anything changed.
                Changed |= (S.Kills != SavedKills) || (S.Consumes != SavedConsumes);
            }
        }
    } while (Changed);
}

bool SuspendCrossingInfo::hasPathCrossingSuspendPoint(BasicBlock* DefBB, BasicBlock* UseBB) const {
    size_t const DefIndex = Mapping.blockToIndex(DefBB);
    size_t const UseIndex = Mapping.blockToIndex(UseBB);

    IGC_ASSERT_MESSAGE(Block[UseIndex].Consumes[DefIndex], "use must consume def");
    bool const Result = Block[UseIndex].Kills[DefIndex];
    return Result;
}

bool SuspendCrossingInfo::isDefinitionAcrossSuspend(BasicBlock* DefBB, User* U) const {
    auto* I = cast<Instruction>(U);

    // We rewrote PHINodes, so that only the ones with exactly one incoming
    // value need to be analyzed.
    if (auto* PN = dyn_cast<PHINode>(I))
        if (PN->getNumIncomingValues() > 1)
            return false;

    BasicBlock* UseBB = I->getParent();
    return hasPathCrossingSuspendPoint(DefBB, UseBB);
}

bool SuspendCrossingInfo::isDefinitionAcrossSuspend(Argument& A, User* U) const {
    return isDefinitionAcrossSuspend(&A.getParent()->getEntryBlock(), U);
}

bool SuspendCrossingInfo::isDefinitionAcrossSuspend(Instruction& I, User* U) const {
    return isDefinitionAcrossSuspend(I.getParent(), U);
}