summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-reachability.cpp
blob: 5a9d732caf16e3c201a98bdc461b84a8524e41a9 (plain)
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
#include "slang-ir-reachability.h"
#include "slang-ir-insts.h"
#include "slang-ir-util.h"

namespace Slang
{
    // Computes whether block1 can reach block2.
    // A block is considered not reachable from itself unless there is a backedge in the CFG.
    ReachabilityContext::ReachabilityContext(IRGlobalValueWithCode* code)
    {
        int id = 0;
        for (auto block : code->getBlocks())
        {
            mapBlockToId[block] = id++;
            allBlocks.add(block);
        }

        sourceBlocks.setCount(allBlocks.getCount());
        for (auto &srcBlock : sourceBlocks)
            srcBlock.resizeAndClear(allBlocks.getCount());

        if (allBlocks.getCount() == 0)
            return;

        List<IRBlock*> workList;
        List<IRBlock*> pendingWorkList;

        workList.add(allBlocks[0]);
        while (workList.getCount())
        {
            pendingWorkList.clear();
            for (Index i = 0; i < workList.getCount(); i++)
            {
                auto src = workList[i];
                auto srcId = mapBlockToId.getValue(src);
                for (auto successor : src->getSuccessors())
                {
                    auto successorId = mapBlockToId.getValue(successor);
                    auto& blockSet = sourceBlocks[successorId];
                    bool changed = false;
                    if (!blockSet.contains(srcId))
                    {
                        blockSet.add(srcId);
                        changed = true;
                    }
                    if (!blockSet.contains(sourceBlocks[srcId]))
                    {
                        blockSet.unionWith(sourceBlocks[srcId]);
                        changed = true;
                    }
                    if (changed)
                        pendingWorkList.add(successor);
                }
            }
            workList.swapWith(pendingWorkList);
        }
    }
    
    bool ReachabilityContext::isInstReachable(IRInst* from, IRInst* to)
    {
        // If inst1 and inst2 are in the same block,
        // we test if inst2 appears after inst1.
        if (getBlock(from) == getBlock(to))
        {
            for (auto inst = from->getNextInst(); inst; inst = inst->getNextInst())
            {
                if (inst == to)
                    return true;
            }
        }

        return isBlockReachable(getBlock(from), getBlock(to));
    }

    bool ReachabilityContext::isBlockReachable(IRBlock* from, IRBlock* to)
    {
        if (!from)
            return false;

        if (!to)
            return false;

        int* fromId = mapBlockToId.tryGetValue(from);
        int* toId = mapBlockToId.tryGetValue(to);
        if (!fromId || !toId)
            return true;

        return sourceBlocks[*toId].contains(*fromId);
    }
}