1+ use crate :: elfcode:: { HookControlFlow , Instruction , Interpreter } ;
12use utils:: number:: sum_of_divisors;
23use utils:: prelude:: * ;
34
45/// Interpreting assembly to calculate the sum of divisors.
56///
6- /// See also [day 16](crate::Day16), which uses the same instruction set .
7+ /// See also [day 16](crate::Day16) and [day 21](crate::Day21) .
78#[ derive( Clone , Debug ) ]
89pub struct Day19 {
9- instruction_pointer : Register ,
10- instructions : Vec < Instruction > ,
11- }
12-
13- // Avoids bounds checks when indexing the register array
14- utils:: enumerable_enum! {
15- #[ repr( u32 ) ]
16- #[ derive( Copy , Clone , Debug , PartialEq ) ]
17- enum Register {
18- A ,
19- B ,
20- C ,
21- D ,
22- E ,
23- F ,
24- }
25- }
26-
27- #[ derive( Copy , Clone , Debug ) ]
28- enum Instruction {
29- Addr ( Register , Register , Register ) ,
30- Addi ( Register , u32 , Register ) ,
31- Mulr ( Register , Register , Register ) ,
32- Muli ( Register , u32 , Register ) ,
33- Banr ( Register , Register , Register ) ,
34- Bani ( Register , u32 , Register ) ,
35- Borr ( Register , Register , Register ) ,
36- Bori ( Register , u32 , Register ) ,
37- Setr ( Register , Register ) ,
38- Seti ( u32 , Register ) ,
39- Gtir ( u32 , Register , Register ) ,
40- Gtri ( Register , u32 , Register ) ,
41- Gtrr ( Register , Register , Register ) ,
42- Eqir ( u32 , Register , Register ) ,
43- Eqri ( Register , u32 , Register ) ,
44- Eqrr ( Register , Register , Register ) ,
10+ interpreter : Interpreter ,
4511}
4612
4713impl Day19 {
4814 pub fn new ( input : & str , _: InputType ) -> Result < Self , InputError > {
49- let register =
50- parser:: byte_range ( b'0' ..=b'5' ) . map ( |b| Register :: from_discriminant ( ( b - b'0' ) as u32 ) ) ;
51- let rrr_instructions = parser:: literal_map!(
52- "addr " => Instruction :: Addr as fn ( _, _, _) -> _,
53- "mulr " => Instruction :: Mulr ,
54- "banr " => Instruction :: Banr ,
55- "borr " => Instruction :: Borr ,
56- "gtrr " => Instruction :: Gtrr ,
57- "eqrr " => Instruction :: Eqrr ,
58- ) ;
59- let rir_instructions = parser:: literal_map!(
60- "addi " => Instruction :: Addi as fn ( _, _, _) -> _,
61- "muli " => Instruction :: Muli ,
62- "bani " => Instruction :: Bani ,
63- "bori " => Instruction :: Bori ,
64- "gtri " => Instruction :: Gtri ,
65- "eqri " => Instruction :: Eqri ,
66- ) ;
67- let instruction = parser:: parse_tree!(
68- ( i @ rrr_instructions, a @ register, b' ' , b @ register, b' ' , c @ register) => i( a, b, c) ,
69- ( i @ rir_instructions, a @ register, b' ' , b @ parser:: u32 ( ) , b' ' , c @ register) => i( a, b, c) ,
70- ( "setr " , a @ register, b' ' , parser:: u32 ( ) , b' ' , c @ register) => Instruction :: Setr ( a, c) ,
71- ( "seti " , a @ parser:: u32 ( ) , b' ' , parser:: u32 ( ) , b' ' , c @ register) => Instruction :: Seti ( a, c) ,
72- ( "gtir " , a @ parser:: u32 ( ) , b' ' , b @ register, b' ' , c @ register) => Instruction :: Gtir ( a, b, c) ,
73- ( "eqir " , a @ parser:: u32 ( ) , b' ' , b @ register, b' ' , c @ register) => Instruction :: Eqir ( a, b, c) ,
74- ) ;
75-
76- let ( instruction_pointer, instructions) = register
77- . with_prefix ( "#ip " )
78- . with_suffix ( parser:: eol ( ) )
79- . then ( instruction. repeat ( parser:: eol ( ) , 1 ) )
80- . parse_complete ( input) ?;
81-
8215 Ok ( Self {
83- instruction_pointer,
84- instructions,
16+ interpreter : Interpreter :: new ( input) ?,
8517 } )
8618 }
8719
@@ -97,9 +29,10 @@ impl Day19 {
9729
9830 fn run ( & self , reg0 : u32 ) -> u32 {
9931 let mut reg = [ reg0, 0 , 0 , 0 , 0 , 0 ] ;
100- while let addr = reg[ self . instruction_pointer ] as usize
101- && addr < self . instructions . len ( )
102- {
32+
33+ self . interpreter . run ( & mut reg, |instructions, instruction_pointer, reg| {
34+ let addr = reg[ instruction_pointer] as usize ;
35+
10336 // Recognize the naive sum of divisors loop and replace it with a native implementation.
10437 // loop0: seti #1 $div
10538 // loop1: seti #1 $mul
@@ -112,7 +45,7 @@ impl Day19 {
11245 // gtrr $mul $tgt $tmp
11346 // addr $ip $tmp $ip
11447 // seti #loop1 $ip
115- // addi $div $ 1 $div
48+ // addi $div # 1 $div
11649 // gtrr $div $tgt $tmp
11750 // addr $tmp $ip $ip
11851 // seti #loop0 $ip
@@ -134,14 +67,14 @@ impl Day19 {
13467 Instruction :: Addr ( tmp8, ip8, ip9) ,
13568 Instruction :: Seti ( loop0, ip10) ,
13669 ..,
137- ] = self . instructions [ addr..]
70+ ] = instructions[ addr..]
13871 && div == div2 && div == div3 && div == div4 && div == div5 && div == div6
13972 && mul == mul2 && mul == mul3 && mul == mul4 && mul == mul5
14073 && tmp == tmp2 && tmp == tmp3 && tmp == tmp4 && tmp == tmp5 && tmp == tmp6 && tmp == tmp7 && tmp == tmp8
14174 && tgt == tgt2 && tgt == tgt3
14275 && ip == ip2 && ip == ip3 && ip == ip4 && ip == ip5 && ip == ip6 && ip == ip7 && ip == ip8 && ip == ip9 && ip == ip10
14376 && sum == sum2
144- && ip == self . instruction_pointer
77+ && ip == instruction_pointer
14578 && loop0 as usize == addr
14679 && loop1 as usize == addr + 1
14780 {
@@ -151,30 +84,11 @@ impl Day19 {
15184 reg[ mul] = reg[ tgt] + 1 ;
15285 reg[ tmp] = 1 ;
15386 reg[ ip] += 15 ;
154- continue ;
87+ return HookControlFlow :: Next
15588 } ;
15689
157- match self . instructions [ addr] {
158- Instruction :: Addr ( a, b, c) => reg[ c] = reg[ a] + reg[ b] ,
159- Instruction :: Addi ( a, b, c) => reg[ c] = reg[ a] + b,
160- Instruction :: Mulr ( a, b, c) => reg[ c] = reg[ a] * reg[ b] ,
161- Instruction :: Muli ( a, b, c) => reg[ c] = reg[ a] * b,
162- Instruction :: Banr ( a, b, c) => reg[ c] = reg[ a] & reg[ b] ,
163- Instruction :: Bani ( a, b, c) => reg[ c] = reg[ a] & b,
164- Instruction :: Borr ( a, b, c) => reg[ c] = reg[ a] | reg[ b] ,
165- Instruction :: Bori ( a, b, c) => reg[ c] = reg[ a] | b,
166- Instruction :: Setr ( a, c) => reg[ c] = reg[ a] ,
167- Instruction :: Seti ( a, c) => reg[ c] = a,
168- Instruction :: Gtir ( a, b, c) => reg[ c] = u32:: from ( a > reg[ b] ) ,
169- Instruction :: Gtri ( a, b, c) => reg[ c] = u32:: from ( reg[ a] > b) ,
170- Instruction :: Gtrr ( a, b, c) => reg[ c] = u32:: from ( reg[ a] > reg[ b] ) ,
171- Instruction :: Eqir ( a, b, c) => reg[ c] = u32:: from ( a == reg[ b] ) ,
172- Instruction :: Eqri ( a, b, c) => reg[ c] = u32:: from ( reg[ a] == b) ,
173- Instruction :: Eqrr ( a, b, c) => reg[ c] = u32:: from ( reg[ a] == reg[ b] ) ,
174- }
175-
176- reg[ self . instruction_pointer ] += 1 ;
177- }
90+ HookControlFlow :: Execute
91+ } ) ;
17892
17993 reg[ 0 ]
18094 }
0 commit comments