[Scummvm-cvs-logs] SF.net SVN: scummvm:[50632] tools/branches/gsoc2010-decompiler/decompiler

pidgeot at users.sourceforge.net pidgeot at users.sourceforge.net
Sat Jul 3 23:07:31 CEST 2010


Revision: 50632
          http://scummvm.svn.sourceforge.net/scummvm/?rev=50632&view=rev
Author:   pidgeot
Date:     2010-07-03 21:07:30 +0000 (Sat, 03 Jul 2010)

Log Message:
-----------
Add detection of break and continue, including tests
Small fix to while loop detection (ingoing edge must not be from do-while)

Modified Paths:
--------------
    tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp
    tools/branches/gsoc2010-decompiler/decompiler/test/cfg_test.h

Modified: tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp	2010-07-03 21:05:51 UTC (rev 50631)
+++ tools/branches/gsoc2010-decompiler/decompiler/control_flow.cpp	2010-07-03 21:07:30 UTC (rev 50632)
@@ -229,13 +229,13 @@
 	VertexRange vr = boost::vertices(_g);
 	for (VertexIterator v = vr.first; v != vr.second; ++v) {
 		Group *gr = GET(*v);
-		// Block ends with conditional jump and has not yet been determined
+		// Undetermined block that ends with conditional jump
 		if (out_degree(*v, _g) == 2 && gr->_type == kNormal) {
 			InEdgeRange ier = boost::in_edges(*v, _g);
 			for (InEdgeIterator e = ier.first; e != ier.second; ++e) {
 				Group *sourceGr = GET(boost::source(*e, _g));
-				// Block has ingoing edge from later in the code
-				if (sourceGr->_start->_address > gr->_start->_address)
+				// Block has ingoing edge from block later in the code that isn't a do-while condition
+				if (sourceGr->_start->_address > gr->_start->_address && sourceGr->_type != kDoWhileCond)
 					gr->_type = kWhileCond;
 			}
 		}
@@ -246,7 +246,7 @@
 	VertexRange vr = boost::vertices(_g);
 	for (VertexIterator v = vr.first; v != vr.second; ++v) {
 		Group *gr = GET(*v);
-		// Block has not yet been determined and ends with conditional jump...
+		// Undetermined block that ends with conditional jump...
 		if (out_degree(*v, _g) == 2 && gr->_type == kNormal) {
 			OutEdgeRange oer = boost::out_edges(*v, _g);
 			for (OutEdgeIterator e = oer.first; e != oer.second; ++e) {
@@ -260,9 +260,44 @@
 }
 
 void ControlFlow::detectBreak() {
+	VertexRange vr = boost::vertices(_g);
+	for (VertexIterator v = vr.first; v != vr.second; ++v) {
+		Group *gr = GET(*v);
+		// Unconditional jump...
+		if ((gr->_end->_type == kJump || gr->_end->_type == kJumpRel) && out_degree(*v, _g) == 1) {
+			OutEdgeIterator oe = boost::out_edges(*v, _g).first;
+			GraphVertex target = boost::target(*oe, _g);
+			Group *targetGr = GET(target);			
+			// ...to somewhere later in the code...
+			if (gr->_start->_address >= targetGr->_start->_address)
+				continue;
+			InEdgeRange ier = boost::in_edges(target, _g);
+			for (InEdgeIterator ie = ier.first; ie != ier.second; ++ie) {
+				Group *sourceGr = GET(boost::source(*ie, _g));
+				// ...to block immediately after a do-while condition, or to jump target of a while condition
+				if ((targetGr->_prev == sourceGr && sourceGr->_type == kDoWhileCond) || sourceGr->_type == kWhileCond) {
+					gr->_type = kBreak;
+				}
+			}
+		}
+	}
 }
 
 void ControlFlow::detectContinue() {
+	VertexRange vr = boost::vertices(_g);
+	for (VertexIterator v = vr.first; v != vr.second; ++v) {
+		Group *gr = GET(*v);
+		// Undetermined block with unconditional jump...
+		if (gr->_type == kNormal && (gr->_end->_type == kJump || gr->_end->_type == kJumpRel) && out_degree(*v, _g) == 1) {
+			OutEdgeIterator oe = boost::out_edges(*v, _g).first;
+			GraphVertex target = boost::target(*oe, _g);
+			Group *targetGr = GET(target);
+			// ...to a while or do-while condition
+			if (targetGr->_type == kWhileCond || targetGr->_type == kDoWhileCond) {
+				gr->_type = kContinue;
+			}
+		}
+	}
 }
 
 void ControlFlow::detectIf() {

Modified: tools/branches/gsoc2010-decompiler/decompiler/test/cfg_test.h
===================================================================
--- tools/branches/gsoc2010-decompiler/decompiler/test/cfg_test.h	2010-07-03 21:05:51 UTC (rev 50631)
+++ tools/branches/gsoc2010-decompiler/decompiler/test/cfg_test.h	2010-07-03 21:07:30 UTC (rev 50632)
@@ -61,6 +61,8 @@
 				TS_ASSERT(false);
 			}
 		}
+		delete c;
+		delete engine;
 	};
 
 	void testBranching() {
@@ -92,6 +94,8 @@
 				TS_ASSERT(false);
 			}
 		}
+		delete c;
+		delete engine;
 	}
 
 	void testGrouping() {
@@ -123,6 +127,8 @@
 				break;
 			}
 		}
+		delete c;
+		delete engine;
 	}
 
 	void testShortCircuitDetection() {
@@ -135,6 +141,8 @@
 		c->createGroups();
 		Graph g = c->getGraph();
 		TS_ASSERT(boost::num_vertices(g) == 3);
+		delete c;
+		delete engine;
 	}
 
 	void testWhileDetection() {
@@ -152,6 +160,8 @@
 			if (gr->_start->_address == 0)
 				TS_ASSERT(gr->_type == kWhileCond);
 		}
+		delete c;
+		delete engine;
 	}
 
 	void testDoWhileDetection() {
@@ -169,5 +179,105 @@
 			if (gr->_start->_address == 3)
 				TS_ASSERT(gr->_type == kDoWhileCond);
 		}
+		delete c;
+		delete engine;
 	}
+
+	void testBreakDetection() {
+		Scumm::v6::Engine *engine = new Scumm::v6::Engine();
+		Disassembler *d = engine->getDisassembler();
+		d->open("decompiler/test/break-while.dmp");
+		std::vector<Instruction> insts = d->disassemble();
+		delete d;
+		ControlFlow *c = new ControlFlow(insts, engine);
+		c->createGroups();
+		Graph g = c->analyze();
+		VertexRange range = boost::vertices(g);
+		for (VertexIterator it = range.first; it != range.second; ++it) {
+			Group *gr = GET(*it);
+			if (gr->_start->_address == 0x14)
+				TS_ASSERT(gr->_type == kBreak);
+		}
+		delete c;
+
+		d = engine->getDisassembler();
+		d->open("decompiler/test/break-do-while.dmp");
+		insts = d->disassemble();
+		delete d;
+		c = new ControlFlow(insts, engine);
+		c->createGroups();
+		g = c->analyze();
+		range = boost::vertices(g);
+		for (VertexIterator it = range.first; it != range.second; ++it) {
+			Group *gr = GET(*it);
+			if (gr->_start->_address == 0xA)
+				TS_ASSERT(gr->_type == kBreak);
+		}
+		delete c;
+
+		d = engine->getDisassembler();
+		d->open("decompiler/test/break-do-while2.dmp");
+		insts = d->disassemble();
+		delete d;
+		c = new ControlFlow(insts, engine);
+		c->createGroups();
+		g = c->analyze();
+		range = boost::vertices(g);
+		for (VertexIterator it = range.first; it != range.second; ++it) {
+			Group *gr = GET(*it);
+			if (gr->_start->_address == 0xD)
+				TS_ASSERT(gr->_type == kBreak);
+		}
+		delete c;
+		delete engine;
+	}
+
+	void testContinueDetection() {
+		Scumm::v6::Engine *engine = new Scumm::v6::Engine();
+		Disassembler *d = engine->getDisassembler();
+		d->open("decompiler/test/continue-while.dmp");
+		std::vector<Instruction> insts = d->disassemble();
+		delete d;
+		ControlFlow *c = new ControlFlow(insts, engine);
+		c->createGroups();
+		Graph g = c->analyze();
+		VertexRange range = boost::vertices(g);
+		for (VertexIterator it = range.first; it != range.second; ++it) {
+			Group *gr = GET(*it);
+			if (gr->_start->_address == 0x14)
+				TS_ASSERT(gr->_type == kContinue);
+		}
+		delete c;
+
+		d = engine->getDisassembler();
+		d->open("decompiler/test/continue-do-while.dmp");
+		insts = d->disassemble();
+		delete d;
+		c = new ControlFlow(insts, engine);
+		c->createGroups();
+		g = c->analyze();
+		range = boost::vertices(g);
+		for (VertexIterator it = range.first; it != range.second; ++it) {
+			Group *gr = GET(*it);
+			if (gr->_start->_address == 0xA)
+				TS_ASSERT(gr->_type == kContinue);
+		}
+		delete c;
+
+		d = engine->getDisassembler();
+		d->open("decompiler/test/continue-do-while2.dmp");
+		insts = d->disassemble();
+		delete d;
+		c = new ControlFlow(insts, engine);
+		c->createGroups();
+		g = c->analyze();
+		range = boost::vertices(g);
+		for (VertexIterator it = range.first; it != range.second; ++it) {
+			Group *gr = GET(*it);
+			if (gr->_start->_address == 0xD)
+				TS_ASSERT(gr->_type == kContinue);
+		}
+		delete c;
+		delete engine;
+	}
 };


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list