autodebug improvements
This commit is contained in:
Родитель
c3408af269
Коммит
4d51d0b276
|
@ -69,7 +69,7 @@ function analyzer(data) {
|
|||
// Internal line
|
||||
if (!currLabelFinished) {
|
||||
item.functions.slice(-1)[0].lines.push(subItem);
|
||||
item.functions.slice(-1)[0].labels.slice(-1)[0].lines.push(subItem);
|
||||
item.functions.slice(-1)[0].labels.slice(-1)[0].lines.push(subItem); // If this line fails, perhaps missing a label? LLVM_STYLE related?
|
||||
if (subItem.intertype === 'branch') {
|
||||
currLabelFinished = true;
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ class RunnerCore(unittest.TestCase):
|
|||
assert 'Could not open input file' not in output, 'Linking error: ' + output
|
||||
|
||||
# Build JavaScript code from source code
|
||||
def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[]):
|
||||
def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None):
|
||||
# Copy over necessary files for compiling the source
|
||||
if main_file is None:
|
||||
f = open(filename, 'w')
|
||||
|
@ -160,6 +160,9 @@ class RunnerCore(unittest.TestCase):
|
|||
|
||||
self.do_llvm_dis(filename)
|
||||
|
||||
if build_ll_hook:
|
||||
build_ll_hook(filename)
|
||||
|
||||
self.do_emscripten(filename, output_processor)
|
||||
|
||||
def do_emscripten(self, filename, output_processor=None):
|
||||
|
@ -204,7 +207,7 @@ if 'benchmark' not in sys.argv:
|
|||
|
||||
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
|
||||
## Does a complete test - builds, runs, checks output, etc.
|
||||
def do_test(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False):
|
||||
def do_test(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None):
|
||||
#print 'Running test:', inspect.stack()[1][3].replace('test_', ''), '[%s,%s,%s]' % (COMPILER.split(os.sep)[-1], 'llvm-optimizations' if LLVM_OPTS else '', 'reloop&optimize' if RELOOP else '')
|
||||
if force_c or (main_file is not None and main_file[-2:]) == '.c':
|
||||
basename = 'src.c'
|
||||
|
@ -214,7 +217,8 @@ if 'benchmark' not in sys.argv:
|
|||
dirname = self.get_dir()
|
||||
filename = os.path.join(dirname, basename)
|
||||
if not no_build:
|
||||
self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes)
|
||||
self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
|
||||
build_ll_hook=build_ll_hook)
|
||||
|
||||
if post_build is not None:
|
||||
post_build(filename + '.o.js')
|
||||
|
@ -1669,7 +1673,10 @@ if 'benchmark' not in sys.argv:
|
|||
def image_compare(output):
|
||||
# Get the image generated by JS, from the JSON.stringify'd array
|
||||
m = re.search('\[[\d, ]*\]', output)
|
||||
js_data = eval(m.group(0))
|
||||
try:
|
||||
js_data = eval(m.group(0))
|
||||
except AttributeError:
|
||||
print 'Failed to find proper image output in: ' + output
|
||||
|
||||
# Generate the native code output using lli
|
||||
lli_file = os.path.join(self.get_dir(), 'lli.raw')
|
||||
|
@ -1690,7 +1697,7 @@ if 'benchmark' not in sys.argv:
|
|||
diff_mean = diff_total/float(num)
|
||||
|
||||
image_mean = 83
|
||||
#print js_mean, image_mean, lli_mean, diff_mean, num
|
||||
print '[image stats:', js_mean, image_mean, lli_mean, diff_mean, num, ']'
|
||||
assert abs(js_mean - image_mean) < 2
|
||||
assert abs(lli_mean - image_mean) < 2
|
||||
assert diff_mean < 2 # XXX All of these are not quite right...
|
||||
|
@ -1707,7 +1714,7 @@ if 'benchmark' not in sys.argv:
|
|||
os.path.join(self.get_building_dir(), 'openjpeg')],
|
||||
force_c=True,
|
||||
post_build=post,
|
||||
output_nicerizer=image_compare)
|
||||
output_nicerizer=image_compare)#, build_ll_hook=self.do_autodebug)
|
||||
|
||||
def zzztest_poppler(self):
|
||||
# Has 'Object', which has a big union with a value that can be of any type (like a dynamic value)
|
||||
|
@ -1752,21 +1759,42 @@ if 'benchmark' not in sys.argv:
|
|||
output = 'hello, world!'
|
||||
self.do_ll_test(path_from_root('tests', 'cases', name), output)
|
||||
|
||||
# Autodebug the code
|
||||
def do_autodebug(self, filename):
|
||||
output = Popen(['python', AUTODEBUGGER, filename+'.o.ll', filename+'.o.ll.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
||||
assert 'Success.' in output, output
|
||||
self.prep_ll_test(filename, filename+'.o.ll.ll', force_recompile=True) # rebuild .bc
|
||||
|
||||
def test_autodebug(self):
|
||||
if COMPILER != LLVM_GCC: return # TODO: Check both
|
||||
if LLVM_OPTS: return # They mess us up
|
||||
|
||||
# Run a test that should work, generating some code
|
||||
self.test_structs()
|
||||
|
||||
# Autodebug the code
|
||||
filename = os.path.join(self.get_dir(), 'src.cpp.o.ll')
|
||||
output = Popen(['python', AUTODEBUGGER, filename, filename+'.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
||||
assert 'Success.' in output
|
||||
filename = os.path.join(self.get_dir(), 'src.cpp')
|
||||
self.do_autodebug(filename)
|
||||
|
||||
# Compare to each other, and to expected output
|
||||
self.do_ll_test(path_from_root('tests', filename+'.ll'), force_recompile=True)
|
||||
self.do_ll_test(path_from_root('tests', filename+'.ll'), '34 : 10\n42 : 7008\n51 : 7018') # No need to force recompile twice - already autodebugged
|
||||
self.do_ll_test(path_from_root('tests', filename+'.o.ll.ll'))
|
||||
self.do_ll_test(path_from_root('tests', filename+'.o.ll.ll'), 'line: 34, value: 10\nline: 43, value: 7008\nline: 53, value: 7018\n')
|
||||
|
||||
# Test using build_ll_hook
|
||||
src = '''
|
||||
#include <stdio.h>
|
||||
|
||||
char cache[256], *next = cache;
|
||||
|
||||
int main()
|
||||
{
|
||||
cache[10] = 25;
|
||||
next[20] = 51;
|
||||
int x = cache[10];
|
||||
printf("*%d,%d*\\n", x, cache[20]);
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
self.do_test(src, build_ll_hook=self.do_autodebug)
|
||||
self.do_test(src, 'line: ', build_ll_hook=self.do_autodebug)
|
||||
|
||||
### Integration tests
|
||||
|
||||
|
|
|
@ -8,17 +8,79 @@ compare that to the output when compiled using emscripten.
|
|||
import os, sys, re
|
||||
|
||||
POSTAMBLE = '''
|
||||
@.emscripten.autodebug.str = private constant [9 x i8] c"%d : %d\\0A\\00", align 1 ; [#uses=1]
|
||||
@.emscripten.autodebug.str = private constant [21 x i8] c"line: %d, value: %d\\0A\\00", align 1 ; [#uses=1]
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug(i32 %line, i32 %value) {
|
||||
define void @emscripten_autodebug_i32(i32 %line, i32 %value) {
|
||||
entry:
|
||||
%0 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, i32 %value) ; [#uses=0]
|
||||
%0 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, i32 %value) ; [#uses=0]
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug_i8(i32 %line, i8 %value) {
|
||||
entry:
|
||||
%0 = zext i8 %value to i32 ; [#uses=1]
|
||||
%1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, i32 %0) ; [#uses=0]
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug_float(i32 %line, float %value) {
|
||||
entry:
|
||||
%0 = fpext float %value to double ; [#uses=1]
|
||||
%1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, double %0) ; [#uses=0]
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug_double(i32 %line, double %value) {
|
||||
entry:
|
||||
%0 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, double %value) ; [#uses=0]
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry
|
||||
ret void
|
||||
}
|
||||
'''
|
||||
|
||||
POSTAMBLE_NEW = '''
|
||||
@.emscripten.autodebug.str = private constant [21 x i8] c"line: %d, value: %d\\0A\\00", align 1 ; [#uses=1]
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug_i32(i32 %line, i32 %value) {
|
||||
%1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, i32 %value) ; [#uses=0]
|
||||
ret void
|
||||
}
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug_i8(i32 %line, i8 %value) {
|
||||
%1 = zext i8 %value to i32 ; [#uses=1]
|
||||
%2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, i32 %1) ; [#uses=0]
|
||||
ret void
|
||||
}
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug_float(i32 %line, float %value) {
|
||||
%1 = fpext float %value to double ; [#uses=1]
|
||||
%2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, double %1) ; [#uses=0]
|
||||
ret void
|
||||
}
|
||||
|
||||
; [#uses=1]
|
||||
define void @emscripten_autodebug_double(i32 %line, double %value) {
|
||||
%1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([21 x i8]* @.emscripten.autodebug.str, i32 0, i32 0), i32 %line, double %value) ; [#uses=0]
|
||||
ret void
|
||||
}
|
||||
'''
|
||||
|
||||
filename, ofilename = sys.argv[1], sys.argv[2]
|
||||
|
@ -32,14 +94,21 @@ if 'declare i32 @printf(' not in data:
|
|||
declare i32 @printf(i8*, ...)
|
||||
'''
|
||||
|
||||
LLVM_STYLE_OLD = '<label>' not in data and 'entry:' in data
|
||||
|
||||
if not LLVM_STYLE_OLD:
|
||||
POSTAMBLE = POSTAMBLE_NEW
|
||||
|
||||
lines_added = 0
|
||||
lines = data.split('\n')
|
||||
for i in range(len(lines)):
|
||||
#if i == 5:
|
||||
# lines[i] += '\n
|
||||
|
||||
m = re.match(' store (?P<type>i64|i32|i16|i8) %(?P<var>[\w.]+), .*', lines[i])
|
||||
if m and m.group('type') == 'i32': # TODO: Other types
|
||||
lines[i] += '\n call void @emscripten_autodebug(i32 %d, i32 %%%s)' % (i+1, m.group('var'))
|
||||
if m and m.group('type') in ['i8', 'i32', 'float', 'double']:
|
||||
lines[i] += '\n call void @emscripten_autodebug_%s(i32 %d, %s %%%s)' % (m.group('type'), i+1+lines_added, m.group('type'), m.group('var'))
|
||||
lines_added += 1
|
||||
|
||||
f = open(ofilename, 'w')
|
||||
f.write('\n'.join(lines) + '\n' + POSTAMBLE + '\n')
|
||||
|
|
Загрузка…
Ссылка в новой задаче