| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/env python |
| 2 # |
| 3 # Copyright 2012 the V8 project authors. All rights reserved. |
| 4 # Redistribution and use in source and binary forms, with or without |
| 5 # modification, are permitted provided that the following conditions are |
| 6 # met: |
| 7 # |
| 8 # * Redistributions of source code must retain the above copyright |
| 9 # notice, this list of conditions and the following disclaimer. |
| 10 # * Redistributions in binary form must reproduce the above |
| 11 # copyright notice, this list of conditions and the following |
| 12 # disclaimer in the documentation and/or other materials provided |
| 13 # with the distribution. |
| 14 # * Neither the name of Google Inc. nor the names of its |
| 15 # contributors may be used to endorse or promote products derived |
| 16 # from this software without specific prior written permission. |
| 17 # |
| 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 |
| 30 import collections |
| 31 import glob |
| 32 import optparse |
| 33 import os |
| 34 from os.path import join |
| 35 import shlex |
| 36 import subprocess |
| 37 import sys |
| 38 import tempfile |
| 39 |
| 40 # Parse() returns: |
| 41 # a map of compilations (functions) |
| 42 # each compilation has a map of phases, and a name |
| 43 # each phase has a map of blocks, and a name |
| 44 # each block has a map of locals, and a map of statements |
| 45 # functions, phases, blocks, statements |
| 46 # |
| 47 # The first statement of foo, in final phase |
| 48 # data["foo"]["Z_Code generation"]["B0"][0] |
| 49 # |
| 50 # a phase is the typical area of work. Offers |
| 51 # phase.visit_statements(visitor) - visit every statement in the phase |
| 52 # phase.visit_blocks(visitor) |
| 53 # |
| 54 # of course, |
| 55 # blocks.visit_statements(visitor) |
| 56 # blocks.visit_locals(visitor) |
| 57 # |
| 58 |
| 59 |
| 60 USAGE="""usage: %prog [OPTION]... |
| 61 |
| 62 Looks at a hydrogen cfg file and produces graphviz (ie, dot) output. |
| 63 Output is directed to stdout for further customization before creating |
| 64 a graph. |
| 65 |
| 66 Examples: |
| 67 # Run on the last function defined in the file, looking at the final |
| 68 # HIR |
| 69 $ %prog > output.dot |
| 70 |
| 71 # Create the graphic too, this time with HIR, all on one line |
| 72 $ %prog --displayHIR | dot -Tpng > out.png |
| 73 |
| 74 # Examine a different phase of compilation for the last function |
| 75 # Output to the screen |
| 76 $ %prog --phase="H_Redundant phi elimination" --displayHIR |
| 77 |
| 78 # Create an html report of the last function, with all HIR |
| 79 $ %prog --command="report" |
| 80 """ |
| 81 |
| 82 |
| 83 def OrderedDictionary(): |
| 84 return collections.OrderedDict() |
| 85 |
| 86 |
| 87 def diemsg(msg): |
| 88 print "Unexpected error: %s" % msg |
| 89 sys.exit(1) |
| 90 |
| 91 |
| 92 class Block(object): |
| 93 """A compilation block.""" |
| 94 |
| 95 def __init__(self, name, predecessors, successors): |
| 96 self.name = name |
| 97 self.predecessors = predecessors |
| 98 self.successors = successors |
| 99 self.hir = OrderedDictionary() |
| 100 self.lir = OrderedDictionary() |
| 101 self.locals = OrderedDictionary() |
| 102 |
| 103 def GetName(self): |
| 104 return self.name |
| 105 |
| 106 def GetPredecessors(self): |
| 107 return self.predecessors |
| 108 |
| 109 def GetSuccessors(self): |
| 110 return self.successors |
| 111 |
| 112 def AddHIR(self,statement): |
| 113 self.hir[len(self.hir)] = statement |
| 114 |
| 115 def GetHIRs(self): |
| 116 return self.hir.values() |
| 117 |
| 118 def AddLIR(self,statement): |
| 119 self.lir[len(self.lir)] = statement |
| 120 |
| 121 def GetLIRs(self): |
| 122 return self.lir.values() |
| 123 |
| 124 def visit(self,visitor): |
| 125 """Visit every HIR statement in the block.""" |
| 126 for h in hir.values(): |
| 127 visitor(h) |
| 128 |
| 129 def AddLocal(self,name,local): |
| 130 self.locals[name] = local |
| 131 |
| 132 def visit_locals(self,visitor): |
| 133 for l in self.locals.values(): |
| 134 visitor(l) |
| 135 |
| 136 def GetLocals(self): |
| 137 return self.locals.values() |
| 138 |
| 139 def __str__(self): |
| 140 return "%s (pred: %d) (succ: %d)" % ( |
| 141 self.name, |
| 142 len(self.predecessors), |
| 143 len(self.successors)) |
| 144 |
| 145 |
| 146 class Phase(object): |
| 147 """A compilation phase.""" |
| 148 |
| 149 def __init__(self, name): |
| 150 self.name = name |
| 151 self.blocks = OrderedDictionary() |
| 152 |
| 153 def GetName(self): |
| 154 return self.name |
| 155 |
| 156 def AddBlock(self,name,block): |
| 157 self.blocks[name] = block |
| 158 |
| 159 def GetBlocks(self): |
| 160 return self.blocks.values() |
| 161 |
| 162 def GetBlock(self,block): |
| 163 return self.blocks[block] |
| 164 |
| 165 def visit_statements(self,visitor): |
| 166 for block in self.blocks: |
| 167 block.visit(visitor) |
| 168 |
| 169 def visit_blocks(self,visitor): |
| 170 for block in self.blocks.values(): |
| 171 visitor(block) |
| 172 |
| 173 def Print(self,p): |
| 174 p.write(self + "\n"); |
| 175 for block in self.blocks.values(): |
| 176 p.write(block + "\n") |
| 177 |
| 178 def __str__(self): |
| 179 return "%s (%d blocks)" % ( |
| 180 self.name, |
| 181 len(self.blocks)) |
| 182 |
| 183 |
| 184 class Compilation(object): |
| 185 """A compilation unit.""" |
| 186 |
| 187 def __init__(self, name, method): |
| 188 self.phases = OrderedDictionary() |
| 189 self.name = name |
| 190 self.method = method |
| 191 |
| 192 def AddPhase(self, name, phase): |
| 193 self.phases[name] = phase |
| 194 |
| 195 def AllPhases(self): |
| 196 for phase in self.phases.itervalues(): |
| 197 yield phase |
| 198 |
| 199 def AllPhaseNames(self): |
| 200 return self.phases.keys() |
| 201 |
| 202 def GetName(self): |
| 203 return self.name |
| 204 |
| 205 def GetPhase(self,phase): |
| 206 return self.phases[phase] |
| 207 |
| 208 def GetPreviousPhase(self,phase): |
| 209 # useful for diffs |
| 210 index = self.phases.keys().index(phase) |
| 211 if index == 0: |
| 212 diemsg("No previous phase of " + phase) |
| 213 return self.phases[self.phases.keys()[index - 1]] |
| 214 |
| 215 def Print(self,p): |
| 216 printer.write("Compilation %s\n" % self.name) |
| 217 for phase in self.AllPhases(): |
| 218 phase.Print(p) |
| 219 |
| 220 def __str__(self): |
| 221 return "%s (%d phases)" % ( |
| 222 self.name, |
| 223 len(self.phases)) |
| 224 |
| 225 |
| 226 def BuildOptions(): |
| 227 result = optparse.OptionParser(USAGE) |
| 228 result.add_option("--input", |
| 229 help="Input file (default %default)", |
| 230 default="hydrogen.cfg") |
| 231 result.add_option("--command", |
| 232 help="The command to run: 'diff','report','%default' (default)", |
| 233 default="blocks") |
| 234 result.add_option("--function", |
| 235 help="The function to analyze (default %default)", |
| 236 default="@last") |
| 237 result.add_option("--phase", |
| 238 help="The compilation phase to examine (default %default)", |
| 239 default="Z_Code generation") |
| 240 result.add_option("--displayHIR", |
| 241 help="Display HIR in blocks? (default %default)", |
| 242 default=False, action="store_true") |
| 243 result.add_option("--displayLIR", |
| 244 help="Display LIR in blocks? (default %default)", |
| 245 default=False, action="store_true") |
| 246 result.add_option("-v", "--verbose", help="Verbose output (default %default)", |
| 247 default=False, action="store_true") |
| 248 result.add_option("-d", "--debug", help="Debug output (default %default)", |
| 249 default=False, action="store_true") |
| 250 return result |
| 251 |
| 252 |
| 253 def ProcessOptions(options): |
| 254 if not options.command in ["blocks","diff","report"]: |
| 255 print "Unknown command %s" % options.command |
| 256 return False |
| 257 return True |
| 258 |
| 259 |
| 260 def parseKeyString(line): |
| 261 tokens = shlex.split(line.strip()) |
| 262 return tokens |
| 263 |
| 264 |
| 265 class CFGReader(object): |
| 266 """CFG file reader.""" |
| 267 |
| 268 def __init__(self, filename): |
| 269 self.file = open(filename, "r") |
| 270 self.savedline = None |
| 271 |
| 272 def Dispose(self): |
| 273 self.log.close() |
| 274 self.log_file.close() |
| 275 |
| 276 def pushline(self,line): |
| 277 self.savedline = line |
| 278 |
| 279 def nextline(self): |
| 280 # we can push one line back |
| 281 if self.savedline: |
| 282 s = self.savedline |
| 283 self.savedline = None |
| 284 return s |
| 285 |
| 286 return self.file.readline() |
| 287 |
| 288 def Parse(self): |
| 289 """Return a map of compilation units.""" |
| 290 compilations = OrderedDictionary() |
| 291 while True: |
| 292 compilation = self.ParseCompilation() |
| 293 if not compilation: |
| 294 break |
| 295 compilations[compilation.name] = compilation |
| 296 return compilations |
| 297 |
| 298 def ParseCompilation(self): |
| 299 line = self.nextline() |
| 300 if not line: |
| 301 return None |
| 302 assert "begin_compilation" == line.strip() |
| 303 pair = parseKeyString(self.nextline()) |
| 304 assert"name" == pair[0] |
| 305 name = pair[1] |
| 306 compilation = Compilation(name,name) |
| 307 # now read into configs |
| 308 while line.strip() != "end_compilation": |
| 309 line = self.nextline() |
| 310 if not line: |
| 311 diemsg("Unexpected end of file") |
| 312 |
| 313 while True: |
| 314 phase = self.ParsePhase() |
| 315 if not phase: |
| 316 break |
| 317 compilation.AddPhase(phase.name,phase) |
| 318 return compilation |
| 319 |
| 320 def ParseHIRs(self,block): |
| 321 while True: |
| 322 line = self.nextline().strip() |
| 323 if line == "end_HIR": |
| 324 break |
| 325 # we don't need the first number ("0 ") and some symbols at the end |
| 326 line = line[2:] |
| 327 line = line.replace("<|@","") |
| 328 block.AddHIR(line) |
| 329 |
| 330 def ParseLIRs(self,block): |
| 331 while True: |
| 332 line = self.nextline().strip() |
| 333 if line == "end_LIR": |
| 334 break |
| 335 # we don't need some symbols at the end |
| 336 line = line.replace("<|@","") |
| 337 block.AddLIR(line) |
| 338 |
| 339 def ParseLocals(self,block): |
| 340 while True: |
| 341 line = self.nextline() |
| 342 line = line.strip() |
| 343 if line == "end_locals": |
| 344 break |
| 345 if len(line) > 0 and (line[0]>='0' and line[0]<='9'): |
| 346 keys = parseKeyString(line) |
| 347 block.AddLocal(keys[1],line) |
| 348 |
| 349 def ParseBlock(self): |
| 350 line = self.nextline() |
| 351 if not line: |
| 352 return None |
| 353 |
| 354 if line.strip() != "begin_block": |
| 355 self.pushline(line) |
| 356 return None |
| 357 |
| 358 assert "begin_block" == line.strip() |
| 359 pair = parseKeyString(self.nextline()) |
| 360 assert "name" == pair[0] |
| 361 name = pair[1] |
| 362 # read pred and succ |
| 363 while True: |
| 364 line = self.nextline() |
| 365 if line.strip() == "begin_states": |
| 366 break; |
| 367 pair = parseKeyString(line) |
| 368 if pair[0] == "predecessors": |
| 369 pred = pair[1:] |
| 370 elif pair[0] == "successors": |
| 371 succ = pair[1:] |
| 372 |
| 373 block = Block(name,pred,succ) |
| 374 # add hrs if found |
| 375 while True: |
| 376 line = self.nextline().strip() |
| 377 if line == "end_block": |
| 378 break; |
| 379 elif line == "begin_locals": |
| 380 self.ParseLocals(block) |
| 381 elif line == "begin_LIR": |
| 382 self.ParseLIRs(block) |
| 383 elif line == "begin_HIR": |
| 384 self.ParseHIRs(block) |
| 385 |
| 386 return block |
| 387 |
| 388 def ParsePhase(self): |
| 389 line = self.nextline() |
| 390 if not line: |
| 391 return None |
| 392 |
| 393 if line.strip() != "begin_cfg": |
| 394 self.pushline(line) |
| 395 return None |
| 396 |
| 397 assert "begin_cfg" == line.strip() |
| 398 pair = parseKeyString(self.nextline()) |
| 399 assert "name" == pair[0] |
| 400 name = pair[1] |
| 401 phase = Phase(name) |
| 402 |
| 403 while True: |
| 404 block = self.ParseBlock() |
| 405 if not block: |
| 406 break |
| 407 phase.AddBlock(block.name,block) |
| 408 |
| 409 # just consume blocks |
| 410 # consume the "end_cfg" message |
| 411 assert "end_cfg" == self.nextline().strip() |
| 412 return phase |
| 413 |
| 414 |
| 415 def DumpCompilations(compilations,p): |
| 416 p.write("len = %d\n" % len(compilations)) |
| 417 for comp in compilations.itervalues(): |
| 418 comp.Print(p) |
| 419 |
| 420 |
| 421 def WriteTempFile(lines): |
| 422 temp = tempfile.NamedTemporaryFile(mode="w+t") |
| 423 for line in lines: |
| 424 temp.write(line) |
| 425 temp.write("\n") |
| 426 temp.seek(0) |
| 427 return temp |
| 428 |
| 429 |
| 430 def diffText(lines1,lines2): |
| 431 """Takes two lists of text lines, creates a diff output of them as an array""" |
| 432 |
| 433 try: |
| 434 temp1 = WriteTempFile(lines1) |
| 435 temp2 = WriteTempFile(lines2) |
| 436 outputlines = [] |
| 437 cmdline = "diff -u %s %s" % (temp1.name, temp2.name) |
| 438 process = subprocess.Popen(cmdline, |
| 439 shell=True, |
| 440 stdout=subprocess.PIPE, |
| 441 stderr=subprocess.STDOUT) |
| 442 pipe = process.stdout |
| 443 try: |
| 444 headerLines = 2 |
| 445 lineCount = 0 |
| 446 for line in pipe: |
| 447 if lineCount > headerLines: |
| 448 # strip newline |
| 449 outputlines.append(line.strip()) |
| 450 lineCount = lineCount + 1 |
| 451 except Exception as e: |
| 452 diemsg("error in diff = " + str(e)) |
| 453 finally: |
| 454 pipe.close() |
| 455 |
| 456 finally: |
| 457 temp1.close() |
| 458 temp2.close() |
| 459 |
| 460 return outputlines |
| 461 |
| 462 |
| 463 def Color(color,line): |
| 464 return "<font color=\"%s\">%s</font>" % (color,line) |
| 465 |
| 466 |
| 467 def LeftLineBreak(): |
| 468 return "<br align=\"left\"/>" |
| 469 |
| 470 |
| 471 def HtmlLikeEscape(line): |
| 472 return line.replace("<","<").replace(">",">") |
| 473 |
| 474 |
| 475 def TableBegin(): |
| 476 return "<table border=\"0\" cellborder=\"1\" cellspacing=\"0\">\n" |
| 477 |
| 478 |
| 479 def TableEnd(): |
| 480 return "</table>\n" |
| 481 |
| 482 |
| 483 def NameRow(blockName): |
| 484 return "<tr><td><b>%s</b></td></tr>\n" % blockName |
| 485 |
| 486 |
| 487 def FormatLine(line): |
| 488 tesc = HtmlLikeEscape(line) |
| 489 # Deal with diff output |
| 490 if tesc.startswith("-"): |
| 491 tesc = Color("red",tesc) |
| 492 elif tesc.startswith("+"): |
| 493 tesc = Color("blue",tesc) |
| 494 return " %s%s\n" % (tesc, LeftLineBreak()) |
| 495 |
| 496 |
| 497 def FormatLines(lineList): |
| 498 result = "" |
| 499 if len(lineList) > 0: |
| 500 result += "<tr><td>\n" |
| 501 for l in lineList: |
| 502 result = result + FormatLine(l) |
| 503 result = result + "</td></tr>\n" |
| 504 return result |
| 505 |
| 506 |
| 507 def FormatLabel(blockName,localsList,hirList,lirList): |
| 508 label = TableBegin() |
| 509 label += NameRow(blockName) |
| 510 label += FormatLines(localsList) |
| 511 label += FormatLines(hirList) |
| 512 label += FormatLines(lirList) |
| 513 label += TableEnd() |
| 514 return label |
| 515 |
| 516 |
| 517 def DotBlockVisit(displayHIR,displayLIR,p,block): |
| 518 localsList = [] |
| 519 hirList = [] |
| 520 lirList = [] |
| 521 |
| 522 if displayHIR or displayLIR: |
| 523 localsList = block.GetLocals() |
| 524 if displayHIR: |
| 525 hirList = block.GetHIRs() |
| 526 if displayLIR: |
| 527 lirList = block.GetLIRs() |
| 528 |
| 529 label = FormatLabel(block.GetName(),localsList,hirList,lirList) |
| 530 # extra newline for readability |
| 531 label = "\n" + label |
| 532 p.write(" block%s [shape=plaintext,label=<%s>];\n" |
| 533 % (block.GetName(), label)) |
| 534 for succ in block.GetSuccessors(): |
| 535 p.write(" block%s -> block%s;\n" % (block.GetName(), succ)) |
| 536 |
| 537 |
| 538 def DotBlocks(functionName,phase,displayHIR,displayLIR,p): |
| 539 """Diagram the blocks in the given function.""" |
| 540 p.write("digraph Blocks_%s {\n" % functionName) |
| 541 p.write(" ratio = 1.0;\n") |
| 542 phase.visit_blocks(lambda b: DotBlockVisit(displayHIR,displayLIR,p,b)) |
| 543 p.write("}\n") |
| 544 |
| 545 |
| 546 def DotDiffVisit(diffs,p,block): |
| 547 label = FormatLabel(block.GetName(),[],diffs[block.GetName()],[]) |
| 548 p.write(" block%s [shape=plaintext,label=<%s>];\n" |
| 549 % (block.GetName(), label)) |
| 550 for succ in block.GetSuccessors(): |
| 551 p.write(" block%s -> block%s;\n" % (block.GetName(), succ)) |
| 552 |
| 553 |
| 554 def DotDiff(functionName, phasePrev, phase, changedBlocksOnly, p): |
| 555 """Run a diff block by block between two phases in the given function.""" |
| 556 p.write("// comparing phase %s with next phase %s\n" % (phasePrev.GetName(), |
| 557 phase.GetName())) |
| 558 p.write("digraph Diff_%s {\n" % functionName) |
| 559 p.write(" ratio = 1.0;\n") |
| 560 # need to run diff -u phasePrev phase |
| 561 # on the HIR output |
| 562 # I think the # of blocks should be the same |
| 563 diffResults = {} |
| 564 blocks = phasePrev.GetBlocks() |
| 565 for blockPrev in blocks: |
| 566 block = phase.GetBlock(blockPrev.GetName()) |
| 567 diffResults[blockPrev.GetName()] = diffText(blockPrev.GetHIRs(), |
| 568 block.GetHIRs()) |
| 569 |
| 570 phasePrev.visit_blocks(lambda b: DotDiffVisit(diffResults,p,b)) |
| 571 p.write("}\n") |
| 572 |
| 573 |
| 574 reportText = """<html> |
| 575 <title>Report on %s</title> |
| 576 <body> |
| 577 <h2>Block structure</h2> |
| 578 <a href=blocks.svg><img width=800 src=blocks.svg></a> |
| 579 <h2>All HIR</h2> |
| 580 <a href=hirblocks.svg><img width=800 src=hirblocks.svg></a> |
| 581 <h2>All LIR</h2> |
| 582 <a href=lirblocks.svg><img width=800 src=lirblocks.svg></a> |
| 583 <h2>Diffs</h2> |
| 584 %s |
| 585 </body> |
| 586 </html>""" |
| 587 |
| 588 |
| 589 diffsTemplate = """<h2>%s</h2> |
| 590 <a href=%s><img width=800 src=%s></a>""" |
| 591 |
| 592 |
| 593 def AsFilename(phaseName,ext): |
| 594 phaseName = phaseName.replace(" ","_") |
| 595 phaseName += ext |
| 596 return phaseName |
| 597 |
| 598 |
| 599 def DotReport(function): |
| 600 """Make a report on the function.""" |
| 601 function_name = function.GetName().replace(".","_") |
| 602 directory_name = "report_%s" % function_name |
| 603 if not os.path.exists(directory_name): |
| 604 os.mkdirs(directory_name) |
| 605 |
| 606 htmlfilename = directory_name + "/index.html" |
| 607 with open(htmlfilename, "w+t") as p: |
| 608 print "Writing %s..." % htmlfilename |
| 609 diffs = "" |
| 610 phases = function.AllPhaseNames() |
| 611 for ph in phases[1:]: |
| 612 phfilename = AsFilename(ph,".svg") |
| 613 diffs += diffsTemplate % (ph,phfilename,phfilename) |
| 614 htmlText = reportText % (function_name,diffs) |
| 615 p.write(htmlText + "\n") |
| 616 |
| 617 |
| 618 # Write all dot files |
| 619 # get last phase |
| 620 phase = function.GetPhase(phases[-1]) |
| 621 with open(directory_name + "/blocks.dot", "w+t") as p: |
| 622 DotBlocks(function_name,phase,False,False,p) |
| 623 |
| 624 with open(directory_name + "/hirblocks.dot", "w+t") as p: |
| 625 DotBlocks(function_name,phase,True,False,p) |
| 626 |
| 627 with open(directory_name + "/lirblocks.dot", "w+t") as p: |
| 628 DotBlocks(function_name,phase,False,True,p) |
| 629 |
| 630 print "Computing diffs..." |
| 631 |
| 632 for ph in phases[1:]: |
| 633 phase = function.GetPhase(ph) |
| 634 phase_previous = function.GetPreviousPhase(ph) |
| 635 with open(directory_name + "/" + AsFilename(ph,".dot"), "w+t") as p: |
| 636 DotDiff(function_name, phase_previous, phase, True, p) |
| 637 |
| 638 # Compile the dot files |
| 639 command_line = "dot -Tsvg %s > %s" |
| 640 # diff -u %s %s" % (temp1.name, temp2.name) |
| 641 files = glob.glob(directory_name + "/*.dot") |
| 642 for f in files: |
| 643 print "compiling " + f |
| 644 process = subprocess.Popen(command_line % (f,f.replace(".dot",".svg")), |
| 645 shell=True) |
| 646 process.wait() |
| 647 print "done" |
| 648 |
| 649 |
| 650 def Main(): |
| 651 parser = BuildOptions() |
| 652 (options, args) = parser.parse_args() |
| 653 if not ProcessOptions(options): |
| 654 parser.print_help() |
| 655 return 1 |
| 656 |
| 657 # Open input file and parse compilations, phases, blocks |
| 658 reader = CFGReader(options.input) |
| 659 compilations = reader.Parse() |
| 660 |
| 661 if options.debug: |
| 662 DumpCompilations(compilations, sys.stdout) |
| 663 |
| 664 function = options.function |
| 665 if function == "@last": |
| 666 function = compilations.keys()[-1] |
| 667 elif function == "@first": |
| 668 function = compilations.keys()[0] |
| 669 if options.verbose: |
| 670 print "// dump function %s" % function |
| 671 |
| 672 phase = options.phase |
| 673 |
| 674 # find the method |
| 675 if not function in compilations: |
| 676 diemsg("function " + function + " not found in input file") |
| 677 |
| 678 function = compilations[function] |
| 679 # find the phase |
| 680 phase = function.GetPhase(phase) |
| 681 |
| 682 # now what we do depends on the command |
| 683 |
| 684 function_name = function.GetName().replace(".","_") |
| 685 if options.command == "blocks": |
| 686 DotBlocks(function_name, phase, options.displayHIR, |
| 687 options.displayLIR, sys.stdout) |
| 688 elif options.command == "diff": |
| 689 # take the phase and the preceding phase. |
| 690 previous_phase = function.GetPreviousPhase(phase.GetName()) |
| 691 DotDiff(function_name, previous_phase, phase, True, sys.stdout) |
| 692 elif options.command == "report": |
| 693 DotReport(function) |
| 694 return 0 |
| 695 |
| 696 |
| 697 if __name__ == "__main__": |
| 698 sys.exit(Main()) |
| OLD | NEW |