From 95e0c5fc6cebc2ced6eaac6dddd7858dc053cf4e Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Wed, 29 Nov 2017 17:07:41 +0000 Subject: [PATCH] Add opt-viewer testing Detects whether we have the Python modules (pygments, yaml) required by opt-viewer and hooks this up to REQUIRES. This fixes https://bugs.llvm.org/show_bug.cgi?id=34129 (the lack of opt-viewer testing). It's also related to https://github.com/apple/swift/pull/12938 and the idea is to expose LLVM_HAVE_OPT_VIEWER_MODULES to the Swift cmake. Differential Revision: https://reviews.llvm.org/D40202 Fixes since the first commit: 1. Disable syntax highlighting as different versions of pygments generate different HTML 2. Use llvm-cxxfilt from the build llvm-svn: 319324 --- llvm/cmake/config-ix.cmake | 31 +++ llvm/test/lit.cfg.py | 5 + llvm/test/lit.site.cfg.py.in | 1 + llvm/test/tools/opt-viewer/Inputs/basic/or.c | 21 ++ llvm/test/tools/opt-viewer/Inputs/basic/or.h | 16 ++ .../tools/opt-viewer/Inputs/basic/or.yaml | 227 ++++++++++++++++ .../opt-viewer/Outputs/basic/basic_or.c.html | 257 ++++++++++++++++++ .../opt-viewer/Outputs/basic/basic_or.h.html | 214 +++++++++++++++ .../tools/opt-viewer/Outputs/basic/index.html | 151 ++++++++++ .../tools/opt-viewer/Outputs/basic/style.css | 208 ++++++++++++++ llvm/test/tools/opt-viewer/basic.test | 9 + llvm/test/tools/opt-viewer/lit.local.cfg | 2 + llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp | 1 + llvm/tools/opt-viewer/opt-viewer.py | 34 ++- llvm/tools/opt-viewer/optrecord.py | 33 ++- 15 files changed, 1186 insertions(+), 24 deletions(-) create mode 100644 llvm/test/tools/opt-viewer/Inputs/basic/or.c create mode 100644 llvm/test/tools/opt-viewer/Inputs/basic/or.h create mode 100644 llvm/test/tools/opt-viewer/Inputs/basic/or.yaml create mode 100644 llvm/test/tools/opt-viewer/Outputs/basic/basic_or.c.html create mode 100644 llvm/test/tools/opt-viewer/Outputs/basic/basic_or.h.html create mode 100644 llvm/test/tools/opt-viewer/Outputs/basic/index.html create mode 100644 llvm/test/tools/opt-viewer/Outputs/basic/style.css create mode 100644 llvm/test/tools/opt-viewer/basic.test create mode 100644 llvm/test/tools/opt-viewer/lit.local.cfg diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake index 23494fb96c6b..caa538082fc7 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -628,3 +628,34 @@ else() endif() string(REPLACE " " ";" LLVM_BINDINGS_LIST "${LLVM_BINDINGS}") + +function(find_python_module module) + string(TOUPPER ${module} module_upper) + set(FOUND_VAR PY_${module_upper}_FOUND) + + execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" "import ${module}" + RESULT_VARIABLE status + ERROR_QUIET) + + if(status) + set(${FOUND_VAR} 0 PARENT_SCOPE) + message(STATUS "Could NOT find Python module ${module}") + else() + set(${FOUND_VAR} 1 PARENT_SCOPE) + message(STATUS "Found Python module ${module}") + endif() +endfunction() + +set (PYTHON_MODULES + pygments + yaml + ) +foreach(module ${PYTHON_MODULES}) + find_python_module(${module}) +endforeach() + +if(PY_PYGMENTS_FOUND AND PY_YAML_FOUND) + set (LLVM_HAVE_OPT_VIEWER_MODULES 1) +else() + set (LLVM_HAVE_OPT_VIEWER_MODULES 0) +endif() diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index e956bb74f5a0..06a23536a8ce 100644 --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -123,6 +123,7 @@ if config.have_ocamlopt: ocamlopt_command = '%s ocamlopt -cclib -L%s -cclib -Wl,-rpath,%s %s' % ( config.ocamlfind_executable, config.llvm_lib_dir, config.llvm_lib_dir, config.ocaml_flags) +opt_viewer_cmd = '%s %s/tools/opt-viewer/opt-viewer.py' % (sys.executable, config.llvm_src_root) tools = [ ToolSubst('%lli', FindTool('lli'), post='.', extra_args=lli_args), @@ -132,6 +133,7 @@ tools = [ ToolSubst('%ld64', ld64_cmd, unresolved='ignore'), ToolSubst('%ocamlc', ocamlc_command, unresolved='ignore'), ToolSubst('%ocamlopt', ocamlopt_command, unresolved='ignore'), + ToolSubst('%opt-viewer', opt_viewer_cmd), ] # FIXME: Why do we have both `lli` and `%lli` that do slightly different things? @@ -286,3 +288,6 @@ if config.have_libxar: if config.llvm_libxml2_enabled == '1': config.available_features.add('libxml2') + +if config.have_opt_viewer_modules: + config.available_features.add('have_opt_viewer_modules') diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in index dff46dcff32e..117af7336d0a 100644 --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -43,6 +43,7 @@ config.link_llvm_dylib = @LLVM_LINK_LLVM_DYLIB@ config.llvm_libxml2_enabled = "@LLVM_LIBXML2_ENABLED@" config.llvm_host_triple = '@LLVM_HOST_TRIPLE@' config.host_arch = "@HOST_ARCH@" +config.have_opt_viewer_modules = @LLVM_HAVE_OPT_VIEWER_MODULES@ # Support substitution of the tools_dir with user parameters. This is # used when we can't determine the tool dir at configuration time. diff --git a/llvm/test/tools/opt-viewer/Inputs/basic/or.c b/llvm/test/tools/opt-viewer/Inputs/basic/or.c new file mode 100644 index 000000000000..6b1c4744cdac --- /dev/null +++ b/llvm/test/tools/opt-viewer/Inputs/basic/or.c @@ -0,0 +1,21 @@ +void bar(); +void foo() { bar(); } + +#include "or.h" + +void Test(int *res, int *c, int *d, int *p, int n) { + int i; + +#pragma clang loop vectorize(assume_safety) + for (i = 0; i < 1600; i++) { + res[i] = (p[i] == 0) ? res[i] : res[i] + d[i]; + } + + for (i = 0; i < 16; i++) { + res[i] = (p[i] == 0) ? res[i] : res[i] + d[i]; + } + + foo(); + + foo(); bar(); foo(); +} diff --git a/llvm/test/tools/opt-viewer/Inputs/basic/or.h b/llvm/test/tools/opt-viewer/Inputs/basic/or.h new file mode 100644 index 000000000000..a1c47edb3d12 --- /dev/null +++ b/llvm/test/tools/opt-viewer/Inputs/basic/or.h @@ -0,0 +1,16 @@ +void TestH(int *res, int *c, int *d, int *p, int n) { + int i; + +#pragma clang loop vectorize(assume_safety) + for (i = 0; i < 1600; i++) { + res[i] = (p[i] == 0) ? res[i] : res[i] + d[i]; + } + + for (i = 0; i < 16; i++) { + res[i] = (p[i] == 0) ? res[i] : res[i] + d[i]; + } + + foo(); + + foo(); bar(); foo(); +} diff --git a/llvm/test/tools/opt-viewer/Inputs/basic/or.yaml b/llvm/test/tools/opt-viewer/Inputs/basic/or.yaml new file mode 100644 index 000000000000..11c5528b43fc --- /dev/null +++ b/llvm/test/tools/opt-viewer/Inputs/basic/or.yaml @@ -0,0 +1,227 @@ +--- !Missed +Pass: inline +Name: NoDefinition +DebugLoc: { File: basic/or.c, Line: 2, Column: 14 } +Function: foo +Args: + - Callee: bar + - String: ' will not be inlined into ' + - Caller: foo + - String: ' because its definition is unavailable' +... +--- !Missed +Pass: inline +Name: NoDefinition +DebugLoc: { File: basic/or.h, Line: 15, Column: 10 } +Function: TestH +Args: + - Callee: bar + - String: ' will not be inlined into ' + - Caller: TestH + - String: ' because its definition is unavailable' +... +--- !Analysis +Pass: inline +Name: CanBeInlined +DebugLoc: { File: basic/or.h, Line: 13, Column: 3 } +Function: TestH +Args: + - Callee: foo + - String: ' can be inlined into ' + - Caller: TestH + - String: ' with cost=' + - Cost: '30' + - String: ' (threshold=' + - Threshold: '412' + - String: ')' +... +--- !Passed +Pass: inline +Name: Inlined +DebugLoc: { File: basic/or.h, Line: 13, Column: 3 } +Function: TestH +Args: + - Callee: foo + - String: ' inlined into ' + - Caller: TestH +... +--- !Analysis +Pass: inline +Name: CanBeInlined +DebugLoc: { File: basic/or.h, Line: 15, Column: 3 } +Function: TestH +Args: + - Callee: foo + - String: ' can be inlined into ' + - Caller: TestH + - String: ' with cost=' + - Cost: '30' + - String: ' (threshold=' + - Threshold: '412' + - String: ')' +... +--- !Passed +Pass: inline +Name: Inlined +DebugLoc: { File: basic/or.h, Line: 15, Column: 3 } +Function: TestH +Args: + - Callee: foo + - String: ' inlined into ' + - Caller: TestH +... +--- !Analysis +Pass: inline +Name: CanBeInlined +DebugLoc: { File: basic/or.h, Line: 15, Column: 17 } +Function: TestH +Args: + - Callee: foo + - String: ' can be inlined into ' + - Caller: TestH + - String: ' with cost=' + - Cost: '30' + - String: ' (threshold=' + - Threshold: '412' + - String: ')' +... +--- !Passed +Pass: inline +Name: Inlined +DebugLoc: { File: basic/or.h, Line: 15, Column: 17 } +Function: TestH +Args: + - Callee: foo + - String: ' inlined into ' + - Caller: TestH +... +--- !Passed +Pass: loop-unroll +Name: FullyUnrolled +DebugLoc: { File: basic/or.h, Line: 9, Column: 3 } +Function: TestH +Args: + - String: 'completely unrolled loop with ' + - UnrollCount: '16' + - String: ' iterations' +... +--- !Missed +Pass: inline +Name: NoDefinition +DebugLoc: { File: basic/or.c, Line: 20, Column: 10 } +Function: Test +Args: + - Callee: bar + - String: ' will not be inlined into ' + - Caller: Test + - String: ' because its definition is unavailable' +... +--- !Analysis +Pass: inline +Name: CanBeInlined +DebugLoc: { File: basic/or.c, Line: 18, Column: 3 } +Function: Test +Args: + - Callee: foo + - String: ' can be inlined into ' + - Caller: Test + - String: ' with cost=' + - Cost: '30' + - String: ' (threshold=' + - Threshold: '412' + - String: ')' +... +--- !Passed +Pass: inline +Name: Inlined +DebugLoc: { File: basic/or.c, Line: 18, Column: 3 } +Function: Test +Args: + - Callee: foo + - String: ' inlined into ' + - Caller: Test +... +--- !Analysis +Pass: inline +Name: CanBeInlined +DebugLoc: { File: basic/or.c, Line: 20, Column: 3 } +Function: Test +Args: + - Callee: foo + - String: ' can be inlined into ' + - Caller: Test + - String: ' with cost=' + - Cost: '30' + - String: ' (threshold=' + - Threshold: '412' + - String: ')' +... +--- !Passed +Pass: inline +Name: Inlined +DebugLoc: { File: basic/or.c, Line: 20, Column: 3 } +Function: Test +Args: + - Callee: foo + - String: ' inlined into ' + - Caller: Test +... +--- !Analysis +Pass: inline +Name: CanBeInlined +DebugLoc: { File: basic/or.c, Line: 20, Column: 17 } +Function: Test +Args: + - Callee: foo + - String: ' can be inlined into ' + - Caller: Test + - String: ' with cost=' + - Cost: '30' + - String: ' (threshold=' + - Threshold: '412' + - String: ')' +... +--- !Passed +Pass: inline +Name: Inlined +DebugLoc: { File: basic/or.c, Line: 20, Column: 17 } +Function: Test +Args: + - Callee: foo + - String: ' inlined into ' + - Caller: Test +... +--- !Passed +Pass: loop-unroll +Name: FullyUnrolled +DebugLoc: { File: basic/or.c, Line: 14, Column: 3 } +Function: Test +Args: + - String: 'completely unrolled loop with ' + - UnrollCount: '16' + - String: ' iterations' +... +--- !Passed +Pass: loop-vectorize +Name: Vectorized +DebugLoc: { File: basic/or.h, Line: 5, Column: 3 } +Function: TestH +Args: + - String: 'vectorized loop (vectorization width: ' + - VectorizationFactor: '4' + - String: ', interleaved count: ' + - InterleaveCount: '2' + - String: ')' +... +--- !Passed +Pass: loop-vectorize +Name: Vectorized +DebugLoc: { File: basic/or.c, Line: 10, Column: 3 } +Function: Test +Args: + - String: 'vectorized loop (vectorization width: ' + - VectorizationFactor: '4' + - String: ', interleaved count: ' + - InterleaveCount: '2' + - String: ')' +... diff --git a/llvm/test/tools/opt-viewer/Outputs/basic/basic_or.c.html b/llvm/test/tools/opt-viewer/Outputs/basic/basic_or.c.html new file mode 100644 index 000000000000..a97b12855bcd --- /dev/null +++ b/llvm/test/tools/opt-viewer/Outputs/basic/basic_or.c.html @@ -0,0 +1,257 @@ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Line +Hotness +Optimization +Source +Inline Context +
1
void bar();
2
void foo() { bar(); }
inline
             
bar will not be inlined into foo because its definition is unavailable 
foo
3
4
#include "or.h"
5
6
void Test(int *res, int *c, int *d, int *p, int n) {
7
  int i;
8
9
#pragma clang loop vectorize(assume_safety)
10
  for (i = 0; i < 1600; i++) {
loop-vectorize
  
vectorized loop (vectorization width: 4, interleaved count: 2) 
Test
11
    res[i] = (p[i] == 0) ? res[i] : res[i] + d[i];
12
  }
13
14
  for (i = 0; i < 16; i++) {
loop-unroll
  
completely unrolled loop with 16 iterations 
Test
15
    res[i] = (p[i] == 0) ? res[i] : res[i] + d[i];
16
  }
17
18
  foo();
inline
  
foo can be inlined into Test with cost=30 (threshold=412) 
Test
inline
  
foo inlined into Test 
Test
19
20
  foo(); bar(); foo();
inline
         
bar will not be inlined into Test because its definition is unavailable 
Test
inline
  
foo can be inlined into Test with cost=30 (threshold=412) 
Test
inline
  
foo inlined into Test 
Test
inline
                
foo can be inlined into Test with cost=30 (threshold=412) 
Test
inline
                
foo inlined into Test 
Test
21
}
22
+ + diff --git a/llvm/test/tools/opt-viewer/Outputs/basic/basic_or.h.html b/llvm/test/tools/opt-viewer/Outputs/basic/basic_or.h.html new file mode 100644 index 000000000000..171bb8355633 --- /dev/null +++ b/llvm/test/tools/opt-viewer/Outputs/basic/basic_or.h.html @@ -0,0 +1,214 @@ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Line +Hotness +Optimization +Source +Inline Context +
1
void TestH(int *res, int *c, int *d, int *p, int n) {
2
  int i;
3
4
#pragma clang loop vectorize(assume_safety)
5
  for (i = 0; i < 1600; i++) {
loop-vectorize
  
vectorized loop (vectorization width: 4, interleaved count: 2) 
TestH
6
    res[i] = (p[i] == 0) ? res[i] : res[i] + d[i];
7
  }
8
9
  for (i = 0; i < 16; i++) {
loop-unroll
  
completely unrolled loop with 16 iterations 
TestH
10
    res[i] = (p[i] == 0) ? res[i] : res[i] + d[i];
11
  }
12
13
  foo();
inline
  
foo can be inlined into TestH with cost=30 (threshold=412) 
TestH
inline
  
foo inlined into TestH 
TestH
14
15
  foo(); bar(); foo();
inline
         
bar will not be inlined into TestH because its definition is unavailable 
TestH
inline
  
foo can be inlined into TestH with cost=30 (threshold=412) 
TestH
inline
  
foo inlined into TestH 
TestH
inline
                
foo can be inlined into TestH with cost=30 (threshold=412) 
TestH
inline
                
foo inlined into TestH 
TestH
16
}
17
+ + diff --git a/llvm/test/tools/opt-viewer/Outputs/basic/index.html b/llvm/test/tools/opt-viewer/Outputs/basic/index.html new file mode 100644 index 000000000000..9fe9a4a7adf7 --- /dev/null +++ b/llvm/test/tools/opt-viewer/Outputs/basic/index.html @@ -0,0 +1,151 @@ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Source LocationHotnessFunctionPass
basic/or.c:2:14fooinline
basic/or.c:10:3Testloop-vectorize
basic/or.c:14:3Testloop-unroll
basic/or.c:18:3Testinline
basic/or.c:18:3Testinline
basic/or.c:20:3Testinline
basic/or.c:20:3Testinline
basic/or.c:20:10Testinline
basic/or.c:20:17Testinline
basic/or.c:20:17Testinline
basic/or.h:5:3TestHloop-vectorize
basic/or.h:9:3TestHloop-unroll
basic/or.h:13:3TestHinline
basic/or.h:13:3TestHinline
basic/or.h:15:3TestHinline
basic/or.h:15:3TestHinline
basic/or.h:15:10TestHinline
basic/or.h:15:17TestHinline
basic/or.h:15:17TestHinline
+ + diff --git a/llvm/test/tools/opt-viewer/Outputs/basic/style.css b/llvm/test/tools/opt-viewer/Outputs/basic/style.css new file mode 100644 index 000000000000..0d3347c1578c --- /dev/null +++ b/llvm/test/tools/opt-viewer/Outputs/basic/style.css @@ -0,0 +1,208 @@ +.source { + table-layout: fixed; + width: 100%; + white-space: nowrap; +} +.source td { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.red { + background-color: #ffd0d0; +} +.cyan { + background-color: cyan; +} +body { + font-family: -apple-system, sans-serif; +} +pre { + margin-top: 0px !important; + margin-bottom: 0px !important; +} +.source-name-title { + padding: 5px 10px; + border-bottom: 1px solid #dbdbdb; + background-color: #eee; + line-height: 35px; +} +.centered { + display: table; + margin-left: left; + margin-right: auto; + border: 1px solid #dbdbdb; + border-radius: 3px; +} +.expansion-view { + background-color: rgba(0, 0, 0, 0); + margin-left: 0px; + margin-top: 5px; + margin-right: 5px; + margin-bottom: 5px; + border: 1px solid #dbdbdb; + border-radius: 3px; +} +table { + border-collapse: collapse; +} +.light-row { + background: #ffffff; + border: 1px solid #dbdbdb; +} +.column-entry { + text-align: right; +} +.column-entry-left { + text-align: left; +} +.column-entry-white { + text-align: right; + background-color: #ffffff; +} +.column-entry-red { + text-align: right; + background-color: #ffd0d0; +} +.column-entry-green { + text-align: right; + background-color: #d0ffd0; +} +.column-entry-yellow { + text-align: left; + background-color: #ffe1a6; +} +.column-entry-0 { + background-color: #ffffff; +} +.column-entry-1 { + background-color: #eeeeee; +} +.line-number { + text-align: right; + color: #aaa; +} +.covered-line { + text-align: right; + color: #0080ff; +} +.uncovered-line { + text-align: right; + color: #ff3300; +} +.tooltip { + position: relative; + display: inline; + background-color: #b3e6ff; + text-decoration: none; +} +.tooltip span.tooltip-content { + position: absolute; + width: 100px; + margin-left: -50px; + color: #FFFFFF; + background: #000000; + height: 30px; + line-height: 30px; + text-align: center; + visibility: hidden; + border-radius: 6px; +} +.tooltip span.tooltip-content:after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + margin-left: -8px; + width: 0; height: 0; + border-top: 8px solid #000000; + border-right: 8px solid transparent; + border-left: 8px solid transparent; +} +:hover.tooltip span.tooltip-content { + visibility: visible; + opacity: 0.8; + bottom: 30px; + left: 50%; + z-index: 999; +} +th, td { + vertical-align: top; + padding: 2px 5px; + border-collapse: collapse; + border-right: solid 1px #eee; + border-left: solid 1px #eee; +} +td:first-child { + border-left: none; +} +td:last-child { + border-right: none; +} + +/* Generated with pygmentize -S colorful -f html >> style.css */ + +.hll { background-color: #ffffcc } +.c { color: #888888 } /* Comment */ +.err { color: #FF0000; background-color: #FFAAAA } /* Error */ +.k { color: #008800; font-weight: bold } /* Keyword */ +.o { color: #333333 } /* Operator */ +.ch { color: #888888 } /* Comment.Hashbang */ +.cm { color: #888888 } /* Comment.Multiline */ +.cp { color: #557799 } /* Comment.Preproc */ +.cpf { color: #888888 } /* Comment.PreprocFile */ +.c1 { color: #888888 } /* Comment.Single */ +.cs { color: #cc0000; font-weight: bold } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #FF0000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #00A000 } /* Generic.Inserted */ +.go { color: #888888 } /* Generic.Output */ +.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0044DD } /* Generic.Traceback */ +.kc { color: #008800; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #003388; font-weight: bold } /* Keyword.Pseudo */ +.kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #333399; font-weight: bold } /* Keyword.Type */ +.m { color: #6600EE; font-weight: bold } /* Literal.Number */ +.s { background-color: #fff0f0 } /* Literal.String */ +.na { color: #0000CC } /* Name.Attribute */ +.nb { color: #007020 } /* Name.Builtin */ +.nc { color: #BB0066; font-weight: bold } /* Name.Class */ +.no { color: #003366; font-weight: bold } /* Name.Constant */ +.nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.ni { color: #880000; font-weight: bold } /* Name.Entity */ +.ne { color: #FF0000; font-weight: bold } /* Name.Exception */ +.nf { color: #0066BB; font-weight: bold } /* Name.Function */ +.nl { color: #997700; font-weight: bold } /* Name.Label */ +.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.nt { color: #007700 } /* Name.Tag */ +.nv { color: #996633 } /* Name.Variable */ +.ow { color: #000000; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mb { color: #6600EE; font-weight: bold } /* Literal.Number.Bin */ +.mf { color: #6600EE; font-weight: bold } /* Literal.Number.Float */ +.mh { color: #005588; font-weight: bold } /* Literal.Number.Hex */ +.mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ +.mo { color: #4400EE; font-weight: bold } /* Literal.Number.Oct */ +.sb { background-color: #fff0f0 } /* Literal.String.Backtick */ +.sc { color: #0044DD } /* Literal.String.Char */ +.sd { color: #DD4422 } /* Literal.String.Doc */ +.s2 { background-color: #fff0f0 } /* Literal.String.Double */ +.se { color: #666666; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */ +.sh { background-color: #fff0f0 } /* Literal.String.Heredoc */ +.si { background-color: #eeeeee } /* Literal.String.Interpol */ +.sx { color: #DD2200; background-color: #fff0f0 } /* Literal.String.Other */ +.sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */ +.s1 { background-color: #fff0f0 } /* Literal.String.Single */ +.ss { color: #AA6600 } /* Literal.String.Symbol */ +.bp { color: #007020 } /* Name.Builtin.Pseudo */ +.vc { color: #336699 } /* Name.Variable.Class */ +.vg { color: #dd7700; font-weight: bold } /* Name.Variable.Global */ +.vi { color: #3333BB } /* Name.Variable.Instance */ +.il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ diff --git a/llvm/test/tools/opt-viewer/basic.test b/llvm/test/tools/opt-viewer/basic.test new file mode 100644 index 000000000000..f0e8fa3ad1bd --- /dev/null +++ b/llvm/test/tools/opt-viewer/basic.test @@ -0,0 +1,9 @@ +# Since we're performing a full compare of the generate HTML files disable +# syntax highlighting; pygments generates slightly different code with +# different versions. + +RUN: %opt-viewer -s %p/Inputs -o %t %p/Inputs/basic/or.yaml --no-highlight --demangler=llvm-cxxfilt +RUN: diff %p/Outputs/basic/index.html %t/index.html +RUN: diff %p/Outputs/basic/basic_or.h.html %t/basic_or.h.html +RUN: diff %p/Outputs/basic/basic_or.c.html %t/basic_or.c.html +RUN: ls %t/style.css diff --git a/llvm/test/tools/opt-viewer/lit.local.cfg b/llvm/test/tools/opt-viewer/lit.local.cfg new file mode 100644 index 000000000000..84dda078f970 --- /dev/null +++ b/llvm/test/tools/opt-viewer/lit.local.cfg @@ -0,0 +1,2 @@ +if 'have_opt_viewer_modules' not in config.available_features: + config.unsupported = True diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp index 13024fbeaeaa..9c6a1612fa08 100644 --- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp +++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp @@ -75,6 +75,7 @@ static void demangle(llvm::raw_ostream &OS, const std::string &Mangled) { } OS << (Undecorated ? Undecorated : Mangled) << '\n'; + OS.flush(); free(Undecorated); } diff --git a/llvm/tools/opt-viewer/opt-viewer.py b/llvm/tools/opt-viewer/opt-viewer.py index 7253d7c13ee8..3000fb12f0b5 100755 --- a/llvm/tools/opt-viewer/opt-viewer.py +++ b/llvm/tools/opt-viewer/opt-viewer.py @@ -60,19 +60,23 @@ class SourceFileRenderer: def render_source_lines(self, stream, line_remarks): file_text = stream.read() - html_highlighted = highlight( + + if args.no_highlight: + html_highlighted = file_text + else: + html_highlighted = highlight( file_text, - self.cpp_lexer, - self.html_formatter) + self.cpp_lexer, + self.html_formatter) - # On Python 3, pygments.highlight() returns a bytes object, not a str. - if sys.version_info >= (3, 0): - html_highlighted = html_highlighted.decode('utf-8') + # On Python 3, pygments.highlight() returns a bytes object, not a str. + if sys.version_info >= (3, 0): + html_highlighted = html_highlighted.decode('utf-8') - # Take off the header and footer, these must be - # reapplied line-wise, within the page structure - html_highlighted = html_highlighted.replace('
', '')
-        html_highlighted = html_highlighted.replace('
', '') + # Take off the header and footer, these must be + # reapplied line-wise, within the page structure + html_highlighted = html_highlighted.replace('
', '')
+            html_highlighted = html_highlighted.replace('
', '') for (linenum, html_line) in enumerate(html_highlighted.split('\n'), start=1): print(''' @@ -274,9 +278,19 @@ if __name__ == '__main__': default=1000, type=int, help='Maximum number of the hottest remarks to appear on the index page') + parser.add_argument( + '--no-highlight', + action='store_true', + default=False, + help='Do not use a syntax highlighter when rendering the source code') + parser.add_argument( + '--demangler', + help='Set the demangler to be used (defaults to %s)' % optrecord.Remark.default_demangler) args = parser.parse_args() print_progress = not args.no_progress_indicator + if args.demangler: + optrecord.Remark.set_demangler(args.demangler) files = optrecord.find_opt_files(*args.yaml_dirs_or_files) if not files: diff --git a/llvm/tools/opt-viewer/optrecord.py b/llvm/tools/opt-viewer/optrecord.py index e68bcb870c60..ce665299e172 100644 --- a/llvm/tools/opt-viewer/optrecord.py +++ b/llvm/tools/opt-viewer/optrecord.py @@ -26,11 +26,6 @@ except: import optpmap - -p = subprocess.Popen(['c++filt', '-n'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) -p_lock = Lock() - - try: dict.iteritems except AttributeError: @@ -47,13 +42,6 @@ else: return d.iteritems() -def demangle(name): - with p_lock: - p.stdin.write((name + '\n').encode('utf-8')) - p.stdin.flush() - return p.stdout.readline().rstrip().decode('utf-8') - - def html_file_name(filename): return filename.replace('/', '_').replace('#', '_') + ".html" @@ -66,6 +54,21 @@ class Remark(yaml.YAMLObject): # Work-around for http://pyyaml.org/ticket/154. yaml_loader = Loader + default_demangler = 'c++filt -n' + demangler_proc = None + + @classmethod + def set_demangler(cls, demangler): + cls.demangler_proc = subprocess.Popen(demangler.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE) + cls.demangler_lock = Lock() + + @classmethod + def demangle(cls, name): + with cls.demangler_lock: + cls.demangler_proc.stdin.write((name + '\n').encode('utf-8')) + cls.demangler_proc.stdin.flush() + return cls.demangler_proc.stdout.readline().rstrip().decode('utf-8') + # Intern all strings since we have lot of duplication across filenames, # remark text. # @@ -133,7 +136,7 @@ class Remark(yaml.YAMLObject): @property def DemangledFunctionName(self): - return demangle(self.Function) + return self.demangle(self.Function) @property def Link(self): @@ -149,7 +152,7 @@ class Remark(yaml.YAMLObject): (key, value) = list(mapping.items())[0] if key == 'Caller' or key == 'Callee': - value = cgi.escape(demangle(value)) + value = cgi.escape(self.demangle(value)) if dl and key != 'Caller': dl_dict = dict(list(dl)) @@ -259,6 +262,8 @@ def get_remarks(input_file): def gather_results(filenames, num_jobs, should_print_progress): if should_print_progress: print('Reading YAML files...') + if not Remark.demangler_proc: + Remark.set_demangler(Remark.default_demangler) remarks = optpmap.pmap( get_remarks, filenames, num_jobs, should_print_progress) max_hotness = max(entry[0] for entry in remarks)