aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/analyzer.js60
-rw-r--r--src/parseTools.js24
-rw-r--r--src/runtime.js10
-rw-r--r--src/utility.js2
-rw-r--r--system/include/libcxx/__locale15
-rw-r--r--system/lib/libcxx/locale.cpp13
-rw-r--r--tests/cases/legalizer_ta2.ll15
-rw-r--r--tests/cases/legalizer_ta2.txt1
-rw-r--r--tests/cases/unaligneddouble.ll24
-rwxr-xr-xtests/runner.py67
-rw-r--r--tools/shared.py15
11 files changed, 211 insertions, 35 deletions
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/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/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/runner.py b/tests/runner.py
index e348d8d8..ae46634c 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -3742,6 +3742,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
@@ -5785,7 +5807,7 @@ elif 'benchmark' in str(sys.argv):
Building.COMPILER_TEST_OPTS = []
TEST_REPS = 10
- TOTAL_TESTS = 8
+ TOTAL_TESTS = 9
tests_done = 0
total_times = map(lambda x: 0., range(TOTAL_TESTS))
@@ -5918,6 +5940,49 @@ elif 'benchmark' in str(sys.argv):
'''
self.do_benchmark(src, [], 'final: 720.')
+ def test_files(self):
+ src = r'''
+ #include<stdio.h>
+ #include<stdlib.h>
+ #include<assert.h>
+ #include <unistd.h>
+
+ int main() {
+ int N = 100;
+ int M = 1000;
+ int K = 1000;
+ unsigned char *k = (unsigned char*)malloc(K+1), *k2 = (unsigned char*)malloc(K+1);
+ for (int i = 0; i < K; i++) {
+ k[i] = (i % 250) + 1;
+ }
+ k[K] = 0;
+ char buf[100];
+ for (int i = 0; i < N; i++) {
+ sprintf(buf, "/dev/shm/file-%d.dat", i);
+ FILE *f = fopen(buf, "w");
+ for (int j = 0; j < M; j++) {
+ fwrite(k, 1, (j % K) + 1, f);
+ }
+ fclose(f);
+ }
+ for (int i = 0; i < N; i++) {
+ sprintf(buf, "/dev/shm/file-%d.dat", i);
+ FILE *f = fopen(buf, "r");
+ for (int j = 0; j < M; j++) {
+ fread(k2, 1, (j % K) + 1, f);
+ }
+ fclose(f);
+ for (int j = 0; j < K; j++) {
+ assert(k[j] == k2[j]);
+ }
+ unlink(buf);
+ }
+ printf("ok");
+ return 1;
+ }
+ '''
+ self.do_benchmark(src, [], 'ok')
+
def test_copy(self):
src = r'''
#include<stdio.h>
diff --git a/tools/shared.py b/tools/shared.py
index 45400581..7f633318 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -367,13 +367,17 @@ class Building:
return env
@staticmethod
- def handle_CMake_toolchain(args):
+ def handle_CMake_toolchain(args, env):
CMakeToolchain = '''# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Linux)
# which C and C++ compiler to use
SET(CMAKE_C_COMPILER $EMSCRIPTEN_ROOT/emcc)
SET(CMAKE_CXX_COMPILER $EMSCRIPTEN_ROOT/em++)
+SET(CMAKE_AR $EMSCRIPTEN_ROOT/emar)
+SET(CMAKE_RANLIB $EMSCRIPTEN_ROOT/emranlib)
+SET(CMAKE_C_FLAGS $CFLAGS)
+SET(CMAKE_CXX_FLAGS $CXXFLAGS)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH $EMSCRIPTEN_ROOT/system/include )
@@ -384,7 +388,10 @@ SET(CMAKE_FIND_ROOT_PATH $EMSCRIPTEN_ROOT/system/include )
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
-set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)'''.replace('$EMSCRIPTEN_ROOT', path_from_root(''))
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' \
+ .replace('$EMSCRIPTEN_ROOT', path_from_root('')) \
+ .replace('$CFLAGS', env['CFLAGS']) \
+ .replace('$CXXFLAGS', env['CFLAGS'])
toolchainFile = mkstemp(suffix='.txt')[1]
open(toolchainFile, 'w').write(CMakeToolchain)
args.append('-DCMAKE_TOOLCHAIN_FILE=%s' % os.path.abspath(toolchainFile))
@@ -395,8 +402,8 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)'''.replace('$EMSCRIPTEN_ROOT', path_
if env is None:
env = Building.get_building_env()
env['EMMAKEN_JUST_CONFIGURE'] = '1'
- if 'cmake' in sys.argv[0]:
- args = Building.handle_CMake_toolchain(args)
+ if 'cmake' in args[0]:
+ args = Building.handle_CMake_toolchain(args, env)
Popen(args, stdout=stdout, stderr=stderr, env=env).communicate()[0]
del env['EMMAKEN_JUST_CONFIGURE']