diff options
-rwxr-xr-x | emar | 4 | ||||
-rwxr-xr-x | emcc | 26 | ||||
-rw-r--r-- | src/analyzer.js | 60 | ||||
-rw-r--r-- | src/library.js | 12 | ||||
-rw-r--r-- | src/parseTools.js | 24 | ||||
-rw-r--r-- | src/runtime.js | 10 | ||||
-rw-r--r-- | src/utility.js | 2 | ||||
-rw-r--r-- | system/include/libcxx/__locale | 15 | ||||
-rw-r--r-- | system/lib/libcxx/locale.cpp | 13 | ||||
-rw-r--r-- | system/lib/libcxx/symbols | 1 | ||||
-rw-r--r-- | tests/cases/legalizer_ta2.ll | 15 | ||||
-rw-r--r-- | tests/cases/legalizer_ta2.txt | 1 | ||||
-rw-r--r-- | tests/cases/unaligneddouble.ll | 24 | ||||
-rw-r--r-- | tests/openjpeg/CMakeLists.txt | 2 | ||||
-rwxr-xr-x | tests/runner.py | 177 | ||||
-rw-r--r-- | tools/shared.py | 62 |
16 files changed, 373 insertions, 75 deletions
@@ -12,11 +12,11 @@ from tools import shared DEBUG = os.environ.get('EMCC_DEBUG') -newargs = [shared.LLVM_LINK] + sys.argv[3:] + ['-o='+sys.argv[2]] +newargs = [shared.LLVM_AR] + sys.argv[1:] if DEBUG: print >> sys.stderr, 'emar:', sys.argv, ' ==> ', newargs if len(newargs) > 2: - os.execvp(shared.LLVM_LINK, newargs) + os.execvp(shared.LLVM_AR, newargs) @@ -239,7 +239,8 @@ if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += EMMAKEN_CFLAGS.split(' ') # ---------------- Utilities --------------- SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc') -BITCODE_SUFFIXES = ('.bc', '.o', '.a', '.dylib', '.so', '.dll') +BITCODE_SUFFIXES = ('.bc', '.o') +SHAREDLIB_SUFFIXES = ('.dylib', '.so', '.dll') ASSEMBLY_SUFFIXES = ('.ll',) def unsuffixed(name): @@ -377,7 +378,7 @@ try: for i in range(len(newargs)): # find input files XXX this a simple heuristic. we should really analyze based on a full understanding of gcc params, # right now we just assume that what is left contains no more |-x OPT| things arg = newargs[i] - if arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + ASSEMBLY_SUFFIXES): # we already removed -o <target>, so all these should be inputs + if arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + SHAREDLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs newargs[i] = '' if os.path.exists(arg): if arg.endswith(SOURCE_SUFFIXES): @@ -425,11 +426,14 @@ try: if DEBUG: print >> sys.stderr, 'emcc: compiling to bitcode' + temp_files = [] + # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for input_file in input_files: if input_file.endswith(SOURCE_SUFFIXES): if DEBUG: print >> sys.stderr, 'emcc: compiling source file: ', input_file output_file = in_temp(unsuffixed_basename(input_file) + '.o') + temp_files.append(output_file) args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file] if DEBUG: print >> sys.stderr, "emcc running:", call, ' '.join(args) Popen([call] + args).communicate() # let compiler frontend print directly, so colors are saved (PIPE kills that) @@ -439,13 +443,22 @@ try: else: # bitcode if input_file.endswith(BITCODE_SUFFIXES): if DEBUG: print >> sys.stderr, 'emcc: copying bitcode file: ', input_file - shutil.copyfile(input_file, in_temp(unsuffixed_basename(input_file) + '.o')) + temp_file = in_temp(unsuffixed_basename(input_file) + '.o') + shutil.copyfile(input_file, temp_file) + temp_files.append(temp_file) + elif input_file.endswith(SHAREDLIB_SUFFIXES) or shared.Building.is_ar(input_file): + if DEBUG: print >> sys.stderr, 'emcc: copying library file: ', input_file + temp_file = in_temp(os.path.basename(input_file)) + shutil.copyfile(input_file, temp_file) + temp_files.append(temp_file) else: #.ll 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 if DEBUG: print >> sys.stderr, 'emcc: assembling assembly file: ', input_file - shared.Building.llvm_as(input_file, in_temp(unsuffixed_basename(input_file) + '.o')) + temp_file = in_temp(unsuffixed_basename(input_file) + '.o') + shared.Building.llvm_as(input_file, temp_file) + temp_files.append(temp_file) # If we were just asked to generate bitcode, stop there if final_suffix not in ['js', 'html']: @@ -461,11 +474,10 @@ try: assert not has_dash_c, 'fatal error: cannot specify -o with -c with multiple files' + str(sys.argv) # We have a specified target (-o <target>), which is not JavaScript or HTML, and # we have multiple files: Link them TODO: llvm link-time opts? - ld_args = map(lambda input_file: in_temp(unsuffixed_basename(input_file) + '.o'), input_files) + \ - ['-o', specified_target] + ld_args = temp_files + ['-b', specified_target] #[arg.split('-Wl,')[1] for arg in filter(lambda arg: arg.startswith('-Wl,'), sys.argv)] if DEBUG: print >> sys.stderr, 'emcc: link: ' + str(ld_args) - Popen([shared.LLVM_LINK] + ld_args).communicate() + Popen([shared.LLVM_LD, '-disable-opt'] + ld_args).communicate() exit(0) ## Continue on to create JavaScript diff --git a/src/analyzer.js b/src/analyzer.js index e1f2f6c1..729d4607 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -169,6 +169,15 @@ function analyzer(data, sidePass) { item[slot] = { intertype: 'value', ident: tempIdent, type: item[slot].type }; return i+1; } + function removeAndAdd(lines, i, toAdd) { + var item = lines[i]; + var interp = getInterp(lines, i, toAdd.length); + for (var k = 0; k < toAdd.length; k++) { + toAdd[k].lineNum = item.lineNum + (k*interp); + } + Array.prototype.splice.apply(lines, [i, 1].concat(toAdd)); + return toAdd.length; + } // Assuming we will replace the item at line i, with num items, returns // the right factor to multiply line numbers by so that they fit in between // the removed line and the line after it @@ -184,16 +193,15 @@ function analyzer(data, sidePass) { if (item.intertype == 'store') { if (isIllegalType(item.valueType)) { dprint('legalizer', 'Legalizing store at line ' + item.lineNum); + var toAdd = []; bits = getBits(item.valueType); i = unfold(label.lines, i, item, 'value'); - var interp = getInterp(label.lines, i, Math.ceil(bits/32)); - label.lines.splice(i, 1); var elements; elements = getLegalVars(item.value.ident, bits); var j = 0; elements.forEach(function(element) { var tempVar = '$st$' + i + '$' + j; - label.lines.splice(i+j*2, 0, { + toAdd.push({ intertype: 'getelementptr', assignTo: tempVar, ident: item.pointer.ident, @@ -203,10 +211,9 @@ function analyzer(data, sidePass) { { intertype: 'value', ident: '0', type: 'i32' }, { intertype: 'value', ident: j.toString(), type: 'i32' } ], - lineNum: item.lineNum + (j*interp) }); var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits - label.lines.splice(i+j*2+1, 0, { + toAdd.push({ intertype: 'store', valueType: actualSizeType, value: { intertype: 'value', ident: element.ident, type: actualSizeType }, @@ -214,12 +221,11 @@ function analyzer(data, sidePass) { ident: tempVar, pointerType: actualSizeType + '*', align: item.align, - lineNum: item.lineNum + ((j+0.5)*interp) }); j++; }); Types.needAnalysis['[0 x i32]'] = 0; - i += j*2; + i += removeAndAdd(label.lines, i, toAdd); continue; } } else if (item.assignTo) { @@ -267,6 +273,38 @@ function analyzer(data, sidePass) { i += j*2; continue; } + break; + } + case 'phi': { + if (isIllegalType(value.type)) { + dprint('legalizer', 'Legalizing phi at line ' + item.lineNum); + bits = getBits(value.type); + var toAdd = []; + var elements = getLegalVars(item.assignTo, bits); + var j = 0; + elements.forEach(function(element) { + toAdd.push({ + intertype: 'phi', + assignTo: element.ident, + type: 'i' + element.bits, + params: value.params.map(function(param) { + return { + intertype: 'phiparam', + label: param.label, + value: { // TODO: unfolding + intertype: 'value', + ident: param.value.ident + '$' + j, + type: 'i' + element.bits, + } + }; + }) + }); + j++; + }); + i += removeAndAdd(label.lines, i, toAdd); + continue; + } + break; } case 'mathop': { if (isIllegalType(value.type)) { @@ -412,14 +450,10 @@ function analyzer(data, sidePass) { legalValue.assignTo = item.assignTo; toAdd.push(legalValue); } - var interp = getInterp(label.lines, i, toAdd.length); - for (var k = 0; k < toAdd.length; k++) { - toAdd[k].lineNum = item.lineNum + (k*interp); - } - Array.prototype.splice.apply(label.lines, [i, 1].concat(toAdd)); - i += toAdd.length; + i += removeAndAdd(label.lines, i, toAdd); continue; } + break; } } } diff --git a/src/library.js b/src/library.js index 6385507c..86c499a7 100644 --- a/src/library.js +++ b/src/library.js @@ -4392,7 +4392,7 @@ LibraryManager.library = { __cxa_free_exception: function(ptr) { return _free(ptr); }, - __cxa_throw__deps: ['llvm_eh_exception'], + __cxa_throw__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv'], __cxa_throw: function(ptr, type, destructor) { #if EXCEPTION_DEBUG print('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + new Error().stack); @@ -4400,6 +4400,11 @@ LibraryManager.library = { {{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}} {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}} {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}} + if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) { + __ZSt18uncaught_exceptionv.uncaught_exception = 1; + } else { + __ZSt18uncaught_exceptionv.uncaught_exception++; + } throw ptr; }, __cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'], @@ -4425,7 +4430,9 @@ LibraryManager.library = { _Unwind_Resume_or_Rethrow: function(ptr) { throw ptr; }, + __cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv'], __cxa_begin_catch: function(ptr) { + __ZSt18uncaught_exceptionv.uncaught_exception--; return ptr; }, __cxa_end_catch__deps: ['llvm_eh_exception', '__cxa_free_exception'], @@ -4455,6 +4462,9 @@ LibraryManager.library = { __cxa_get_exception_ptr: function(ptr) { return ptr; }, + _ZSt18uncaught_exceptionv: function() { // std::uncaught_exception() + return !!__ZSt18uncaught_exceptionv.uncaught_exception; + }, __cxa_call_unexpected: function(exception) { ABORT = true; diff --git a/src/parseTools.js b/src/parseTools.js index a5752e67..3cc17cc4 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -962,32 +962,32 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { return '(tempDoubleF64[0]=' + value + ',' + - makeSetValue(ptr, pos, 'tempDoubleI32[0]', 'i32', noNeedFirst, ignore, align) + ',' + - makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleI32[1]', 'i32', noNeedFirst, ignore, align) + ')'; + makeSetValue(ptr, pos, 'tempDoubleI32[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + + makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleI32[1]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')'; } - if (USE_TYPED_ARRAYS == 2 && align) { - // Alignment is important here. May need to split this up + var needSplitting = isIntImplemented(type) && !isPowerOfTwo(getBits(type)); // an unnatural type like i24 + if (USE_TYPED_ARRAYS == 2 && (align || needSplitting)) { + // Alignment is important here, or we need to split this up for other reasons. var bytes = Runtime.getNativeTypeSize(type); - if (bytes > align) { + if (bytes > align || needSplitting) { var ret = ''; if (isIntImplemented(type)) { if (bytes == 4 && align == 2) { // Special case that we can optimize ret += 'tempBigInt=' + value + sep; ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2) + sep; - ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2) + sep; - } else if (bytes <= 4) { + ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2); + } else if (bytes != 8) { ret += 'tempBigInt=' + value + sep; for (var i = 0; i < bytes; i++) { - ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1) + sep; - if (i < bytes-1) ret += 'tempBigInt>>=8' + sep; + ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1); + if (i < bytes-1) ret += sep + 'tempBigInt>>=8' + sep; } - } else { - assert(bytes == 8); + } else { // bytes == 8, specific optimization ret += 'tempPair=' + ensureI64_1(value) + sep; ret += makeSetValue(ptr, pos, 'tempPair[0]', 'i32', noNeedFirst, ignore, align) + sep; - ret += makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempPair[1]', 'i32', noNeedFirst, ignore, align) + sep; + ret += makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempPair[1]', 'i32', noNeedFirst, ignore, align); } } else { ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8) + sep; diff --git a/src/runtime.js b/src/runtime.js index 190260e6..b5663045 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -185,8 +185,14 @@ var Runtime = { "%float": 4, "%double": 8 }['%'+type]; // add '%' since float and double confuse Closure compiler as keys, and also spidermonkey as a compiler will remove 's from '_i8' etc - if (!size && type[type.length-1] == '*') { - size = Runtime.QUANTUM_SIZE; // A pointer + if (!size) { + if (type[type.length-1] == '*') { + size = Runtime.QUANTUM_SIZE; // A pointer + } else if (type[0] == 'i') { + var bits = parseInt(type.substr(1)); + assert(bits % 8 == 0); + size = bits/8; + } } return size; }, diff --git a/src/utility.js b/src/utility.js index 5ddccfd4..31eff100 100644 --- a/src/utility.js +++ b/src/utility.js @@ -21,7 +21,7 @@ function dump(item) { ret.push(i + ': [?]'); } } - return lineify(ret.join(', ')); + return ret.join(',\n'); } } diff --git a/system/include/libcxx/__locale b/system/include/libcxx/__locale index f63815c3..7b7cfcd7 100644 --- a/system/include/libcxx/__locale +++ b/system/include/libcxx/__locale @@ -330,8 +330,21 @@ public: static const mask punct = _PUNCT; static const mask xdigit = _HEX; static const mask blank = _BLANK; +#elif defined( EMSCRIPTEN ) + #define _ISbit(bit) ((bit) < 8 ? ((1 << (bit)) << 8) : ((1 << (bit)) >> 8)) + typedef __uint16_t mask; + static const mask upper = _ISbit( 0 ); + static const mask lower = _ISbit( 1 ); + static const mask alpha = _ISbit( 2 ); + static const mask digit = _ISbit( 3 ); + static const mask xdigit = _ISbit( 4 ); + static const mask space = _ISbit( 5 ); + static const mask print = _ISbit( 6 ); + static const mask blank = _ISbit( 8 ); + static const mask cntrl = _ISbit( 9 ); + static const mask punct = _ISbit( 10 ); #else // __GLIBC__ || _WIN32 -#if defined(__APPLE__) || defined(EMSCRIPTEN) +#if defined(__APPLE__) typedef __uint32_t mask; #elif __FreeBSD__ typedef unsigned long mask; diff --git a/system/lib/libcxx/locale.cpp b/system/lib/libcxx/locale.cpp index 388660d2..4675fec3 100644 --- a/system/lib/libcxx/locale.cpp +++ b/system/lib/libcxx/locale.cpp @@ -909,6 +909,11 @@ ctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, return low; } +// XXX Emscripten define local table +extern "C" const unsigned short ** __ctype_b_loc(); +extern "C" const int ** __ctype_tolower_loc(); +extern "C" const int ** __ctype_toupper_loc(); + const ctype<char>::mask* ctype<char>::classic_table() _NOEXCEPT { @@ -918,6 +923,8 @@ ctype<char>::classic_table() _NOEXCEPT return __cloc()->__ctype_b; // This is assumed to be safe, which is a nonsense assumption because we're // going to end up dereferencing it later... +#elif defined(EMSCRIPTEN) + return *__ctype_b_loc(); #else return NULL; #endif @@ -931,6 +938,8 @@ ctype<char>::__classic_lower_table() _NOEXCEPT return _DefaultRuneLocale.__maplower; #elif defined(__GLIBC__) return __cloc()->__ctype_tolower; +#elif defined(EMSCRIPTEN) + return *__ctype_tolower_loc(); #else return NULL; #endif @@ -943,6 +952,8 @@ ctype<char>::__classic_upper_table() _NOEXCEPT return _DefaultRuneLocale.__mapupper; #elif defined(__GLIBC__) return __cloc()->__ctype_toupper; +#elif defined(EMSCRIPTEN) + return *__ctype_toupper_loc(); #else return NULL; #endif @@ -1041,7 +1052,7 @@ ctype_byname<wchar_t>::do_is(mask m, char_type c) const #ifdef _LIBCPP_WCTYPE_IS_MASK return static_cast<bool>(iswctype_l(c, m, __l)); #else - // FIXME: This is broken for things that test more than one flag. + // FIXME: This is broken for things that test more than one flag. if (m & space && !iswspace_l(c, __l)) return false; if (m & print && !iswprint_l(c, __l)) return false; if (m & cntrl && !iswcntrl_l(c, __l)) return false; diff --git a/system/lib/libcxx/symbols b/system/lib/libcxx/symbols index 0cea51cb..23d4a7a4 100644 --- a/system/lib/libcxx/symbols +++ b/system/lib/libcxx/symbols @@ -2577,7 +2577,6 @@ T _ZSt17current_exceptionv T _ZSt17rethrow_exceptionSt13exception_ptr C _ZSt18make_exception_ptrINSt3__112future_errorEESt13exception_ptrT_ - T _ZSt18uncaught_exceptionv D _ZSt7nothrow D _ZTCNSt3__110istrstreamE0_NS_13basic_istreamIcNS_11char_traitsIcEEEE D _ZTCNSt3__110ostrstreamE0_NS_13basic_ostreamIcNS_11char_traitsIcEEEE diff --git a/tests/cases/legalizer_ta2.ll b/tests/cases/legalizer_ta2.ll index a877c683..67cd9feb 100644 --- a/tests/cases/legalizer_ta2.ll +++ b/tests/cases/legalizer_ta2.ll @@ -101,6 +101,21 @@ entry: store i80 %loaded.short, i80* bitcast ([300 x i8]* @globaliz to i80*), align 4 call i32 (i8*)* @puts(i8* bitcast ([300 x i8]* @globaliz to i8*)) +; phi + %if = trunc i104 %ander to i1 + %first = trunc i104 %xored to i88 + br i1 %if, label %a17, label %a26 + +a17: + %second = trunc i104 %loaded to i88 + br label %a26 + +a26: + %a27 = phi i88 [ %first, %entry ], [ %second, %a17 ] + store i104 0, i104* %bundled, align 4 ; wipe it out + store i88 %a27, i88* bitcast ([300 x i8]* @globaliz to i88*), align 4 + call i32 (i8*)* @puts(i8* bitcast ([300 x i8]* @globaliz to i8*)) + ret i32 1 } diff --git a/tests/cases/legalizer_ta2.txt b/tests/cases/legalizer_ta2.txt index e05a4816..e25076e6 100644 --- a/tests/cases/legalizer_ta2.txt +++ b/tests/cases/legalizer_ta2.txt @@ -15,3 +15,4 @@ hellon worod hello, war`d hello, wor-d hello, wor +hello, worl diff --git a/tests/cases/unaligneddouble.ll b/tests/cases/unaligneddouble.ll new file mode 100644 index 00000000..22b92741 --- /dev/null +++ b/tests/cases/unaligneddouble.ll @@ -0,0 +1,24 @@ +; ModuleID = 'tests/hello_world.bc' +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" + +@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*] + +; [#uses=0] +define i32 @main() { +entry: + %retval = alloca i32, align 4 ; [#uses=1 type=i32*] + %doub = alloca double, align 4 + store i32 0, i32* %retval + %0 = bitcast double* %doub to i32 + %1 = uitofp i32 %0 to double + store double %1, double* %doub, align 1 + store double %1, double* %doub, align 2 + store double %1, double* %doub, align 4 + store double %1, double* %doub, align 8 + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32] + ret i32 1 +} + +; [#uses=1] +declare i32 @printf(i8*, ...) diff --git a/tests/openjpeg/CMakeLists.txt b/tests/openjpeg/CMakeLists.txt index 52150f5f..d8671fed 100644 --- a/tests/openjpeg/CMakeLists.txt +++ b/tests/openjpeg/CMakeLists.txt @@ -22,6 +22,8 @@ STRING(TOLOWER ${OPENJPEG_NAMESPACE} OPENJPEG_LIBRARY_NAME) PROJECT(${OPENJPEG_NAMESPACE} C) +include(CMakeDetermineSystem) + # Do full dependency headers. INCLUDE_REGULAR_EXPRESSION("^.*$") diff --git a/tests/runner.py b/tests/runner.py index ea7a72f4..b8927332 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -260,11 +260,13 @@ process(sys.argv[1]) if self.library_cache is not None: if cache and self.library_cache.get(cache_name): print >> sys.stderr, '<load build from cache> ', - bc_file = os.path.join(output_dir, 'lib' + name + '.bc') - f = open(bc_file, 'wb') - f.write(self.library_cache[cache_name]) - f.close() - return bc_file + generated_libs = [] + for bc_file in self.library_cache[cache_name]: + f = open(bc_file, 'wb') + f.write(self.library_cache[cache_name][bc_file]) + f.close() + generated_libs.append(bc_file) + return generated_libs print >> sys.stderr, '<building and saving into cache> ', @@ -917,6 +919,46 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): ''' self.do_run(src, '*1 2*') + def test_multiply_defined_symbols(self): + a1 = "int f() { return 1; }" + a1_name = os.path.join(self.get_dir(), 'a1.c') + open(a1_name, 'w').write(a1) + a2 = "void x() {}" + a2_name = os.path.join(self.get_dir(), 'a2.c') + open(a2_name, 'w').write(a2) + b1 = "int f() { return 2; }" + b1_name = os.path.join(self.get_dir(), 'b1.c') + open(b1_name, 'w').write(b1) + b2 = "void y() {}" + b2_name = os.path.join(self.get_dir(), 'b2.c') + open(b2_name, 'w').write(b2) + main = r''' + #include <stdio.h> + int f(); + int main() { + printf("result: %d\n", f()); + return 0; + } + ''' + main_name = os.path.join(self.get_dir(), 'main.c') + open(main_name, 'w').write(main) + + Building.emcc(a1_name) + Building.emcc(a2_name) + Building.emcc(b1_name) + Building.emcc(b2_name) + Building.emcc(main_name) + + liba_name = os.path.join(self.get_dir(), 'liba.a') + Building.emar('cr', liba_name, [a1_name + '.o', a2_name + '.o']) + libb_name = os.path.join(self.get_dir(), 'libb.a') + Building.emar('cr', libb_name, [b1_name + '.o', b2_name + '.o']) + + all_name = os.path.join(self.get_dir(), 'all.bc') + Building.link([main_name + '.o', liba_name, libb_name], all_name) + + self.do_ll_run(all_name, 'result: 1') + def test_if(self): src = ''' #include <stdio.h> @@ -1360,6 +1402,32 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): Settings.DISABLE_EXCEPTION_CATCHING = 0 self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...') + def test_uncaught_exception(self): + Settings.EXCEPTION_DEBUG = 0 # Messes up expected output. + Settings.DISABLE_EXCEPTION_CATCHING = 0 + + src = r''' + #include <stdio.h> + #include <exception> + struct X { + ~X() { + printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no"); + } + }; + int main() { + printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no"); + try { + X x; + throw 1; + } catch(...) { + printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no"); + } + printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no"); + return 0; + } + ''' + self.do_run(src, 'exception? no\nexception? yes\nexception? no\nexception? no\n') + def test_typed_exceptions(self): return self.skip('TODO: fix this for llvm 3.0') @@ -3742,6 +3810,28 @@ def process(filename): } ''' self.do_run(src, "some string constant") + + def test_istream(self): + if self.emcc_args is None: return self.skip('requires libcxx') + + src = ''' + #include <string> + #include <sstream> + #include <iostream> + + int main() + { + std::string mystring("1 2 3"); + std::istringstream is(mystring); + int one, two, three; + + is >> one >> two >> three; + + printf( "%i %i %i", one, two, three ); + } + ''' + self.do_run(src, "1 2 3") + def test_fs_base(self): Settings.INCLUDE_FULL_LIBRARY = 1 @@ -4298,7 +4388,7 @@ def process(filename): self.do_run(open(path_from_root('tests', 'freetype', 'main.c'), 'r').read(), open(path_from_root('tests', 'freetype', 'ref.txt'), 'r').read(), ['font.ttf', 'test!', '150', '120', '25'], - libraries=[self.get_freetype()], + libraries=self.get_freetype(), includes=[path_from_root('tests', 'freetype', 'include')], post_build=post) #build_ll_hook=self.do_autodebug) @@ -4339,7 +4429,7 @@ def process(filename): self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(), open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(), - libraries=[self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a'])], + libraries=self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']), includes=[path_from_root('tests', 'zlib')], force_c=True) @@ -4356,10 +4446,10 @@ def process(filename): self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(), [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read()], - libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a'), - os.path.join('src', '.libs', 'libBulletDynamics.a'), + libraries=self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'), + os.path.join('src', '.libs', 'libBulletCollision.a'), os.path.join('src', '.libs', 'libLinearMath.a')], - configure_args=['--disable-demos','--disable-dependency-tracking'])], + configure_args=['--disable-demos','--disable-dependency-tracking']), includes=[path_from_root('tests', 'bullet', 'src')], js_engines=[SPIDERMONKEY_ENGINE]) # V8 issue 1407 @@ -4400,15 +4490,15 @@ def process(filename): freetype = self.get_freetype() poppler = self.get_library('poppler', - [os.path.join('poppler', '.libs', self.get_shared_library_name('libpoppler.so.13')), - os.path.join('utils', 'pdftoppm.o'), - os.path.join('utils', 'parseargs.o')], - configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms']) + [os.path.join('utils', 'pdftoppm.o'), + os.path.join('utils', 'parseargs.o'), + os.path.join('poppler', '.libs', 'libpoppler.a')], + configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--enable-shared=no']) # Combine libraries combined = os.path.join(self.get_dir(), 'poppler-combined.bc') - Building.link([freetype, poppler], combined) + Building.link(poppler + freetype, combined) self.do_ll_run(combined, map(ord, open(path_from_root('tests', 'poppler', 'ref.ppm'), 'r').read()).__str__().replace(' ', ''), @@ -4442,11 +4532,11 @@ def process(filename): shutil.copy(path_from_root('tests', 'openjpeg', 'opj_config.h'), self.get_dir()) lib = self.get_library('openjpeg', - [os.path.join('bin', self.get_shared_library_name('libopenjpeg.so.1.4.0')), - os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')), + [os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')), os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'.split('/')), os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'.split('/')), - os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'.split('/'))], + os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'.split('/')), + os.path.join('bin', self.get_shared_library_name('libopenjpeg.so.1.4.0'))], configure=['cmake', '.'], #configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'], make_args=[]) # no -j 2, since parallel builds can fail @@ -4490,7 +4580,7 @@ def process(filename): self.do_run(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(), 'Successfully generated', # The real test for valid output is in image_compare '-i image.j2k -o image.raw'.split(' '), - libraries=[lib], + libraries=lib, includes=[path_from_root('tests', 'openjpeg', 'libopenjpeg'), path_from_root('tests', 'openjpeg', 'codec'), path_from_root('tests', 'openjpeg', 'common'), @@ -5552,9 +5642,9 @@ Options that are modified or new in %s include: # XXX find a way to test this: assert ('& 255' in generated or '&255' in generated) == (opt_level <= 2), 'corrections should be in opt <= 2' assert ('(__label__)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2' assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0' - assert 'var $i;' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on' + assert 'var $i;' in generated or 'var $i_01;' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on' if opt_level >= 1: - assert 'HEAP8[HEAP32[' in generated or 'HEAP8[$vla1 + $storemerge4 / 2 | 0]' in generated or 'HEAP8[$vla1 + ($storemerge4 / 2 | 0)]' in generated or 'HEAP8[$vla1 + $i_04 / 2 | 0]' in generated or 'HEAP8[$vla1 + ($i_04 / 2 | 0)]' in generated, 'eliminator should create compound expressions, and fewer one-time vars' + assert 'HEAP8[HEAP32[' in generated or 'HEAP8[$vla1 + $storemerge4 / 2 | 0]' in generated or 'HEAP8[$vla1 + ($storemerge4 / 2 | 0)]' in generated or 'HEAP8[$vla1 + $i_04 / 2 | 0]' in generated or 'HEAP8[$vla1 + ($i_04 / 2 | 0)]' in generated or 'HEAP8[$1 + $i_01 / 2 | 0]' in generated or 'HEAP8[$1 + ($i_01 / 2 | 0)]' in generated, 'eliminator should create compoun |