// Replaces all uses of a node with another value. This both modifies // the DataFlow IR to make the other users point to this one, and // updates the underlying Binaryen IR as well. // This can be used to "replace" a node with itself, which makes sense // when the node contents have changed and so the users must be updated. void replaceAllUsesWith(DataFlow::Node* node, DataFlow::Node* with) { // Const nodes are trivial to replace, but other stuff is trickier - // in particular phis. assert(with->isConst()); // TODO // All the users should be worked on later, as we will update them. auto& users = nodeUsers.getUsers(node); for (auto* user : users) { // Add the user to the work left to do, as we are modifying it. workLeft.insert(user); // `with` is getting another user. nodeUsers.addUser(with, user); // Replacing in the DataFlow IR is simple - just replace it, // in all the indexes it appears. std::vector<Index> indexes; for (Index i = 0; i < user->values.size(); i++) { if (user->values[i] == node) { user->values[i] = with; indexes.push_back(i); } } assert(!indexes.empty()); // Replacing in the Binaryen IR requires more care switch (user->type) { case DataFlow::Node::Type::Expr: { auto* expr = user->expr; for (auto index : indexes) { *(getIndexPointer(expr, index)) = graph.makeUse(with); } break; } case DataFlow::Node::Type::Phi: { // Nothing to do: a phi is not in the Binaryen IR. // If the entire phi can become a constant, that will be // propagated when we process that phi later. break; } case DataFlow::Node::Type::Cond: { // Nothing to do: a cond is not in the Binaryen IR. // If the cond input is a constant, that might indicate // useful optimizations are possible, which perhaps we // should look into TODO break; } case DataFlow::Node::Type::Zext: { // Nothing to do: a zext is not in the Binaryen IR. // If the cond input is a constant, that might indicate // useful optimizations are possible, which perhaps we // should look into TODO break; } default: WASM_UNREACHABLE(); } } // No one is a user of this node after we replaced all the uses. nodeUsers.removeAllUsesOf(node); }
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); }
//// Drawable functions //// void DMesh::draw( RenderInfo& r) { glPushMatrix(); glMultMatrixf(m_transform); // Material r.material( Drawable::m_material ); r.state( 1 + (getNormalPointer()? 2:0) + (getTexCoordPointer()?4:0) ); glVertexPointer(3, GL_FLOAT, getStride(), getVertexPointer()); glNormalPointer( GL_FLOAT, getStride(), getNormalPointer()); glTexCoordPointer(2, GL_FLOAT, getStride(), getTexCoordPointer()); // Tangents? if(getTangentPointer() && base::Shader::current().ready()) { base::Shader::current().AttributePointer("tangent", 3, GL_FLOAT, 0, getStride(), getTangentPointer()); } // Draw it if(hasIndices()) glDrawElements( getMode(), getSize(), GL_UNSIGNED_SHORT, getIndexPointer()); else glDrawArrays( getMode(), 0, getSize()); glPopMatrix(); }