3rdparty/bgfx/3rdparty/glslang/glslang/MachineIndependent/linkValidate.cpp
//
// See which functions are reachable from the entry point and which have bodies.
// Reachable ones with missing bodies are errors.
// Unreachable bodies are dead code.
//
See which functions are reachable from the entry point and which have bodies.
Reachable ones with missing bodies are errors.
Unreachable bodies are dead code.
See which functions are reachable from the entry point and which have bodies . Reachable ones with missing bodies are errors . Unreachable bodies are dead code .
void TIntermediate::checkCallGraphBodies(TInfoSink& infoSink, bool keepUncalled)
{
    for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
        call->visited = false;
        call->calleeBodyPosition = -1;
    }
    TIntermSequence &functionSequence = getTreeRoot()->getAsAggregate()->getSequence();
    std::vector<bool> reachable(functionSequence.size(), true); 
    for (int f = 0; f < (int)functionSequence.size(); ++f) {
        glslang::TIntermAggregate* node = functionSequence[f]->getAsAggregate();
        if (node && (node->getOp() == glslang::EOpFunction)) {
            if (node->getName().compare(getEntryPointMangledName().c_str()) != 0)
                reachable[f] = false; 
            for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
                if (call->callee == node->getName())
                    call->calleeBodyPosition = f;
            }
        }
    }
    for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
        if (call->caller.compare(getEntryPointMangledName().c_str()) == 0)
            call->visited = true;
    }
    bool changed;
    do {
        changed = false;
        for (auto call1 = callGraph.begin(); call1 != callGraph.end(); ++call1) {
            if (call1->visited) {
                for (TGraph::iterator call2 = callGraph.begin(); call2 != callGraph.end(); ++call2) {
                    if (! call2->visited) {
                        if (call1->callee == call2->caller) {
                            changed = true;
                            call2->visited = true;
                        }
                    }
                }
            }
        }
    } while (changed);
    for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
        if (call->visited) {
            if (call->calleeBodyPosition == -1) {
                error(infoSink, "No function definition (body) found: ");
                infoSink.info << "    " << call->callee << "\n";
            } else
                reachable[call->calleeBodyPosition] = true;
        }
    }
    if (! keepUncalled) {
        for (int f = 0; f < (int)functionSequence.size(); ++f) {
            if (! reachable[f])
                functionSequence[f] = nullptr;
        }
        functionSequence.erase(std::remove(functionSequence.begin(), functionSequence.end(), nullptr), functionSequence.end());
    }
}
void TIntermediate :: checkCallGraphBodies ( TInfoSink & infoSink , bool keepUncalled ) { for ( TGraph :: iterator call = callGraph . begin ( ) ; call != callGraph . end ( ) ; ++ call ) { call -> visited = false ; call -> calleeBodyPosition = -1 ; } TIntermSequence & functionSequence = getTreeRoot ( ) -> getAsAggregate ( ) -> getSequence ( ) ; std :: vector < bool > reachable ( functionSequence . size ( ) , true ) ; for ( int f = 0 ; f < ( int ) functionSequence . size ( ) ; ++ f ) { glslang :: TIntermAggregate * node = functionSequence [ f ] -> getAsAggregate ( ) ; if ( node && ( node -> getOp ( ) == glslang :: EOpFunction ) ) { if ( node -> getName ( ) . compare ( getEntryPointMangledName ( ) . c_str ( ) ) != 0 ) reachable [ f ] = false ; for ( TGraph :: iterator call = callGraph . begin ( ) ; call != callGraph . end ( ) ; ++ call ) { if ( call -> callee == node -> getName ( ) ) call -> calleeBodyPosition = f ; } } } for ( TGraph :: iterator call = callGraph . begin ( ) ; call != callGraph . end ( ) ; ++ call ) { if ( call -> caller . compare ( getEntryPointMangledName ( ) . c_str ( ) ) == 0 ) call -> visited = true ; } bool changed ; do { changed = false ; for ( auto call1 = callGraph . begin ( ) ; call1 != callGraph . end ( ) ; ++ call1 ) { if ( call1 -> visited ) { for ( TGraph :: iterator call2 = callGraph . begin ( ) ; call2 != callGraph . end ( ) ; ++ call2 ) { if ( ! call2 -> visited ) { if ( call1 -> callee == call2 -> caller ) { changed = true ; call2 -> visited = true ; } } } } } } while ( changed ) ; for ( TGraph :: iterator call = callGraph . begin ( ) ; call != callGraph . end ( ) ; ++ call ) { if ( call -> visited ) { if ( call -> calleeBodyPosition == -1 ) { error ( infoSink , " " ) ; infoSink . info << " " << call -> callee << " \n " ; } else reachable [ call -> calleeBodyPosition ] = true ; } } if ( ! keepUncalled ) { for ( int f = 0 ; f < ( int ) functionSequence . size ( ) ; ++ f ) { if ( ! reachable [ f ] ) functionSequence [ f ] = nullptr ; } functionSequence . erase ( std :: remove ( functionSequence . begin ( ) , functionSequence . end ( ) , nullptr ) , functionSequence . end ( ) ) ; } }
See which functions are reachable from the entry point and which have bodies.
See which functions are reachable from the entry point and which have bodies .
// Clear fields we'll use for this. // The top level of the AST includes function definitions (bodies). // Compare these to function calls in the call graph. // We'll end up knowing which have bodies, and if so, // how to map the call-graph node to the location in the AST. // so that non-functions are reachable // so that function bodies are unreachable, until proven otherwise // Start call-graph traversal by visiting the entry point nodes. // Propagate 'visited' through the call-graph to every part of the graph it // can reach (seeded with the entry-point setting above). // Any call-graph node set to visited but without a callee body is an error. // Bodies in the AST not reached by the call graph are dead; // clear them out, since they can't be reached and also can't // be translated further due to possibility of being ill defined.