void workOn(DataFlow::Node* node) { if (node->isConst()) return; // If there are no uses, there is no point to work. if (nodeUsers.getNumUses(node) == 0) return; // Optimize: Look for nodes that we can easily convert into // something simpler. // TODO: we can expressionify and run full normal opts on that, // then copy the result if it's smaller. if (node->isPhi() && DataFlow::allInputsIdentical(node)) { // Note we don't need to check for effects when replacing, as in // flattened IR expression children are local.gets or consts. auto* value = node->getValue(1); if (value->isConst()) { replaceAllUsesWith(node, value); } } else if (node->isExpr() && DataFlow::allInputsConstant(node)) { assert(!node->isConst()); // If this is a concrete value (not e.g. an eqz of unreachable), // it can definitely be precomputed into a constant. if (isConcreteType(node->expr->type)) { // This can be precomputed. // TODO not just all-constant inputs? E.g. i32.mul of 0 and X. optimizeExprToConstant(node); } } }
void eliminateNopTranspose(std::shared_ptr<Graph>& graph) { for(auto it = graph->nodes().begin(), end = graph->nodes().end(); it != end; ++it) { auto n = *it; if (n->kind() == kTranspose) { if (isNopTranspose(n->is(kperm))) { n->replaceAllUsesWith(n->input()->node()); it.destroyCurrent(); continue; } } } }
void optimizeExprToConstant(DataFlow::Node* node) { assert(node->isExpr()); assert(!node->isConst()); //std::cout << "will optimize an Expr of all constant inputs. before" << '\n'; //dump(node, std::cout); auto* expr = node->expr; // First, note that some of the expression's children may be // local.gets that we inferred during SSA analysis as constant. // We can apply those now. for (Index i = 0; i < node->values.size(); i++) { if (node->values[i]->isConst()) { auto* currp = getIndexPointer(expr, i); // Directly represent it as a constant. (Note that it may already be // a constant, but for now to avoid corner cases just replace them // all here.) auto* c = node->values[i]->expr->dynCast<Const>(); *currp = Builder(*getModule()).makeConst(c->value); } } // Now we know that all our DataFlow inputs are constant, and all // our Binaryen IR representations of them are constant too. RUn // precompute, which will transform the expression into a constanat. Module temp; // XXX we should copy expr here, in principle, and definitely will need to // when we do arbitrarily regenerated expressions auto* func = Builder(temp).makeFunction("temp", std::vector<Type>{}, none, std::vector<Type>{}, expr); PassRunner runner(&temp); runner.setIsNested(true); runner.add("precompute"); runner.runOnFunction(func); // Get the optimized thing auto* result = func->body; // It may not be a constant, e.g. 0 / 0 does not optimize to 0 if (!result->is<Const>()) return; // All good, copy it. node->expr = Builder(*getModule()).makeConst(result->cast<Const>()->value); assert(node->isConst()); // We no longer have values, and so do not use anything. nodeUsers.stopUsingValues(node); node->values.clear(); // Our contents changed, update our users. replaceAllUsesWith(node, node); }