/* * Copyright 2016 WebAssembly Community Group participants * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef wasm_ast_cost_h #define wasm_ast_cost_h namespace wasm { // Measure the execution cost of an AST. Very handwave-ey struct CostAnalyzer : public Visitor { CostAnalyzer(Expression *ast) { assert(ast); cost = visit(ast); } Index cost; Index maybeVisit(Expression* curr) { return curr ? visit(curr) : 0; } Index visitBlock(Block *curr) { Index ret = 0; for (auto* child : curr->list) ret += visit(child); return ret; } Index visitIf(If *curr) { return 1 + visit(curr->condition) + std::max(visit(curr->ifTrue), maybeVisit(curr->ifFalse)); } Index visitLoop(Loop *curr) { return 5 * visit(curr->body); } Index visitBreak(Break *curr) { return 1 + maybeVisit(curr->value) + maybeVisit(curr->condition); } Index visitSwitch(Switch *curr) { return 2 + visit(curr->condition) + maybeVisit(curr->value); } Index visitCall(Call *curr) { Index ret = 4; for (auto* child : curr->operands) ret += visit(child); return ret; } Index visitCallImport(CallImport *curr) { Index ret = 15; for (auto* child : curr->operands) ret += visit(child); return ret; } Index visitCallIndirect(CallIndirect *curr) { Index ret = 6 + visit(curr->target); for (auto* child : curr->operands) ret += visit(child); return ret; } Index visitGetLocal(GetLocal *curr) { return 0; } Index visitSetLocal(SetLocal *curr) { return 1; } Index visitGetGlobal(GetGlobal *curr) { return 1; } Index visitSetGlobal(SetGlobal *curr) { return 2; } Index visitLoad(Load *curr) { return 1 + visit(curr->ptr); } Index visitStore(Store *curr) { return 2 + visit(curr->ptr) + visit(curr->value); } Index visitConst(Const *curr) { return 1; } Index visitUnary(Unary *curr) { Index ret = 0; switch (curr->op) { case ClzInt32: case CtzInt32: case PopcntInt32: case NegFloat32: case AbsFloat32: case CeilFloat32: case FloorFloat32: case TruncFloat32: case NearestFloat32: case ClzInt64: case CtzInt64: case PopcntInt64: case NegFloat64: case AbsFloat64: case CeilFloat64: case FloorFloat64: case TruncFloat64: case NearestFloat64: case EqZInt32: case EqZInt64: case ExtendSInt32: case ExtendUInt32: case WrapInt64: case PromoteFloat32: case DemoteFloat64: case TruncSFloat32ToInt32: case TruncUFloat32ToInt32: case TruncSFloat64ToInt32: case TruncUFloat64ToInt32: case ReinterpretFloat32: case TruncSFloat32ToInt64: case TruncUFloat32ToInt64: case TruncSFloat64ToInt64: case TruncUFloat64ToInt64: case ReinterpretFloat64: case ReinterpretInt32: case ConvertSInt32ToFloat32: case ConvertUInt32ToFloat32: case ConvertSInt64ToFloat32: case ConvertUInt64ToFloat32: case ReinterpretInt64: case ConvertSInt32ToFloat64: case ConvertUInt32ToFloat64: case ConvertSInt64ToFloat64: case ConvertUInt64ToFloat64: ret = 1; break; case SqrtFloat32: case SqrtFloat64: ret = 2; break; default: WASM_UNREACHABLE(); } return ret + visit(curr->value); } Index visitBinary(Binary *curr) { Index ret = 0; switch (curr->op) { case AddInt32: ret = 1; break; case SubInt32: ret = 1; break; case MulInt32: ret = 2; break; case DivSInt32: ret = 3; break; case DivUInt32: ret = 3; break; case RemSInt32: ret = 3; break; case RemUInt32: ret = 3; break; case AndInt32: ret = 1; break; case OrInt32: ret = 1; break; case XorInt32: ret = 1; break; case ShlInt32: ret = 1; break; case ShrUInt32: ret = 1; break; case ShrSInt32: ret = 1; break; case RotLInt32: ret = 1; break; case RotRInt32: ret = 1; break; case AddInt64: ret = 1; break; case SubInt64: ret = 1; break; case MulInt64: ret = 2; break; case DivSInt64: ret = 3; break; case DivUInt64: ret = 3; break; case RemSInt64: ret = 3; break; case RemUInt64: ret = 3; break; case AndInt64: ret = 1; break; case OrInt64: ret = 1; break; case XorInt64: ret = 1; break; case ShlInt64: ret = 1; break; case ShrUInt64: ret = 1; break; case ShrSInt64: ret = 1; break; case RotLInt64: ret = 1; break; case RotRInt64: ret = 1; break; case AddFloat32: ret = 1; break; case SubFloat32: ret = 1; break; case MulFloat32: ret = 2; break; case DivFloat32: ret = 3; break; case CopySignFloat32: ret = 1; break; case MinFloat32: ret = 1; break; case MaxFloat32: ret = 1; break; case AddFloat64: ret = 1; break; case SubFloat64: ret = 1; break; case MulFloat64: ret = 2; break; case DivFloat64: ret = 3; break; case CopySignFloat64: ret = 1; break; case MinFloat64: ret = 1; break; case MaxFloat64: ret = 1; break; case LtUInt32: ret = 1; break; case LtSInt32: ret = 1; break; case LeUInt32: ret = 1; break; case LeSInt32: ret = 1; break; case GtUInt32: ret = 1; break; case GtSInt32: ret = 1; break; case GeUInt32: ret = 1; break; case GeSInt32: ret = 1; break; case LtUInt64: ret = 1; break; case LtSInt64: ret = 1; break; case LeUInt64: ret = 1; break; case LeSInt64: ret = 1; break; case GtUInt64: ret = 1; break; case GtSInt64: ret = 1; break; case GeUInt64: ret = 1; break; case GeSInt64: ret = 1; break; case LtFloat32: ret = 1; break; case GtFloat32: ret = 1; break; case LeFloat32: ret = 1; break; case GeFloat32: ret = 1; break; case LtFloat64: ret = 1; break; case GtFloat64: ret = 1; break; case LeFloat64: ret = 1; break; case GeFloat64: ret = 1; break; case EqInt32: ret = 1; break; case NeInt32: ret = 1; break; case EqInt64: ret = 1; break; case NeInt64: ret = 1; break; case EqFloat32: ret = 1; break; case NeFloat32: ret = 1; break; case EqFloat64: ret = 1; break; case NeFloat64: ret = 1; break; default: WASM_UNREACHABLE(); } return ret + visit(curr->left) + visit(curr->right); } Index visitSelect(Select *curr) { return 2 + visit(curr->condition) + visit(curr->ifTrue) + visit(curr->ifFalse); } Index visitDrop(Drop *curr) { return visit(curr->value); } Index visitReturn(Return *curr) { return maybeVisit(curr->value); } Index visitHost(Host *curr) { return 100; } Index visitNop(Nop *curr) { return 0; } Index visitUnreachable(Unreachable *curr) { return 0; } }; } // namespace wasm #endif // wasm_ast_cost_h