void visitSelect(Select* curr) { if (isDead(curr->ifTrue)) { replaceCurrent(curr->ifTrue); return; } if (isDead(curr->ifFalse)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(2); block->list[0] = curr->ifTrue; block->list[1] = curr->ifFalse; block->finalize(); replaceCurrent(block); return; } if (isDead(curr->condition)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(3); block->list[0] = curr->ifTrue; block->list[1] = curr->ifFalse; block->list[2] = curr->condition; block->finalize(); replaceCurrent(block); return; } }
void visitCallImport(CallImport *curr) { WasmType type = getModule()->getFunctionType(getModule()->getImport(curr->target)->functionType)->result; if (type == none) { replaceCurrent(getModule()->allocator.alloc<Nop>()); } else { Literal nopLiteral; nopLiteral.type = type; replaceCurrent(getModule()->allocator.alloc<Const>()->set(nopLiteral)); } }
void visitCallImport(CallImport *curr) { WasmType type = module->getImport(curr->target)->type->result; if (type == none) { replaceCurrent(allocator->alloc<Nop>()); } else { Literal nopLiteral; nopLiteral.type = type; replaceCurrent(allocator->alloc<Const>()->set(nopLiteral)); } }
void visitBinary(Binary* curr) { if (isDead(curr->left)) { replaceCurrent(curr->left); return; } if (isDead(curr->right)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(2); block->list[0] = curr->left; block->list[1] = curr->right; block->finalize(); replaceCurrent(block); } }
void visitStore(Store* curr) { if (isDead(curr->ptr)) { replaceCurrent(curr->ptr); return; } if (isDead(curr->value)) { auto* block = getModule()->allocator.alloc<Block>(); block->list.resize(2); block->list[0] = curr->ptr; block->list[1] = curr->value; block->finalize(); replaceCurrent(block); } }
void visitReturn(Return* curr) { if (isDead(curr->value)) { replaceCurrent(curr->value); return; } reachable = false; }
Block* optimize(Expression* curr, Expression*& child, Block* outer = nullptr, Expression** dependency1 = nullptr, Expression** dependency2 = nullptr) { if (!child) return outer; if (dependency1 && *dependency1 && EffectAnalyzer(*dependency1).hasSideEffects()) return outer; if (dependency2 && *dependency2 && EffectAnalyzer(*dependency2).hasSideEffects()) return outer; if (auto* block = child->dynCast<Block>()) { if (!block->name.is() && block->list.size() >= 2) { child = block->list.back(); if (outer == nullptr) { // reuse the block, move it out block->list.back() = curr; block->finalize(); // last block element was our input, and is now our output, which may differ TODO optimize replaceCurrent(block); return block; } else { // append to an existing outer block assert(outer->list.back() == curr); outer->list.pop_back(); for (Index i = 0; i < block->list.size() - 1; i++) { outer->list.push_back(block->list[i]); } outer->list.push_back(curr); } } } return outer; }
void visitCallIndirect(CallIndirect* curr) { if (isDead(curr->target)) { replaceCurrent(curr->target); return; } handleCall(curr, curr->target); }
void visitCallImport(CallImport* curr) { auto iter = illegalToLegal->find(curr->target); if (iter == illegalToLegal->end()) return; if (iter->second == getFunction()->name) return; // inside the stub function itself, is the one safe place to do the call replaceCurrent(Builder(*getModule()).makeCall(iter->second, curr->operands, curr->type)); }
// preparation: try to unify branches, as the fewer there are, the higher a chance we can remove them // specifically for if-else, turn an if-else with branches to the same target at the end of each // child, and with a value, to a branch to that target containing the if-else void visitIf(If* curr) override { if (!curr->ifFalse) return; if (curr->type != none) return; // already has a returned value // an if_else that indirectly returns a value by breaking to the same target can potentially remove both breaks, and break outside once auto getLast = [](Expression *side) -> Expression* { Block* b = side->dyn_cast<Block>(); if (!b) return nullptr; if (b->list.size() == 0) return nullptr; return b->list.back(); }; auto process = [&](Expression *side, bool doIt) { Expression* last = getLast(side); if (!last) return Name(); Block* b = side->cast<Block>(); Break* br = last->dyn_cast<Break>(); if (!br) return Name(); if (br->condition) return Name(); if (!br->value) return Name(); if (doIt) { b->list[b->list.size()-1] = br->value; } return br->name; }; // do both, or none if (process(curr->ifTrue, false).is() && process(curr->ifTrue, false) == process(curr->ifFalse, false)) { auto br = getLast(curr->ifTrue)->cast<Break>(); // we are about to discard this, so why not reuse it! process(curr->ifTrue, true); process(curr->ifFalse, true); curr->type = br->value->type; // if_else now returns a value br->value = curr; // no need to change anything else in the br - target is correct already replaceCurrent(br); } }
void visitSetLocal(SetLocal* curr) { if (curr->index == labelIndex) { if (Index(curr->value->cast<Const>()->value.geti32()) == targetNum) { replaceCurrent(Builder(*getModule()).makeBreak(targetName)); } } }
void PlaylistHistory::addToCurrent(const QList<QUrl> &filelist) { Playlist *playlist = current(); if (playlist != 0) playlist->append(filelist); else replaceCurrent(new Playlist(filelist)); }
void visitIf(If* curr) { // the ifStack has the branch that joins us, either from before if just an if, or the ifTrue if an if-else reachable = reachable || ifStack.back(); ifStack.pop_back(); if (isDead(curr->condition)) { replaceCurrent(curr->condition); } }
void visitSetLocal(SetLocal* curr) { if (ExpressionAnalyzer::isResultUsed(expressionStack, getFunction())) { Builder builder(*getModule()); replaceCurrent(builder.makeSequence( curr, builder.makeGetLocal(curr->index, curr->type) )); } }
void visitCallImport(CallImport* curr) { // special asm.js imports can be optimized auto* import = getModule()->getImport(curr->target); if (import->module == GLOBAL_MATH) { if (import->base == POW) { if (auto* exponent = curr->operands[1]->dynCast<Const>()) { if (exponent->value == Literal(double(2.0))) { // This is just a square operation, do a multiply Localizer localizer(curr->operands[0], getFunction(), getModule()); Builder builder(*getModule()); replaceCurrent(builder.makeBinary(MulFloat64, localizer.expr, builder.makeGetLocal(localizer.index, localizer.expr->type))); } else if (exponent->value == Literal(double(0.5))) { // This is just a square root operation replaceCurrent(Builder(*getModule()).makeUnary(SqrtFloat64, curr->operands[0])); } } } } }
void visitBlock(Block* curr) { blockStack.pop_back(); if (curr->name.is()) { reachable = reachable || reachableBreaks.count(curr->name); reachableBreaks.erase(curr->name); } if (curr->list.size() == 1 && isDead(curr->list[0])) { replaceCurrent(curr->list[0]); } }
void visitGetLocal(GetLocal *curr) { auto found = sinkables.find(curr->name); if (found != sinkables.end()) { // sink it, and nop the origin TODO: clean up nops replaceCurrent(*found->second.item); // reuse the getlocal that is dying *found->second.item = curr; ExpressionManipulator::nop(curr); sinkables.erase(found); } }
/* TextEditor::onFRDBtnReplace * Called when the 'Replace' button on the Find+Replace frame is * clicked *******************************************************************/ void TextEditor::onFRDBtnReplace(wxCommandEvent& e) { // Set search options int flags = 0; if (dlg_fr->matchCase()) flags |= wxSTC_FIND_MATCHCASE; if (dlg_fr->matchWord()) flags |= wxSTC_FIND_WHOLEWORD; SetSearchFlags(flags); // Do replace replaceCurrent(dlg_fr->getFindString(), dlg_fr->getReplaceString()); }
void visitCall(Call* curr) { auto* import = getModule()->getFunctionOrNull(curr->target); if (!import || !import->imported() || import->module != ENV) return; for (auto name : ATEXIT_NAMES) { if (name == import->base) { replaceCurrent( Builder(*getModule()).replaceWithIdenticalType(curr) ); } } }
void visitBreak(Break* curr) { if (isDead(curr->value)) { // the condition is evaluated last, so if the value was unreachable, the whole thing is replaceCurrent(curr->value); return; } addBreak(curr->name); if (!curr->condition) { reachable = false; } }
void visitIf(If* curr) { if (!curr->ifFalse) { // if without an else. try to reduce if (condition) br => br_if (condition) Break* br = curr->ifTrue->dynCast<Break>(); if (br && !br->condition) { // TODO: if there is a condition, join them br->condition = curr->condition; replaceCurrent(br); anotherCycle = true; } } }
void visitSwitch(Switch* curr) { if (isDead(curr->value)) { replaceCurrent(curr->value); return; } for (auto target : curr->targets) { addBreak(target); } addBreak(curr->default_); reachable = false; }
void visitLoad(Load* curr) { if (curr->align == 0 || curr->align >= curr->bytes) { return; } // Switch unaligned loads of floats to unaligned loads of integers (which we // can actually implement) and then use reinterpretation to get the float // back out. switch (curr->type) { case f32: curr->type = i32; replaceCurrent(builder->makeUnary(ReinterpretInt32, curr)); break; case f64: curr->type = i64; replaceCurrent(builder->makeUnary(ReinterpretInt64, curr)); break; default: break; } }
void visitBlock(Block *curr) { // compress out nops and other dead code int skip = 0; auto& list = curr->list; size_t size = list.size(); bool needResize = false; for (size_t z = 0; z < size; z++) { auto* optimized = optimize(list[z], z == size - 1 && isConcreteWasmType(curr->type)); if (!optimized) { skip++; needResize = true; } else { if (optimized != list[z]) { list[z] = optimized; } if (skip > 0) { list[z - skip] = list[z]; } // if this is an unconditional br, the rest is dead code Break* br = list[z - skip]->dynCast<Break>(); Switch* sw = list[z - skip]->dynCast<Switch>(); if ((br && !br->condition) || sw) { auto* last = list.back(); list.resize(z - skip + 1); // if we removed the last one, and it was a return value, it must be returned if (list.back() != last && isConcreteWasmType(last->type)) { list.push_back(last); } needResize = false; break; } } } if (needResize) { list.resize(size - skip); } if (!curr->name.is()) { if (list.size() == 1) { // just one element. replace the block, either with it or with a nop if it's not needed if (isConcreteWasmType(curr->type) || EffectAnalyzer(getPassOptions(), list[0]).hasSideEffects()) { replaceCurrent(list[0]); } else { if (curr->type == unreachable) { ExpressionManipulator::convert<Block, Unreachable>(curr); } else { ExpressionManipulator::nop(curr); } } } else if (list.size() == 0) { ExpressionManipulator::nop(curr); } } }
void visitLoop(Loop* curr) { if (curr->in.is()) { reachableBreaks.erase(curr->in); } if (curr->out.is()) { reachable = reachable || reachableBreaks.count(curr->out); reachableBreaks.erase(curr->out); } if (isDead(curr->body)) { replaceCurrent(curr->body); return; } }
void rewriteCopysign(Binary* curr) { Literal signBit, otherBits; UnaryOp int2float, float2int; BinaryOp bitAnd, bitOr; switch (curr->op) { case CopySignFloat32: float2int = ReinterpretFloat32; int2float = ReinterpretInt32; bitAnd = AndInt32; bitOr = OrInt32; signBit = Literal(uint32_t(1 << 31)); otherBits = Literal(uint32_t(1 << 31) - 1); break; case CopySignFloat64: float2int = ReinterpretFloat64; int2float = ReinterpretInt64; bitAnd = AndInt64; bitOr = OrInt64; signBit = Literal(uint64_t(1) << 63); otherBits = Literal((uint64_t(1) << 63) - 1); break; default: return; } replaceCurrent( builder->makeUnary( int2float, builder->makeBinary( bitOr, builder->makeBinary( bitAnd, builder->makeUnary( float2int, curr->left ), builder->makeConst(otherBits) ), builder->makeBinary( bitAnd, builder->makeUnary( float2int, curr->right ), builder->makeConst(signBit) ) ) ) ); }
void visitIf(If* curr) { // if the condition is a constant, just apply it // we can just return the ifTrue or ifFalse. if (auto* value = curr->condition->dynCast<Const>()) { if (value->value.getInteger()) { replaceCurrent(curr->ifTrue); return; } else { if (curr->ifFalse) { replaceCurrent(curr->ifFalse); } else { ExpressionManipulator::nop(curr); } return; } } if (curr->ifFalse) { if (curr->ifFalse->is<Nop>()) { curr->ifFalse = nullptr; } else if (curr->ifTrue->is<Nop>()) { curr->ifTrue = curr->ifFalse; curr->ifFalse = nullptr; curr->condition = Builder(*getModule()).makeUnary(EqZInt32, curr->condition); } else if (curr->ifTrue->is<Drop>() && curr->ifFalse->is<Drop>()) { // instead of dropping both sides, drop the if curr->ifTrue = curr->ifTrue->cast<Drop>()->value; curr->ifFalse = curr->ifFalse->cast<Drop>()->value; curr->finalize(); replaceCurrent(Builder(*getModule()).makeDrop(curr)); } } else { // no else if (curr->ifTrue->is<Nop>()) { // no nothing replaceCurrent(Builder(*getModule()).makeDrop(curr->condition)); } } }
void visitExpression(Expression* curr) { if (curr->is<Const>()) return; // try to evaluate this into a const Flow flow; try { flow = StandaloneExpressionRunner().visit(curr); } catch (StandaloneExpressionRunner::NonstandaloneException& e) { return; } if (flow.breaking()) return; // TODO: can create a break as a replacement in some cases (not NONSTANDALONE) if (isConcreteWasmType(flow.value.type)) { replaceCurrent(Builder(*getModule()).makeConst(flow.value)); } }
/* TextEditor::onFRDKeyDown * Called when a key is pressed on the Find+Replace frame *******************************************************************/ void TextEditor::onFRDKeyDown(wxKeyEvent& e) { // Esc (close) if (e.GetKeyCode() == WXK_ESCAPE) dlg_fr->Close(); // Enter else if (e.GetKeyCode() == WXK_RETURN) { // Find Next if (dlg_fr->getTextFind()->HasFocus()) { // Check find string string find = dlg_fr->getFindString(); if (find.IsEmpty()) return; // Set search options int flags = 0; if (dlg_fr->matchCase()) flags |= wxSTC_FIND_MATCHCASE; if (dlg_fr->matchWord()) flags |= wxSTC_FIND_WHOLEWORD; SetSearchFlags(flags); // Do find if (!findNext(find)) wxLogMessage("No text matching \"%s\" found.", find); } // Replace else if (dlg_fr->getTextReplace()->HasFocus()) { // Set search options int flags = 0; if (dlg_fr->matchCase()) flags |= wxSTC_FIND_MATCHCASE; if (dlg_fr->matchWord()) flags |= wxSTC_FIND_WHOLEWORD; SetSearchFlags(flags); // Do replace replaceCurrent(dlg_fr->getFindString(), dlg_fr->getReplaceString()); } else e.Skip(); } // Other else e.Skip(); }
void visitIf(If *curr) { if (curr->ifFalse) { auto block = allocator->alloc<Block>(); auto name = namer->getUnique("L"); // TODO: getUniqueInFunction block->name = name; block->list.push_back(curr); block->list.push_back(curr->ifFalse); curr->ifFalse = nullptr; auto break_ = allocator->alloc<Break>(); break_->name = name; break_->value = curr->ifTrue; curr->ifTrue = break_; replaceCurrent(block); } }