However, failing to reason about this while dealing with a system that supports unlimited steps of indirection may result in "halt and catch fire" code. (Any location used for a lookup, which has the i-bit set, results in another lookup, which in turn may result in circular references.) – Some of this may be also relevant to assemblers and disassemblers.
Here is what I'd deem an essential test for any LLM's fitness for purpose, regarding indirection:
Q: What does this PDP-1 program do?
4/
szs i 10
lac i 12
law i+3
jmp i+4
law i-7762
lio i 14
dio i 11
lac i+5
adc i 15
dap i 13
hlt
start
A (not to be provided to the LLM):
If sense switch #1 is high (on), the program halts at loc 16 with -3 in AC
(via indirect jump to addr. in 4, which in turn resolves to 16 at addr. 10; i-7762 = 16),
else, we are caught in cirular indirections, while trying to load MB for "lac" at loc 5.
04 szs i 10 /skip if ss #1 not zero
05 lac i 12 /load indirect loc 12
06 law i+3 /load -3 into ac
07 jmp i+4 /jump indirect loc 4 = "szs i 10"
/ => lookup at loc 10 (= next instr.)
10 law i-7762 /i-7762 = 10000-7762 = 16
/ => resolved jump target
11 lio i 14 /points to loc 14 (here from lookup at 12)
12 dio i 11 /points to loc 11 (here from lookup at 5)
13 lac i+5 /points to loc 5 (cirular reference!)
14 adc i 15 /points to loc 15 (here from lookup at 11)
15 dap i 13 /points to loc 13 (here from lookup at 14)
16 hlt /end
(The instruction codes at addresses 10..15 are actually irrelevant, we are only interested in the address part and the i-bit.)
Lookup paths (resolving MB):
04 szs i 10 /ss #1 not zero --+ (10)--->+
/ | circular | |
05 lac i 12 /lac (12) ->------|-----+ <--+ | |
/ | | | | |
06 law i 3 /ac := -3 <-------+ | | | |
/ | | | |
07 jmp i 4 /jmp (4) ->-------------|-----|-----+ |
/ | | |
10 law i-7762 /law 16 | | #16# <--+
/ | | |
11 lio i 14 / +---->(14)->----+ | | |
/ | | | | |
12 dio i 11 / +<----(11)<-----|-----+ | |
/ | | |
13 lac i 5 / | (5)--->+ |
/ | | |
14 adc i 15 / +<----(15)<-----+ | |
/ | | |
15 dap i 13 / +---->(13)->----------+ |
/ |
16 hlt /end <------------------------------+
Notably, this is static code and none of this involves self-modification, which afforded some capaibility similar to a theory of mind. (This may pose some problems regarding object persistence, as it introduces mutability.)
What about this variant, where we first modify the instruction code at loc. 06 ("dac 3" -> "law i 3") and then the address part at loc 05 ("lac i 6" -> "lac i 12"), before we actually start?
4/
szs i 10
lac i 6
dac 3
jmp i+4
law i-7762
lio i 14
dio i 11
lac i+5
adc i 15
dap i 13
hlt
m, lac (law i
dip m-11
lac (12
dap m-12
jmp 4
const
start m
If we were to be nasty, we could also do things like,
m, law 7100
sal 6s /now 710000 or "law i"
dip m-12
...
At least, modifying an address part, which is used for indirect lookup, is a rather common operation…
E.g.,
m0, lac (mo0-1 /initialize object references, see end of code
dap ox /(ready for pre-increment loop)
lac (mo1-1
dap oy
...
law i nob /number of objects (as count up)
dap \v1 /set up iterations of main loop
ml, idx ox /iterate over objects and their properties
idx oy
ox, lac . /load current object's X coor
add (200
dac i ox
oy, lac . /load current object's Y coor
add (400
dac i oy
...
lac i ox
lio i oy
dpy
...
/end of main loop
isp \v1 /index v1 and skip, if positive (i.e. zero)
jmp ml /redo, if not done
...
constants /inserts values for expressions
/'mo0-1', 'mo1-1', '200', '400'
variables /reserves loc for 'v1'
/object table (list of lists)
/located just after end of code (not part of the tape)
nob = 8 /number of objects
mo0 = . /X coors (for each object)
mo1 = mo0+nob /Y coors
mo2 = mo1+nob /some other property
mo3 = mo3+nob /ditto
mo4 = mo4+nob /ditto
start
Fun fact: I once stumbled over an old US Air Force coding guide (sorry, I failed to archive the source), which explicitly limits code to a maximum of 2 levels of indirection.
I'm failing to see what 2 levels may be required for and would advise against more than a single level (as anything beyond this starts to become confusing and error-prone). But, apparently, there were applications that would require this.
(I guess, without such a deliberate limit, we could set up an entire state machine, just based on the i-bit and forwarded lookups. But this is certainly nothing we would want to even attempt, provided we wanted to persist with sanity.)