:TODO: Document extraFrameBound in the Tech Report (and implement it in Haskell) */ Given a well-typed dag representing a Simplicity expression, compute the memory and CPU requirements for evaluation. * * If 'malloc' fails, then returns SIMPLICITY_ERR_MALLOC. * When maxCells < UBOUNDED_MAX, if the bounds on the number of cells needed for evaluation of 'dag' on an idealized Bit Machine exceeds m
| 586 | * and if maxCells < UBOUNDED_MAX then '*frameBound' bounds the number of stack frames needed during execution of 'dag'. |
| 587 | */ |
| 588 | simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBound, ubounded *frameBound, ubounded *costBound |
| 589 | , ubounded maxCells, ubounded minCost, ubounded maxCost, const dag_node* dag, const type* type_dag, const size_t len) { |
| 590 | static_assert(DAG_LEN_MAX <= SIZE_MAX / sizeof(boundsAnalysis), "bound array too large."); |
| 591 | static_assert(1 <= DAG_LEN_MAX, "DAG_LEN_MAX is zero."); |
| 592 | static_assert(DAG_LEN_MAX - 1 <= UINT32_MAX, "bound array index does not fit in uint32_t."); |
| 593 | simplicity_assert(1 <= len); |
| 594 | simplicity_assert(len <= DAG_LEN_MAX); |
| 595 | boundsAnalysis* bound = simplicity_malloc(len * sizeof(boundsAnalysis)); |
| 596 | if (!bound) return SIMPLICITY_ERR_MALLOC; |
| 597 | |
| 598 | /* Sum up the total costs. |
| 599 | * The computations for extraCells and cost are clipped at UBOUNDED_MAX, |
| 600 | * so a result of UBOUNDED_MAX means "UBOUNDED_MAX or larger". |
| 601 | * |
| 602 | * The extraUWORD computation may produce unsigned overflow. |
| 603 | * However the extraUWORD true value is less than the true value of extraCells. |
| 604 | * As long as extraCells is strictly less than UBOUNDED_MAX, extraUWORD will be too. |
| 605 | * |
| 606 | * The extraFrame computation is bounded by DAG_LEN, and cannot overflow. |
| 607 | */ |
| 608 | for (size_t i = 0; i < len; ++i) { |
| 609 | switch (dag[i].tag) { |
| 610 | case ASSERTL: |
| 611 | case ASSERTR: |
| 612 | case CASE: |
| 613 | bound[i].extraCellsBound[0] = bounded_max( bound[dag[i].child[0]].extraCellsBound[0] |
| 614 | , bound[dag[i].child[1]].extraCellsBound[0] ); |
| 615 | bound[i].extraCellsBound[1] = bounded_max( bound[dag[i].child[0]].extraCellsBound[1] |
| 616 | , bound[dag[i].child[1]].extraCellsBound[1] ); |
| 617 | |
| 618 | bound[i].extraUWORDBound[0] = bounded_max( bound[dag[i].child[0]].extraUWORDBound[0] |
| 619 | , bound[dag[i].child[1]].extraUWORDBound[0] ); |
| 620 | bound[i].extraUWORDBound[1] = bounded_max( bound[dag[i].child[0]].extraUWORDBound[1] |
| 621 | , bound[dag[i].child[1]].extraUWORDBound[1] ); |
| 622 | |
| 623 | bound[i].extraFrameBound[0] = bounded_max( bound[dag[i].child[0]].extraFrameBound[0] |
| 624 | , bound[dag[i].child[1]].extraFrameBound[0] ); |
| 625 | bound[i].extraFrameBound[1] = bounded_max( bound[dag[i].child[0]].extraFrameBound[1] |
| 626 | , bound[dag[i].child[1]].extraFrameBound[1] ); |
| 627 | bound[i].cost = bounded_add(overhead, bounded_max( bound[dag[i].child[0]].cost |
| 628 | , bound[dag[i].child[1]].cost )); |
| 629 | break; |
| 630 | case DISCONNECT: |
| 631 | bound[i].extraCellsBound[1] = type_dag[DISCONNECT_W256A(dag, type_dag, i)].bitSize; |
| 632 | bound[i].extraCellsBound[0] = bounded_max( |
| 633 | bounded_add( type_dag[DISCONNECT_BC(dag, type_dag, i)].bitSize |
| 634 | , bounded_max( bounded_add(bound[i].extraCellsBound[1], bound[dag[i].child[0]].extraCellsBound[1]) |
| 635 | , bounded_max(bound[dag[i].child[0]].extraCellsBound[0], bound[dag[i].child[1]].extraCellsBound[1]))), |
| 636 | bound[dag[i].child[1]].extraCellsBound[0]); |
| 637 | bound[i].extraUWORDBound[1] = (ubounded)ROUND_UWORD(type_dag[DISCONNECT_W256A(dag, type_dag, i)].bitSize); |
| 638 | bound[i].extraUWORDBound[0] = bounded_max( |
| 639 | (ubounded)ROUND_UWORD(type_dag[DISCONNECT_BC(dag, type_dag, i)].bitSize) + |
| 640 | bounded_max( bound[i].extraUWORDBound[1] + bound[dag[i].child[0]].extraUWORDBound[1] |
| 641 | , bounded_max(bound[dag[i].child[0]].extraUWORDBound[0], bound[dag[i].child[1]].extraUWORDBound[1])), |
| 642 | bound[dag[i].child[1]].extraUWORDBound[0]); |
| 643 | |
| 644 | bound[i].extraFrameBound[1] = bounded_max( bound[dag[i].child[0]].extraFrameBound[1] + 1 |
| 645 | , bound[dag[i].child[1]].extraFrameBound[1]); |