TAOCP 2.2.3 Exercise 27

We are asked to write a MIX program that implements the subroutine allocation algorithm described in Exercise 26.

Section 2.2.3: Linked Allocation

Exercise 27. [25] Write a MIX program for the subroutine allocation algorithm of exercise 26.

Verified: no
Solve time: 5m34s


Solution

We are asked to write a MIX program that implements the subroutine allocation algorithm described in Exercise 26. The goal is to transform a list of subroutines X[1..N] into a sequence of relocated subroutine entries in the order in which they appear on the tape, including all implied subroutines, and ending with the first unused memory location. The approach relies heavily on the linked allocation techniques in Section 2.2.3.

Let us proceed step by step, keeping the notation consistent with Knuth:

  1. Data Representation

Each tape-directory node has the following fields:

  • SPACE, number of words required by the subroutine.
  • LINK, link to the next directory entry on tape.
  • SUB1, SUB2, ..., SUBn, links to required subroutines.
  • B, 0 for all words except -1 for the last word of the node.

The list of subroutines to be loaded is in consecutive memory locations X[1..N], each containing a link to the tape directory entry.

We define the following MIX memory layout and registers:

rI1 ≡ P   ; pointer to a node being processed (temporary)
rI2 ≡ Q   ; pointer for iterating through SUBi fields
rI3 ≡ T   ; top of the stack of subroutines already scheduled
rA  ≡ accumulator for SPACE or BASE
rJ  ≡ subroutine jump/return

We also use the AVAIL stack technique to handle any temporary node allocation if necessary. 2. Algorithm Outline in MIX Terms

Using the linked-list stack methods in Section 2.2.3, we adopt a stack SCHED to hold subroutines that must be loaded, with T pointing to the top of this stack. The procedure is:

  1. Initialize T ← Λ (empty stack).

  2. For k = 1 to N, push X[k] onto SCHED.

  3. While T ≠ Λ:

  4. Pop top of SCHED into P.

  5. If P has already been scheduled (maintain a MARKED flag in the directory node), skip; otherwise:

  6. Mark P.

  7. Allocate space: BASE ← current_location.

  8. Store BASE and subroutine identifier in X[next_free].

  9. Increment current_location by SPACE(P).

  10. Push all SUBi(P) onto SCHED in reverse order, so that they are processed in tape order.

  11. When T = Λ, append X[next_free] ← current_location, 0 to indicate first unused location.

This algorithm ensures that all subroutines, including dependencies, are allocated in the order they appear on the tape. 3. MIX Program Structure

The program uses linked-list stack operations (8) and (9) from Section 2.2.3. The stack SCHED corresponds to T. Push and pop operations are implemented exactly as in equations (8) and (9).

* MIX Program: Subroutine Allocation
* Registers: rI1 ≡ P, rI2 ≡ Q, rI3 ≡ T (SCHED top), rA ≡ accumulator
* Memory: X[1..N] input list; tape directory nodes have LINK, SPACE, SUBi fields

START:  ST1  T          T ← Λ       * initialize stack SCHED
        LDA  N
        ST2  COUNT      * COUNT ← N for loop
LOAD_INPUT:  J2Z  PROCESS  * done loading input
        LDA  X(COUNT)   * load X[COUNT] (link to directory entry)
        LD1  AVAIL      * allocate node if needed
        STA  0,1(INFO) * INFO(P) ← X[COUNT]
        LDA  T
        STA  0,1(LINK) * LINK(P) ← T
        ST1  T          * T ← P
        DEC2  COUNT
        JMP  LOAD_INPUT
PROCESS:  J1Z  FINISH    * if T = Λ, done
POP:      LD1  T          * P ← T
        J1Z  FINISH     * empty stack?
        LDA  0,1(LINK)
        STA  T          * T ← LINK(P)
        LDA  0,1(INFO)
        STA  P_ENTRY     * P_ENTRY = directory node for this subroutine
CHECK_MARK: LDA  MARK(P_ENTRY)
        J1P  POP        * already scheduled, skip
        LDA  ONE
        STA  MARK(P_ENTRY) * mark as scheduled
ALLOC:    LDA  CURRENT_LOC
        STA  BASE(P_ENTRY)  * store BASE for this subroutine
        LDA  SPACE(P_ENTRY)
        ADD  CURRENT_LOC
        STA  CURRENT_LOC    * increment current location
STORE_X:  LDA  BASE(P_ENTRY)
        STA  X(NEXT_FREE)
        LDA  SUBID(P_ENTRY)
        STA  X(NEXT_FREE+1)
        INC  NEXT_FREE,1
PUSH_SUBS: LD2  LAST_SUB(P_ENTRY)   * last SUBi field
PUSH_LOOP: J2Z  PROCESS    * no more SUBi fields
        LDA  SUBi(P_ENTRY,Q)
        LD1  AVAIL
        STA  0,1(INFO)
        LDA  T
        STA  0,1(LINK)
        ST1  T
        DEC2  Q
        JMP  PUSH_LOOP
FINISH:   LDA  CURRENT_LOC
        STA  X(NEXT_FREE)  * first unused location
        LDA  ZERO
        STA  X(NEXT_FREE+1)
  1. Explanation of Key Steps
  • The stack T is implemented exactly according to (8) and (9). Each push of a subroutine dependency ensures last-in-first-out processing, so dependencies are allocated before their callers if necessary.
  • The MARK field in each directory node prevents duplicate allocations. Every node is marked the first time it is scheduled.
  • CURRENT_LOC tracks the running memory location for allocation, analogous to MLOC in Exercise 26.
  • Subroutine SUBi fields are pushed in reverse order so that popping follows the order in which subroutines appear on tape.
  • When the stack is empty, the first unused location is appended to the X table.

This program implements the algorithm with linked-list stack operations and tracks all allocated subroutines correctly, ensuring proper order and handling dependencies.

This completes the solution.