aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemcc74
-rw-r--r--src/compiler.js2
-rw-r--r--src/jsifier.js80
-rw-r--r--src/library.js17
-rw-r--r--src/library_browser.js2
-rw-r--r--src/parseTools.js17
-rw-r--r--src/relooper/Relooper.cpp74
-rw-r--r--src/relooper/Relooper.h2
-rw-r--r--src/settings.js17
-rw-r--r--src/shell.html2
-rw-r--r--system/include/libc/grp.h2
-rw-r--r--system/include/libc/sys/signal.h1
-rw-r--r--system/include/libc/sys/stat.h42
-rw-r--r--system/include/libc/time.h3
-rw-r--r--system/include/net/netinet/in.h94
-rw-r--r--system/include/sys/socket.h2
-rw-r--r--tests/embind/shell.html6
-rwxr-xr-xtests/fuzz/creduce_tester.py54
-rwxr-xr-xtests/fuzz/csmith_driver.py30
-rw-r--r--tests/hello_world_gles_shell.html3
-rwxr-xr-xtests/runner.py181
-rw-r--r--tools/js-optimizer.js25
-rw-r--r--tools/shared.py46
-rwxr-xr-xtools/source-maps/sourcemapper.js2
-rw-r--r--tools/test-js-optimizer-asm-last-output.js28
-rw-r--r--tools/test-js-optimizer-asm-last.js34
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js1
-rw-r--r--tools/test-js-optimizer-asm-pre.js1
29 files changed, 534 insertions, 309 deletions
diff --git a/AUTHORS b/AUTHORS
index 27206740..229a9cad 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -85,3 +85,4 @@ a license to everyone to use it as detailed in LICENSE.)
* Ludovic Perrine <jazzzz@gmail.com>
* David Barksdale <david.barksdale@adcedosolutions.com>
* Manfred Manik Nerurkar <nerurkar*at*made-apps.biz> (copyright owned by MADE, GmbH)
+* Joseph Gentle <me@josephg.com>
diff --git a/emcc b/emcc
index fb73ef6b..75750e1e 100755
--- a/emcc
+++ b/emcc
@@ -127,11 +127,6 @@ Options that are modified or new in %s include:
(For details on the affects of different
opt levels, see apply_opt_level() in
tools/shared.py and also src/settings.js.)
- Note: Optimizations are only done when
- compiling to JavaScript, not to intermediate
- bitcode, *unless* you build with
- EMCC_OPTIMIZE_NORMALLY=1 (not recommended
- unless you know what you are doing!)
-O2 As -O1, plus the relooper (loop recreation),
LLVM -O2 optimizations, and
@@ -144,7 +139,7 @@ Options that are modified or new in %s include:
-s DOUBLE_MODE=0
-s PRECISE_I64_MATH=0
--closure 1
- --llvm-lto 1
+ --llvm-lto 3
This is not recommended at all. A better idea
is to try each of these separately on top of
@@ -220,10 +215,15 @@ Options that are modified or new in %s include:
2: -O2 LLVM optimizations
3: -O3 LLVM optimizations (default in -O2+)
- --llvm-lto <level> 0: No LLVM LTO (default in -O2 and below)
- 1: LLVM LTO (default in -O3)
+ --llvm-lto <level> 0: No LLVM LTO (default)
+ 1: LLVM LTO is performed
+ 2: We combine all the bitcode and run LLVM opt -O3
+ on that (which optimizes across modules, but is
+ not the same as normal LTO), but do not do normal
+ LTO
+ 3: We do both 2 and then 1
Note: If LLVM optimizations are not run
- (see --llvm-opts), setting this to 1 has no
+ (see --llvm-opts), setting this has no
effect.
--closure <on> 0: No closure compiler (default in -O2 and below)
@@ -884,10 +884,14 @@ try:
newargs = newargs + [default_cxx_std]
if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level]
- if llvm_lto is None: llvm_lto = opt_level >= 3
+ if llvm_lto is None and opt_level >= 3: llvm_lto = 3
if opt_level == 0: debug_level = 4
if closure is None and opt_level == 3: closure = True
+ if llvm_lto is None and bind:
+ logging.debug('running lto for embind') # XXX this is a workaround for a pointer issue
+ llvm_lto = 1
+
# TODO: support source maps with js_transform
if js_transform and debug_level >= 4:
logging.warning('disabling source maps because a js transform is being done')
@@ -1058,6 +1062,10 @@ try:
else:
raise Exception('unknown llvm target: ' + str(shared.LLVM_TARGET))
+ if shared.Settings.USE_TYPED_ARRAYS != 2 and llvm_opts > 0:
+ logging.warning('disabling LLVM optimizations, need typed arrays mode 2 for them')
+ llvm_opts = 0
+
## Compile source code to bitcode
logging.debug('compiling to bitcode')
@@ -1097,20 +1105,20 @@ try:
shared.Building.llvm_as(input_file, temp_file)
temp_files.append(temp_file)
- if not LEAVE_INPUTS_RAW: assert len(temp_files) == len(input_files)
+ if not LEAVE_INPUTS_RAW:
+ assert len(temp_files) == len(input_files)
+
+ # Optimize source files
+ if llvm_opts > 0:
+ for i in range(len(input_files)):
+ input_file = input_files[i]
+ if input_files[i].endswith(SOURCE_SUFFIXES):
+ temp_file = temp_files[i]
+ logging.debug('optimizing %s with -O%d' % (input_file, llvm_opts))
+ shared.Building.llvm_opt(temp_file, llvm_opts)
# If we were just asked to generate bitcode, stop there
if final_suffix not in JS_CONTAINING_SUFFIXES:
- if llvm_opts > 0:
- if not os.environ.get('EMCC_OPTIMIZE_NORMALLY'):
- logging.warning('-Ox flags ignored, since not generating JavaScript')
- else:
- for input_file in input_files:
- if input_file.endswith(SOURCE_SUFFIXES):
- logging.debug('optimizing %s with -O%d since EMCC_OPTIMIZE_NORMALLY defined' % (input_file, llvm_opts))
- shared.Building.llvm_opt(in_temp(unsuffixed(uniquename(input_file)) + '.o'), llvm_opts)
- else:
- logging.debug('not optimizing %s despite EMCC_OPTIMIZE_NORMALLY since not source code' % (input_file))
if not specified_target:
for input_file in input_files:
shutil.move(in_temp(unsuffixed(uniquename(input_file)) + '.o'), unsuffixed_basename(input_file) + '.' + final_suffix)
@@ -1142,6 +1150,8 @@ try:
symbols = filter(lambda symbol: symbol not in exclude, symbols)
return set(symbols)
+ lib_opts = ['-O2']
+
# XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not
# a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible.
libc_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libc.symbols'))
@@ -1150,7 +1160,7 @@ try:
libcxx_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxx', 'symbols'), exclude=libc_symbols)
libcxxabi_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols'), exclude=libc_symbols)
- # XXX we should disable EMCC_DEBUG (and EMCC_OPTIMIZE_NORMALLY?) when building libs, just like in the relooper
+ # XXX we should disable EMCC_DEBUG when building libs, just like in the relooper
def build_libc(lib_filename, files):
o_s = []
@@ -1159,7 +1169,7 @@ try:
musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal')
for src in files:
o = in_temp(os.path.basename(src) + '.o')
- execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes], stdout=stdout, stderr=stderr)
+ execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes] + lib_opts, stdout=stdout, stderr=stderr)
o_s.append(o)
if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx
shared.Building.link(o_s, in_temp(lib_filename))
@@ -1170,7 +1180,7 @@ try:
for src in files:
o = in_temp(src + '.o')
srcfile = shared.path_from_root(src_dirname, src)
- execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'], stdout=stdout, stderr=stderr)
+ execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'] + lib_opts, stdout=stdout, stderr=stderr)
o_s.append(o)
shared.Building.link(o_s, in_temp(lib_filename))
return in_temp(lib_filename)
@@ -1418,16 +1428,14 @@ try:
if not LEAVE_INPUTS_RAW:
link_opts = [] if debug_level >= 4 else ['-strip-debug'] # remove LLVM debug if we are not asked for it
- if llvm_opts > 0:
- if not os.environ.get('EMCC_OPTIMIZE_NORMALLY'):
- shared.Building.llvm_opt(in_temp(target_basename + '.bc'), llvm_opts)
- if DEBUG: save_intermediate('opt', 'bc')
- # Do LTO in a separate pass to work around LLVM bug XXX (see failure e.g. in cubescript)
- else:
- logging.debug('not running opt because EMCC_OPTIMIZE_NORMALLY was specified, opt should have been run before')
+ if llvm_lto >= 2:
+ logging.debug('running LLVM opt -O3 as pre-LTO')
+ shared.Building.llvm_opt(in_temp(target_basename + '.bc'), ['-O3'])
+ if DEBUG: save_intermediate('opt', 'bc')
+
if shared.Building.can_build_standalone():
# If we can LTO, do it before dce, since it opens up dce opportunities
- if llvm_lto and shared.Building.can_use_unsafe_opts():
+ if llvm_lto and llvm_lto != 2 and shared.Building.can_use_unsafe_opts():
if not shared.Building.can_inline(): link_opts.append('-disable-inlining')
# do not internalize in std-link-opts - it ignores internalize-public-api-list - and add a manual internalize
link_opts += ['-disable-internalize'] + shared.Building.get_safe_internalize() + ['-std-link-opts']
@@ -1631,7 +1639,7 @@ try:
match = re.match('.*?<script[^>]*>{{{ SCRIPT_CODE }}}</script>', shell,
re.DOTALL)
if match is None:
- raise RuntimeError('Could not find script insertion point')
+ raise RuntimeError('''Could not find script insertion point - make sure you have <script type='text/javascript'>{{{ SCRIPT_CODE }}}</script> in your HTML file (with no newlines)''')
generate_source_map(target, match.group().count('\n'))
html.write(shell.replace('{{{ SCRIPT_CODE }}}', open(final).read()))
else:
diff --git a/src/compiler.js b/src/compiler.js
index 94e77e26..365ff32f 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -176,6 +176,8 @@ DEAD_FUNCTIONS = numberedSet(DEAD_FUNCTIONS);
RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG;
+if (SAFE_HEAP) USE_BSS = 0; // must initialize heap for safe heap
+
// Settings sanity checks
assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4');
diff --git a/src/jsifier.js b/src/jsifier.js
index b13d39a3..885fbc30 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -285,42 +285,60 @@ function JSify(data, functionsOnly, givenFunctions) {
index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this
allocator = 'ALLOC_NONE';
}
- if (item.external) {
- if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
- constant = zeros(Runtime.getNativeFieldSize(item.type));
- } else {
- constant = makeEmptyStruct(item.type);
+
+ if (isBSS(item)) {
+ var length = calcAllocatedSize(item.type);
+ length = Runtime.alignMemory(length);
+
+ // If using indexed globals, go ahead and early out (no need to explicitly
+ // initialize).
+ if (!NAMED_GLOBALS) {
+ return ret;
+ }
+ // If using named globals, we can at least shorten the call to allocate by
+ // passing an integer representing the size of memory to alloc instead of
+ // an array of 0s of size length.
+ else {
+ constant = length;
}
} else {
- constant = parseConst(item.value, item.type, item.ident);
- }
- assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
-
- // This is a flattened object. We need to find its idents, so they can be assigned to later
- constant.forEach(function(value, i) {
- if (needsPostSet(value)) { // ident, or expression containing an ident
- ret.push({
- intertype: 'GlobalVariablePostSet',
- JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
- });
- constant[i] = '0';
+ if (item.external) {
+ if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
+ constant = zeros(Runtime.getNativeFieldSize(item.type));
+ } else {
+ constant = makeEmptyStruct(item.type);
+ }
+ } else {
+ constant = parseConst(item.value, item.type, item.ident);
}
- });
+ assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
+
+ // This is a flattened object. We need to find its idents, so they can be assigned to later
+ constant.forEach(function(value, i) {
+ if (needsPostSet(value)) { // ident, or expression containing an ident
+ ret.push({
+ intertype: 'GlobalVariablePostSet',
+ JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
+ });
+ constant[i] = '0';
+ }
+ });
- if (item.external) {
- // External variables in shared libraries should not be declared as
- // they would shadow similarly-named globals in the parent, so do nothing here.
- if (BUILD_AS_SHARED_LIB) return ret;
- // Library items need us to emit something, but everything else requires nothing.
- if (!LibraryManager.library[item.ident.slice(1)]) return ret;
- }
+ if (item.external) {
+ // External variables in shared libraries should not be declared as
+ // they would shadow similarly-named globals in the parent, so do nothing here.
+ if (BUILD_AS_SHARED_LIB) return ret;
+ // Library items need us to emit something, but everything else requires nothing.
+ if (!LibraryManager.library[item.ident.slice(1)]) return ret;
+ }
- // ensure alignment
- constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length));
+ // ensure alignment
+ constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length));
- // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
- if (item.ident.substr(0, 5) == '__ZTV') {
- constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE)));
+ // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
+ if (item.ident.substr(0, 5) == '__ZTV') {
+ constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE)));
+ }
}
// NOTE: This is the only place that could potentially create static
@@ -1568,7 +1586,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n');
}
var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable);
- print(generated.map(function(item) { return item.JS }).join('\n'));
+ print(generated.map(function(item) { return item.JS; }).join('\n'));
if (phase == 'pre') {
if (memoryInitialization.length > 0) {
diff --git a/src/library.js b/src/library.js
index 01a67804..822f4319 100644
--- a/src/library.js
+++ b/src/library.js
@@ -7224,6 +7224,23 @@ LibraryManager.library = {
return 1;
},
+ // netinet/in.h
+
+ _in6addr_any:
+ 'allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_STATIC)',
+ _in6addr_loopback:
+ 'allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], "i8", ALLOC_STATIC)',
+ _in6addr_linklocal_allnodes:
+ 'allocate([255,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1], "i8", ALLOC_STATIC)',
+ _in6addr_linklocal_allrouters:
+ 'allocate([255,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2], "i8", ALLOC_STATIC)',
+ _in6addr_interfacelocal_allnodes:
+ 'allocate([255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1], "i8", ALLOC_STATIC)',
+ _in6addr_interfacelocal_allrouters:
+ 'allocate([255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2], "i8", ALLOC_STATIC)',
+ _in6addr_sitelocal_allrouters:
+ 'allocate([255,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2], "i8", ALLOC_STATIC)',
+
// ==========================================================================
// netdb.h
// ==========================================================================
diff --git a/src/library_browser.js b/src/library_browser.js
index d007d9a7..d9fd3ee5 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -805,7 +805,7 @@ mergeInto(LibraryManager.library, {
var t = process['hrtime']();
return t[0] * 1e3 + t[1] / 1e6;
}
- else if (window['performance'] && window['performance']['now']) {
+ else if (ENVIRONMENT_IS_WEB && window['performance'] && window['performance']['now']) {
return window['performance']['now']();
} else {
return Date.now();
diff --git a/src/parseTools.js b/src/parseTools.js
index 0b83a12b..6bc0b7ea 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -467,6 +467,18 @@ function isIndexableGlobal(ident) {
return !data.alias && !data.external;
}
+function isBSS(item) {
+ if (!USE_BSS) {
+ return false;
+ }
+
+ if (item.external) return false; // externals are typically implemented in a JS library, and must be accessed by name, explicitly
+
+ // return true if a global is uninitialized or initialized to 0
+ return (item.value && item.value.intertype === 'emptystruct') ||
+ (item.value && item.value.value !== undefined && item.value.value === '0');
+}
+
function makeGlobalDef(ident) {
if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '';
return 'var ' + ident + ';';
@@ -490,7 +502,10 @@ function sortGlobals(globals) {
ks.sort();
var inv = invertArray(ks);
return values(globals).sort(function(a, b) {
- return inv[b.ident] - inv[a.ident];
+ // sort globals based on if they need to be explicitly initialized or not (moving
+ // values that don't need to be to the end of the array). if equal, sort by name.
+ return (Number(isBSS(a)) - Number(isBSS(b))) ||
+ (inv[b.ident] - inv[a.ident]);
});
}
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp
index aa7e71a1..ca9c6ab1 100644
--- a/src/relooper/Relooper.cpp
+++ b/src/relooper/Relooper.cpp
@@ -10,6 +10,10 @@
// TODO: move all set to unorderedset
+template <class T, class U> bool contains(const T& container, const U& contained) {
+ return container.find(contained) != container.end();
+}
+
#if DEBUG
static void PrintDebug(const char *Format, ...);
#define DebugDump(x, ...) Debugging::Dump(x, __VA_ARGS__)
@@ -100,7 +104,7 @@ void Branch::Render(Block *Target, bool SetLabel) {
int Block::IdCounter = 1; // 0 is reserved for clearings
-Block::Block(const char *CodeInit) : Parent(NULL), Id(Block::IdCounter++), DefaultTarget(NULL), IsCheckedMultipleEntry(false) {
+Block::Block(const char *CodeInit) : Parent(NULL), Id(Block::IdCounter++), IsCheckedMultipleEntry(false) {
Code = strdup(CodeInit);
}
@@ -113,7 +117,7 @@ Block::~Block() {
}
void Block::AddBranchTo(Block *Target, const char *Condition, const char *Code) {
- assert(BranchesOut.find(Target) == BranchesOut.end()); // cannot add more than one branch to the same target
+ assert(!contains(BranchesOut, Target)); // cannot add more than one branch to the same target
BranchesOut[Target] = new Branch(Condition, Code);
}
@@ -174,6 +178,8 @@ void Block::Render(bool InLoop) {
}
}
+ Block *DefaultTarget(NULL); // The block we branch to without checking the condition, if none of the other conditions held.
+
// We must do this here, because blocks can be split and even comparing their Ids is not enough. We must check the conditions.
for (BlockBranchMap::iterator iter = ProcessedBranchesOut.begin(); iter != ProcessedBranchesOut.end(); iter++) {
if (!iter->second->Condition) {
@@ -181,7 +187,7 @@ void Block::Render(bool InLoop) {
DefaultTarget = iter->first;
}
}
- assert(DefaultTarget); // Must be a default
+ assert(DefaultTarget); // Since each block *must* branch somewhere, this must be set
ministring RemainingConditions;
bool First = true;
@@ -198,7 +204,7 @@ void Block::Render(bool InLoop) {
Details = ProcessedBranchesOut[DefaultTarget];
}
bool SetCurrLabel = SetLabel && Target->IsCheckedMultipleEntry;
- bool HasFusedContent = Fused && Fused->InnerMap.find(Target) != Fused->InnerMap.end();
+ bool HasFusedContent = Fused && contains(Fused->InnerMap, Target);
bool HasContent = SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent || Details->Code;
if (iter != ProcessedBranchesOut.end()) {
// If there is nothing to show in this branch, omit the condition
@@ -356,7 +362,7 @@ void Relooper::Calculate(Block *Entry) {
while (ToInvestigate.size() > 0) {
Block *Curr = ToInvestigate.front();
ToInvestigate.pop_front();
- if (Live.find(Curr) != Live.end()) continue;
+ if (contains(Live, Curr)) continue;
Live.insert(Curr);
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
ToInvestigate.push_back(iter->first);
@@ -380,7 +386,7 @@ void Relooper::Calculate(Block *Entry) {
for (BlockSet::iterator iter = Live.begin(); iter != Live.end(); iter++) {
Block *Original = *iter;
if (Original->BranchesIn.size() <= 1 || Original->BranchesOut.size() > 0) continue; // only dead ends, for now
- if (Original->BranchesOut.find(Original) != Original->BranchesOut.end()) continue; // cannot split a looping node
+ if (contains(Original->BranchesOut, Original)) continue; // cannot split a looping node
if (strlen(Original->Code)*(Original->BranchesIn.size()-1) > TotalCodeSize/5) continue; // if splitting increases raw code size by a significant amount, abort
// Split the node (for simplicity, we replace all the blocks, even though we could have reused the original)
PrintDebug("Splitting block %d\n", Original->Id);
@@ -423,7 +429,7 @@ void Relooper::Calculate(Block *Entry) {
// Add incoming branches from live blocks, ignoring dead code
for (int i = 0; i < Blocks.size(); i++) {
Block *Curr = Blocks[i];
- if (Pre.Live.find(Curr) == Pre.Live.end()) continue;
+ if (!contains(Pre.Live, Curr)) continue;
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
iter->first->BranchesIn.insert(Curr);
}
@@ -445,7 +451,7 @@ void Relooper::Calculate(Block *Entry) {
// will appear
void GetBlocksOut(Block *Source, BlockSet& Entries, BlockSet *LimitTo=NULL) {
for (BlockBranchMap::iterator iter = Source->BranchesOut.begin(); iter != Source->BranchesOut.end(); iter++) {
- if (!LimitTo || LimitTo->find(iter->first) != LimitTo->end()) {
+ if (!LimitTo || contains(*LimitTo, iter->first)) {
Entries.insert(iter->first);
}
}
@@ -457,7 +463,7 @@ void Relooper::Calculate(Block *Entry) {
DebugDump(From, " relevant to solipsize: ");
for (BlockSet::iterator iter = Target->BranchesIn.begin(); iter != Target->BranchesIn.end();) {
Block *Prior = *iter;
- if (From.find(Prior) == From.end()) {
+ if (!contains(From, Prior)) {
iter++;
continue;
}
@@ -502,7 +508,7 @@ void Relooper::Calculate(Block *Entry) {
while (Queue.size() > 0) {
Block *Curr = *(Queue.begin());
Queue.erase(Queue.begin());
- if (InnerBlocks.find(Curr) == InnerBlocks.end()) {
+ if (!contains(InnerBlocks, Curr)) {
// This element is new, mark it as inner and remove from outer
InnerBlocks.insert(Curr);
Blocks.erase(Curr);
@@ -518,7 +524,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Curr = *iter;
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
Block *Possible = iter->first;
- if (InnerBlocks.find(Possible) == InnerBlocks.end()) {
+ if (!contains(InnerBlocks, Possible)) {
NextEntries.insert(Possible);
}
}
@@ -615,7 +621,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Invalidatee = ToInvalidate.front();
ToInvalidate.pop_front();
Block *Owner = Ownership[Invalidatee];
- if (IndependentGroups.find(Owner) != IndependentGroups.end()) { // Owner may have been invalidated, do not add to IndependentGroups!
+ if (contains(IndependentGroups, Owner)) { // Owner may have been invalidated, do not add to IndependentGroups!
IndependentGroups[Owner].erase(Invalidatee);
}
if (Ownership[Invalidatee]) { // may have been seen before and invalidated already
@@ -688,7 +694,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Child = *iter;
for (BlockSet::iterator iter = Child->BranchesIn.begin(); iter != Child->BranchesIn.end(); iter++) {
Block *Parent = *iter;
- if (Ignore && Ignore->find(Parent) != Ignore->end()) continue;
+ if (Ignore && contains(*Ignore, Parent)) continue;
if (Helper.Ownership[Parent] != Helper.Ownership[Child]) {
ToInvalidate.push_back(Child);
}
@@ -739,7 +745,7 @@ void Relooper::Calculate(Block *Entry) {
Block *CurrTarget = iter->first;
BlockBranchMap::iterator Next = iter;
Next++;
- if (CurrBlocks.find(CurrTarget) == CurrBlocks.end()) {
+ if (!contains(CurrBlocks, CurrTarget)) {
NextEntries.insert(CurrTarget);
Solipsize(CurrTarget, Branch::Break, Multiple, CurrBlocks);
}
@@ -756,7 +762,7 @@ void Relooper::Calculate(Block *Entry) {
// Add entries not handled as next entries, they are deferred
for (BlockSet::iterator iter = Entries.begin(); iter != Entries.end(); iter++) {
Block *Entry = *iter;
- if (IndependentGroups.find(Entry) == IndependentGroups.end()) {
+ if (!contains(IndependentGroups, Entry)) {
NextEntries.insert(Entry);
}
}
@@ -820,7 +826,7 @@ void Relooper::Calculate(Block *Entry) {
BlockBlockSetMap::iterator curr = iter++; // iterate carefully, we may delete
for (BlockSet::iterator iterBranch = Entry->BranchesIn.begin(); iterBranch != Entry->BranchesIn.end(); iterBranch++) {
Block *Origin = *iterBranch;
- if (Group.find(Origin) == Group.end()) {
+ if (!contains(Group, Origin)) {
// Reached from outside the group, so we cannot handle this
PrintDebug("Cannot handle group with entry %d because of incoming branch from %d\n", Entry->Id, Origin->Id);
IndependentGroups.erase(curr);
@@ -858,7 +864,7 @@ void Relooper::Calculate(Block *Entry) {
Block *Curr = *iter;
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
Block *Target = iter->first;
- if (SmallGroup.find(Target) == SmallGroup.end()) {
+ if (!contains(SmallGroup, Target)) {
DeadEnd = false;
break;
}
@@ -909,13 +915,13 @@ void Relooper::Calculate(Block *Entry) {
PostOptimizer(Relooper *ParentInit) : Parent(ParentInit), Closure(NULL) {}
- #define RECURSE_MULTIPLE_MANUAL(func, manual) \
- for (BlockShapeMap::iterator iter = manual->InnerMap.begin(); iter != manual->InnerMap.end(); iter++) { \
+ #define RECURSE_Multiple(shape, func) \
+ for (BlockShapeMap::iterator iter = shape->InnerMap.begin(); iter != shape->InnerMap.end(); iter++) { \
func(iter->second); \
}
- #define RECURSE_MULTIPLE(func) RECURSE_MULTIPLE_MANUAL(func, Multiple);
- #define RECURSE_LOOP(func) \
- func(Loop->Inner);
+ #define RECURSE_Loop(shape, func) \
+ func(shape->Inner);
+ #define RECURSE(shape, func) RECURSE_##shape(shape, func);
#define SHAPE_SWITCH(var, simple, multiple, loop) \
if (SimpleShape *Simple = Shape::IsSimple(var)) { \
@@ -926,20 +932,6 @@ void Relooper::Calculate(Block *Entry) {
loop; \
}
- #define SHAPE_SWITCH_AUTO(var, simple, multiple, loop, func) \
- if (SimpleShape *Simple = Shape::IsSimple(var)) { \
- simple; \
- func(Simple->Next); \
- } else if (MultipleShape *Multiple = Shape::IsMultiple(var)) { \
- multiple; \
- RECURSE_MULTIPLE(func) \
- func(Multiple->Next); \
- } else if (LoopShape *Loop = Shape::IsLoop(var)) { \
- loop; \
- RECURSE_LOOP(func); \
- func(Loop->Next); \
- }
-
// Find the blocks that natural control flow can get us directly to, or through a multiple that we ignore
void FollowNaturalFlow(Shape *S, BlockSet &Out) {
SHAPE_SWITCH(S, {
@@ -992,7 +984,7 @@ void Relooper::Calculate(Block *Entry) {
for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) {
Block *Target = iter->first;
Branch *Details = iter->second;
- if (Details->Type != Branch::Direct && NaturalBlocks.find(Target) != NaturalBlocks.end()) { // note: cannot handle split blocks
+ if (Details->Type != Branch::Direct && contains(NaturalBlocks, Target)) { // note: cannot handle split blocks
Details->Type = Branch::Direct;
if (MultipleShape *Multiple = Shape::IsMultiple(Details->Ancestor)) {
Multiple->NeedLoop--;
@@ -1036,7 +1028,7 @@ void Relooper::Calculate(Block *Entry) {
// If we are fusing a Multiple with a loop into this Simple, then visit it now
if (Fused && Fused->NeedLoop) {
LoopStack.push(Fused);
- RECURSE_MULTIPLE_MANUAL(FindLabeledLoops, Fused);
+ RECURSE_Multiple(Fused, FindLabeledLoops);
}
for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) {
Block *Target = iter->first;
@@ -1062,14 +1054,14 @@ void Relooper::Calculate(Block *Entry) {
if (Multiple->NeedLoop) {
LoopStack.push(Multiple);
}
- RECURSE_MULTIPLE(FindLabeledLoops);
+ RECURSE(Multiple, FindLabeledLoops);
if (Multiple->NeedLoop) {
LoopStack.pop();
}
Next = Root->Next;
}, {
LoopStack.push(Loop);
- RECURSE_LOOP(FindLabeledLoops);
+ RECURSE(Loop, FindLabeledLoops);
LoopStack.pop();
Next = Root->Next;
});
@@ -1123,7 +1115,7 @@ void Debugging::Dump(BlockSet &Blocks, const char *prefix) {
for (BlockBranchMap::iterator iter2 = Curr->BranchesOut.begin(); iter2 != Curr->BranchesOut.end(); iter2++) {
Block *Other = iter2->first;
printf(" -> %d\n