call_graph.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // Copyright (c) 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/call_graph.h"
  15. #include <queue>
  16. namespace spvtools {
  17. namespace fuzz {
  18. CallGraph::CallGraph(opt::IRContext* context) {
  19. // Initialize function in-degree and call graph edges to 0 and empty.
  20. for (auto& function : *context->module()) {
  21. function_in_degree_[function.result_id()] = 0;
  22. call_graph_edges_[function.result_id()] = std::set<uint32_t>();
  23. }
  24. // Consider every function.
  25. for (auto& function : *context->module()) {
  26. // Avoid considering the same callee of this function multiple times by
  27. // recording known callees.
  28. std::set<uint32_t> known_callees;
  29. // Consider every function call instruction in every block.
  30. for (auto& block : function) {
  31. for (auto& instruction : block) {
  32. if (instruction.opcode() != SpvOpFunctionCall) {
  33. continue;
  34. }
  35. // Get the id of the function being called.
  36. uint32_t callee = instruction.GetSingleWordInOperand(0);
  37. if (known_callees.count(callee)) {
  38. // We have already considered a call to this function - ignore it.
  39. continue;
  40. }
  41. // Increase the callee's in-degree and add an edge to the call graph.
  42. function_in_degree_[callee]++;
  43. call_graph_edges_[function.result_id()].insert(callee);
  44. // Mark the callee as 'known'.
  45. known_callees.insert(callee);
  46. }
  47. }
  48. }
  49. }
  50. void CallGraph::PushDirectCallees(uint32_t function_id,
  51. std::queue<uint32_t>* queue) const {
  52. for (auto callee : GetDirectCallees(function_id)) {
  53. queue->push(callee);
  54. }
  55. }
  56. std::set<uint32_t> CallGraph::GetIndirectCallees(uint32_t function_id) const {
  57. std::set<uint32_t> result;
  58. std::queue<uint32_t> queue;
  59. PushDirectCallees(function_id, &queue);
  60. while (!queue.empty()) {
  61. auto next = queue.front();
  62. queue.pop();
  63. if (result.count(next)) {
  64. continue;
  65. }
  66. result.insert(next);
  67. PushDirectCallees(next, &queue);
  68. }
  69. return result;
  70. }
  71. } // namespace fuzz
  72. } // namespace spvtools