diff options
53 files changed, 2329 insertions, 1780 deletions
@@ -113,3 +113,4 @@ a license to everyone to use it as detailed in LICENSE.) * Heidi Pan <heidi.pan@intel.com> (copyright owned by Intel) * Vasilis Kalintiris <ehostunreach@gmail.com> * Adam C. Clifton <adam@hulkamaniac.com> +* Volo Zyko <volo.zyko@gmail.com> diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake index c30632ca..4f434d14 100644 --- a/cmake/Platform/Emscripten.cmake +++ b/cmake/Platform/Emscripten.cmake @@ -109,6 +109,8 @@ set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") # Specify the program to use when building static libraries. Force Emscripten-related command line options to clang. set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_AR} rc <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_AR} rc <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") +set(CMAKE_CXX_ARCHIVE_APPEND "${CMAKE_AR} r <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") +set(CMAKE_C_ARCHIVE_APPEND "${CMAKE_AR} r <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}") # Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten. # There seems to be some kind of bug with CMake, so you might need to define this manually on the command line with "-DEMSCRIPTEN=1". @@ -122,22 +124,22 @@ SET(APPLE) set(CMAKE_C_SIZEOF_DATA_PTR 4) set(CMAKE_CXX_SIZEOF_DATA_PTR 4) -set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE") -set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO") -set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELEASE") -set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_MINSIZEREL") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELWITHDEBINFO") +set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE") +set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO") +set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELEASE") +set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_MINSIZEREL") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELWITHDEBINFO") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELEASE") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_MINSIZEREL") -set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELEASE") set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL") -set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO") set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELEASE") set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL") -set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2 -g" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO") function(em_validate_asmjs_after_build target) add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo Validating build output for asm.js... COMMAND "python" ARGS "${EMSCRIPTEN_ROOT_PATH}/tools/validate_asmjs.py" "$<TARGET_FILE:${target}>") @@ -203,3 +205,24 @@ endfunction() function(em_link_post_js target) em_add_tracked_link_flag(${target} "--post-js" ${ARGN}) endfunction() + +# Experimental support for targeting generation of Visual Studio project files (vs-tool) of Emscripten projects for Windows. +# To use this, pass the combination -G "Visual Studio 10" -DCMAKE_TOOLCHAIN_FILE=Emscripten.cmake +if ("${CMAKE_GENERATOR}" MATCHES "^Visual Studio.*") + # By default, CMake generates VS project files with a <GenerateManifest>true</GenerateManifest> directive. + # This causes VS to attempt to invoke rc.exe during the build, which will fail since app manifests are meaningless for Emscripten. + # To disable this, add the following linker flag. This flag will not go to emcc, since the Visual Studio CMake generator will swallow it. + set(EMSCRIPTEN_VS_LINKER_FLAGS "/MANIFEST:NO") + # CMake is hardcoded to write a ClCompile directive <ObjectFileName>$(IntDir)</ObjectFileName> in all VS project files it generates. + # This makes VS pass emcc a -o param that points to a directory instead of a file, which causes emcc autogenerate the output filename. + # CMake is hardcoded to assume all object files have the suffix .obj, so adjust the emcc-autogenerated default suffix name to match. + set(EMSCRIPTEN_VS_LINKER_FLAGS "${EMSCRIPTEN_VS_LINKER_FLAGS} --default-obj-ext .obj") + # Also hint CMake that it should not hardcode <ObjectFileName> generation. Requires a custom CMake build for this to work (ignored on others) + # See http://www.cmake.org/Bug/view.php?id=14673 and https://github.com/juj/CMake + set(CMAKE_VS_NO_DEFAULT_OBJECTFILENAME 1) + + # Apply and cache Emscripten Visual Studio IDE-specific linker flags. + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${EMSCRIPTEN_VS_LINKER_FLAGS}" CACHE STRING "") +endif() @@ -53,14 +53,17 @@ from tools import shared, jsrun from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename, WINDOWS from tools.response_file import read_response_file -C_SUFFIXES = ('.c', '.C') -CXX_SUFFIXES = ('.cpp', '.cxx', '.cc', '.CPP', '.CXX', '.CC') -SOURCE_SUFFIXES = C_SUFFIXES + CXX_SUFFIXES + ('.m', '.mm') -BITCODE_SUFFIXES = ('.bc', '.o', '.obj') -DYNAMICLIB_SUFFIXES = ('.dylib', '.so', '.dll') -STATICLIB_SUFFIXES = ('.a',) -ASSEMBLY_SUFFIXES = ('.ll',) +# endings = dot + a suffix, safe to test by filename.endswith(endings) +C_ENDINGS = ('.c', '.C') +CXX_ENDINGS = ('.cpp', '.cxx', '.cc', '.CPP', '.CXX', '.CC') +SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + ('.m', '.mm') +BITCODE_ENDINGS = ('.bc', '.o', '.obj') +DYNAMICLIB_ENDINGS = ('.dylib', '.so', '.dll') +STATICLIB_ENDINGS = ('.a',) +ASSEMBLY_ENDINGS = ('.ll',) + LIB_PREFIXES = ('', 'lib') + JS_CONTAINING_SUFFIXES = ('js', 'html') # Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt @@ -345,7 +348,9 @@ Options that are modified or new in %s include: --embed-file and --preload-file wildcard is supported - --compression <codec> Compress both the compiled code and embedded/ + --compression <codec> **THIS OPTION IS DEPRECATED** + + Compress both the compiled code and embedded/ preloaded files. <codec> should be a triple, <native_encoder>,<js_decoder>,<js_name> @@ -514,6 +519,13 @@ Options that are modified or new in %s include: file, and if that is not set, the default location ~/.emscripten is assumed. + --default-obj-ext .ext Specifies the file suffix to generate if the location + of a directory name is passed to -o directive, e.g. + emcc -c a.c -o dir/ + will by default generate an output name 'dir/a.o', + but this cmdline param can be passed to generate a + file with a custom suffix 'dir/a.ext'. + The target file, if specified (-o <target>), defines what will be generated: @@ -762,9 +774,13 @@ def in_temp(name): def filename_type_suffix(filename): for i in reversed(filename.split('.')[1:]): if not i.isdigit(): - return '.' + i + return i return '' +def filename_type_ending(filename): + suffix = filename_type_suffix(filename) + return '' if not suffix else ('.' + suffix) + try: call = CXX if use_cxx else CC @@ -797,6 +813,7 @@ try: use_preload_cache = False no_heap_copy = False proxy_to_worker = False + default_object_extension = '.o' if use_cxx: default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline. @@ -907,6 +924,7 @@ try: newargs[i] = '' newargs[i+1] = '' elif newargs[i].startswith('--compression'): + logging.warning('--compression is deprecated. Instead, it is recommended you use native gzip compression in your webserver') check_bad_eq(newargs[i]) parts = newargs[i+1].split(',') assert len(parts) == 3, '--compression requires specifying native_encoder,js_decoder,js_name - see emcc --help. got: %s' % newargs[i+1] @@ -992,6 +1010,12 @@ try: # This option is parsed in tools/shared.py, here only clean it up from being passed to clang. newargs[i] = '' newargs[i+1] = '' + elif newargs[i] == '--default-obj-ext': + newargs[i] = '' + default_object_extension = newargs[i+1] + if not default_object_extension.startswith('.'): + default_object_extension = '.' + default_object_extension + newargs[i+1] = '' newargs = [ arg for arg in newargs if arg is not '' ] @@ -1053,23 +1077,23 @@ try: prev = newargs[i-1] if prev in ['-MT', '-MF', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L']: continue # ignore this gcc-style argument - if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES)): + if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS)): arg = os.path.realpath(arg) if not arg.startswith('-'): if not os.path.exists(arg): - logging.error(arg + ': No such file or directory') + logging.error('%s: No such file or directory ("%s" was expected to be an input file, based on the commandline arguments provided)' % (arg, arg)) exit(1) - arg_suffix = filename_type_suffix(arg) - if arg_suffix.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs + arg_ending = filename_type_ending(arg) + if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs newargs[i] = '' - if arg_suffix.endswith(SOURCE_SUFFIXES): + if arg_ending.endswith(SOURCE_ENDINGS): input_files.append(arg) has_source_inputs = True - elif arg_suffix.endswith(ASSEMBLY_SUFFIXES) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid + elif arg_ending.endswith(ASSEMBLY_ENDINGS) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid input_files.append(arg) - elif arg_suffix.endswith(STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES): + elif arg_ending.endswith(STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS): # if it's not, and it's a library, just add it to libs to find later l = unsuffixed_basename(arg) for prefix in LIB_PREFIXES: @@ -1081,10 +1105,10 @@ try: newargs[i] = '' else: logging.warning(arg + ' is not valid LLVM bitcode') - elif arg_suffix.endswith(STATICLIB_SUFFIXES): + elif arg_ending.endswith(STATICLIB_ENDINGS): if not shared.Building.is_ar(arg): if shared.Building.is_bitcode(arg): - logging.error(arg + ': File has a suffix of a static library ' + str(STATICLIB_SUFFIXES) + ', but instead is an LLVM bitcode file! When linking LLVM bitcode files, use one of the suffixes ' + str(BITCODE_SUFFIXES)) + logging.error(arg + ': File has a suffix of a static library ' + str(STATICLIB_ENDINGS) + ', but instead is an LLVM bitcode file! When linking LLVM bitcode files, use one of the suffixes ' + str(BITCODE_ENDINGS)) else: logging.error(arg + ': Unknown format, not a static library!') exit(1) @@ -1109,17 +1133,12 @@ try: target = target_basename + '.o' final_suffix = 'o' - # do not link in libs when just generating object code (not an 'executable', i.e. JS, or a library) - if ('.' + final_suffix) in BITCODE_SUFFIXES and len(libs) > 0: - logging.warning('not linking against libraries since only compiling to bitcode') - libs = [] - # Find library files for lib in libs: logging.debug('looking for library "%s"' % lib) found = False for prefix in LIB_PREFIXES: - for suff in STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES: + for suff in STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS: name = prefix + lib + suff for lib_dir in lib_dirs: path = os.path.join(lib_dir, name) @@ -1130,12 +1149,21 @@ try: break if found: break if found: break - - if ignore_dynamic_linking: - input_files = filter(lambda input_file: not input_file.endswith(DYNAMICLIB_SUFFIXES), input_files) + if not found: logging.warning('emcc: cannot find library "%s"' % lib) + + # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so + # ignore dynamic linking, since multiple dynamic linkings can interfere with each other + if not filename_type_suffix(target) in JS_CONTAINING_SUFFIXES or ignore_dynamic_linking: + def check(input_file): + if filename_type_ending(input_file) in DYNAMICLIB_ENDINGS: + if not ignore_dynamic_linking: logging.warning('ignoring dynamic library %s because not compiling to JS or HTML, remember to link it when compiling to JS or HTML at the end' % os.path.basename(input_file)) + return False + else: + return True + input_files = filter(lambda input_file: check(input_file), input_files) if len(input_files) == 0: - logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + STATICLIB_SUFFIXES + ASSEMBLY_SUFFIXES)) + logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + STATICLIB_ENDINGS + ASSEMBLY_ENDINGS)) exit(0) newargs = CC_ADDITIONAL_ARGS + newargs @@ -1162,7 +1190,9 @@ try: logging.warning('disabling asm.js since embind is not ready for it yet') shared.Settings.ASM_JS = 0 - if os.environ.get('EMCC_FAST_COMPILER'): + fastcomp = os.environ.get('EMCC_FAST_COMPILER') == '1' + + if fastcomp: shared.Settings.ASM_JS = 1 if shared.Settings.DISABLE_EXCEPTION_CATCHING == 0: logging.warning('disabling exception catching since not supported in fastcomp yet') @@ -1181,9 +1211,12 @@ try: assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp' assert shared.Settings.TARGET_LE32 == 1, 'fastcomp requires le32' assert not bind, 'embind not supported in fastcomp yet' + if jcache: + logging.warning('jcache is not supported in fastcomp (you should not need it anyhow), disabling') + jcache = False if shared.Settings.ASM_JS: - assert opt_level >= 1 or os.environ.get('EMCC_FAST_COMPILER'), 'asm.js requires -O1 or above' + assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above' if bind: shared.Settings.RESERVED_FUNCTION_POINTERS = max(shared.Settings.RESERVED_FUNCTION_POINTERS, 10) @@ -1195,16 +1228,6 @@ try: shared.Settings.CORRECT_OVERFLOWS = 1 assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' - heap = 4096 - while heap < shared.Settings.TOTAL_MEMORY: - if heap < 16*1024*1024: - heap *= 2 - else: - heap += 16*1024*1024 - if heap != shared.Settings.TOTAL_MEMORY: - logging.warning('increasing TOTAL_MEMORY to %d to be more reasonable for asm.js' % heap) - shared.Settings.TOTAL_MEMORY = heap - if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2: debug_level = 4 # must keep debug info to do line-by-line operations @@ -1272,14 +1295,14 @@ try: # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for input_file in input_files: - file_suffix = filename_type_suffix(input_file) - if file_suffix.endswith(SOURCE_SUFFIXES): + file_ending = filename_type_ending(input_file) + if file_ending.endswith(SOURCE_ENDINGS): logging.debug('compiling source file: ' + input_file) input_file = shared.Building.preprocess(input_file, in_temp(uniquename(input_file))) output_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') temp_files.append(output_file) args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file] - if file_suffix.endswith(CXX_SUFFIXES): + if file_ending.endswith(CXX_ENDINGS): args += shared.EMSDK_CXX_OPTS logging.debug("running: " + call + ' ' + ' '.join(args)) execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) @@ -1287,17 +1310,17 @@ try: logging.error('compiler frontend failed to generate LLVM bitcode, halting') sys.exit(1) else: # bitcode - if file_suffix.endswith(BITCODE_SUFFIXES): + if file_ending.endswith(BITCODE_ENDINGS): logging.debug('copying bitcode file: ' + input_file) temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') shutil.copyfile(input_file, temp_file) temp_files.append(temp_file) - elif file_suffix.endswith(DYNAMICLIB_SUFFIXES) or shared.Building.is_ar(input_file): + elif file_ending.endswith(DYNAMICLIB_ENDINGS) or shared.Building.is_ar(input_file): logging.debug('copying library file: ' + input_file) temp_file = in_temp(uniquename(input_file)) shutil.copyfile(input_file, temp_file) temp_files.append(temp_file) - elif file_suffix.endswith(ASSEMBLY_SUFFIXES): + elif file_ending.endswith(ASSEMBLY_ENDINGS): if not LEAVE_INPUTS_RAW: # Note that by assembling the .ll file, then disassembling it later, we will # remove annotations which is a good thing for compilation time @@ -1315,8 +1338,8 @@ try: # Optimize source files if llvm_opts > 0: for i, input_file in enumerate(input_files): - file_suffix = filename_type_suffix(input_file) - if file_suffix.endswith(SOURCE_SUFFIXES): + file_ending = filename_type_ending(input_file) + if file_ending.endswith(SOURCE_ENDINGS): temp_file = temp_files[i] logging.debug('optimizing %s with -O%s' % (input_file, llvm_opts)) shared.Building.llvm_opt(temp_file, llvm_opts) @@ -1329,7 +1352,16 @@ try: else: if len(input_files) == 1: temp_output_base = in_temp(unsuffixed(uniquename(input_files[0]))) - shutil.move(temp_output_base + '.o', specified_target) + if specified_target.endswith('/') or specified_target.endswith('\\') or os.path.isdir(specified_target): # User passed '-o <directory' as the location to output to. + obj_output_name = os.path.join(specified_target, os.path.splitext(os.path.basename(input_file))[0] + default_object_extension) + logging.debug('User specified -o <directoryname> as the location of the output. Generating output file ' + obj_output_name) + try: + shutil.move(temp_output_base + '.o', obj_output_name) + except IOError, e: + logging.error('Could not write to output file ' + obj_output_name + '. Perhaps the output directory does not exist?') + exit(1) + else: # User passed '-o <filename>' as the location to output to. + shutil.move(temp_output_base + '.o', specified_target) if os.path.exists(temp_output_base + '.d'): # There was a .d file generated, from -MD or -MMD and friends, save a copy of it to where the output resides, # adjusting the target name away from the temporary file name to the specified target. @@ -1661,11 +1693,11 @@ try: # First, combine the bitcode files if there are several. We must also link if we have a singleton .a if len(input_files) + len(extra_files_to_link) > 1 or \ - (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_SUFFIXES or suffix(temp_files[0]) in DYNAMICLIB_SUFFIXES) and shared.Building.is_ar(temp_files[0])): + (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_ENDINGS or suffix(temp_files[0]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0])): linker_inputs = temp_files + extra_files_to_link logging.debug('linking: ' + str(linker_inputs)) t0 = time.time() - shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_SUFFIXES), temp_files)) == 0) + shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_ENDINGS), temp_files)) == 0) t1 = time.time() logging.debug(' linking took %.2f seconds' % (t1 - t0)) final = in_temp(target_basename + '.bc') @@ -1711,22 +1743,25 @@ try: # At minimum remove dead functions etc., this potentially saves a lot in the size of the generated code (and the time to compile it) link_opts += shared.Building.get_safe_internalize() + ['-globaldce'] - # Simplify LLVM bitcode for fastcomp - if os.environ.get('EMCC_FAST_COMPILER') and not AUTODEBUG: - link_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] - if (not save_bc and not os.environ.get('EMCC_FAST_COMPILER')) or AUTODEBUG: + if (not save_bc and not fastcomp) or AUTODEBUG: # let llvm opt directly emit ll, to skip writing and reading all the bitcode link_opts += ['-S'] shared.Building.llvm_opt(final, link_opts, final + '.link.ll') final = final + '.link.ll' if DEBUG: save_intermediate('linktime', 'll') else: + if fastcomp and not save_bc: + # Simplify LLVM bitcode for fastcomp + link_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] shared.Building.llvm_opt(final, link_opts) if DEBUG: save_intermediate('linktime', 'bc') - - if save_bc: - shutil.copyfile(final, save_bc) + if save_bc: + shutil.copyfile(final, save_bc) + if fastcomp: + shared.Building.llvm_opt(final, ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'], final + '.adsimp.bc') + final += '.adsimp.bc' + if DEBUG: save_intermediate('adsimp', 'bc') # Prepare .ll for Emscripten if not LEAVE_INPUTS_RAW: @@ -1743,7 +1778,7 @@ try: if DEBUG: save_intermediate('autodebug', 'll') # Simplify bitcode after autodebug - if os.environ.get('EMCC_FAST_COMPILER') and AUTODEBUG: + if fastcomp and (AUTODEBUG or LEAVE_INPUTS_RAW): shared.Building.llvm_opt(final, ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'], final + '.adsimp.bc') final += '.adsimp.bc' if DEBUG: save_intermediate('adsimp', 'bc') @@ -492,15 +492,18 @@ def win_print_gpu_info(): print "GPU"+str(i)+ ": " + gpus[i] + " with " + gpu_memory[i] + " MBs of VRAM" def linux_print_gpu_info(): - glxinfo = subprocess.check_output('glxinfo') - for line in glxinfo.split("\n"): - if "OpenGL vendor string:" in line: - gl_vendor = line[len("OpenGL vendor string:"):].strip() - if "OpenGL version string:" in line: - gl_version = line[len("OpenGL version string:"):].strip() - if "OpenGL renderer string:" in line: - gl_renderer = line[len("OpenGL renderer string:"):].strip() - logi('GPU: ' + gl_vendor + ' ' + gl_renderer + ', GL version ' + gl_version) + try: + glxinfo = subprocess.check_output('glxinfo') + for line in glxinfo.split("\n"): + if "OpenGL vendor string:" in line: + gl_vendor = line[len("OpenGL vendor string:"):].strip() + if "OpenGL version string:" in line: + gl_version = line[len("OpenGL version string:"):].strip() + if "OpenGL renderer string:" in line: + gl_renderer = line[len("OpenGL renderer string:"):].strip() + logi('GPU: ' + gl_vendor + ' ' + gl_renderer + ', GL version ' + gl_version) + except: + pass def osx_print_gpu_info(): try: @@ -722,11 +725,12 @@ def find_browser(name): ('firefox_beta', os.path.expanduser('~/firefox_beta/firefox')), ('firefox_aurora', os.path.expanduser('~/firefox_aurora/firefox')), ('firefox_nightly', os.path.expanduser('~/firefox_nightly/firefox')), - ('chrome', which('google-chrome-stable'))] + ('chrome', which('google-chrome-stable')), + ('chrome', which('google-chrome'))] for (alias, browser_exe) in browser_locations: if name == alias: - if os.path.isfile(browser_exe): + if browser_exe is not None and os.path.isfile(browser_exe): return [browser_exe] return None # Could not find the browser diff --git a/src/analyzer.js b/src/analyzer.js index 17582ea3..e8ca6cf6 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1570,7 +1570,17 @@ function analyzer(data, sidePass) { for (var j = 0; j < label.lines.length; j++) { var line = label.lines[j]; if ((line.intertype == 'call' || line.intertype == 'invoke') && line.ident == setjmp) { - // Add a new label + if (line.intertype == 'invoke') { + // setjmp cannot trigger unwinding, so just reduce the invoke to a call + branch + line.intertype = 'call'; + label.lines.push({ + intertype: 'branch', + label: line.toLabel, + lineNum: line.lineNum + 0.01, // XXX legalizing might confuse this + }); + line.toLabel = line.unwindLabel = -2; + } + // split this label into up to the setjmp (including), then a new label for the rest. longjmp will reach the rest var oldLabel = label.ident; var newLabel = func.labelIdCounter++; if (!func.setjmpTable) func.setjmpTable = []; diff --git a/src/compiler.js b/src/compiler.js index 7d768c3d..e4ce1c88 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -134,7 +134,7 @@ load('settings.js'); var settings_file = arguments_[0]; var ll_file = arguments_[1]; phase = arguments_[2]; -if (phase == 'pre') { +if (phase == 'pre' || phase == 'glue') { additionalLibraries = Array.prototype.slice.call(arguments_, 3); } else { var forwardedDataFile = arguments_[3]; diff --git a/src/jsifier.js b/src/jsifier.js index 6b831b04..58dc4653 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -6,7 +6,6 @@ // Handy sets var STRUCT_LIST = set('struct', 'list'); -var UNDERSCORE_OPENPARENS = set('_', '('); var RELOOP_IGNORED_LASTS = set('return', 'unreachable', 'resume'); var addedLibraryItems = {}; @@ -96,19 +95,6 @@ function JSify(data, functionsOnly, givenFunctions) { // Functions - Functions.currExternalFunctions = !mainPass ? givenFunctions.currExternalFunctions : {}; - - data.functionStubs.forEach(function(func) { - // Don't overwrite stubs that have more info. - if (!Functions.currExternalFunctions.hasOwnProperty(func.ident) || - !Functions.currExternalFunctions[func.ident].numParams === undefined) { - Functions.currExternalFunctions[func.ident] = { - hasVarArgs: func.hasVarArgs, - numParams: func.params && func.params.length - }; - } - }); - if (phase == 'funcs') { // || phase == 'pre') { // pre has function shells, just to defined implementedFunctions var MAX_BATCH_FUNC_LINES = 1000; while (data.unparsedFunctions.length > 0) { @@ -1824,7 +1810,7 @@ function JSify(data, functionsOnly, givenFunctions) { print('staticSealed = true; // seal the static portion of memory\n'); print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n'); print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n'); - print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n'); + print('assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");\n'); } if (asmLibraryFunctions.length > 0) { diff --git a/src/library.js b/src/library.js index fc731e01..354e5549 100644 --- a/src/library.js +++ b/src/library.js @@ -8858,7 +8858,8 @@ LibraryManager.library = { } } str += ')'; - args = args.callee.caller.arguments; + var caller = args.callee.caller; + args = caller ? caller.arguments : []; if (first) str = ''; return [args, funcname, str]; diff --git a/src/library_gl.js b/src/library_gl.js index 29f78c8a..075d7cb5 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -268,11 +268,27 @@ var LibraryGL = { return; case "object": if (result === null) { - GL.recordError(0x0500); // GL_INVALID_ENUM + // null is a valid result for some (e.g., which buffer is bound - perhaps nothing is bound), but otherwise + // can mean an invalid name_, which we need to report as an error + switch(name_) { + case 0x8894: // ARRAY_BUFFER_BINDING + case 0x8B8D: // CURRENT_PROGRAM + case 0x8895: // ELEMENT_ARRAY_BUFFER_BINDING + case 0x8CA6: // FRAMEBUFFER_BINDING + case 0x8CA7: // RENDERBUFFER_BINDING + case 0x8069: // TEXTURE_BINDING_2D + case 0x8514: { // TEXTURE_BINDING_CUBE_MAP + ret = 0; + break; + } + default: { + GL.recordError(0x0500); // GL_INVALID_ENUM #if GL_ASSERTIONS - Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(' + name_ + ') and it returns null!'); + Module.printErr('GL_INVALID_ENUM in glGet' + type + 'v(' + name_ + ') and it returns null!'); #endif - return; + return; + } + } } else if (result instanceof Float32Array || result instanceof Uint32Array || result instanceof Int32Array || @@ -547,6 +563,9 @@ var LibraryGL = { Module.ctx.getExtension('WEBKIT_EXT_texture_filter_anisotropic'); GL.floatExt = Module.ctx.getExtension('OES_texture_float'); + + // Extension available from Firefox 26 and Google Chrome 30 + GL.instancedArraysExt = Module.ctx.getExtension('ANGLE_instanced_arrays'); // These are the 'safe' feature-enabling extensions that don't add any performance impact related to e.g. debugging, and // should be enabled by default so that client GLES2/GL code will not need to go through extra hoops to get its stuff working. @@ -1685,7 +1704,7 @@ var LibraryGL = { glGetFramebufferAttachmentParameteriv__sig: 'viiii', glGetFramebufferAttachmentParameteriv: function(target, attachment, pname, params) { var result = Module.ctx.getFramebufferAttachmentParameter(target, attachment, pname); - {{{ makeSetValue('params', '0', 'params', 'i32') }}}; + {{{ makeSetValue('params', '0', 'result', 'i32') }}}; }, glIsFramebuffer__sig: 'ii', @@ -1916,6 +1935,13 @@ var LibraryGL = { return id; }; + function ensurePrecision(source) { + if (!/precision +(low|medium|high)p +float *;/.test(source)) { + source = 'precision mediump float;\n' + source; + } + return source; + } + var glShaderSource = _glShaderSource; _glShaderSource = function _glShaderSource(shader, count, string, length) { var source = GL.getSource(shader, count, string, length); @@ -1989,6 +2015,7 @@ var LibraryGL = { source = 'varying float v_fogFragCoord; \n' + source.replace(/gl_FogFragCoord/g, 'v_fogFragCoord'); } + source = ensurePrecision(source); } else { // Fragment shader for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) { var old = source; @@ -2020,7 +2047,7 @@ var LibraryGL = { source = 'varying float v_fogFragCoord; \n' + source.replace(/gl_FogFragCoord/g, 'v_fogFragCoord'); } - source = 'precision mediump float;\n' + source; + source = ensurePrecision(source); } #if GL_DEBUG GL.shaderSources[shader] = source; @@ -4959,6 +4986,45 @@ var LibraryGL = { return Module.ctx.getError(); } }, + + // ANGLE_instanced_arrays WebGL extension related functions + + glVertexAttribDivisor__sig: 'vii', + glVertexAttribDivisor: function(index, divisor) { +#if GL_ASSERTIONS + assert(GL.instancedArraysExt, 'Must have ANGLE_instanced_arrays extension to use WebGL instancing'); +#endif + GL.instancedArraysExt.vertexAttribDivisorANGLE(index, divisor); + }, + + glDrawArraysInstanced__sig: 'viiii', + glDrawArraysInstanced: function(mode, first, count, primcount) { +#if GL_ASSERTIONS + assert(GL.instancedArraysExt, 'Must have ANGLE_instanced_arrays extension to use WebGL instancing'); +#endif + GL.instancedArraysExt.drawArraysInstancedANGLE(mode, first, count, primcount); + }, + + glDrawElementsInstanced__sig: 'viiiii', + glDrawElementsInstanced: function(mode, count, type, indices, primcount) { +#if GL_ASSERTIONS + assert(GL.instancedArraysExt, 'Must have ANGLE_instanced_arrays extension to use WebGL instancing'); +#endif + GL.instancedArraysExt.drawElementsInstancedANGLE(mode, count, type, indices, primcount); + }, + + // OpenGL Desktop/ES 2.0 instancing extensions compatibility + + glVertexAttribDivisorNV: 'glVertexAttribDivisor', + glDrawArraysInstancedNV: 'glDrawArraysInstanced', + glDrawElementsInstancedNV: 'glDrawElementsInstanced', + glVertexAttribDivisorEXT: 'glVertexAttribDivisor', + glDrawArraysInstancedEXT: 'glDrawArraysInstanced', + glDrawElementsInstancedEXT: 'glDrawElementsInstanced', + glVertexAttribDivisorARB: 'glVertexAttribDivisor', + glDrawArraysInstancedARB: 'glDrawArraysInstanced', + glDrawElementsInstancedARB: 'glDrawElementsInstanced', + // signatures of simple pass-through functions, see later glActiveTexture__sig: 'vi', diff --git a/src/library_sdl.js b/src/library_sdl.js index 2efc1271..fc38dd1c 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1059,11 +1059,35 @@ var LibrarySDL = { var src = buffer >> 2; var dst = 0; var isScreen = surf == SDL.screen; - var data32 = new Uint32Array(data.buffer); - var num = data32.length; - while (dst < num) { - // HEAP32[src++] is an optimization. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}}; - data32[dst++] = HEAP32[src++] | (isScreen ? 0xff000000 : 0); + var num; + if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) { + // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray, + // not UInt8ClampedArray. These don't have buffers, so we need to revert + // to copying a byte at a time. We do the undefined check because modern + // browsers do not define CanvasPixelArray anymore. + num = data.length; + while (dst < num) { + var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}}; + data[dst ] = val & 0xff; + data[dst+1] = (val >> 8) & 0xff; + data[dst+2] = (val >> 16) & 0xff; + data[dst+3] = isScreen ? 0xff : ((val >> 24) & 0xff); + src++; + dst += 4; + } + } else { + var data32 = new Uint32Array(data.buffer); + num = data32.length; + if (isScreen) { + while (dst < num) { + // HEAP32[src++] is an optimization. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}}; + data32[dst++] = HEAP32[src++] | 0xff000000; + } + } else { + while (dst < num) { + data32[dst++] = HEAP32[src++]; + } + } } #else var num = surfData.image.data.length; @@ -1220,6 +1244,7 @@ var LibrarySDL = { if (surf) SDL.freeSurface(surf); }, + SDL_UpperBlit__deps: ['SDL_LockSurface'], SDL_UpperBlit: function(src, srcrect, dst, dstrect) { var srcData = SDL.surfaces[src]; var dstData = SDL.surfaces[dst]; diff --git a/src/parseTools.js b/src/parseTools.js index ff981264..874514b1 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -16,6 +16,7 @@ function processMacros(text) { // Simple #if/else/endif preprocessing for a file. Checks if the // ident checked is true in our global. +// Also handles #include x.js (similar to C #include <file>) function preprocess(text) { var lines = text.split('\n'); var ret = ''; @@ -30,25 +31,29 @@ function preprocess(text) { ret += line + '\n'; } } else { - if (line[1] && line[1] == 'i') { // if - var parts = line.split(' '); - var ident = parts[1]; - var op = parts[2]; - var value = parts[3]; - if (op) { - if (op === '==') { - showStack.push(ident in this && this[ident] == value); - } else if (op === '!=') { - showStack.push(!(ident in this && this[ident] == value)); + if (line[1] == 'i') { + if (line[2] == 'f') { // if + var parts = line.split(' '); + var ident = parts[1]; + var op = parts[2]; + var value = parts[3]; + if (op) { + if (op === '==') { + showStack.push(ident in this && this[ident] == value); + } else if (op === '!=') { + showStack.push(!(ident in this && this[ident] == value)); + } else { + error('unsupported preprecessor op ' + op); + } } else { - error('unsupported preprecessor op ' + op); + showStack.push(ident in this && this[ident] > 0); } - } else { - showStack.push(ident in this && this[ident] > 0); + } else if (line[2] == 'n') { // include + ret += '\n' + read(line.substr(line.indexOf(' ')+1)) + '\n' } - } else if (line[2] && line[2] == 'l') { // else + } else if (line[2] == 'l') { // else showStack.push(!showStack.pop()); - } else if (line[2] && line[2] == 'n') { // endif + } else if (line[2] == 'n') { // endif showStack.pop(); } else { throw "Unclear preprocessor command: " + line; diff --git a/src/preamble.js b/src/preamble.js index 832ec2c3..f9fccdf6 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -866,6 +866,21 @@ var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}}; var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}}; var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}}; +#if ASM_JS +var totalMemory = 4096; +while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) { + if (totalMemory < 16*1024*1024) { + totalMemory *= 2; + } else { + totalMemory += 16*1024*1024 + } +} +if (totalMemory !== TOTAL_MEMORY) { + Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable'); + TOTAL_MEMORY = totalMemory; +} +#endif + // Initialize the runtime's memory #if USE_TYPED_ARRAYS // check for full engine support (use string 'subarray' to avoid closure compiler confusion) diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index d2a48f63..de69e0ef 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -101,9 +101,7 @@ void Branch::Render(Block *Target, bool SetLabel) { // Block -int Block::IdCounter = 1; // 0 is reserved for clearings - -Block::Block(const char *CodeInit, const char *BranchVarInit) : Parent(NULL), Id(Block::IdCounter++), IsCheckedMultipleEntry(false) { +Block::Block(const char *CodeInit, const char *BranchVarInit) : Parent(NULL), Id(-1), IsCheckedMultipleEntry(false) { Code = strdup(CodeInit); BranchVar = BranchVarInit ? strdup(BranchVarInit) : NULL; } @@ -142,6 +140,7 @@ void Block::Render(bool InLoop) { if (!ProcessedBranchesOut.size()) return; bool SetLabel = true; // in some cases it is clear we can avoid setting label, see later + bool ForceSetLabel = Shape::IsEmulated(Parent); // A setting of the label variable (label = x) is necessary if it can // cause an impact. The main case is where we set label to x, then elsewhere @@ -210,7 +209,7 @@ void Block::Render(bool InLoop) { Target = DefaultTarget; Details = ProcessedBranchesOut[DefaultTarget]; } - bool SetCurrLabel = SetLabel && Target->IsCheckedMultipleEntry; + bool SetCurrLabel = (SetLabel && Target->IsCheckedMultipleEntry) || ForceSetLabel; bool HasFusedContent = Fused && contains(Fused->InnerMap, Target); bool HasContent = SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent || Details->Code; if (iter != ProcessedBranchesOut.end()) { @@ -272,10 +271,6 @@ void Block::Render(bool InLoop) { } } -// Shape - -int Shape::IdCounter = 0; - // MultipleShape void MultipleShape::RenderLoopPrefix() { @@ -330,16 +325,19 @@ void LoopShape::Render(bool InLoop) { if (Next) Next->Render(InLoop); }; -/* // EmulatedShape void EmulatedShape::Render(bool InLoop) { + PrintIndented("label = %d;\n", Entry->Id); + if (Labeled) { + PrintIndented("L%d: ", Id); + } PrintIndented("while(1) {\n"); Indenter::Indent(); - PrintIndented("switch(label) {\n"); + PrintIndented("switch(label|0) {\n"); Indenter::Indent(); - for (int i = 0; i < Blocks.size(); i++) { - Block *Curr = Blocks[i]; + for (BlockSet::iterator iter = Blocks.begin(); iter != Blocks.end(); iter++) { + Block *Curr = *iter; PrintIndented("case %d: {\n", Curr->Id); Indenter::Indent(); Curr->Render(InLoop); @@ -353,11 +351,10 @@ void EmulatedShape::Render(bool InLoop) { PrintIndented("}\n"); if (Next) Next->Render(InLoop); }; -*/ // Relooper -Relooper::Relooper() : Root(NULL) { +Relooper::Relooper() : Root(NULL), Emulate(false), BlockIdCounter(1), ShapeIdCounter(0) { // block ID 0 is reserved for clearings } Relooper::~Relooper() { @@ -366,6 +363,7 @@ Relooper::~Relooper() { } void Relooper::AddBlock(Block *New) { + New->Id = BlockIdCounter++; Blocks.push_back(New); } @@ -419,7 +417,7 @@ void Relooper::Calculate(Block *Entry) { for (BlockSet::iterator iter = Original->BranchesIn.begin(); iter != Original->BranchesIn.end(); iter++) { Block *Prior = *iter; Block *Split = new Block(Original->Code, Original->BranchVar); - Parent->Blocks.push_back(Split); + Parent->AddBlock(Split); PrintDebug(" to %d\n", Split->Id); Split->BranchesIn.insert(Prior); Branch *Details = Prior->BranchesOut[Original]; @@ -461,7 +459,7 @@ void Relooper::Calculate(Block *Entry) { } } - Pre.SplitDeadEnds(); + if (!Emulate) Pre.SplitDeadEnds(); // Recursively process the graph @@ -470,6 +468,7 @@ void Relooper::Calculate(Block *Entry) { // Add a shape to the list of shapes in this Relooper calculation void Notice(Shape *New) { + New->Id = Parent->ShapeIdCounter++; Parent->Shapes.push_back(New); } @@ -526,6 +525,21 @@ void Relooper::Calculate(Block *Entry) { return Simple; } + Shape *MakeEmulated(BlockSet &Blocks, Block *Entry, BlockSet &NextEntries) { + PrintDebug("creating emulated block with entry #%d and everything it can reach, %d blocks\n", Entry->Id, Blocks.size()); + EmulatedShape *Emulated = new EmulatedShape; + Notice(Emulated); + Emulated->Entry = Entry; + for (BlockSet::iterator iter = Blocks.begin(); iter != Blocks.end(); iter++) { + Block *Curr = *iter; + Emulated->Blocks.insert(Curr); + Curr->Parent = Emulated; + Solipsize(Curr, Branch::Continue, Emulated, Blocks); + } + Blocks.clear(); + return Emulated; + } + Shape *MakeLoop(BlockSet &Blocks, BlockSet& Entries, BlockSet &NextEntries) { // Find the inner blocks in this loop. Proceed backwards from the entries until // you reach a seen block, collecting as you go. @@ -837,6 +851,9 @@ void Relooper::Calculate(Block *Entry) { if (Entries->size() == 0) return Ret; if (Entries->size() == 1) { Block *Curr = *(Entries->begin()); + if (Parent->Emulate) { + Make(MakeEmulated(Blocks, Curr, *NextEntries)); + } if (Curr->BranchesIn.size() == 0) { // One entry, no looping ==> Simple Make(MakeSimple(Blocks, Curr, *NextEntries)); @@ -844,6 +861,7 @@ void Relooper::Calculate(Block *Entry) { // One entry, looping ==> Loop Make(MakeLoop(Blocks, *Entries, *NextEntries)); } + // More than one entry, try to eliminate through a Multiple groups of // independent blocks from an entry/ies. It is important to remove through // multiples as opposed to looping since the former is more performant. diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h index f3dedf8c..04f2ffc3 100644 --- a/src/relooper/Relooper.h +++ b/src/relooper/Relooper.h @@ -57,7 +57,7 @@ struct Block { BlockBranchMap ProcessedBranchesOut; BlockSet ProcessedBranchesIn; Shape *Parent; // The shape we are directly inside - int Id; // A unique identifier + int Id; // A unique identifier, defined when added to relooper const char *Code; // The string representation of the code in this block. Owning pointer (we copy the input) const char *BranchVar; // If we have more than one branch out, the variable whose value determines where we go bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable @@ -69,9 +69,6 @@ struct Block { // Prints out the instructions code and branchings void Render(bool InLoop); - - // INTERNAL - static int IdCounter; }; // Represents a structured control flow shape, one of @@ -96,20 +93,22 @@ class SimpleShape; class LabeledShape; class MultipleShape; class LoopShape; +class EmulatedShape; struct Shape { - int Id; // A unique identifier. Used to identify loops, labels are Lx where x is the Id. + int Id; // A unique identifier. Used to identify loops, labels are Lx where x is the Id. Defined when added to relooper Shape *Next; // The shape that will appear in the code right after this one Shape *Natural; // The shape that control flow gets to naturally (if there is Next, then this is Next) enum ShapeType { Simple, Multiple, - Loop + Loop, + Emulated }; ShapeType Type; - Shape(ShapeType TypeInit) : Id(Shape::IdCounter++), Next(NULL), Type(TypeInit) {} + Shape(ShapeType TypeInit) : Id(-1), Next(NULL), Type(TypeInit) {} virtual ~Shape() {} virtual void Render(bool InLoop) = 0; @@ -118,9 +117,7 @@ struct Shape { static MultipleShape *IsMultiple(Shape *It) { return It && It->Type == Multiple ? (MultipleShape*)It : NULL; } static LoopShape *IsLoop(Shape *It) { return It && It->Type == Loop ? (LoopShape*)It : NULL; } static LabeledShape *IsLabeled(Shape *It) { return IsMultiple(It) || IsLoop(It) ? (LabeledShape*)It : NULL; } - - // INTERNAL - static int IdCounter; + static EmulatedShape *IsEmulated(Shape *It) { return It && It->Type == Emulated ? (EmulatedShape*)It : NULL; } }; struct SimpleShape : public Shape { @@ -162,12 +159,15 @@ struct LoopShape : public LabeledShape { void Render(bool InLoop); }; -/* -struct EmulatedShape : public Shape { - std::deque<Block*> Blocks; +// TODO EmulatedShape is only partially functional. Currently it can be used for the +// entire set of blocks being relooped, but not subsets. +struct EmulatedShape : public LabeledShape { + Block *Entry; + BlockSet Blocks; + + EmulatedShape() : LabeledShape(Emulated) { Labeled = true; } void Render(bool InLoop); }; -*/ // Implements the relooper algorithm for a function's blocks. // @@ -184,6 +184,9 @@ struct Relooper { std::deque<Block*> Blocks; std::deque<Shape*> Shapes; Shape *Root; + bool Emulate; + int BlockIdCounter; + int ShapeIdCounter; Relooper(); ~Relooper(); @@ -204,6 +207,9 @@ struct Relooper { // Sets asm.js mode on or off (default is off) static void SetAsmJSMode(int On); + + // Sets whether we must emulate everything with switch-loop code + void SetEmulate(int E) { Emulate = E; } }; typedef std::map<Block*, BlockSet> BlockBlockSetMap; diff --git a/src/relooper/fuzzer.py b/src/relooper/fuzzer.py index 50846d10..fa47583e 100644 --- a/src/relooper/fuzzer.py +++ b/src/relooper/fuzzer.py @@ -87,6 +87,12 @@ int main() { Relooper r; ''' + if random.random() < 0.1: + print 'emulate' + fast += ''' + r.SetEmulate(true); +''' + for i in range(num): fast += ''' r.AddBlock(b%d); ''' % i diff --git a/src/relooper/test.cpp b/src/relooper/test.cpp index fbd9c7aa..773f6ee4 100644 --- a/src/relooper/test.cpp +++ b/src/relooper/test.cpp @@ -258,5 +258,33 @@ int main() { puts(buffer); } + + if (1) { + Relooper::SetOutputBuffer(buffer, sizeof(buffer)); + + printf("\n\n-- If pattern, emulated --\n\n", "the_var"); + + Block *b_a = new Block("// block A\n", NULL); + Block *b_b = new Block("// block B\n", "b_check()"); + Block *b_c = new Block("// block C\n", NULL); + + b_a->AddBranchTo(b_b, "check == 10", "atob();"); + b_a->AddBranchTo(b_c, NULL, "atoc();"); + + b_b->AddBranchTo(b_c, "case 17:", "btoc();"); + b_b->AddBranchTo(b_a, NULL, NULL); + + Relooper r; + r.SetEmulate(true); + r.AddBlock(b_a); + r.AddBlock(b_b); + r.AddBlock(b_c); + + r.Calculate(b_a); + printf("\n\n", "the_var"); + r.Render(); + + puts(buffer); + } } diff --git a/src/relooper/test.txt b/src/relooper/test.txt index 2c530567..540f7bdb 100644 --- a/src/relooper/test.txt +++ b/src/relooper/test.txt @@ -4,23 +4,23 @@ -// block A -switch (the_var) { -check == 10 { - atob(); - // block B + // block A switch (the_var) { + check == 10 { + atob(); + // block B + switch (the_var) { + default: { + btoc(); + } + } + break; + } default: { - btoc(); + atoc(); } } - break; -} -default: { - atoc(); -} -} -// block C + // block C @@ -28,25 +28,25 @@ default: { -// block A -switch (the_var) { -check == 15 { - // block B + // block A switch (the_var) { - default: { - } + check == 15 { + // block B + switch (the_var) { + default: { + } + } + break; } - break; -} -default: { - // block C - switch (the_var) { default: { + // block C + switch (the_var) { + default: { + } + } } } -} -} -// block D + // block D @@ -54,81 +54,81 @@ default: { -L9: while(1) { - // block A - var check = maybe(); - switch (the_var) { - default: { - } - } - // block B - switch (the_var) { - check == 41 { - break; - } - default: { - break L9; - } + L0: while(1) { + // block A + var check = maybe(); + switch (the_var) { + default: { + } + } + // block B + switch (the_var) { + check == 41 { + break; + } + default: { + break L0; + } + } } -} -// block C + // block C -- Loop with phi to head -// code 1 -switch (the_var) { -default: { - var $i_0 = 0;var $x_0 = 5; -} -} -L14: while(1) { - // code 2 + // code 1 switch (the_var) { - $2 { - break; - } default: { - var $x_1 = $x_0; - label = 18; - break L14; + var $i_0 = 0;var $x_0 = 5; + } + } + L1: while(1) { + // code 2 + switch (the_var) { + $2 { + break; + } + default: { + var $x_1 = $x_0; + label = -1; + break L1; + } + } + // code 3 + switch (the_var) { + $6 { + break L1; + break; + } + default: { + var $i_0 = $7;var $x_0 = $5; + } + } } + if (label == -1) { + // code 7 } - // code 3 + // code 4 switch (the_var) { - $6 { - break L14; + $10 { + // code 5 + switch (the_var) { + default: { + } + } break; } default: { - var $i_0 = $7;var $x_0 = $5; } } -} -if (label == 18) { - // code 7 -} -// code 4 -switch (the_var) { -$10 { - // code 5 + // code 6 switch (the_var) { default: { + var $x_1 = $13; } } - break; -} -default: { -} -} -// code 6 -switch (the_var) { -default: { - var $x_1 = $13; -} -} -// code 7 + // code 7 @@ -136,30 +136,30 @@ default: { -// block A................................................................................................... -switch (the_var) { -chak() { - atob(); - // block B................................................................................................... + // block A................................................................................................... switch (the_var) { - default: { - btod(); - } + chak() { + atob(); + // block B................................................................................................... + switch (the_var) { + default: { + btod(); + } + } + // block D + break; } - // block D - break; -} -default: { - atoc(); - // block C................................................................................................... - switch (the_var) { default: { - ctod2(); + atoc(); + // block C................................................................................................... + switch (the_var) { + default: { + ctod2(); + } + } + // block D } } - // block D -} -} @@ -167,27 +167,27 @@ default: { -// block A -switch (the_var) { -check == 10 { - break; -} -default: { - return C; -} -} -while(1) { - // block B + // block A switch (the_var) { - default: { - } + check == 10 { + break; } - // block D - switch (the_var) { default: { + return C; } } -} + while(1) { + // block B + switch (the_var) { + default: { + } + } + // block D + switch (the_var) { + default: { + } + } + } @@ -195,51 +195,51 @@ while(1) { -// block A -L37: do { - switch (the_var) { - expensive() { - label = 33; - break; - } - default: { - // block B + // block A + L1: do { switch (the_var) { - expensive2() { - label = 33; - break L37; + expensive() { + label = 3; break; } default: { + // block B + switch (the_var) { + expensive2() { + label = 3; + break L1; + break; + } + default: { + } + } + // block D + switch (the_var) { + default: { + } + } } } - // block D + } while(0); + if (label == 3) { + // block C; switch (the_var) { default: { } } } + while(1) { + // block E + switch (the_var) { + default: { + } + } + // block F + switch (the_var) { + default: { + } + } } -} while(0); -if (label == 33) { - // block C; - switch (the_var) { - default: { - } - } -} -while(1) { - // block E - switch (the_var) { - default: { - } - } - // block F - switch (the_var) { - default: { - } - } -} @@ -247,26 +247,71 @@ while(1) { -// block A -L46: do { - switch (the_var) { - shouldLoop() { - while(1) { - // block B - switch (the_var) { - moarLoop() { + // block A + L1: do { + switch (the_var) { + shouldLoop() { + while(1) { + // block B + switch (the_var) { + moarLoop() { + break; + } + default: { + break L1; + } + } + } + break; + } + default: { + } + } + } while(0); + // block C + + + +-- If pattern, emulated -- + + + + label = 1; + L0: while(1) { + switch(label|0) { + case 3: { + // block C break; } - default: { - break L46; + case 1: { + // block A + if (check == 10) { + atob(); + label = 2; + continue L0; + } else { + atoc(); + label = 3; + continue L0; + } + break; } + case 2: { + // block B + switch (b_check()) { + case 17: { + btoc(); + label = 3; + continue L0; + break; + } + default: { + label = 1; + continue L0; + } + } + break; } } - break; - } - default: { - } } -} while(0); -// block C diff --git a/src/relooper/test2.txt b/src/relooper/test2.txt index a558a8b7..aba9ec1f 100644 --- a/src/relooper/test2.txt +++ b/src/relooper/test2.txt @@ -1,26 +1,26 @@ -ep -L1: do { - switch (var) { - ep -> LBB1 { - LBB1 - switch (the_var) { - LBB1 -> LBB2 { + ep + L1: do { + switch (var) { + ep -> LBB1 { + LBB1 + switch (the_var) { + LBB1 -> LBB2 { + break; + } + default: { + break L1; + } + } + LBB2 + switch (the_var) { + default: { + } + } break; } default: { - break L1; } } - LBB2 - switch (the_var) { - default: { - } - } - break; - } - default: { - } - } -} while(0); -LBB3 + } while(0); + LBB3 diff --git a/src/relooper/test3.txt b/src/relooper/test3.txt index f77e2618..33f85a7e 100644 --- a/src/relooper/test3.txt +++ b/src/relooper/test3.txt @@ -1,56 +1,56 @@ -ep -L1: do { - switch (the_var) { - ep -> LBB1 { - LBB1 + ep + L1: do { switch (the_var) { - LBB1 -> LBB2 { + ep -> LBB1 { + LBB1 + switch (the_var) { + LBB1 -> LBB2 { + break; + } + default: { + break L1; + } + } + LBB2 + switch (the_var) { + default: { + } + } break; } default: { - break L1; - } - } - LBB2 - switch (the_var) { - default: { } } - break; - } - default: { - } - } -} while(0); -LBB3 -L5: do { - switch (the_var) { - LBB3 -> LBB4 { - LBB4 + } while(0); + LBB3 + L5: do { switch (the_var) { - LBB4 -> LBB5 { - break; - } - default: { - break L5; - } - } - while(1) { - LBB5 + LBB3 -> LBB4 { + LBB4 switch (the_var) { - LBB5 -> LBB6 { - break L5; + LBB4 -> LBB5 { break; } default: { + break L5; + } } + while(1) { + LBB5 + switch (the_var) { + LBB5 -> LBB6 { + break L5; + break; + } + default: { + } + } } + break; + } + default: { + } } - break; - } - default: { - } - } -} while(0); -LBB6 + } while(0); + LBB6 diff --git a/src/relooper/test4.txt b/src/relooper/test4.txt index 1829e523..7e3fe8e1 100644 --- a/src/relooper/test4.txt +++ b/src/relooper/test4.txt @@ -1,44 +1,44 @@ -//19 -L1: do { - switch (the_var) { - 1 { - //20 + //19 + L1: do { switch (the_var) { 1 { + //20 + switch (the_var) { + 1 { + break; + } + default: { + label = 4; + break L1; + } + } + //21 + switch (the_var) { + default: { + } + } break; } default: { label = 4; - break L1; } } - //21 + } while(0); + if (label == 4) { + //22 switch (the_var) { default: { } } - break; - } - default: { - label = 4; } - } -} while(0); -if (label == 4) { - //22 + //23 switch (the_var) { + 1 { + //24 + break; + } default: { + //28 } } -} -//23 -switch (the_var) { - 1 { - //24 - break; -} -default: { - //28 -} -} diff --git a/src/relooper/test5.txt b/src/relooper/test5.txt index 82ef5edf..e3c204f6 100644 --- a/src/relooper/test5.txt +++ b/src/relooper/test5.txt @@ -1,56 +1,56 @@ -//0 -switch (the_var) { -check(0) { - L2: while(1) { - //1 - switch (the_var) { - check(1) { - break; - } - default: { - break L2; - } - } + //0 + switch (the_var) { + check(0) { + L2: while(1) { + //1 + switch (the_var) { + check(1) { + break; + } + default: { + break L2; + } + } + } + L4: while(1) { + //2 + switch (the_var) { + check(2) { + break; + } + default: { + break L4; + } + } + } + //3 + break; } - L4: while(1) { - //2 - switch (the_var) { - check(2) { - break; - } - default: { - break L4; - } - } + default: { + goingFrom0to4(); + L7: while(1) { + //4 + switch (the_var) { + check(4) { + break; + } + default: { + break L7; + } + } + } + L9: while(1) { + //5 + switch (the_var) { + check(5) { + break L9; + break; + } + default: { + } + } + } + //3 } - //3 - break; -} -default: { - goingFrom0to4(); - L7: while(1) { - //4 - switch (the_var) { - check(4) { - break; - } - default: { - break L7; - } - } - } - L9: while(1) { - //5 - switch (the_var) { - check(5) { - break L9; - break; - } - default: { - } - } } - //3 -} -} diff --git a/src/relooper/test6.txt b/src/relooper/test6.txt index f9d6e93a..837fc243 100644 --- a/src/relooper/test6.txt +++ b/src/relooper/test6.txt @@ -1,26 +1,26 @@ -//0 -L1: do { - switch (the_var) { - check(0) { - //1 + //0 + L1: do { switch (the_var) { - check(1) { + check(0) { + //1 + switch (the_var) { + check(1) { + break; + } + default: { + break L1; + } + } + //2 + switch (the_var) { + default: { + } + } break; } default: { - break L1; } } - //2 - switch (the_var) { - default: { - } - } - break; - } - default: { - } - } -} while(0); -//3 + } while(0); + //3 diff --git a/src/relooper/test_dead.txt b/src/relooper/test_dead.txt index ae54e2cd..43d557ae 100644 --- a/src/relooper/test_dead.txt +++ b/src/relooper/test_dead.txt @@ -4,6 +4,6 @@ -// block A + // block A I did not crash even though I have dead code with a branch! diff --git a/src/relooper/test_debug.txt b/src/relooper/test_debug.txt index eb33fdbc..498dee39 100644 --- a/src/relooper/test_debug.txt +++ b/src/relooper/test_debug.txt @@ -4,18 +4,18 @@ int main() { rl_set_output_buffer(buffer); void *block_map[10000]; void *rl = rl_new_relooper(); - void *b1 = rl_new_block("// code 1"); - block_map[1] = b1; - rl_relooper_add_block(rl, block_map[1]); - void *b2 = rl_new_block("// code 2"); - block_map[2] = b2; - rl_relooper_add_block(rl, block_map[2]); - void *b3 = rl_new_block("// code 3"); - block_map[3] = b3; - rl_relooper_add_block(rl, block_map[3]); - void *b4 = rl_new_block("// code 4"); - block_map[4] = b4; - rl_relooper_add_block(rl, block_map[4]); + void *b-1 = rl_new_block("// code -1"); + block_map[-1] = b-1; + rl_relooper_add_block(rl, block_map[-1]); + void *b-1 = rl_new_block("// code -1"); + block_map[-1] = b-1; + rl_relooper_add_block(rl, block_map[-1]); + void *b-1 = rl_new_block("// code -1"); + block_map[-1] = b-1; + rl_relooper_add_block(rl, block_map[-1]); + void *b-1 = rl_new_block("// code -1"); + block_map[-1] = b-1; + rl_relooper_add_block(rl, block_map[-1]); rl_block_add_branch_to(block_map[1], block_map[2], "ep -> LBB1", NULL); rl_block_add_branch_to(block_map[1], block_map[4], NULL, NULL); rl_block_add_branch_to(block_map[2], block_map[3], "LBB1 -> LBB2", NULL); @@ -114,29 +114,29 @@ int main() { // Process() returning // === Optimizing shapes === // Fusing Multiple to Simple -ep -L1: do { - switch (the_var) { - ep -> LBB1 { - LBB1 + ep + L1: do { switch (the_var) { - LBB1 -> LBB2 { + ep -> LBB1 { + LBB1 + switch (the_var) { + LBB1 -> LBB2 { + break; + } + default: { + break L1; + } + } + LBB2 + switch (the_var) { + default: { + } + } break; } default: { - break L1; } } - LBB2 - switch (the_var) { - default: { - } - } - break; - } - default: { - } - } -} while(0); -LBB3 + } while(0); + LBB3 diff --git a/src/relooper/test_fuzz1.txt b/src/relooper/test_fuzz1.txt index d887f5b8..ccd38934 100644 --- a/src/relooper/test_fuzz1.txt +++ b/src/relooper/test_fuzz1.txt @@ -1,72 +1,72 @@ -print('entry'); var label; var state; var decisions = [4, 1, 7, 2, 6, 6, 8]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } -switch (the_var) { -default: { -} -} -print(5); state = check(); -switch (the_var) { -default: { -} -} -print(6); state = check(); -switch (the_var) { -state == 7 { - print(7); state = check(); + print('entry'); var label; var state; var decisions = [4, 1, 7, 2, 6, 6, 8]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } switch (the_var) { default: { - label = 3; } } - break; -} -default: { -} -} -L5: while(1) { - if (label == 3) { - label = 0; - print(2); state = check(); + print(5); state = check(); + switch (the_var) { + default: { + } + } + print(6); state = check(); + switch (the_var) { + state == 7 { + print(7); state = check(); switch (the_var) { default: { + label = 3; } } + break; } - print(1); state = check(); - switch (the_var) { default: { } } - while(1) { - print(3); state = check(); - switch (the_var) { - state == 8 { - break; + L5: while(1) { + if (label == 3) { + label = 0; + print(2); state = check(); + switch (the_var) { + default: { + } + } } - default: { - continue L5; - } - } - print(8); state = check(); + print(1); state = check(); switch (the_var) { - state == 4 { - break; - } default: { - label = 3; - continue L5; } } - print(4); state = check(); - switch (the_var) { - state == 3 { - break; - } - default: { - continue L5; - } + while(1) { + print(3); state = check(); + switch (the_var) { + state == 8 { + break; + } + default: { + continue L5; + } + } + print(8); state = check(); + switch (the_var) { + state == 4 { + break; + } + default: { + label = 3; + continue L5; + } + } + print(4); state = check(); + switch (the_var) { + state == 3 { + break; + } + default: { + continue L5; + } + } } } -} diff --git a/src/relooper/test_fuzz2.txt b/src/relooper/test_fuzz2.txt index 69f4350c..a94908a1 100644 --- a/src/relooper/test_fuzz2.txt +++ b/src/relooper/test_fuzz2.txt @@ -1,30 +1,30 @@ -print('entry'); var label; var state; var decisions = [4, 1, 4, 3, 4, 1, 2, 5, 1, 3, 5, 5, 1, 5, 2, 4, 4, 3]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } -switch (the_var) { -state == 1 { - while(1) { - print(1); state = check(); - switch (the_var) { - default: { - } + print('entry'); var label; var state; var decisions = [4, 1, 4, 3, 4, 1, 2, 5, 1, 3, 5, 5, 1, 5, 2, 4, 4, 3]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } + switch (the_var) { + state == 1 { + while(1) { + print(1); state = check(); + switch (the_var) { + default: { + } + } } + break; } - break; -} -default: { -} -} -while(1) { - print(3); state = check(); - switch (the_var) { default: { } } - print(2); state = check(); - switch (the_var) { - default: { - } + while(1) { + print(3); state = check(); + switch (the_var) { + default: { + } + } + print(2); state = check(); + switch (the_var) { + default: { + } + } } -} diff --git a/src/relooper/test_fuzz3.txt b/src/relooper/test_fuzz3.txt index 398b4803..15037eec 100644 --- a/src/relooper/test_fuzz3.txt +++ b/src/relooper/test_fuzz3.txt @@ -1,25 +1,25 @@ -print('entry'); var label; var state; var decisions = [3, 3, 4, 1, 2, 1, 2, 4, 4, 4, 2, 3, 3, 1, 2]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } -switch (the_var) { -default: { -} -} -print(1); state = check(); -switch (the_var) { -default: { -} -} -print(3); state = check(); -switch (the_var) { -default: { -} -} -while(1) { - print(4); state = check(); + print('entry'); var label; var state; var decisions = [3, 3, 4, 1, 2, 1, 2, 4, 4, 4, 2, 3, 3, 1, 2]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } switch (the_var) { default: { } } -} + print(1); state = check(); + switch (the_var) { + default: { + } + } + print(3); state = check(); + switch (the_var) { + default: { + } + } + while(1) { + print(4); state = check(); + switch (the_var) { + default: { + } + } + } diff --git a/src/relooper/test_fuzz4.txt b/src/relooper/test_fuzz4.txt index 2e2f2c6f..adf879f9 100644 --- a/src/relooper/test_fuzz4.txt +++ b/src/relooper/test_fuzz4.txt @@ -1,41 +1,41 @@ -print('entry'); var label; var state; var decisions = [2, 2, 1, 3, 2, 2, 1, 3, 2, 3, 3, 1, 3, 2, 1]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } -switch (the_var) { -state == 2 { - while(1) { - print(2); state = check(); - switch (the_var) { - default: { - } - } - } - break; -} -default: { -} -} -L4: while(1) { - print(4); state = check(); + print('entry'); var label; var state; var decisions = [2, 2, 1, 3, 2, 2, 1, 3, 2, 3, 3, 1, 3, 2, 1]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } switch (the_var) { - state == 4 { + state == 2 { + while(1) { + print(2); state = check(); + switch (the_var) { + default: { + } + } + } break; } default: { - break L4; } } -} -print(3); state = check(); -switch (the_var) { -default: { -} -} -while(1) { - print(1); state = check(); + L4: while(1) { + print(4); state = check(); + switch (the_var) { + state == 4 { + break; + } + default: { + break L4; + } + } + } + print(3); state = check(); switch (the_var) { default: { } } -} + while(1) { + print(1); state = check(); + switch (the_var) { + default: { + } + } + } diff --git a/src/relooper/test_fuzz5.txt b/src/relooper/test_fuzz5.txt index f87e5b79..fea540ed 100644 --- a/src/relooper/test_fuzz5.txt +++ b/src/relooper/test_fuzz5.txt @@ -1,86 +1,86 @@ -print('entry'); var label; var state; var decisions = [133, 98, 134, 143, 162, 187, 130, 87, 91, 49, 102, 47, 9, 132, 179, 176, 157, 25, 64, 161, 57, 107, 16, 167, 185, 45, 191, 180, 23, 131]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } -switch (the_var) { -default: { -} -} -L1: while(1) { - print(7); state = check(); + print('entry'); var label; var state; var decisions = [133, 98, 134, 143, 162, 187, 130, 87, 91, 49, 102, 47, 9, 132, 179, 176, 157, 25, 64, 161, 57, 107, 16, 167, 185, 45, 191, 180, 23, 131]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } switch (the_var) { - state % 3 == 1 { - label = 3; - break; + default: { + } } - state % 3 == 0 { - print(8); state = check(); + L1: while(1) { + print(7); state = check(); switch (the_var) { - state % 2 == 0 { - label = 5; + state % 3 == 1 { + label = 3; break; } - default: { - label = 7; - } - } - break; - } - default: { - break L1; - } - } - L5: while(1) { - if (label == 3) { - label = 0; - print(2); state = check(); - switch (the_var) { - default: { - } - } - print(1); state = check(); + state % 3 == 0 { + print(8); state = check(); switch (the_var) { state % 2 == 0 { label = 5; - continue L5; break; } default: { label = 7; - continue L5; } } + break; } - else if (label == 5) { - label = 0; - print(4); state = check(); - switch (the_var) { - default: { - label = 3; - continue L5; - } - } + default: { + break L1; } - else if (label == 7) { - label = 0; - print(6); state = check(); - switch (the_var) { - state % 2 == 0 { - continue L1; - break; + } + L5: while(1) { + if (label == 3) { + label = 0; + print(2); state = check(); + switch (the_var) { + default: { + } + } + print(1); state = check(); + switch (the_var) { + state % 2 == 0 { + label = 5; + continue L5; + break; + } + default: { + label = 7; + continue L5; + } + } } - default: { - label = 7; - continue L5; + else if (label == 5) { + label = 0; + print(4); state = check(); + switch (the_var) { + default: { + label = 3; + continue L5; + } + } } + else if (label == 7) { + label = 0; + print(6); state = check(); + switch (the_var) { + state % 2 == 0 { + continue L1; + break; + } + default: { + label = 7; + continue L5; + } + } } } } -} -while(1) { - print(3); state = check(); - switch (the_var) { - default: { - } + while(1) { + print(3); state = check(); + switch (the_var) { + default: { + } + } } -} diff --git a/src/relooper/test_fuzz6.txt b/src/relooper/test_fuzz6.txt index b9c1499a..40605dfc 100644 --- a/src/relooper/test_fuzz6.txt +++ b/src/relooper/test_fuzz6.txt @@ -1,291 +1,291 @@ -print('entry'); var label; var state; var decisions = [759, 1223, 618, 1805, 277, 512, 204, 1545, 606, 734, 585, 447, 1670, 1031, 665, 1728, 353, 634, 1033, 13, 658, 589, 474, 854, 405, 1111, 1640, 697, 1156, 1357, 317, 618, 990, 1401, 405, 564, 497, 829, 653, 1194, 25, 322, 1178, 198, 1565, 1419, 1608, 486, 368, 606, 813, 22, 148, 141, 261, 375, 472, 964, 1106, 694, 205, 771, 44, 675, 545, 1027, 1528, 240, 1289, 564, 792, 744, 366, 668, 823, 210, 428, 1009, 1662, 1317, 1183, 681, 14, 1334, 712, 506, 224, 695, 401, 1035, 384, 486, 1519, 122, 1186, 1487, 1819, 1702, 463, 1706, 660, 1642, 847, 991, 976, 940, 867, 46, 23, 1449, 56, 1711, 634, 404, 1558, 168, 710, 1581, 1302, 870, 997, 1295, 1739, 769, 1005, 291, 1638, 1771, 842, 659, 1695, 713, 935, 802, 1173, 1572, 850, 607, 996, 55, 1576, 321, 1815, 662, 1044, 1612, 1680, 1050, 844, 553, 278, 1447, 1662, 1094, 1797, 774, 1013, 1204, 907, 340, 1172, 1460, 869, 1264, 111, 1176, 484, 845, 258, 417, 1246, 1017, 745, 189, 333, 1658, 1395, 1764, 1786, 165, 404, 847, 1429, 1574, 403, 718, 1118, 1756, 94, 56, 1498, 1696, 1355, 840, 50, 82, 371, 1087, 875, 1337, 267, 958, 1209, 1167, 1025, 1684, 184, 962, 1496, 201, 127, 372, 1, 1005, 402, 1387, 213, 1143, 1271, 167, 10, 12, 1060, 1390, 1366, 893, 747, 1005, 481, 876, 227, 514, 589, 250, 273, 1188, 1052, 719, 219, 1006, 38, 120, 1454, 489, 672, 149, 534, 1081, 1721, 586, 330, 25, 356, 1743, 1607, 336, 981, 419, 1036, 1293, 1026, 1300, 1453, 792, 22, 45, 420, 409, 1027, 1437, 1421, 795, 136, 1276, 1610, 1593]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } -switch (the_var) { -default: { -} -} -L1: while(1) { - print(30); state = check();// ................................................................................................................................................................................................................. - switch (the_var) { - state % 3 == 0 { - break; - } - state % 3 == 1 { - label = 67; - break L1; - break; - } - default: { - break L1; - } - } - print(58); state = check();// ...................................................................................... - switch (the_var) { - default: { - } - } -} -if (label == 67) { - print(66); state = check();// ............................................................................................................... + print('entry'); var label; var state; var decisions = [759, 1223, 618, 1805, 277, 512, 204, 1545, 606, 734, 585, 447, 1670, 1031, 665, 1728, 353, 634, 1033, 13, 658, 589, 474, 854, 405, 1111, 1640, 697, 1156, 1357, 317, 618, 990, 1401, 405, 564, 497, 829, 653, 1194, 25, 322, 1178, 198, 1565, 1419, 1608, 486, 368, 606, 813, 22, 148, 141, 261, 375, 472, 964, 1106, 694, 205, 771, 44, 675, 545, 1027, 1528, 240, 1289, 564, 792, 744, 366, 668, 823, 210, 428, 1009, 1662, 1317, 1183, 681, 14, 1334, 712, 506, 224, 695, 401, 1035, 384, 486, 1519, 122, 1186, 1487, 1819, 1702, 463, 1706, 660, 1642, 847, 991, 976, 940, 867, 46, 23, 1449, 56, 1711, 634, 404, 1558, 168, 710, 1581, 1302, 870, 997, 1295, 1739, 769, 1005, 291, 1638, 1771, 842, 659, 1695, 713, 935, 802, 1173, 1572, 850, 607, 996, 55, 1576, 321, 1815, 662, 1044, 1612, 1680, 1050, 844, 553, 278, 1447, 1662, 1094, 1797, 774, 1013, 1204, 907, 340, 1172, 1460, 869, 1264, 111, 1176, 484, 845, 258, 417, 1246, 1017, 745, 189, 333, 1658, 1395, 1764, 1786, 165, 404, 847, 1429, 1574, 403, 718, 1118, 1756, 94, 56, 1498, 1696, 1355, 840, 50, 82, 371, 1087, 875, 1337, 267, 958, 1209, 1167, 1025, 1684, 184, 962, 1496, 201, 127, 372, 1, 1005, 402, 1387, 213, 1143, 1271, 167, 10, 12, 1060, 1390, 1366, 893, 747, 1005, 481, 876, 227, 514, 589, 250, 273, 1188, 1052, 719, 219, 1006, 38, 120, 1454, 489, 672, 149, 534, 1081, 1721, 586, 330, 25, 356, 1743, 1607, 336, 981, 419, 1036, 1293, 1026, 1300, 1453, 792, 22, 45, 420, 409, 1027, 1437, 1421, 795, 136, 1276, 1610, 1593]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] } switch (the_var) { default: { } } -} -print(6); state = check();// ......... -switch (the_var) { -default: { -} -} -while(1) { - print(88); state = check();// .................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... - switch (the_var) { - default: { + L1: while(1) { + print(30); state = check();// ................................................................................................................................................................................................................. + switch (the_var) { + state % 3 == 0 { + break; + } + state % 3 == 1 { + label = 67; + break L1; + break; + } + default: { + break L1; + } + } + print(58); state = check();// ...................................................................................... + switch (the_var) { + default: { + } + } } + if (label == 67) { + print(66); state = check();// ............................................................................................................... + switch (the_var) { + default: { + } + } } - print(70); state = check();// .......................................................................................................................... + print(6); state = check();// ......... switch (the_var) { default: { } } - L10: while(1) { - print(47); state = check();// .................................................................................................................................... + while(1) { + print(88); state = check();// .................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... switch (the_var) { default: { } } - print(28); state = check();// .............................................................................................................. + print(70); state = check();// .......................................................................................................................... switch (the_var) { default: { } } - L13: while(1) { - print(75); state = check();// ............................................. + L10: while(1) { + print(47); state = check();// .................................................................................................................................... switch (the_var) { default: { } } - print(7); state = check();// ............................................................................................................................................................................................. + print(28); state = check();// .............................................................................................................. switch (the_var) { - state % 2 == 0 { - break; - } default: { - break L13; - } } - } - print(89); state = check();// ...................................................................................................................................................................................................................................................................................................................................................... - switch (the_var) { - default: { - } - } - print(68); state = check();// ...................................................................................................................................................................................................................................................................................................................... - switch (the_var) { - default: { - } - } - L18: while(1) { - print(51); state = check();// ............................................................................................. - switch (the_var) { - default: { } - } - L20: while(1) { - print(36); state = check();// ......................... + L13: while(1) { + print(75); state = check();// ............................................. switch (the_var) { - state % 2 == 0 { - break L20; - break; - } default: { } } - print(16); state = check();// ................................................................................................................................................................................................................................................................................................................................................................ + print(7); state = check();// ............................................................................................................................................................................................. switch (the_var) { - default: { - } + state % 2 == 0 { + break; } - print(57); state = check();// ........................................................................................................................................................................................................................................................................................................................... - switch (the_var) { default: { + break L13; } } - print(39); state = check();// ................ + } + print(89); state = check();// ...................................................................................................................................................................................................................................................................................................................................................... + switch (the_var) { + default: { + } + } + print(68); state = check();// ...................................................................................................................................................................................................................................................................................................................... + switch (the_var) { + default: { + } + } + L18: while(1) { + print(51); state = check();// ............................................................................................. switch (the_var) { - state % 3 == 0 { - break; - } - state % 3 == 1 { - label = 74; - break; - } default: { - label = 32; - break L20; } } - L25: while(1) { - if (label == 74) { - label = 0; - print(73); state = check();// . + L20: while(1) { + print(36); state = check();// ......................... + switch (the_var) { + state % 2 == 0 { + break L20; + break; + } + default: { + } + } + print(16); state = check();// ................................................................................................................................................................................................................................................................................................................................................................ + switch (the_var) { + default: { + } + } + print(57); state = check();// ........................................................................................................................................................................................................................................................................................................................... + switch (the_var) { + default: { + } + } + print(39); state = check();// ................ + switch (the_var) { + state % 3 == 0 { + break; + } + state % 3 == 1 { + label = 74; + break; + } + default: { + label = 32; + break L20; + } + } + L25: while(1) { + if (label == 74) { + label = 0; + print(73); state = check();// . + switch (the_var) { + state % 3 == 1 { + label = 32; + break L20; + break; + } + state % 3 == 0 { + break L25; + break; + } + default: { + } + } + print(43); state = check();// ......... + switch (the_var) { + default: { + } + } + print(32); state = check();// ...................................................................................................... + switch (the_var) { + default: { + } + } + print(83); state = check();// ........................................................................................ + switch (the_var) { + default: { + } + } + print(77); state = check();// ........................................................................................................................................................................................................................................................................................... + switch (the_var) { + default: { + } + } + print(76); state = check();// .............................................................................................................................................................................................................................................................................................................................................................................................................................. + switch (the_var) { + default: { + } + } + print(22); state = check();// ......................................................................................................... + switch (the_var) { + default: { + } + } + } + print(72); state = check();// .......................................................................................................... switch (the_var) { - state % 3 == 1 { - label = 32; + state % 2 == 0 { + label = 92; break L20; break; } - state % 3 == 0 { - break L25; + default: { + } + } + print(80); state = check();// .................................... + switch (the_var) { + state % 2 == 0 { + continue L18; break; } default: { } } - print(43); state = check();// ......... + print(50); state = check();// ........................................ switch (the_var) { default: { } } - print(32); state = check();// ...................................................................................................... + print(29); state = check();// ............... switch (the_var) { default: { } } - print(83); state = check();// ........................................................................................ + print(8); state = check();// .................................................................................................................................................................................................................................................... switch (the_var) { + state % 2 == 0 { + continue L10; + break; + } default: { } } - print(77); state = check();// ........................................................................................................................................................................................................................................................................................... + print(19); state = check();// ...................................................................................................................................................................................................................... switch (the_var) { default: { } } - print(76); state = check();// .............................................................................................................................................................................................................................................................................................................................................................................................................................. + print(56); state = check();// .................................................................................................................................................................................................................... switch (the_var) { default: { } } - print(22); state = check();// ......................................................................................................... + print(34); state = check();// .......................................................................................................................................... switch (the_var) { default: { + label = 74; } } } - print(72); state = check();// .......................................................................................................... - switch (the_var) { - state % 2 == 0 { - label = 92; - break L20; - break; - } - default: { - } - } - print(80); state = check();// .................................... - switch (the_var) { - state % 2 == 0 { - continue L18; - break; - } - default: { - } - } - print(50); state = check();// ........................................ - switch (the_var) { - default: { - } - } - print(29); state = check();// ............... - switch (the_var) { - default: { - } - } - print(8); state = check();// .................................................................................................................................................................................................................................................... + print(62); state = check();// ....................................................................................... switch (the_var) { - state % 2 == 0 { - continue L10; - break; - } default: { } } - print(19); state = check();// ...................................................................................................................................................................................................................... + } + if (label == 32) { + label = 0; + print(31); state = check();// .......................................................................................................................................................................................................... switch (the_var) { default: { } } - print(56); state = check();// .................................................................................................................................................................................................................... + } + else if (label == 92) { + label = 0; + print(91); state = check();// .............................................. switch (the_var) { default: { } } - print(34); state = check();// .......................................................................................................................................... + print(33); state = check();// .... switch (the_var) { default: { - label = 74; } } } - print(62); state = check();// ....................................................................................... + print(60); state = check();// ...................................................................................................................................................................................................................................... switch (the_var) { default: { } } - } - if (label == 32) { - label = 0; - print(31); state = check();// .......................................................................................................................................................................................................... + print(10); state = check();// ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... switch (the_var) { default: { } } - } - else if (label == 92) { - label = 0; - print(91); state = check();// .............................................. + print(52); state = check();// .............................................................................. switch (the_var) { + state % 2 == 0 { + break L10; + break; + } default: { } } - print(33); state = check();// .... + print(2); state = check();// ......... switch (the_var) { default: { } } } - print(60); state = check();// ...................................................................................................................................................................................................................................... - switch (the_var) { - default: { - } - } - print(10); state = check();// ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... - switch (the_var) { - default: { - } - } - print(52); state = check();// .............................................................................. - switch (the_var) { - state % 2 == 0 { - break L10; - break; - } - default: { - } - } - print(2); state = check();// ......... - switch (the_var) { - default: { - } - } + } + print(61); state = check();// ......................................................................................................................................................... + switch (the_var) { + default: { + } } } - print(61); state = check();// ......................................................................................................................................................... - switch (the_var) { - default: { - } - } -} diff --git a/src/relooper/test_inf.txt b/src/relooper/test_inf.txt index 6db32edb..2acadbfb 100644 --- a/src/relooper/test_inf.txt +++ b/src/relooper/test_inf.txt @@ -1,1072 +1,1039 @@ -code 0 -switch (the_var) { -uint(i4) >= uint(i5) { - code 2 + code 0 switch (the_var) { - default: { - } - } - break; -} -default: { - code 1 - switch (the_var) { - default: { - } - } -} -} -code 3 -L5: do { - switch (the_var) { - i2 == 0 { + uint(i4) >= uint(i5) { + code 2 + switch (the_var) { + default: { + } + } break; } default: { - code 4 + code 1 switch (the_var) { default: { } } - while(1) { - code 5 + } + } + code 3 + L5: do { + switch (the_var) { + i2 == 0 { + break; + } + default: { + code 4 switch (the_var) { - uint(i6) >= uint(i7) { - code 7 - switch (the_var) { - default: { - } - } - break; - } default: { - code 6 - switch (the_var) { - default: { - } - } } } - code 8 - switch (the_var) { - uint(i6) >= uint(i7) { - code 10 + while(1) { + code 5 switch (the_var) { + uint(i6) >= uint(i7) { + code 7 + switch (the_var) { + default: { + } + } + break; + } default: { + code 6 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 9 + code 8 switch (the_var) { + uint(i6) >= uint(i7) { + code 10 + switch (the_var) { + default: { + } + } + break; + } default: { + code 9 + switch (the_var) { + default: { + } + } } } - } - } - code 11 - switch (the_var) { - uint(i5) >= uint(i6) { - code 13 + code 11 switch (the_var) { + uint(i5) >= uint(i6) { + code 13 + switch (the_var) { + default: { + } + } + break; + } default: { + code 12 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 12 + code 14 switch (the_var) { + i2 != 0 { + break; + } default: { + break L5; } } } - } - code 14 - switch (the_var) { - i2 != 0 { - break; - } - default: { - break L5; - } - } } - } - } -} while(0); -code 15 -switch (the_var) { -uint(i4) >= uint(i5) { - code 17 - switch (the_var) { - default: { - } - } - break; -} -default: { - code 16 - switch (the_var) { - default: { - } - } -} -} -code 18 -L26: do { + } + } while(0); + code 15 switch (the_var) { - i2 == 0 { + uint(i4) >= uint(i5) { + code 17 + switch (the_var) { + default: { + } + } break; } default: { - code 19 + code 16 switch (the_var) { default: { } } - while(1) { - code 20 + } + } + code 18 + L26: do { + switch (the_var) { + i2 == 0 { + break; + } + default: { + code 19 switch (the_var) { - uint(i5) >= uint(i6) { - code 22 - switch (the_var) { - default: { - } - } - break; - } default: { - code 21 - switch (the_var) { - default: { - } - } } } - code 23 - switch (the_var) { - uint(i5) >= uint(i6) { - code 25 + while(1) { + code 20 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 22 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 24 - switch (the_var) { default: { + code 21 + switch (the_var) { + default: { + } + } } } - } - } - code 26 - switch (the_var) { - uint(i5) >= uint(i6) { - code 28 + code 23 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 25 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 27 - switch (the_var) { default: { + code 24 + switch (the_var) { + default: { + } + } } } - } - } - code 29 - switch (the_var) { - uint(i5) >= uint(i6) { - code 31 + code 26 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 28 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 30 - switch (the_var) { default: { + code 27 + switch (the_var) { + default: { + } + } } } - } - } - code 32 - switch (the_var) { - uint(i5) >= uint(i6) { - code 34 + code 29 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 31 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 33 - switch (the_var) { default: { + code 30 + switch (the_var) { + default: { + } + } } } - } - } - code 35 - switch (the_var) { - uint(i5) >= uint(i6) { - code 37 + code 32 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 34 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 36 - switch (the_var) { default: { + code 33 + switch (the_var) { + default: { + } + } } } - } - } - code 38 - switch (the_var) { - uint(i5) >= uint(i6) { - code 40 + code 35 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 37 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 39 - switch (the_var) { default: { + code 36 + switch (the_var) { + default: { + } + } } } - } - } - code 41 - switch (the_var) { - uint(i5) >= uint(i6) { - code 43 + code 38 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 40 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 42 - switch (the_var) { default: { + code 39 + switch (the_var) { + default: { + } + } } } - } - } - code 44 - switch (the_var) { - uint(i5) >= uint(i6) { - code 46 + code 41 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 43 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 45 - switch (the_var) { default: { + code 42 + switch (the_var) { + default: { + } + } } } - } - } - code 47 - switch (the_var) { - uint(i5) >= uint(i6) { - code 49 + code 44 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 46 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 48 - switch (the_var) { default: { + code 45 + switch (the_var) { + default: { + } + } } } - } - } - code 50 - switch (the_var) { - uint(i5) >= uint(i6) { - code 52 + code 47 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 49 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 51 - switch (the_var) { default: { + code 48 + switch (the_var) { + default: { + } + } } } - } - } - code 53 - switch (the_var) { - uint(i5) >= uint(i6) { - code 55 + code 50 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 52 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 54 - switch (the_var) { default: { + code 51 + switch (the_var) { + default: { + } + } } } - } - } - code 56 - switch (the_var) { - uint(i5) >= uint(i6) { - code 58 + code 53 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 55 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 57 - switch (the_var) { default: { + code 54 + switch (the_var) { + default: { + } + } } } - } - } - code 59 - switch (the_var) { - uint(i5) >= uint(i6) { - code 61 + code 56 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 58 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 60 - switch (the_var) { default: { + code 57 + switch (the_var) { + default: { + } + } } } - } - } - code 62 - switch (the_var) { - uint(i5) >= uint(i6) { - code 64 + code 59 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 61 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 63 - switch (the_var) { default: { + code 60 + switch (the_var) { + default: { + } + } } } - } - } - code 65 - switch (the_var) { - uint(i5) >= uint(i6) { - code 67 + code 62 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 64 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 66 - switch (the_var) { default: { + code 63 + switch (the_var) { + default: { + } + } } } - } - } - code 68 - switch (the_var) { - uint(i5) >= uint(i6) { - code 70 + code 65 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 67 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 69 - switch (the_var) { default: { + code 66 + switch (the_var) { + default: { + } + } } } - } - } - code 71 - switch (the_var) { - uint(i5) >= uint(i6) { - code 73 + code 68 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 70 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 72 - switch (the_var) { default: { + code 69 + switch (the_var) { + default: { + } + } } } - } - } - code 74 - switch (the_var) { - uint(i5) >= uint(i6) { - code 76 + code 71 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 73 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 75 - switch (the_var) { default: { + code 72 + switch (the_var) { + default: { + } + } } } - } - } - code 77 - switch (the_var) { - uint(i5) >= uint(i6) { - code 79 + code 74 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 76 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 78 - switch (the_var) { default: { + code 75 + switch (the_var) { + default: { + } + } } } - } - } - code 80 - switch (the_var) { - uint(i5) >= uint(i6) { - code 82 + code 77 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 79 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 81 - switch (the_var) { default: { + code 78 + switch (the_var) { + default: { + } + } } } - } - } - code 83 - switch (the_var) { - uint(i5) >= uint(i6) { - code 85 + code 80 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 82 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 84 - switch (the_var) { default: { + code 81 + switch (the_var) { + default: { + } + } } } - } - } - code 86 - switch (the_var) { - uint(i5) >= uint(i6) { - code 88 + code 83 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 85 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 87 - switch (the_var) { default: { + code 84 + switch (the_var) { + default: { + } + } } } - } - } - code 89 - switch (the_var) { - uint(i5) >= uint(i6) { - code 91 + code 86 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 88 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 90 - switch (the_var) { default: { + code 87 + switch (the_var) { + default: { + } + } } } - } - } - code 92 - switch (the_var) { - uint(i5) >= uint(i6) { - code 94 + code 89 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 91 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 93 - switch (the_var) { default: { + code 90 + switch (the_var) { + default: { + } + } } } - } - } - code 95 - switch (the_var) { - uint(i5) >= uint(i6) { - code 97 + code 92 switch (the_var) { + uint(i5) >= uint(i6) { + code 94 + switch (the_var) { + default: { + } + } + break; + } default: { + code 93 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 96 + code 95 switch (the_var) { + uint(i5) >= uint(i6) { + code 97 + switch (the_var) { + default: { + } + } + break; + } default: { + code 96 + switch (the_var) { + default: { + } + } } } - } - } - code 98 - switch (the_var) { - uint(i5) >= uint(i6) { - code 100 + code 98 switch (the_var) { + uint(i5) >= uint(i6) { + code 100 + switch (the_var) { + default: { + } + } + break; + } default: { + code 99 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 99 + code 101 switch (the_var) { + i2 != 0 { + break; + } default: { + break L26; } } } - } - code 101 - switch (the_var) { - i2 != 0 { - break; - } - default: { - break L26; - } - } } - } - } -} while(0); -code 102 -switch (the_var) { -uint(i4) >= uint(i5) { - code 104 - switch (the_var) { - default: { - } - } - break; -} -default: { - code 103 - switch (the_var) { - default: { - } - } -} -} -code 105 -L143: do { + } + } while(0); + code 102 switch (the_var) { - i2 == 0 { + uint(i4) >= uint(i5) { + code 104 + switch (the_var) { + default: { + } + } break; } default: { - code 106 + code 103 switch (the_var) { default: { } } - while(1) { - code 107 + } + } + code 105 + L143: do { + switch (the_var) { + i2 == 0 { + break; + } + default: { + code 106 switch (the_var) { - uint(i5) >= uint(i6) { - code 109 - switch (the_var) { - default: { - } - } - break; - } default: { - code 108 - switch (the_var) { - default: { - } - } } } - code 110 - switch (the_var) { - uint(i5) >= uint(i6) { - code 112 + while(1) { + code 107 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 109 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 111 - switch (the_var) { default: { + code 108 + switch (the_var) { + default: { + } + } } } - } - } - code 113 - switch (the_var) { - uint(i5) >= uint(i6) { - code 115 + code 110 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 112 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 114 - switch (the_var) { default: { + code 111 + switch (the_var) { + default: { + } + } } } - } - } - code 116 - switch (the_var) { - uint(i5) >= uint(i6) { - code 118 + code 113 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 115 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 117 - switch (the_var) { default: { + code 114 + switch (the_var) { + default: { + } + } } } - } - } - code 119 - switch (the_var) { - uint(i5) >= uint(i6) { - code 121 + code 116 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 118 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 120 - switch (the_var) { default: { + code 117 + switch (the_var) { + default: { + } + } } } - } - } - code 122 - switch (the_var) { - uint(i5) >= uint(i6) { - code 124 + code 119 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 121 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 123 - switch (the_var) { default: { + code 120 + switch (the_var) { + default: { + } + } } } - } - } - code 125 - switch (the_var) { - uint(i5) >= uint(i6) { - code 127 + code 122 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 124 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 126 - switch (the_var) { default: { + code 123 + switch (the_var) { + default: { + } + } } } - } - } - code 128 - switch (the_var) { - uint(i5) >= uint(i6) { - code 130 + code 125 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 127 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 129 - switch (the_var) { default: { + code 126 + switch (the_var) { + default: { + } + } } } - } - } - code 131 - switch (the_var) { - uint(i5) >= uint(i6) { - code 133 + code 128 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 130 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 132 - switch (the_var) { default: { + code 129 + switch (the_var) { + default: { + } + } } } - } - } - code 134 - switch (the_var) { - uint(i5) >= uint(i6) { - code 136 + code 131 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 133 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 135 - switch (the_var) { default: { + code 132 + switch (the_var) { + default: { + } + } } } - } - } - code 137 - switch (the_var) { - uint(i5) >= uint(i6) { - code 139 + code 134 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 136 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 138 - switch (the_var) { default: { + code 135 + switch (the_var) { + default: { + } + } } } - } - } - code 140 - switch (the_var) { - uint(i5) >= uint(i6) { - code 142 + code 137 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 139 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 141 - switch (the_var) { default: { + code 138 + switch (the_var) { + default: { + } + } } } - } - } - code 143 - switch (the_var) { - uint(i5) >= uint(i6) { - code 145 + code 140 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 142 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 144 - switch (the_var) { default: { + code 141 + switch (the_var) { + default: { + } + } } } - } - } - code 146 - switch (the_var) { - uint(i5) >= uint(i6) { - code 148 + code 143 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 145 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 147 - switch (the_var) { default: { + code 144 + switch (the_var) { + default: { + } + } } } - } - } - code 149 - switch (the_var) { - uint(i5) >= uint(i6) { - code 151 + code 146 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 148 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 150 - switch (the_var) { default: { + code 147 + switch (the_var) { + default: { + } + } } } - } - } - code 152 - switch (the_var) { - uint(i5) >= uint(i6) { - code 154 + code 149 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 151 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 153 - switch (the_var) { default: { + code 150 + switch (the_var) { + default: { + } + } } } - } - } - code 155 - switch (the_var) { - uint(i5) >= uint(i6) { - code 157 + code 152 switch (the_var) { - default: { + uint(i5) >= uint(i6) { + code 154 + switch (the_var) { + default: { + } + } + break; } - } - break; - } - default: { - code 156 - switch (the_var) { default: { + code 153 + switch (the_var) { + default: { + } + } } } - } - } - code 158 - switch (the_var) { - uint(i5) >= uint(i6) { - code 160 + code 155 switch (the_var) { - default: { - } + uint(i5) >= uint(i6) { + code 157 + switch (the_var) { + default: { + } + } + break; } - break; - } - default: { - code 159 - switch (the_var) { default: { + code 156 + switch (the_var) { + default: { + } + } } } - } - } - code 161 - switch (the_var) { - uint(i5) >= uint(i6) { - code 163 + code 158 switch (the_var) { + uint(i5) >= uint(i6) { + code 160 + switch (the_var) { + default: { + } + } + break; + } default: { + code 159 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 162 + code 161 switch (the_var) { + uint(i5) >= uint(i6) { + code 163 + switch (the_var) { + default: { + } + } + break; + } default: { + code 162 + switch (the_var) { + default: { + } + } } } - } - } - code 164 - switch (the_var) { - uint(i5) >= uint(i6) { - code 166 + code 164 switch (the_var) { + uint(i5) >= uint(i6) { + code 166 + switch (the_var) { + default: { + } + } + break; + } default: { + code 165 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 165 + code 167 switch (the_var) { + i2 != 0 { + break; + } default: { + break L143; } } } - } - code 167 - switch (the_var) { - i2 != 0 { - break; - } - default: { - break L143; - } - } } - } - } -} while(0); -code 168 -switch (the_var) { -uint(i4) >= uint(i5) { - code 170 - switch (the_var) { - default: { - } - } - break; -} -default: { - code 169 - switch (the_var) { - default: { - } - } -} -} -code 171 -switch (the_var) { -i2 == 0 { - code 183 - break; -} -default: { -} -} -code 172 -switch (the_var) { -default: { -} -} -L235: while(1) { - code 173 + } + } while(0); + code 168 switch (the_var) { - uint(i5) >= uint(i6) { - code 175 + uint(i4) >= uint(i5) { + code 170 switch (the_var) { default: { } @@ -1074,58 +1041,91 @@ L235: while(1) { break; } default: { - code 174 + code 169 switch (the_var) { default: { } } } } - code 176 + code 171 + switch (the_var) { + i2 == 0 { + code 183 + break; + } + default: { + } + } + code 172 switch (the_var) { - uint(i5) >= uint(i6) { - code 178 + default: { + } + } + L235: while(1) { + code 173 switch (the_var) { + uint(i5) >= uint(i6) { + code 175 + switch (the_var) { + default: { + } + } + break; + } default: { + code 174 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 177 + code 176 switch (the_var) { + uint(i5) >= uint(i6) { + code 178 + switch (the_var) { + default: { + } + } + break; + } default: { + code 177 + switch (the_var) { + default: { + } + } } } - } - } - code 179 - switch (the_var) { - uint(i4) >= uint(i5) { - code 181 + code 179 switch (the_var) { + uint(i4) >= uint(i5) { + code 181 + switch (the_var) { + default: { + } + } + break; + } default: { + code 180 + switch (the_var) { + default: { + } + } } } - break; - } - default: { - code 180 + code 182 switch (the_var) { + i2 != 0 { + break; + } default: { + break L235; } } } - } - code 182 - switch (the_var) { - i2 != 0 { - break; - } - default: { - break L235; - } - } -} -code 183 + code 183 diff --git a/src/relooper/testit.sh b/src/relooper/testit.sh index 88db35fb..6e984b5a 100755 --- a/src/relooper/testit.sh +++ b/src/relooper/testit.sh @@ -2,61 +2,61 @@ echo "test" ./test &> test.out -diff -U 5 test.txt test.out +diff -w -U 5 test.txt test.out echo "test 2" ./test2 &> test2.out -diff -U 5 test2.txt test2.out +diff -w -U 5 test2.txt test2.out echo "test 3" ./test3 &> test3.out -diff -U 5 test3.txt test3.out +diff -w -U 5 test3.txt test3.out echo "test debug" ./test_debug &> test_debug.out -diff -U 5 test_debug.txt test_debug.out +diff -w -U 5 test_debug.txt test_debug.out echo "test dead" ./test_dead &> test_dead.out -diff -U 5 test_dead.txt test_dead.out +diff -w -U 5 test_dead.txt test_dead.out echo "test 4" ./test4 &> test4.out -diff -U 5 test4.txt test4.out +diff -w -U 5 test4.txt test4.out echo "test 5" ./test5 &> test5.out -diff -U 5 test5.txt test5.out +diff -w -U 5 test5.txt test5.out echo "test 6" ./test6 &> test6.out -diff -U 5 test6.txt test6.out +diff -w -U 5 test6.txt test6.out echo "test inf" ./test_inf &> test_inf.out -diff -U 5 test_inf.txt test_inf.out +diff -w -U 5 test_inf.txt test_inf.out echo "test fuzz1" ./test_fuzz1 &> test_fuzz1.out -diff -U 5 test_fuzz1.txt test_fuzz1.out +diff -w -U 5 test_fuzz1.txt test_fuzz1.out echo "test fuzz2" ./test_fuzz2 &> test_fuzz2.out -diff -U 5 test_fuzz2.txt test_fuzz2.out +diff -w -U 5 test_fuzz2.txt test_fuzz2.out echo "test fuzz3" ./test_fuzz3 &> test_fuzz3.out -diff -U 5 test_fuzz3.txt test_fuzz3.out +diff -w -U 5 test_fuzz3.txt test_fuzz3.out echo "test fuzz4" ./test_fuzz4 &> test_fuzz4.out -diff -U 5 test_fuzz4.txt test_fuzz4.out +diff -w -U 5 test_fuzz4.txt test_fuzz4.out echo "test fuzz5" ./test_fuzz5 &> test_fuzz5.out -diff -U 5 test_fuzz5.txt test_fuzz5.out +diff -w -U 5 test_fuzz5.txt test_fuzz5.out echo "test fuzz6" ./test_fuzz6 &> test_fuzz6.out -diff -U 5 test_fuzz6.txt test_fuzz6.out +diff -w -U 5 test_fuzz6.txt test_fuzz6.out diff --git a/src/runtime.js b/src/runtime.js index 8ba5d08d..cd3afb4b 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -250,7 +250,7 @@ var Runtime = { prev = curr; return curr; }); - if (type.name_[0] === '[') { + if (type.name_ && type.name_[0] === '[') { // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid // allocating a potentially huge array for [999999 x i8] etc. type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2; diff --git a/tests/aniso.c b/tests/aniso.c index f1674cad..443e50aa 100644 --- a/tests/aniso.c +++ b/tests/aniso.c @@ -151,6 +151,11 @@ int main(int argc, char *argv[]) assert(!glGetError()); glBindFramebuffer(GL_RENDERBUFFER, 0); assert(glGetError()); + + GLint out = 321; + assert(!glGetError()); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &out); // invalid, just test output + assert(out == 0); } // Prepare and Render diff --git a/tests/cases/longjmp_tiny_invoke_phi.ll b/tests/cases/longjmp_tiny_invoke_phi.ll new file mode 100644 index 00000000..30c43339 --- /dev/null +++ b/tests/cases/longjmp_tiny_invoke_phi.ll @@ -0,0 +1,46 @@ +; ModuleID = '/tmp/emscripten_temp/src.cpp.o' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@_ZL3buf = internal global [20 x i16] zeroinitializer, align 2 +@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1 +@.str1 = private unnamed_addr constant [6 x i8] c"more\0A\00", align 1 +@.str2 = private unnamed_addr constant [6 x i8] c"fair\0A\00", align 1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = invoke i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice + to label %allgood unwind label %awful + +allgood: + %p = phi i32 [0, %entry], [1, %if.else] + %calll = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0)) + %total = add i32 %p, %call + %tobool = icmp ne i32 %total, 10 + br i1 %tobool, label %if.then, label %if.else + +if.then: ; preds = %entry + %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0)) + call void @longjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0), i32 10) + br label %if.end + +if.else: ; preds = %entry + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0)) + %chak = icmp ne i32 %call2, 1337 + br i1 %chak, label %if.end, label %allgood + +if.end: ; preds = %if.else, %if.then + ret i32 0 + +awful: + ret i32 1 +} + +declare i32 @setjmp(i16*) returns_twice + +declare i32 @printf(i8*, ...) + +declare void @longjmp(i16*, i32) + diff --git a/tests/cases/longjmp_tiny_invoke_phi.txt b/tests/cases/longjmp_tiny_invoke_phi.txt new file mode 100644 index 00000000..aaa41d11 --- /dev/null +++ b/tests/cases/longjmp_tiny_invoke_phi.txt @@ -0,0 +1,4 @@ +fair +hello world +fair +more diff --git a/tests/core/closebitcasts.c b/tests/core/closebitcasts.c new file mode 100644 index 00000000..2c9d5ab5 --- /dev/null +++ b/tests/core/closebitcasts.c @@ -0,0 +1,32 @@ +#include <stdio.h> + +int main(int argc, char **argv) { + float x = argc%17, y = (argc+1)*(argc+2)*(argc+3)*(argc+4)*(argc*5); + y *= 1<<30; + y *= -13; + if (argc == 17) { x++; y--; } + int *xi = (int*)&x; + int *yi = (int*)&y; + int z = *xi - *yi; + while (z % 15) { + z++; + } + printf("!%d\n", z); + + double xd = x, yd = y; + yd = yd*yd; + yd = yd*yd; + int *xl = (int*)&xd; + int *xh = &((int*)&xd)[1]; + int *yl = (int*)&yd; + int *yh = &((int*)&yd)[1]; + int l = *xl - *yl; + int h = *xh - *yh; + while (l % 15) { + l++; + h += 3; + } + printf("%d,%d!\n", l, h); + return 0; +} + diff --git a/tests/core/closebitcasts.txt b/tests/core/closebitcasts.txt new file mode 100644 index 00000000..f97366cd --- /dev/null +++ b/tests/core/closebitcasts.txt @@ -0,0 +1,2 @@ +!1787576325 +589815810,-179981561! diff --git a/tests/cubegeom.c b/tests/cubegeom.c index 96d56339..e749045b 100644 --- a/tests/cubegeom.c +++ b/tests/cubegeom.c @@ -54,9 +54,21 @@ int main(int argc, char *argv[]) // Create a texture + GLuint boundTex = 123; + assert(!glGetError()); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + assert(!glGetError()); + assert(boundTex == 0); + GLuint texture; glGenTextures( 1, &texture ); glBindTexture( GL_TEXTURE_2D, texture ); + + assert(!glGetError()); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + assert(!glGetError()); + assert(boundTex == texture); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); GLubyte textureData[16*16*4]; diff --git a/tests/fuzz/test.sh b/tests/fuzz/test.sh index cc77dba4..166d4bab 100755 --- a/tests/fuzz/test.sh +++ b/tests/fuzz/test.sh @@ -2,22 +2,38 @@ # ~/Dev/emscripten/tests/fuzz$ CSMITH=~/Dev/csmith/src/csmith CSMITH_PATH=~/Dev/csmith python ./csmith_driver.py # to find failures, then check those out with this script -echo "0" -gcc $1 -I/home/alon/Dev/csmith/runtime &> /dev/null -~/Dev/emscripten/emcc $1 -I/home/alon/Dev/csmith/runtime &> /dev/null -./a.out > o -mozjs a.out.js > b -diff o b -echo "1" -gcc -O1 $1 -I/home/alon/Dev/csmith/runtime &> /dev/null -~/Dev/emscripten/emcc -O1 $1 -I/home/alon/Dev/csmith/runtime &> /dev/null -./a.out > o -mozjs a.out.js > b -diff o b -echo "2" -gcc -O2 $1 -I/home/alon/Dev/csmith/runtime &> /dev/null -~/Dev/emscripten/emcc -O2 $1 -I/home/alon/Dev/csmith/runtime &> /dev/null -./a.out > o -mozjs a.out.js > b -diff o b +echo "builds" +gcc $@ -I/home/alon/Dev/csmith/runtime -o n1.out &> /dev/null +/home/alon/Dev/fastcomp/build/Release/bin/clang $@ -I/home/alon/Dev/csmith/runtime -o n2.out &> /dev/null +/home/alon/Dev/fastcomp/build/Release/bin/clang $@ -I/home/alon/Dev/csmith/runtime -emit-llvm -c -o bc.bc &> o +~/Dev/emscripten/emcc $@ -I/home/alon/Dev/csmith/runtime -o js.out.js &> /dev/null +#~/Dev/emscripten/emcc $@ -s UNALIGNED_MEMORY=1 -I/home/alon/Dev/csmith/runtime -o ua.out.js &> /dev/null +#~/Dev/emscripten/emcc $@ -s SAFE_HEAP=1 -I/home/alon/Dev/csmith/runtime -o sh.out.js &> /dev/null +EMCC_FAST_COMPILER=1 ~/Dev/emscripten/emcc $@ -I/home/alon/Dev/csmith/runtime -o fc.out.js &> /dev/null +echo "run n1" +./n1.out &> n1 +echo "run n2" +./n2.out &> n2 +echo "run bc" +/home/alon/Dev/fastcomp/build/Release/bin/lli bc.bc &> bc +echo "run js" +mozjs js.out.js &> js +echo "run ua" +#mozjs ua.out.js &> ua +echo "run sh" +#mozjs sh.out.js &> sh +echo "run fc" +mozjs fc.out.js &> fc +echo "n/n" +diff n1 n2 +echo "n/bc" +diff n1 bc +echo "n/js" +diff n1 js | grep -v warning +echo "n/js-ua" +#diff n1 ua | grep -v warning +echo "n/js-sh" +#diff n1 sh | grep -v warning +echo "js/js" +diff js fc | grep -v warning diff --git a/tests/runner.py b/tests/runner.py index 37e307e9..72e940cb 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -649,6 +649,7 @@ class BrowserCore(RunnerCore): def btest(self, filename, expected=None, reference=None, force_c=False, reference_slack=0, manual_reference=False, post_build=None, args=[], outfile='test.html', message='.'): # TODO: use in all other tests + if os.environ.get('EMCC_FAST_COMPILER') == '1' and 'LEGACY_GL_EMULATION=1' in args: return self.skip('no legacy gl emulation in fastcomp') # if we are provided the source and not a path, use that filename_is_src = '\n' in filename src = filename if filename_is_src else '' diff --git a/tests/sdl_canvas.c b/tests/sdl_canvas.c index 6bd659b8..cab48985 100644 --- a/tests/sdl_canvas.c +++ b/tests/sdl_canvas.c @@ -62,6 +62,8 @@ int main(int argc, char **argv) { printf("you should see two lines of text in different colors and a blue rectangle\n"); + SDL_UnlockSurface(screen); + SDL_Quit(); printf("done.\n"); diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 60670ed4..625340ea 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -58,7 +58,7 @@ class NativeBenchmarker(Benchmarker): def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder): self.parent = parent - if lib_builder: native_args += lib_builder(self.name, native=True, env_init={ 'CC': self.cc, 'CXX': self.cxx }) + if lib_builder: native_args = native_args + lib_builder(self.name, native=True, env_init={ 'CC': self.cc, 'CXX': self.cxx }) if not native_exec: compiler = self.cxx if filename.endswith('cpp') else self.cc process = Popen([compiler, '-O2', '-fno-math-errno', filename, '-o', filename+'.native'] + shared_args + native_args, stdout=PIPE, stderr=parent.stderr_redirect) @@ -90,7 +90,7 @@ class JSBenchmarker(Benchmarker): def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder): self.filename = filename - if lib_builder: emcc_args += lib_builder('js', native=False, env_init={}) + if lib_builder: emcc_args = emcc_args + lib_builder('js', native=False, env_init={}) open('hardcode.py', 'w').write(''' def process(filename): @@ -124,7 +124,7 @@ benchmarkers = [ #NativeBenchmarker('gcc', 'gcc', 'g++'), #JSBenchmarker('sm-f32', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2']), JSBenchmarker('sm', SPIDERMONKEY_ENGINE), - JSBenchmarker('sm-fc', SPIDERMONKEY_ENGINE, env={ 'EMCC_FAST_COMPILER': '1' }), + #JSBenchmarker('sm-fc', SPIDERMONKEY_ENGINE, env={ 'EMCC_FAST_COMPILER': '1' }), #JSBenchmarker('sm-noasm', SPIDERMONKEY_ENGINE + ['--no-asmjs']), #JSBenchmarker('sm-noasm-f32', SPIDERMONKEY_ENGINE + ['--no-asmjs'], ['-s', 'PRECISE_F32=2']), #JSBenchmarker('v8', V8_ENGINE) diff --git a/tests/test_browser.py b/tests/test_browser.py index 920c6f8c..20b38bb5 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -120,6 +120,8 @@ If manually bisecting: ''' def test_emscripten_log(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('fastcomp uses asm, where call stacks are sometimes less clear') + src = os.path.join(self.get_dir(), 'src.cpp') open(src, 'w').write(self.with_report_result(open(path_from_root('tests', 'emscripten_log', 'emscripten_log.cpp')).read())) @@ -680,10 +682,7 @@ If manually bisecting: self.btest('sdl_stb_image_data.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not']) def test_sdl_canvas(self): - open(os.path.join(self.get_dir(), 'sdl_canvas.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas.c')).read())) - - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() - self.run_browser('page.html', '', '/report_result?1') + self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_sdl_canvas_proxy(self): def post(): @@ -1111,6 +1110,8 @@ keydown(100);keyup(100); // trigger the end self.run_browser('page.html', '', '/report_result?1') def test_sdl_audio_beeps(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo c++ exceptions in fastcomp') + open(os.path.join(self.get_dir(), 'sdl_audio_beep.cpp'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_beep.cpp')).read())) # use closure to check for a possible bug with closure minifying away newer Audio() attributes @@ -1194,10 +1195,7 @@ keydown(100);keyup(100); // trigger the end self.btest('openal_buffers.c', '0', args=['--preload-file', 'the_entertainer.wav'],) def test_glfw(self): - open(os.path.join(self.get_dir(), 'glfw.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'glfw.c')).read())) - - Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() - self.run_browser('page.html', '', '/report_result?1') + self.btest('glfw.c', '1', args=['-s', 'LEGACY_GL_EMULATION=1']) def test_egl(self): open(os.path.join(self.get_dir(), 'test_egl.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl.c')).read())) @@ -1436,6 +1434,8 @@ keydown(100);keyup(100); // trigger the end self.btest('sdl_resize.c', '1') def test_gc(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('flaky in fastcomp and also non-fastcomp -O1, timing issues') + self.btest('browser_gc.cpp', '1') def test_glshaderinfo(self): @@ -1622,11 +1622,12 @@ keydown(100);keyup(100); // trigger the end self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1']) def test_aniso(self): - if SPIDERMONKEY_ENGINE in JS_ENGINES: + if SPIDERMONKEY_ENGINE in JS_ENGINES and os.environ.get('EMCC_FAST_COMPILER') != '1': # asm.js-ification check Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1']).communicate() Settings.ASM_JS = 1 self.run_generated_code(SPIDERMONKEY_ENGINE, 'a.out.js') + print 'passed asm test' shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds') self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-s', 'LEGACY_GL_EMULATION=1']) @@ -1681,6 +1682,8 @@ keydown(100);keyup(100); // trigger the end self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')]) def test_module(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + Popen([PYTHON, EMCC, path_from_root('tests', 'browser_module.cpp'), '-o', 'module.js', '-O2', '-s', 'SIDE_MODULE=1', '-s', 'DLOPEN_SUPPORT=1', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two"]']).communicate() self.btest('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE=1', '-s', 'DLOPEN_SUPPORT=1'], expected='8') diff --git a/tests/test_core.py b/tests/test_core.py index 2430aa1c..6442f894 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -771,6 +771,12 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co self.do_run_from_file(src, output) + def test_closebitcasts(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2') + test_path = path_from_root('tests', 'core', 'closebitcasts') + src, output = (test_path + s for s in ('.c', '.txt')) + self.do_run_from_file(src, output) + def test_fast_math(self): if self.emcc_args is None: return self.skip('requires emcc') Building.COMPILER_TEST_OPTS += ['-ffast-math'] @@ -931,6 +937,8 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co for named in (0, 1): print named + if os.environ.get('EMCC_FAST_COMPILER') == '1' and named: continue # no named globals in fastcomp + Settings.NAMED_GLOBALS = named self.do_run_from_file(src, output, ['wowie', 'too', '74']) @@ -5026,8 +5034,8 @@ def process(filename): 'structphiparam', 'callwithstructural_ta2', 'callwithstructural64_ta2', 'structinparam', # pnacl limitations in ExpandStructRegs '2xi40', # pnacl limitations in ExpandGetElementPtr 'legalizer_ta2', '514_ta2', # pnacl limitation in not legalizing i104, i96, etc. - 'longjmp_tiny', 'longjmp_tiny_invoke', 'longjmp_tiny_phi', 'longjmp_tiny_phi2', 'indirectbrphi', 'ptrtoint_blockaddr', 'quoted', # current fastcomp limitations FIXME - 'sillyfuncast', 'sillyfuncast2', 'sillybitcast', # TODO very very soon XXX + 'longjmp_tiny', 'longjmp_tiny_invoke', 'longjmp_tiny_phi', 'longjmp_tiny_phi2', 'longjmp_tiny_invoke_phi', 'indirectbrphi', 'ptrtoint_blockaddr', 'quoted', # current fastcomp limitations FIXME + 'sillyfuncast', 'sillyfuncast2', 'sillybitcast', 'atomicrmw_unaligned' # TODO XXX ]: continue if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2: print self.skip('case "%s" only relevant for ta2' % shortname) @@ -6085,6 +6093,7 @@ def process(filename): self.build(src, dirname, os.path.join(dirname, 'src.cpp'), post_build=(None, post)) def test_emscripten_log(self): + self.banned_js_engines = [SPIDERMONKEY_ENGINE] # XXX, emscripten_log is broken in spidermonkey currently, issue #1970 if self.emcc_args is None: return self.skip('This test needs libc.') if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g') self.do_run('#define RUN_FROM_JS_SHELL\n' + open(path_from_root('tests', 'emscripten_log', 'emscripten_log.cpp')).read(), "Success!") diff --git a/tests/test_other.py b/tests/test_other.py index a6e8b533..4bdd889b 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -397,6 +397,8 @@ f.close() self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js'))) def test_unaligned_memory(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' #include <stdio.h> #include <stdarg.h> @@ -421,6 +423,8 @@ f.close() self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js'))) def test_unaligned_memory_2(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r''' #include <string> #include <stdio.h> @@ -463,6 +467,7 @@ f.close() assert 'function _malloc' in src def test_dangerous_func_cast(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') src = r''' #include <stdio.h> typedef void (*voidfunc)(); @@ -522,6 +527,8 @@ f.close() assert not os.path.exists('a.out') and not os.path.exists('a.exe'), 'Must not leave unneeded linker stubs' def test_static_link(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + def test(name, header, main, side, expected, args=[], suffix='cpp', first=True): print name #t = main ; main = side ; side = t @@ -1165,7 +1172,7 @@ f.close() ''') Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--js-library', os.path.join(self.get_dir(), 'mylib1.js'), - '--js-library', os.path.join(self.get_dir(), 'mylib2.js')]).communicate() + '--js-library', os.path.join(self.get_dir(), 'mylib2.js')]).communicate() self.assertContained('hello from lib!\n*32*\n', run_js(os.path.join(self.get_dir(), 'a.out.js'))) def test_identical_basenames(self): @@ -1374,60 +1381,66 @@ f.close() assert output == '' def test_multidynamic_link(self): - # Linking the same dynamic library in will error, normally, since we statically link it, causing dupe symbols - # A workaround is to use --ignore-dynamic-linking, see emcc --help for details + # Linking the same dynamic library in statically will error, normally, since we statically link it, causing dupe symbols - open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' - #include <stdio.h> - extern void printey(); - extern void printother(); - int main() { - printf("*"); - printey(); - printf("\n"); - printother(); - printf("\n"); - printf("*"); - return 0; - } - ''') + def test(link_cmd, lib_suffix=''): + print link_cmd, lib_suffix - try: - os.makedirs(os.path.join(self.get_dir(), 'libdir')); - except: - pass + self.clear() - open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write(''' - #include <stdio.h> - void printey() { - printf("hello from lib"); - } - ''') + open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' + #include <stdio.h> + extern void printey(); + extern void printother(); + int main() { + printf("*"); + printey(); + printf("\n"); + printother(); + printf("\n"); + printf("*"); + return 0; + } + ''') - open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write(''' - #include <stdio.h> - extern void printey(); - void printother() { - printf("|"); - printey(); - printf("|"); - } - ''') + try: + os.makedirs(os.path.join(self.get_dir(), 'libdir')); + except: + pass - # This lets us link the same dynamic lib twice. We will need to link it in manually at the end. - compiler = [PYTHON, EMCC, '--ignore-dynamic-linking'] + open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write(''' + #include <stdio.h> + void printey() { + printf("hello from lib"); + } + ''') - # Build libfile normally into an .so - Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so')]).communicate() - # Build libother and dynamically link it to libfile - but add --ignore-dynamic-linking - Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate() - # Build the main file, linking in both the libs - Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother', '-c']).communicate() + open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write(''' + #include <stdio.h> + extern void printey(); + void printother() { + printf("|"); + printey(); + printf("|"); + } + ''') + + compiler = [PYTHON, EMCC] + + # Build libfile normally into an .so + Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so' + lib_suffix)]).communicate() + # Build libother and dynamically link it to libfile + Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp')] + link_cmd + ['-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate() + # Build the main file, linking in both the libs + Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp')] + link_cmd + ['-lother', '-c']).communicate() + print '...' + # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o')] + link_cmd + ['-lother']).communicate() - # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother']).communicate() + self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js'))) - self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + test(['-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile']) # -l, auto detection from library path + test(['-L' + os.path.join(self.get_dir(), 'libdir'), os.path.join(self.get_dir(), 'libdir', 'libfile.so.3.1.4.1.5.9')], '.3.1.4.1.5.9') # handle libX.so.1.2.3 as well def test_js_link(self): open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(''' @@ -1785,6 +1798,7 @@ f.close() assert 'If you see this - the world is all right!' in output def test_embind(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') for args, fail in [ ([], True), # without --bind, we fail (['--bind'], False), @@ -1850,6 +1864,8 @@ seeked= file. assert output == invalid def test_link_s(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo safe heap in fastcomp') + # -s OPT=VALUE can conflict with -s as a linker option. We warn and ignore open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' extern "C" { @@ -1944,19 +1960,19 @@ seeked= file. # crunch should not be run if a .crn exists that is more recent than the .dds shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds') time.sleep(0.1) - Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() + Popen([PYTHON, FILE_PACKAGER, 'test.data', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() assert os.stat('test.data').st_size < 0.25*os.stat('ship.dds').st_size, 'Compressed should be much smaller than dds' crunch_time = os.stat('ship.crn').st_mtime dds_time = os.stat('ship.dds').st_mtime assert crunch_time > dds_time, 'Crunch is more recent' # run again, should not recrunch! time.sleep(0.1) - Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() + Popen([PYTHON, FILE_PACKAGER, 'test.data', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() assert crunch_time == os.stat('ship.crn').st_mtime, 'Crunch is unchanged' # update dds, so should recrunch time.sleep(0.1) os.utime('ship.dds', None) - Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() + Popen([PYTHON, FILE_PACKAGER, 'test.data', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate() assert crunch_time < os.stat('ship.crn').st_mtime, 'Crunch was changed' def test_headless(self): @@ -2133,6 +2149,8 @@ int main() self.assertContained('File size: 722', out) def test_simd(self): + if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') + self.clear() Popen([PYTHON, EMCC, path_from_root('tests', 'linpack.c'), '-O2', '-DSP', '--llvm-opts', '''['-O3', '-vectorize', '-vectorize-loops', '-bb-vectorize-vector-bits=128', '-force-vector-width=4']''']).communicate() self.assertContained('Unrolled Single Precision', run_js('a.out.js')) @@ -2181,3 +2199,12 @@ mergeInto(LibraryManager.library, { out, err = process.communicate() assert process.returncode is 0, 'float.h should agree with our system: ' + out + '\n\n\n' + err + def test_default_obj_ext(self): + outdir = os.path.join(self.get_dir(), 'out_dir') + '/' + os.mkdir(outdir) + process = Popen([PYTHON, EMCC, '-c', path_from_root('tests', 'hello_world.c'), '-o', outdir], stdout=PIPE, stderr=PIPE) + process.communicate() + assert(os.path.isfile(outdir + 'hello_world.o')) + process = Popen([PYTHON, EMCC, '-c', path_from_root('tests', 'hello_world.c'), '-o', outdir, '--default-obj-ext', 'obj'], stdout=PIPE, stderr=PIPE) + process.communicate() + assert(os.path.isfile(outdir + 'hello_world.obj')) diff --git a/tests/test_sanity.py b/tests/test_sanity.py index dc3d53db..e8b1f885 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -195,6 +195,34 @@ class sanity(RunnerCore): finally: del os.environ['EM_IGNORE_SANITY'] + def test_llvm_fastcomp(self): + if os.environ.get('EMCC_FAST_COMPILER') != '1': return self.skip('not using fastcomp') + + WARNING = 'fastcomp in use, but LLVM has not been built with the JavaScript backend as a target' + + restore() + + # Should see js backend during sanity check + assert check_fastcomp() + output = self.check_working(EMCC) + assert WARNING not in output, output + + # Fake incorrect llc output, no mention of js backend + restore() + f = open(CONFIG_FILE, 'a') + f.write('LLVM_ROOT = "' + path_from_root('tests', 'fake') + '"') + f.close() + + if not os.path.exists(path_from_root('tests', 'fake')): + os.makedirs(path_from_root('tests', 'fake')) + + f = open(path_from_root('tests', 'fake', 'llc'), 'w') + f.write('#!/bin/sh\n') + f.write('echo "llc fake output\nRegistered Targets:\nno j-s backend for you!"') + f.close() + os.chmod(path_from_root('tests', 'fake', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) + output = self.check_working(EMCC, WARNING) + def test_node(self): NODE_WARNING = 'node version appears too old' NODE_WARNING_2 = 'cannot check node version' diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index 434fbaf9..a344fc35 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -280,9 +280,10 @@ function tempDouble2($46, $14, $28, $42, $20, $32, $45) { $20 = $20 | 0; $32 = $32 | 0; $45 = $45 | 0; - var $_sroa_06_0_insert_insert$1 = 0; + var $46 = 0, $_sroa_06_0_insert_insert$1 = 0; + $46 = (HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0); $_sroa_06_0_insert_insert$1 = (HEAPF32[tempDoublePtr >> 2] = ($20 < $32 ? $20 : $32) - $42, HEAP32[tempDoublePtr >> 2] | 0) | 0; - HEAP32[$45 >> 2] = 0 | (HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0); + HEAP32[$45 >> 2] = 0 | $46; HEAP32[$45 + 4 >> 2] = $_sroa_06_0_insert_insert$1; HEAP32[$45 + 8 >> 2] = $_sroa_06_0_insert_insert$1; } @@ -298,4 +299,9 @@ function select2($foundBase_0_off0) { STACKTOP = sp; return ($foundBase_0_off0 ? 0 : $call24) | 0; } +function binary(x) { + x = x | 0; + memset(f(x)) | 0; + +dmemset(f(x)); +} diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index 7ec277d5..4b45e4d4 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -370,5 +370,13 @@ function select2($foundBase_0_off0) { STACKTOP = sp; return $retval_0 | 0; } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2"] +function binary(x) { + x = x | 0; + var y = 0, z = 0; + y = f(x); + memset(y) | 0; + z = f(x); + +dmemset(z); +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary"] diff --git a/tools/eliminator/eliminator-test-output.js b/tools/eliminator/eliminator-test-output.js index 0171e99b..4551fb34 100644 --- a/tools/eliminator/eliminator-test-output.js +++ b/tools/eliminator/eliminator-test-output.js @@ -6122,4 +6122,15 @@ function intoCond() { function math(a, b, c, d) { print(Math_imul(d) + (Math_fround(c) + (a + Math_abs(b)))); } +function td(x, y) { + HEAP32[tempDoublePtr >> 2] = x; + var xf = HEAPF32[tempDoublePtr >> 2]; + HEAP32[tempDoublePtr >> 2] = y; + func(xf, HEAPF32[tempDoublePtr >> 2]); + HEAPF64[tempDoublePtr >> 3] = x; + var xl = HEAP32[tempDoublePtr >> 2]; + var xh = HEAP32[tempDoublePtr >> 2]; + HEAPF64[tempDoublePtr >> 3] = y; + func(xl, xh, HEAP32[tempDoublePtr >> 2], HEAP32[tempDoublePtr >> 2]); +} diff --git a/tools/eliminator/eliminator-test.js b/tools/eliminator/eliminator-test.js index ef17b388..e629d9f0 100644 --- a/tools/eliminator/eliminator-test.js +++ b/tools/eliminator/eliminator-test.js @@ -8860,5 +8860,20 @@ function math(a, b, c, d) { w = Math_imul(d); print(x + y + z + w); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "c", "f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1", "_inflate", "_malloc", "_mallocNoU", "asm", "phi", "intoCond", "math"] +function td(x, y) { // tempDoublePtr should invalidate each other + HEAP32[tempDoublePtr>>2] = x; + var xf = HEAPF32[tempDoublePtr>>2]; + HEAP32[tempDoublePtr>>2] = y; + var yf = HEAPF32[tempDoublePtr>>2]; + func(xf, yf); + // + HEAPF64[tempDoublePtr>>3] = x; + var xl = HEAP32[tempDoublePtr>>2]; + var xh = HEAP32[tempDoublePtr>>2]; + HEAPF64[tempDoublePtr>>3] = y; + var yl = HEAP32[tempDoublePtr>>2]; + var yh = HEAP32[tempDoublePtr>>2]; + func(xl, xh, yl, yh); +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "c", "f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1", "_inflate", "_malloc", "_mallocNoU", "asm", "phi", "intoCond", "math", "td"] diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 9efca25f..161ed59c 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -271,6 +271,16 @@ function isEmptyNode(node) { return node.length === 2 && node[0] === 'toplevel' && node[1].length === 0; } +function clearEmptyNodes(list) { + for (var i = 0; i < list.length;) { + if (isEmptyNode(list[i]) || (list[i][0] === 'stat' && isEmptyNode(list[i][1]))) { + list.splice(i, 1); + } else { + i++; + } + } +} + // Passes // Dump the AST. Useful for debugging. For example, @@ -2134,14 +2144,11 @@ function registerize(ast) { // In memSafe mode, we are more careful and assume functions can replace HEAP and FUNCTION_TABLE, which // can happen in ALLOW_MEMORY_GROWTH mode -var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch'); // do is checked carefully, however +var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch', 'binary', 'unary-prefix'); // do is checked carefully, however var IGNORABLE_ELIMINATOR_SCAN_NODES = set('num', 'toplevel', 'string', 'break', 'continue', 'dot'); // dot can only be STRING_TABLE.* var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body) function isTempDoublePtrAccess(node) { // these are used in bitcasts; they are not really affecting memory, and should cause no invalidation - // XXX note that we assume they have no effect. this is only true due to the compiler emitting (write, read) - // using the comma operator, so they are not split up. Otherwise, we would need to invalidate - // tempDoublePtr when it is used, so write; read; write; read; would not become write; write; read; read; assert(node[0] === 'sub'); return (node[2][0] === 'name' && node[2][1] === 'tempDoublePtr') || (node[2][0] === 'binary' && ((node[2][2][0] === 'name' && node[2][2][1] === 'tempDoublePtr') || @@ -2427,7 +2434,12 @@ function eliminate(ast, memSafe) { if (allowTracking) track(name, node[3], node); } } else if (target[0] === 'sub') { - if (!isTempDoublePtrAccess(target) && !memoryInvalidated) { + if (isTempDoublePtrAccess(target)) { + if (!globalsInvalidated) { + invalidateGlobals(); + globalsInvalidated = true; + } + } else if (!memoryInvalidated) { invalidateMemory(); memoryInvalidated = true; } @@ -2687,6 +2699,7 @@ function eliminate(ast, memSafe) { } if (ifTrue[1][0] && ifTrue[1][0][0] === 'break') { var assigns = ifFalse[1]; + clearEmptyNodes(assigns); var loopers = [], helpers = []; for (var i = 0; i < assigns.length; i++) { if (assigns[i][0] === 'stat' && assigns[i][1][0] === 'assign') { @@ -3112,6 +3125,17 @@ function outline(ast) { parts = []; var curr = node; while (1) { + if (!curr[3]) { + // we normally expect ..if (cond) { .. } else [if (nextCond) {] (in [] is what we hope to see) + // but are now seeing ..if (cond) { .. } with no else. This might be + // ..if (cond) if (nextCond) { + // which vacuum can generate from if (cond) {} else if (nextCond), making it + // if (!cond) if (nextCond) + // so we undo that, in hopes of making it more flattenable + curr[3] = curr[2]; + curr[2] = ['block', []]; + curr[1] = simplifyNotCompsDirect(['unary-prefix', '!', curr[1]]); + } parts.push({ condition: curr[1], body: curr[2] }); curr = curr[3]; if (!curr) break; diff --git a/tools/shared.py b/tools/shared.py index 443ff4c7..5b02fa4c 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -286,6 +286,21 @@ def check_llvm_version(): except Exception, e: logging.warning('Could not verify LLVM version: %s' % str(e)) +def check_fastcomp(): + try: + llc_version_info = Popen([LLVM_COMPILER, '--version'], stdout=PIPE).communicate()[0] + pre, targets = llc_version_info.split('Registered Targets:') + if 'js' not in targets or 'JavaScript (asm.js, emscripten) backend' not in targets: + logging.critical('fastcomp in use, but LLVM has not been built with the JavaScript backend as a target, llc reports:') + print >> sys.stderr, '===========================================================================' + print >> sys.stderr, llc_version_info, + print >> sys.stderr, '===========================================================================' + return False + return True + except Exception, e: + logging.warning('cound not check fastcomp: %s' % str(e)) + return True + EXPECTED_NODE_VERSION = (0,8,0) def check_node_version(): @@ -322,7 +337,7 @@ def find_temp_directory(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.7.8' +EMSCRIPTEN_VERSION = '1.8.2' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT @@ -353,9 +368,11 @@ def check_sanity(force=False): Cache.erase() force = False # the check actually failed, so definitely write out the sanity file, to avoid others later seeing failures too - # some warning, not fatal checks - do them even if EM_IGNORE_SANITY is on + # some warning, mostly not fatal checks - do them even if EM_IGNORE_SANITY is on check_llvm_version() check_node_version() + if os.environ.get('EMCC_FAST_COMPILER') == '1': + fastcomp_ok = check_fastcomp() if os.environ.get('EM_IGNORE_SANITY'): logging.info('EM_IGNORE_SANITY set, ignoring sanity checks') @@ -377,6 +394,11 @@ def check_sanity(force=False): logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG)) sys.exit(1) + if os.environ.get('EMCC_FAST_COMPILER') == '1': + if not fastcomp_ok: + logging.critical('failing sanity checks due to previous fastcomp failure') + sys.exit(1) + try: subprocess.call([JAVA, '-version'], stdout=PIPE, stderr=PIPE) except: @@ -682,7 +704,7 @@ def line_splitter(data): return out -def limit_size(string, MAX=12000*20): +def limit_size(string, MAX=800*20): if len(string) < MAX: return string return string[0:MAX/2] + '\n[..]\n' + string[-MAX/2:] @@ -1094,7 +1116,7 @@ class Building: # 8k is a bit of an arbitrary limit, but a reasonable one # for max command line size before we use a respose file response_file = None - if WINDOWS and len(' '.join(link_cmd)) > 8192: + if len(' '.join(link_cmd)) > 8192: logging.debug('using response file for llvm-link') [response_fd, response_file] = mkstemp(suffix='.response', dir=TEMP_DIR) @@ -1438,7 +1460,7 @@ class Building: @staticmethod def ensure_relooper(relooper): if os.path.exists(relooper): return - if os.environ.get('EMCC_FAST_COMPILER'): + if os.environ.get('EMCC_FAST_COMPILER') == '1': logging.debug('not building relooper to js, using it in c++ backend') return @@ -1513,6 +1535,8 @@ class Building: text = m.groups(0)[0] assert text.count('(') == 1 and text.count(')') == 1, 'must have simple expressions in emscripten_jcache_printf calls, no parens' assert text.count('"') == 2, 'must have simple expressions in emscripten_jcache_printf calls, no strings as varargs parameters' + if os.environ.get('EMCC_FAST_COMPILER') == '1': # fake it in fastcomp + return text.replace('emscripten_jcache_printf', 'printf') start = text.index('(') end = text.rindex(')') args = text[start+1:end].split(',') |