10 bool __attribute__((format(printf
, 1, 2)))
11 debug(const char *fmt
, ...) {
13 if (getenv("DEBUG")) {
15 vfprintf(stderr
, fmt
, ap
);
22 static int64_t regs
[6];
32 static unsigned int max
;
34 static int lookup(const char *opcode
) {
37 return opcode
[3] == 'i';
39 return 2 + (opcode
[3] == 'i');
41 return 4 + 2 * (opcode
[1] == 'o') + (opcode
[3] == 'i');
43 return 8 + (opcode
[3] == 'i');
45 return 10 + (opcode
[2] == 'r') + (opcode
[3] == opcode
[2]);
47 return 13 + (opcode
[2] == 'r') + (opcode
[3] == opcode
[2]);
49 fprintf(stderr
, "failed decoding instruction %s\n", opcode
);
53 static int64_t get(int r
) {
54 assert(0 <= r
&& r
< sizeof regs
/ sizeof *regs
);
58 static void set(int r
, int64_t v
) {
59 assert(0 <= r
&& r
< sizeof regs
/ sizeof *regs
);
61 assert(v
>= 0 || !"resize regs to be larger type");
64 static const char *step(int op
, int a
, int b
, int c
) {
67 set(c
, get(a
) + get(b
)); return "addr";
69 set(c
, get(a
) + b
); return "addi";
71 set(c
, get(a
) * get(b
)); return "mulr";
73 set(c
, get(a
) * b
); return "muli";
75 set(c
, get(a
) & get(b
)); return "banr";
77 set(c
, get(a
) & b
); return "bani";
79 set(c
, get(a
) | get(b
)); return "borr";
81 set(c
, get(a
) | b
); return "bori";
83 set(c
, get(a
)); return "setr";
85 set(c
, a
); return "seti";
87 set(c
, a
> get(b
)); return "gtir";
89 set(c
, get(a
) > b
); return "gtri";
91 set(c
, get(a
) > get(b
)); return "gtrr";
93 set(c
, a
== get(b
)); return "eqir";
95 set(c
, get(a
) == b
); return "eqri";
97 set(c
, get(a
) == get(b
)); return "eqrr";
103 static uint32_t shuffle(uint32_t in
) {
107 int r4
= in
& 0xffffff;
109 r3
= r4
| 65536; // bori 4 65536 3
110 r4
= 4332021; // seti 4332021 4 4
112 r2
= r3
& 255; // bani 3 255 2
113 r4
+= r2
; // addr 4 2 4
114 r4
&= 16777215; // bani 4 16777215 4
115 r4
*= 65899; // muli 4 65899 4
116 r4
&= 16777215; // bani 4 16777215 4
117 r2
= 256 > r3
; // gtir 256 3 2
118 if (r2
) // addr 2 5 5; addi 5 1 5
119 goto l27
; // seti 27 5 5
120 r2
= 0; // seti 0 2 2
122 r1
= r2
+ 1; // addi 2 1 1
123 r1
*= 256; // muli 1 256 1
124 r1
= r1
> r3
; // gtrr 1 3 1
125 if (r1
) // addr 1 5 5; addi 5 1 5
126 goto l25
; // seti 25 2 5
128 goto l17
; // seti 17 3 5
130 r3
= r2
; // setr 2 7 3
131 goto l7
; // seti 7 1 5
133 assert((r3
& 0xff) == r3
&& (r4
& 0xffffff) == r4
);
134 return (r3
<< 24) | r4
;
137 int main(int argc
, char **argv
) {
138 size_t len
= 0, count
= 0;
141 uint32_t limit
= 100000;
143 /* Part 1 - read in entire program */
145 limit
= atoll(argv
[3]);
147 regs
[0] = atoi(argv
[2]);
148 if (argc
> 1 && !(stdin
= freopen(argv
[1], "r", stdin
))) {
153 if (getline(&line
, &len
, stdin
) < 0 ||
154 sscanf(line
, "#ip %hhu\n", &ip
) != 1) {
155 fprintf(stderr
, "missing #ip line\n");
158 while (getline(&line
, &len
, stdin
) > 0) {
159 program
= reallocarray(program
, ++count
, sizeof *program
);
160 o
= &program
[count
- 1];
161 o
->op
= lookup(line
);
162 if (sscanf(line
+ 5, "%d %d %d\n", &o
->a
, &o
->b
, &o
->c
) != 3) {
163 fprintf(stderr
, "corrupt program\n");
168 printf("program has %u instructions\n", max
= count
);
170 /* Part 2 - run it */
173 while (regs
[ip
] < max
&& count
< limit
) {
176 if (!(count
% 1000000))
177 printf("%8zu...\n", count
);
179 debug("%5zu: ip=%"PRId64
" [%"PRIx64
", %"PRIx64
", %"PRIx64
", %"PRIx64
180 ", %"PRIx64
", %"PRIx64
"] ", count
, regs
[ip
], regs
[0],
181 regs
[1], regs
[2], regs
[3], regs
[4], regs
[5]);
183 o
= &program
[regs
[ip
]];
184 s
= step(o
->op
, o
->a
, o
->b
, o
->c
);
186 debug("%s %d %d %d ", s
, o
->a
, o
->b
, o
->c
);
189 debug("[%"PRIx64
", %"PRIx64
", %"PRIx64
", %"PRIx64
", %"PRIx64
", %"PRIx64
190 "] (%d)\n", regs
[0], regs
[1], regs
[2],
191 regs
[3], regs
[4], regs
[5], o
->visited
);
194 printf("%s execution after %zu steps\n",
195 regs
[ip
] < max
? "gave up" : "completed", count
);
196 for (int i
= 0; 0 && i
< max
; i
++) {
198 if (!debug("program line %s %d %d %d executed %d times\n",
199 step(o
->op
, 0, 0, 0), o
->a
, o
->b
, o
->c
, o
->visited
))
203 /* Part 3: look for cycle with hand-rolled retype of program for speed */
207 slow
= fast
= 0x0191f7da;
210 slow
= shuffle(slow
);
211 prev
= shuffle(fast
);
212 fast
= shuffle(prev
);
213 if (count
< 10 || count
> 6300)
214 debug(" %08zu: %08x %08x %08x\n", count
, slow
, prev
, fast
);
215 } while ((slow
& 0xffffff) != (fast
& 0xffffff));
216 printf("found loop after %zu cycles, now finding last integer in loop\n",
220 while ((slow
& 0xffffff) != (fast
& 0xffffff)) {
223 slow
= shuffle(slow
);
224 fast
= shuffle(fast
);
226 debug(" %08zu: %08x %08x %08x\n", count
, slow
, prev
, fast
);
228 printf("repeat state after %zu cycles, previous state %d\n",
229 count
, prev
& 0xffffff);
230 printf("checking: %x %x %x\n", prev
, shuffle(prev
), slow
);