control_flow.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /* ScummVM Tools
  2. *
  3. * ScummVM Tools is the legal property of its developers, whose
  4. * names are too numerous to list here. Please refer to the
  5. * COPYRIGHT file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. */
  21. #include "decompiler/control_flow.h"
  22. #include "decompiler/stack.h"
  23. #include <algorithm>
  24. #include <iostream>
  25. #include <set>
  26. #include <boost/format.hpp>
  27. #define PUT(vertex, group) boost::put(boost::vertex_name, _g, vertex, group);
  28. #define PUT_EDGE(edge, isJump) boost::put(boost::edge_attribute, _g, edge, isJump);
  29. #define PUT_ID(vertex, id) boost::put(boost::vertex_index, _g, vertex, id);
  30. #define GET(vertex) (boost::get(boost::vertex_name, _g, vertex))
  31. #define GET_EDGE(edge) (boost::get(boost::edge_attribute, _g, edge))
  32. ControlFlow::ControlFlow(InstVec& insts, Engine& engine)
  33. : mInsts(insts),
  34. mEngine(engine)
  35. {
  36. // Automatically add a function if we're not supposed to look for more functions and no functions are defined
  37. // This avoids a special case for when no real functions exist in the script
  38. if (mEngine._functions.empty())
  39. {
  40. mEngine._functions[(*insts.begin())->_address] = Function((*insts.begin())->_address, (insts.back())->_address);
  41. }
  42. GroupPtr prev = NULL;
  43. int id = 0;
  44. // Create vertices
  45. for (InstIterator it = insts.begin(); it != insts.end(); ++it) {
  46. GraphVertex cur = boost::add_vertex(_g);
  47. _addrMap[(*it)->_address] = cur;
  48. PUT(cur, new Group(cur, it, it, prev));
  49. PUT_ID(cur, id);
  50. id++;
  51. // Add reference to vertex if function starts here
  52. if (mEngine._functions.find((*it)->_address) != mEngine._functions.end())
  53. mEngine._functions[(*it)->_address]._v = cur;
  54. prev = GET(cur);
  55. }
  56. // Add regular edges
  57. FuncMap::iterator fn;
  58. GraphVertex last = {};
  59. bool addEdge = false;
  60. prev = NULL;
  61. for (InstIterator it = insts.begin(); it != insts.end(); ++it) {
  62. if (mEngine._functions.find((*it)->_address) != mEngine._functions.end()) {
  63. addEdge = false;
  64. }
  65. GraphVertex cur = find(it);
  66. if (addEdge) {
  67. GraphEdge e = boost::add_edge(last, cur, _g).first;
  68. PUT_EDGE(e, false);
  69. }
  70. last = cur;
  71. addEdge = !((*it)->IsUncondJump() || (*it)->isReturn());
  72. prev = GET(cur);
  73. }
  74. // Add jump edges
  75. for (InstIterator it = insts.begin(); it != insts.end(); ++it) {
  76. if ((*it)->isJump()) {
  77. GraphEdge e = boost::add_edge(find(it), find((*it)->GetDestAddress()), _g).first;
  78. PUT_EDGE(e, true);
  79. }
  80. }
  81. }
  82. GraphVertex ControlFlow::find(const InstPtr inst) {
  83. return _addrMap[inst->_address];
  84. }
  85. GraphVertex ControlFlow::find(ConstInstIterator it) {
  86. return _addrMap[(*it)->_address];
  87. }
  88. GraphVertex ControlFlow::find(uint32 address) {
  89. std::map<uint32, GraphVertex>::iterator it = _addrMap.find(address);
  90. if (it == _addrMap.end())
  91. std::cerr << "Request for instruction at unknown address " << boost::format("0x%08x") % address << std::endl;
  92. return it->second;
  93. }
  94. void ControlFlow::merge(GraphVertex g1, GraphVertex g2) {
  95. // Update property
  96. GroupPtr gr1 = GET(g1);
  97. GroupPtr gr2 = GET(g2);
  98. gr1->end_ = gr2->end_;
  99. PUT(g1, gr1);
  100. // Update address map
  101. ConstInstIterator it = gr2->start_;
  102. do {
  103. _addrMap[(*it)->_address] = g1;
  104. ++it;
  105. } while (gr2->start_ != gr2->end_ && it != gr2->end_);
  106. // Add outgoing edges from g2
  107. OutEdgeRange r = boost::out_edges(g2, _g);
  108. for (OutEdgeIterator e = r.first; e != r.second; ++e) {
  109. GraphEdge newE = boost::add_edge(g1, boost::target(*e, _g), _g).first;
  110. PUT_EDGE(newE, GET_EDGE(*e));
  111. }
  112. // Update _next pointer
  113. gr1->_next = gr2->_next;
  114. if (gr2->_next != NULL)
  115. gr2->_next->_prev = gr2->_prev;
  116. // Remove edges to/from g2
  117. boost::clear_vertex(g2, _g);
  118. // Remove vertex
  119. boost::remove_vertex(g2, _g);
  120. }
  121. typedef std::pair<GraphVertex, int> LevelEntry;
  122. void ControlFlow::setStackLevel(GraphVertex g, int level) {
  123. Stack<LevelEntry> levelStack;
  124. std::set<GraphVertex> seen;
  125. levelStack.push(LevelEntry(g, level));
  126. seen.insert(g);
  127. while (!levelStack.empty()) {
  128. LevelEntry e = levelStack.pop();
  129. GroupPtr gr = GET(e.first);
  130. if (gr->_stackLevel != -1) {
  131. if (gr->_stackLevel != e.second)
  132. std::cerr << boost::format("WARNING: Inconsistency in expected stack level for instruction at address 0x%08x (current: %d, requested: %d)\n") % (*gr->start_)->_address % gr->_stackLevel % e.second;
  133. continue;
  134. }
  135. gr->_stackLevel = e.second;
  136. OutEdgeRange r = boost::out_edges(e.first, _g);
  137. for (OutEdgeIterator oe = r.first; oe != r.second; ++oe) {
  138. GraphVertex target = boost::target(*oe, _g);
  139. if (seen.find(target) == seen.end()) {
  140. levelStack.push(LevelEntry(target, e.second + (*gr->start_)->_stackChange));
  141. seen.insert(target);
  142. }
  143. }
  144. }
  145. }
  146. void ControlFlow::createGroups()
  147. {
  148. if (!mEngine._functions.empty() && GET(mEngine._functions.begin()->second._v)->_stackLevel != -1)
  149. {
  150. return;
  151. }
  152. for (FuncMap::iterator fn = mEngine._functions.begin(); fn != mEngine._functions.end(); ++fn)
  153. setStackLevel(fn->second._v, 0);
  154. ConstInstIterator curInst, nextInst;
  155. nextInst = mInsts.begin();
  156. nextInst++;
  157. int stackLevel = 0;
  158. int expectedStackLevel = 0;
  159. for (curInst = mInsts.begin(); nextInst != mInsts.end(); ++curInst, ++nextInst) {
  160. GraphVertex cur = find(curInst);
  161. GraphVertex next = find(nextInst);
  162. GroupPtr grCur = GET(cur);
  163. GroupPtr grNext = GET(next);
  164. // Don't process unreachable code
  165. if (grCur->_stackLevel < 0) {
  166. stackLevel = grNext->_stackLevel;
  167. continue;
  168. }
  169. expectedStackLevel = grCur->_stackLevel;
  170. // If expected stack level decreases in next vertex, then use next vertex level as expected level
  171. if (expectedStackLevel > grNext->_stackLevel && grNext->_stackLevel >= 0) {
  172. expectedStackLevel = grNext->_stackLevel;
  173. // Also set the stack level of the current group to remember that we expect it to be lower
  174. grCur->_stackLevel = expectedStackLevel;
  175. }
  176. stackLevel += (*curInst)->_stackChange;
  177. // For stack operations, the new stack level becomes the expected stack level starting from the next group
  178. if ((*curInst)->isStackOp()) {
  179. expectedStackLevel = stackLevel;
  180. grNext->_stackLevel = stackLevel;
  181. }
  182. // Group ends after a jump
  183. if ((*curInst)->isJump()) {
  184. stackLevel = grNext->_stackLevel;
  185. continue;
  186. }
  187. // Group ends with a return
  188. if ((*curInst)->isReturn()) {
  189. stackLevel = grNext->_stackLevel;
  190. continue;
  191. }
  192. // Group ends before target of a jump
  193. if (in_degree(next, _g) != 1) {
  194. stackLevel = grNext->_stackLevel;
  195. continue;
  196. }
  197. // This part is only relevant if we use the stack level.
  198. if (!mEngine.UsePureGrouping()) {
  199. // If group has no instructions with stack effect >= 0, don't merge on balanced stack
  200. bool forceMerge = true;
  201. ConstInstIterator it = grCur->start_;
  202. do {
  203. if ((*it)->_stackChange >= 0)
  204. forceMerge = false;
  205. ++it;
  206. } while (grCur->start_ != grCur->end_ && it != grCur->end_);
  207. // Group ends when stack is balanced, unless just before conditional jump
  208. if (stackLevel == expectedStackLevel && !forceMerge && !(*nextInst)->isCondJump()) {
  209. continue;
  210. }
  211. }
  212. // All checks passed, merge groups
  213. merge(cur, next);
  214. }
  215. // FIXME: The short-circuit detection is disabled because short-circuited groups require some special handling
  216. // in the code generation. It's not entirely clear how to handle it properly, though: you need to deduce which
  217. // effect is created by the conditional jumps in the middle of a block, which seems to get fairly complex when
  218. // you have multiple groups that are merged by the short-circuit detection.
  219. //detectShortCircuit();
  220. }
  221. void ControlFlow::detectShortCircuit() {
  222. ConstInstIterator lastInst = mInsts.end();
  223. --lastInst;
  224. GraphVertex cur = find(lastInst);
  225. GroupPtr gr = GET(cur);
  226. while (gr->_prev != NULL) {
  227. bool doMerge = false;
  228. cur = find(gr->start_);
  229. GraphVertex prev = find(gr->_prev->start_);
  230. // Block is candidate for short-circuit merging if it and the preceding block both end with conditional jumps
  231. if (out_degree(cur, _g) == 2 && out_degree(prev, _g) == 2) {
  232. doMerge = true;
  233. OutEdgeRange rCur = boost::out_edges(cur, _g);
  234. std::vector<GraphVertex> succs;
  235. // Find possible target vertices
  236. for (OutEdgeIterator it = rCur.first; it != rCur.second; ++it) {
  237. succs.push_back(boost::target(*it, _g));
  238. }
  239. // Check if vertex would add new targets - if yes, don't merge
  240. OutEdgeRange rPrev = boost::out_edges(prev, _g);
  241. for (OutEdgeIterator it = rPrev.first; it != rPrev.second; ++it) {
  242. GraphVertex target = boost::target(*it, _g);
  243. doMerge &= (std::find(succs.begin(), succs.end(), target) != succs.end() || target == cur);
  244. }
  245. if (doMerge) {
  246. gr = gr->_prev;
  247. merge(prev, cur);
  248. continue;
  249. }
  250. }
  251. gr = gr->_prev;
  252. }
  253. }
  254. const Graph &ControlFlow::analyze() {
  255. detectDoWhile();
  256. detectWhile();
  257. detectBreak();
  258. detectContinue();
  259. detectIf();
  260. detectElse();
  261. return _g;
  262. }
  263. void ControlFlow::detectWhile() {
  264. VertexRange vr = boost::vertices(_g);
  265. for (VertexIterator v = vr.first; v != vr.second; ++v) {
  266. GroupPtr gr = GET(*v);
  267. // Undetermined block that ends with conditional jump
  268. if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
  269. InEdgeRange ier = boost::in_edges(*v, _g);
  270. bool isWhile = false;
  271. for (InEdgeIterator e = ier.first; e != ier.second; ++e) {
  272. GroupPtr sourceGr = GET(boost::source(*e, _g));
  273. // Block has ingoing edge from block later in the code that isn't a do-while condition
  274. if ((*sourceGr->start_)->_address > (*gr->start_)->_address && sourceGr->_type != kDoWhileCondGroupType)
  275. isWhile = true;
  276. }
  277. if (isWhile)
  278. gr->_type = kWhileCondGroupType;
  279. }
  280. }
  281. }
  282. void ControlFlow::detectDoWhile() {
  283. VertexRange vr = boost::vertices(_g);
  284. for (VertexIterator v = vr.first; v != vr.second; ++v) {
  285. GroupPtr gr = GET(*v);
  286. // Undetermined block that ends with conditional jump...
  287. if (out_degree(*v, _g) == 2 && gr->_type == kNormalGroupType) {
  288. OutEdgeRange oer = boost::out_edges(*v, _g);
  289. for (OutEdgeIterator e = oer.first; e != oer.second; ++e) {
  290. GroupPtr targetGr = GET(boost::target(*e, _g));
  291. // ...to earlier in code
  292. if ((*targetGr->start_)->_address < (*gr->start_)->_address)
  293. gr->_type = kDoWhileCondGroupType;
  294. }
  295. }
  296. }
  297. }
  298. void ControlFlow::detectBreak() {
  299. VertexRange vr = boost::vertices(_g);
  300. for (VertexIterator v = vr.first; v != vr.second; ++v) {
  301. GroupPtr gr = GET(*v);
  302. // Undetermined block with unconditional jump...
  303. if (gr->_type == kNormalGroupType && ((*gr->end_)->IsUncondJump()) && out_degree(*v, _g) == 1) {
  304. OutEdgeIterator oe = boost::out_edges(*v, _g).first;
  305. GraphVertex target = boost::target(*oe, _g);
  306. GroupPtr targetGr = GET(target);
  307. // ...to somewhere later in the code...
  308. if ((*gr->start_)->_address >= (*targetGr->start_)->_address)
  309. continue;
  310. InEdgeRange ier = boost::in_edges(target, _g);
  311. for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
  312. GroupPtr sourceGr = GET(boost::source(*ie, _g));
  313. // ...to block immediately after a do-while condition, or to jump target of a while condition
  314. if ((targetGr->_prev == sourceGr && sourceGr->_type == kDoWhileCondGroupType) || sourceGr->_type == kWhileCondGroupType) {
  315. if (validateBreakOrContinue(gr, sourceGr))
  316. gr->_type = kBreakGroupType;
  317. }
  318. }
  319. }
  320. }
  321. }
  322. void ControlFlow::detectContinue() {
  323. VertexRange vr = boost::vertices(_g);
  324. for (VertexIterator v = vr.first; v != vr.second; ++v) {
  325. GroupPtr gr = GET(*v);
  326. // Undetermined block with unconditional jump...
  327. if (gr->_type == kNormalGroupType && ((*gr->end_)->IsUncondJump()) && out_degree(*v, _g) == 1) {
  328. OutEdgeIterator oe = boost::out_edges(*v, _g).first;
  329. GraphVertex target = boost::target(*oe, _g);
  330. GroupPtr targetGr = GET(target);
  331. // ...to a while or do-while condition...
  332. if (targetGr->_type == kWhileCondGroupType || targetGr->_type == kDoWhileCondGroupType) {
  333. bool isContinue = true;
  334. // ...unless...
  335. OutEdgeRange toer = boost::out_edges(target, _g);
  336. bool afterJumpTargets = true;
  337. for (OutEdgeIterator toe = toer.first; toe != toer.second; ++toe) {
  338. // ...it is targeting a while condition which jumps to the next sequential group
  339. if (targetGr->_type == kWhileCondGroupType && GET(boost::target(*toe, _g)) == gr->_next)
  340. isContinue = false;
  341. // ...or the instruction is placed after all jump targets from condition
  342. if ((*GET(boost::target(*toe, _g))->start_)->_address > (*gr->start_)->_address)
  343. afterJumpTargets = false;
  344. }
  345. if (afterJumpTargets)
  346. isContinue = false;
  347. if (isContinue && validateBreakOrContinue(gr, targetGr))
  348. gr->_type = kContinueGroupType;
  349. }
  350. }
  351. }
  352. }
  353. bool ControlFlow::validateBreakOrContinue(GroupPtr gr, GroupPtr condGr) {
  354. GroupPtr from, to, cursor;
  355. if (condGr->_type == kDoWhileCondGroupType) {
  356. to = condGr;
  357. from = gr;
  358. } else {
  359. to = gr;
  360. from = condGr->_next;
  361. }
  362. GroupType ogt = (condGr->_type == kDoWhileCondGroupType ? kWhileCondGroupType : kDoWhileCondGroupType);
  363. // Verify that destination deals with innermost while/do-while
  364. for (cursor = from; cursor->_next != NULL && cursor != to; cursor = cursor->_next) {
  365. if (cursor->_type == condGr->_type) {
  366. OutEdgeRange oerValidate = boost::out_edges(find(cursor->start_), _g);
  367. for (OutEdgeIterator oeValidate = oerValidate.first; oeValidate != oerValidate.second; ++oeValidate) {
  368. GraphVertex vValidate = boost::target(*oeValidate, _g);
  369. GroupPtr gValidate = GET(vValidate);
  370. // For all other loops of same type found in range, all targets must fall within that range
  371. if ((*gValidate->start_)->_address < (*from->start_)->_address || (*gValidate->start_)->_address > (*to->start_)->_address )
  372. return false;
  373. InEdgeRange ierValidate = boost::in_edges(vValidate, _g);
  374. for (InEdgeIterator ieValidate = ierValidate.first; ieValidate != ierValidate.second; ++ieValidate) {
  375. GroupPtr igValidate = GET(boost::source(*ieValidate, _g));
  376. // All loops of other type going into range must be placed within range
  377. if (igValidate->_type == ogt && ((*igValidate->start_)->_address < (*from->start_)->_address || (*igValidate->start_)->_address > (*to->start_)->_address ))
  378. return false;
  379. }
  380. }
  381. }
  382. }
  383. return true;
  384. }
  385. void ControlFlow::detectIf() {
  386. VertexRange vr = boost::vertices(_g);
  387. for (VertexIterator v = vr.first; v != vr.second; ++v) {
  388. GroupPtr gr = GET(*v);
  389. // if: Undetermined block with conditional jump
  390. if (gr->_type == kNormalGroupType && ((*gr->end_)->isCondJump())) {
  391. gr->_type = kIfCondGroupType;
  392. }
  393. }
  394. }
  395. void ControlFlow::detectElse() {
  396. VertexRange vr = boost::vertices(_g);
  397. for (VertexIterator v = vr.first; v != vr.second; ++v) {
  398. GroupPtr gr = GET(*v);
  399. if (gr->_type == kIfCondGroupType) {
  400. OutEdgeRange oer = boost::out_edges(*v, _g);
  401. GraphVertex target;
  402. uint32 maxAddress = 0;
  403. GroupPtr targetGr;
  404. // Find jump target
  405. for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
  406. targetGr = GET(boost::target(*oe, _g));
  407. if ((*targetGr->start_)->_address > maxAddress) {
  408. target = boost::target(*oe, _g);
  409. maxAddress = (*targetGr->start_)->_address;
  410. }
  411. }
  412. targetGr = GET(target);
  413. // else: Jump target of if immediately preceded by an unconditional jump...
  414. if (!(*targetGr->_prev->end_)->IsUncondJump())
  415. continue;
  416. // ...which is not a break or a continue...
  417. if (targetGr->_prev->_type == kContinueGroupType || targetGr->_prev->_type == kBreakGroupType)
  418. continue;
  419. // ...to later in the code
  420. OutEdgeIterator toe = boost::out_edges(find((*targetGr->_prev->start_)->_address), _g).first;
  421. GroupPtr targetTargetGr = GET(boost::target(*toe, _g));
  422. if ((*targetTargetGr->start_)->_address > (*targetGr->end_)->_address) {
  423. if (validateElseBlock(gr, targetGr, targetTargetGr)) {
  424. targetGr->_startElse = true;
  425. targetTargetGr->_prev->_endElse.push_back(targetGr.get());
  426. }
  427. }
  428. }
  429. }
  430. }
  431. bool ControlFlow::validateElseBlock(GroupPtr ifGroup, GroupPtr start, GroupPtr end) {
  432. for (GroupPtr cursor = start; cursor != end; cursor = cursor->_next) {
  433. if (cursor->_type == kIfCondGroupType || cursor->_type == kWhileCondGroupType || cursor->_type == kDoWhileCondGroupType) {
  434. // Validate outgoing edges of conditions
  435. OutEdgeRange oer = boost::out_edges(find(cursor->start_), _g);
  436. for (OutEdgeIterator oe = oer.first; oe != oer.second; ++oe) {
  437. GraphVertex target = boost::target(*oe, _g);
  438. GroupPtr targetGr = GET(target);
  439. // Each edge from condition must not leave the range [start, end]
  440. if ((*start->start_)->_address > (*targetGr->start_)->_address || (*targetGr->start_)->_address > (*end->start_)->_address)
  441. return false;
  442. }
  443. }
  444. // If previous group ends an else, that else must start inside the range
  445. for (ElseEndIterator it = cursor->_prev->_endElse.begin(); it != cursor->_prev->_endElse.end(); ++it)
  446. {
  447. if ((*(*it)->start_)->_address < (*start->start_)->_address)
  448. return false;
  449. }
  450. // Unless group is a simple unconditional jump...
  451. if ((*cursor->start_)->IsUncondJump())
  452. continue;
  453. // ...validate ingoing edges
  454. InEdgeRange ier = boost::in_edges(find(cursor->start_), _g);
  455. for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
  456. GraphVertex source = boost::source(*ie, _g);
  457. GroupPtr sourceGr = GET(source);
  458. // Edges going to conditions...
  459. if (sourceGr->_type == kIfCondGroupType || sourceGr->_type == kWhileCondGroupType || sourceGr->_type == kDoWhileCondGroupType) {
  460. // ...must not come from outside the range [start, end]...
  461. if ((*start->start_)->_address > (*sourceGr->start_)->_address || (*sourceGr->start_)->_address > (*end->start_)->_address) {
  462. // ...unless source is simple unconditional jump...
  463. if ((*sourceGr->start_)->IsUncondJump())
  464. continue;
  465. // ...or the edge is from the if condition associated with this else
  466. if (ifGroup == sourceGr)
  467. continue;
  468. return false;
  469. }
  470. }
  471. }
  472. }
  473. return true;
  474. }