function.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  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/val/function.h"
  15. #include <algorithm>
  16. #include <cassert>
  17. #include <sstream>
  18. #include <unordered_map>
  19. #include <unordered_set>
  20. #include <utility>
  21. #include "source/cfa.h"
  22. #include "source/val/basic_block.h"
  23. #include "source/val/construct.h"
  24. #include "source/val/validate.h"
  25. namespace spvtools {
  26. namespace val {
  27. // Universal Limit of ResultID + 1
  28. static const uint32_t kInvalidId = 0x400000;
  29. Function::Function(uint32_t function_id, uint32_t result_type_id,
  30. SpvFunctionControlMask function_control,
  31. uint32_t function_type_id)
  32. : id_(function_id),
  33. function_type_id_(function_type_id),
  34. result_type_id_(result_type_id),
  35. function_control_(function_control),
  36. declaration_type_(FunctionDecl::kFunctionDeclUnknown),
  37. end_has_been_registered_(false),
  38. blocks_(),
  39. current_block_(nullptr),
  40. pseudo_entry_block_(0),
  41. pseudo_exit_block_(kInvalidId),
  42. cfg_constructs_(),
  43. variable_ids_(),
  44. parameter_ids_() {}
  45. bool Function::IsFirstBlock(uint32_t block_id) const {
  46. return !ordered_blocks_.empty() && *first_block() == block_id;
  47. }
  48. spv_result_t Function::RegisterFunctionParameter(uint32_t parameter_id,
  49. uint32_t type_id) {
  50. assert(current_block_ == nullptr &&
  51. "RegisterFunctionParameter can only be called when parsing the binary "
  52. "outside of a block");
  53. // TODO(umar): Validate function parameter type order and count
  54. // TODO(umar): Use these variables to validate parameter type
  55. (void)parameter_id;
  56. (void)type_id;
  57. return SPV_SUCCESS;
  58. }
  59. spv_result_t Function::RegisterLoopMerge(uint32_t merge_id,
  60. uint32_t continue_id) {
  61. RegisterBlock(merge_id, false);
  62. RegisterBlock(continue_id, false);
  63. BasicBlock& merge_block = blocks_.at(merge_id);
  64. BasicBlock& continue_target_block = blocks_.at(continue_id);
  65. assert(current_block_ &&
  66. "RegisterLoopMerge must be called when called within a block");
  67. current_block_->RegisterStructuralSuccessor(&merge_block);
  68. current_block_->RegisterStructuralSuccessor(&continue_target_block);
  69. current_block_->set_type(kBlockTypeLoop);
  70. merge_block.set_type(kBlockTypeMerge);
  71. continue_target_block.set_type(kBlockTypeContinue);
  72. Construct& loop_construct =
  73. AddConstruct({ConstructType::kLoop, current_block_, &merge_block});
  74. Construct& continue_construct =
  75. AddConstruct({ConstructType::kContinue, &continue_target_block});
  76. continue_construct.set_corresponding_constructs({&loop_construct});
  77. loop_construct.set_corresponding_constructs({&continue_construct});
  78. merge_block_header_[&merge_block] = current_block_;
  79. if (continue_target_headers_.find(&continue_target_block) ==
  80. continue_target_headers_.end()) {
  81. continue_target_headers_[&continue_target_block] = {current_block_};
  82. } else {
  83. continue_target_headers_[&continue_target_block].push_back(current_block_);
  84. }
  85. return SPV_SUCCESS;
  86. }
  87. spv_result_t Function::RegisterSelectionMerge(uint32_t merge_id) {
  88. RegisterBlock(merge_id, false);
  89. BasicBlock& merge_block = blocks_.at(merge_id);
  90. current_block_->set_type(kBlockTypeSelection);
  91. merge_block.set_type(kBlockTypeMerge);
  92. merge_block_header_[&merge_block] = current_block_;
  93. current_block_->RegisterStructuralSuccessor(&merge_block);
  94. AddConstruct({ConstructType::kSelection, current_block(), &merge_block});
  95. return SPV_SUCCESS;
  96. }
  97. spv_result_t Function::RegisterSetFunctionDeclType(FunctionDecl type) {
  98. assert(declaration_type_ == FunctionDecl::kFunctionDeclUnknown);
  99. declaration_type_ = type;
  100. return SPV_SUCCESS;
  101. }
  102. spv_result_t Function::RegisterBlock(uint32_t block_id, bool is_definition) {
  103. assert(
  104. declaration_type_ == FunctionDecl::kFunctionDeclDefinition &&
  105. "RegisterBlocks can only be called after declaration_type_ is defined");
  106. std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block;
  107. bool success = false;
  108. tie(inserted_block, success) =
  109. blocks_.insert({block_id, BasicBlock(block_id)});
  110. if (is_definition) { // new block definition
  111. assert(current_block_ == nullptr &&
  112. "Register Block can only be called when parsing a binary outside of "
  113. "a BasicBlock");
  114. undefined_blocks_.erase(block_id);
  115. current_block_ = &inserted_block->second;
  116. ordered_blocks_.push_back(current_block_);
  117. } else if (success) { // Block doesn't exist but this is not a definition
  118. undefined_blocks_.insert(block_id);
  119. }
  120. return SPV_SUCCESS;
  121. }
  122. void Function::RegisterBlockEnd(std::vector<uint32_t> next_list) {
  123. assert(
  124. current_block_ &&
  125. "RegisterBlockEnd can only be called when parsing a binary in a block");
  126. std::vector<BasicBlock*> next_blocks;
  127. next_blocks.reserve(next_list.size());
  128. std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block;
  129. bool success;
  130. for (uint32_t successor_id : next_list) {
  131. tie(inserted_block, success) =
  132. blocks_.insert({successor_id, BasicBlock(successor_id)});
  133. if (success) {
  134. undefined_blocks_.insert(successor_id);
  135. }
  136. next_blocks.push_back(&inserted_block->second);
  137. }
  138. if (current_block_->is_type(kBlockTypeLoop)) {
  139. // For each loop header, record the set of its successors, and include
  140. // its continue target if the continue target is not the loop header
  141. // itself.
  142. std::vector<BasicBlock*>& next_blocks_plus_continue_target =
  143. loop_header_successors_plus_continue_target_map_[current_block_];
  144. next_blocks_plus_continue_target = next_blocks;
  145. auto continue_target =
  146. FindConstructForEntryBlock(current_block_, ConstructType::kLoop)
  147. .corresponding_constructs()
  148. .back()
  149. ->entry_block();
  150. if (continue_target != current_block_) {
  151. next_blocks_plus_continue_target.push_back(continue_target);
  152. }
  153. }
  154. current_block_->RegisterSuccessors(next_blocks);
  155. current_block_ = nullptr;
  156. return;
  157. }
  158. void Function::RegisterFunctionEnd() {
  159. if (!end_has_been_registered_) {
  160. end_has_been_registered_ = true;
  161. ComputeAugmentedCFG();
  162. }
  163. }
  164. size_t Function::block_count() const { return blocks_.size(); }
  165. size_t Function::undefined_block_count() const {
  166. return undefined_blocks_.size();
  167. }
  168. const std::vector<BasicBlock*>& Function::ordered_blocks() const {
  169. return ordered_blocks_;
  170. }
  171. std::vector<BasicBlock*>& Function::ordered_blocks() { return ordered_blocks_; }
  172. const BasicBlock* Function::current_block() const { return current_block_; }
  173. BasicBlock* Function::current_block() { return current_block_; }
  174. const std::list<Construct>& Function::constructs() const {
  175. return cfg_constructs_;
  176. }
  177. std::list<Construct>& Function::constructs() { return cfg_constructs_; }
  178. const BasicBlock* Function::first_block() const {
  179. if (ordered_blocks_.empty()) return nullptr;
  180. return ordered_blocks_[0];
  181. }
  182. BasicBlock* Function::first_block() {
  183. if (ordered_blocks_.empty()) return nullptr;
  184. return ordered_blocks_[0];
  185. }
  186. bool Function::IsBlockType(uint32_t merge_block_id, BlockType type) const {
  187. bool ret = false;
  188. const BasicBlock* block;
  189. std::tie(block, std::ignore) = GetBlock(merge_block_id);
  190. if (block) {
  191. ret = block->is_type(type);
  192. }
  193. return ret;
  194. }
  195. std::pair<const BasicBlock*, bool> Function::GetBlock(uint32_t block_id) const {
  196. const auto b = blocks_.find(block_id);
  197. if (b != end(blocks_)) {
  198. const BasicBlock* block = &(b->second);
  199. bool defined =
  200. undefined_blocks_.find(block->id()) == std::end(undefined_blocks_);
  201. return std::make_pair(block, defined);
  202. } else {
  203. return std::make_pair(nullptr, false);
  204. }
  205. }
  206. std::pair<BasicBlock*, bool> Function::GetBlock(uint32_t block_id) {
  207. const BasicBlock* out;
  208. bool defined;
  209. std::tie(out, defined) =
  210. const_cast<const Function*>(this)->GetBlock(block_id);
  211. return std::make_pair(const_cast<BasicBlock*>(out), defined);
  212. }
  213. Function::GetBlocksFunction Function::AugmentedCFGSuccessorsFunction() const {
  214. return [this](const BasicBlock* block) {
  215. auto where = augmented_successors_map_.find(block);
  216. return where == augmented_successors_map_.end() ? block->successors()
  217. : &(*where).second;
  218. };
  219. }
  220. Function::GetBlocksFunction Function::AugmentedCFGPredecessorsFunction() const {
  221. return [this](const BasicBlock* block) {
  222. auto where = augmented_predecessors_map_.find(block);
  223. return where == augmented_predecessors_map_.end() ? block->predecessors()
  224. : &(*where).second;
  225. };
  226. }
  227. Function::GetBlocksFunction Function::AugmentedStructuralCFGSuccessorsFunction()
  228. const {
  229. return [this](const BasicBlock* block) {
  230. auto where = augmented_successors_map_.find(block);
  231. return where == augmented_successors_map_.end()
  232. ? block->structural_successors()
  233. : &(*where).second;
  234. };
  235. }
  236. Function::GetBlocksFunction
  237. Function::AugmentedStructuralCFGPredecessorsFunction() const {
  238. return [this](const BasicBlock* block) {
  239. auto where = augmented_predecessors_map_.find(block);
  240. return where == augmented_predecessors_map_.end()
  241. ? block->structural_predecessors()
  242. : &(*where).second;
  243. };
  244. }
  245. void Function::ComputeAugmentedCFG() {
  246. // Compute the successors of the pseudo-entry block, and
  247. // the predecessors of the pseudo exit block.
  248. auto succ_func = [](const BasicBlock* b) {
  249. return b->structural_successors();
  250. };
  251. auto pred_func = [](const BasicBlock* b) {
  252. return b->structural_predecessors();
  253. };
  254. CFA<BasicBlock>::ComputeAugmentedCFG(
  255. ordered_blocks_, &pseudo_entry_block_, &pseudo_exit_block_,
  256. &augmented_successors_map_, &augmented_predecessors_map_, succ_func,
  257. pred_func);
  258. }
  259. Construct& Function::AddConstruct(const Construct& new_construct) {
  260. cfg_constructs_.push_back(new_construct);
  261. auto& result = cfg_constructs_.back();
  262. entry_block_to_construct_[std::make_pair(new_construct.entry_block(),
  263. new_construct.type())] = &result;
  264. return result;
  265. }
  266. Construct& Function::FindConstructForEntryBlock(const BasicBlock* entry_block,
  267. ConstructType type) {
  268. auto where =
  269. entry_block_to_construct_.find(std::make_pair(entry_block, type));
  270. assert(where != entry_block_to_construct_.end());
  271. auto construct_ptr = (*where).second;
  272. assert(construct_ptr);
  273. return *construct_ptr;
  274. }
  275. int Function::GetBlockDepth(BasicBlock* bb) {
  276. // Guard against nullptr.
  277. if (!bb) {
  278. return 0;
  279. }
  280. // Only calculate the depth if it's not already calculated.
  281. // This function uses memoization to avoid duplicate CFG depth calculations.
  282. if (block_depth_.find(bb) != block_depth_.end()) {
  283. return block_depth_[bb];
  284. }
  285. // Avoid recursion. Something is wrong if the same block is encountered
  286. // multiple times.
  287. block_depth_[bb] = 0;
  288. BasicBlock* bb_dom = bb->immediate_dominator();
  289. if (!bb_dom || bb == bb_dom) {
  290. // This block has no dominator, so it's at depth 0.
  291. block_depth_[bb] = 0;
  292. } else if (bb->is_type(kBlockTypeContinue)) {
  293. // This rule must precede the rule for merge blocks in order to set up
  294. // depths correctly. If a block is both a merge and continue then the merge
  295. // is nested within the continue's loop (or the graph is incorrect).
  296. // The depth of the continue block entry point is 1 + loop header depth.
  297. Construct* continue_construct =
  298. entry_block_to_construct_[std::make_pair(bb, ConstructType::kContinue)];
  299. assert(continue_construct);
  300. // Continue construct has only 1 corresponding construct (loop header).
  301. Construct* loop_construct =
  302. continue_construct->corresponding_constructs()[0];
  303. assert(loop_construct);
  304. BasicBlock* loop_header = loop_construct->entry_block();
  305. // The continue target may be the loop itself (while 1).
  306. // In such cases, the depth of the continue block is: 1 + depth of the
  307. // loop's dominator block.
  308. if (loop_header == bb) {
  309. block_depth_[bb] = 1 + GetBlockDepth(bb_dom);
  310. } else {
  311. block_depth_[bb] = 1 + GetBlockDepth(loop_header);
  312. }
  313. } else if (bb->is_type(kBlockTypeMerge)) {
  314. // If this is a merge block, its depth is equal to the block before
  315. // branching.
  316. BasicBlock* header = merge_block_header_[bb];
  317. assert(header);
  318. block_depth_[bb] = GetBlockDepth(header);
  319. } else if (bb_dom->is_type(kBlockTypeSelection) ||
  320. bb_dom->is_type(kBlockTypeLoop)) {
  321. // The dominator of the given block is a header block. So, the nesting
  322. // depth of this block is: 1 + nesting depth of the header.
  323. block_depth_[bb] = 1 + GetBlockDepth(bb_dom);
  324. } else {
  325. block_depth_[bb] = GetBlockDepth(bb_dom);
  326. }
  327. return block_depth_[bb];
  328. }
  329. void Function::RegisterExecutionModelLimitation(SpvExecutionModel model,
  330. const std::string& message) {
  331. execution_model_limitations_.push_back(
  332. [model, message](SpvExecutionModel in_model, std::string* out_message) {
  333. if (model != in_model) {
  334. if (out_message) {
  335. *out_message = message;
  336. }
  337. return false;
  338. }
  339. return true;
  340. });
  341. }
  342. bool Function::IsCompatibleWithExecutionModel(SpvExecutionModel model,
  343. std::string* reason) const {
  344. bool return_value = true;
  345. std::stringstream ss_reason;
  346. for (const auto& is_compatible : execution_model_limitations_) {
  347. std::string message;
  348. if (!is_compatible(model, &message)) {
  349. if (!reason) return false;
  350. return_value = false;
  351. if (!message.empty()) {
  352. ss_reason << message << "\n";
  353. }
  354. }
  355. }
  356. if (!return_value && reason) {
  357. *reason = ss_reason.str();
  358. }
  359. return return_value;
  360. }
  361. bool Function::CheckLimitations(const ValidationState_t& _,
  362. const Function* entry_point,
  363. std::string* reason) const {
  364. bool return_value = true;
  365. std::stringstream ss_reason;
  366. for (const auto& is_compatible : limitations_) {
  367. std::string message;
  368. if (!is_compatible(_, entry_point, &message)) {
  369. if (!reason) return false;
  370. return_value = false;
  371. if (!message.empty()) {
  372. ss_reason << message << "\n";
  373. }
  374. }
  375. }
  376. if (!return_value && reason) {
  377. *reason = ss_reason.str();
  378. }
  379. return return_value;
  380. }
  381. } // namespace val
  382. } // namespace spvtools