ckb_vm/
decoder.rs

1use ckb_vm_definitions::instructions::{self as insts};
2use ckb_vm_definitions::registers::{RA, ZERO};
3
4use crate::instructions::{
5    a, b, extract_opcode, i, instruction_length, m, rvc, set_instruction_length_n, Instruction,
6    InstructionFactory, Itype, R4type, R5type, Register, Rtype, Utype,
7};
8use crate::machine::VERSION2;
9use crate::memory::Memory;
10use crate::{Error, ISA_A, ISA_B, ISA_MOP, RISCV_PAGESIZE};
11
12const RISCV_PAGESIZE_MASK: u64 = RISCV_PAGESIZE as u64 - 1;
13const INSTRUCTION_CACHE_SIZE: usize = 2048;
14
15pub struct Decoder {
16    factories: Vec<InstructionFactory>,
17    mop: bool,
18    version: u32,
19    // Use a cache of instructions to avoid decoding the same instruction
20    // twice, pc is the key and the instruction is the value.
21    //
22    // Use Vector so that the data is on the heap. Otherwise, if there is
23    // a vm call chain, it will quickly consume Rust's 2M stack space.
24    instructions_cache: Vec<(u64, u64)>,
25}
26
27impl Decoder {
28    pub fn new(mop: bool, version: u32) -> Decoder {
29        Decoder {
30            factories: vec![],
31            mop,
32            version,
33            instructions_cache: vec![(u64::MAX as u64, 0); INSTRUCTION_CACHE_SIZE],
34        }
35    }
36
37    pub fn add_instruction_factory(&mut self, factory: InstructionFactory) {
38        self.factories.push(factory);
39    }
40
41    // This method is used to decode instruction raw bits from memory pointed
42    // by current PC. Right now we support 32-bit instructions and RVC compressed
43    // instructions. In future version we might add support for longer instructions.
44    //
45    // This decode method actually leverages a trick from little endian encoding:
46    // the format for a full 32 bit RISC-V instruction is as follows:
47    //
48    // WWWWWWWWZZZZZZZZYYYYYYYYXXXXXX11
49    //
50    // While the format for a 16 bit RVC RIST-V instruction is one of the following 3:
51    //
52    // YYYYYYYYXXXXXX00
53    // YYYYYYYYXXXXXX01
54    // YYYYYYYYXXXXXX10
55    //
56    // Here X, Y, Z and W stands for arbitrary bits.
57    // However the above is the representation in a 16-bit or 32-bit integer, since
58    // we are using little endian, in memory it's actually in following reversed order:
59    //
60    // XXXXXX11 YYYYYYYY ZZZZZZZZ WWWWWWWW
61    // XXXXXX00 YYYYYYYY
62    // XXXXXX01 YYYYYYYY
63    // XXXXXX10 YYYYYYYY
64    //
65    // One observation here, is the first byte in memory is always the least
66    // significant byte whether we load a 32-bit or 16-bit integer.
67    // So when we are decoding an instruction, we can first load 2 bytes forming
68    // a 16-bit integer, then we check the 2 least significant bits, if the 2 bitss
69    // are 0b11, we know this is a 32-bit instruction, we should load another 2 bytes
70    // from memory and concat the 2 16-bit integers into a full 32-bit integers.
71    // Otherwise, we know we are loading a RVC integer, and we are done here.
72    // Also, due to RISC-V encoding behavior, it's totally okay when we cast a 16-bit
73    // RVC instruction into a 32-bit instruction, the meaning of the instruction stays
74    // unchanged in the cast conversion.
75    fn decode_bits<M: Memory>(&self, memory: &mut M, pc: u64) -> Result<u32, Error> {
76        // when the address is not the last 2 bytes of an executable page,
77        // use a faster path to load instruction bits
78        if pc & RISCV_PAGESIZE_MASK < RISCV_PAGESIZE_MASK - 1 {
79            let mut instruction_bits = memory.execute_load32(pc)?;
80            if instruction_bits & 0x3 != 0x3 {
81                instruction_bits &= 0xffff;
82            }
83            Ok(instruction_bits)
84        } else {
85            let mut instruction_bits = u32::from(memory.execute_load16(pc)?);
86            if instruction_bits & 0x3 == 0x3 {
87                instruction_bits |= u32::from(memory.execute_load16(pc + 2)?) << 16;
88            }
89            Ok(instruction_bits)
90        }
91    }
92
93    pub fn decode_raw<M: Memory>(&mut self, memory: &mut M, pc: u64) -> Result<Instruction, Error> {
94        // since we are using u64::MAX as the default key in the instruction cache, have to check out of bound
95        // error first.
96        if pc as usize >= memory.memory_size() {
97            return Err(Error::MemOutOfBound);
98        }
99        let instruction_cache_key = {
100            // according to RISC-V instruction encoding, the lowest bit in PC will always be zero
101            let pc = pc >> 1;
102            // This indexing strategy optimizes instruction cache utilization by improving the distribution of addresses.
103            // - `pc >> 5`: Incorporates higher bits to ensure a more even spread across cache indices.
104            // - `pc << 1`: Spreads lower-bit information into higher positions, enhancing variability.
105            // - `^` (XOR): Further randomizes index distribution, reducing cache conflicts and improving hit rates.
106            //
107            // This approach helps balance cache efficiency between local execution and remote function calls,
108            // reducing hotspots and improving overall performance.
109            ((pc >> 5) ^ (pc << 1)) as usize % INSTRUCTION_CACHE_SIZE
110        };
111        let cached_instruction = self.instructions_cache[instruction_cache_key];
112        if cached_instruction.0 == pc {
113            return Ok(cached_instruction.1);
114        }
115        let instruction_bits = self.decode_bits(memory, pc)?;
116        for factory in &self.factories {
117            if let Some(instruction) = factory(instruction_bits, self.version) {
118                self.instructions_cache[instruction_cache_key] = (pc, instruction);
119                return Ok(instruction);
120            }
121        }
122        Err(Error::InvalidInstruction {
123            pc,
124            instruction: instruction_bits,
125        })
126    }
127
128    // Macro-Operation Fusion (also Macro-Op Fusion, MOP Fusion, or Macrofusion) is a hardware optimization technique found
129    // in many modern microarchitectures whereby a series of adjacent macro-operations are merged into a single
130    // macro-operation prior or during decoding. Those instructions are later decoded into fused-µOPs.
131    //
132    // - https://riscv.org/wp-content/uploads/2016/07/Tue1130celio-fusion-finalV2.pdf
133    // - https://en.wikichip.org/wiki/macro-operation_fusion#Proposed_fusion_operations
134    // - https://carrv.github.io/2017/papers/clark-rv8-carrv2017.pdf
135    pub fn decode_mop<M: Memory>(&mut self, memory: &mut M, pc: u64) -> Result<Instruction, Error> {
136        let head_instruction = self.decode_raw(memory, pc)?;
137        let head_opcode = extract_opcode(head_instruction);
138        match head_opcode {
139            insts::OP_ADD => {
140                let rule_adc = |decoder: &mut Self,
141                                memory: &mut M|
142                 -> Result<Option<Instruction>, Error> {
143                    let head_inst = Rtype(head_instruction);
144                    let head_size = instruction_length(head_instruction);
145                    if head_inst.rd() != head_inst.rs1() || head_inst.rs1() == head_inst.rs2() {
146                        return Ok(None);
147                    }
148                    let next_instruction = decoder.decode_raw(memory, pc + head_size as u64)?;
149                    let next_opcode = extract_opcode(next_instruction);
150                    if next_opcode != insts::OP_SLTU {
151                        return Ok(None);
152                    }
153                    let next_inst = Rtype(next_instruction);
154                    let next_size = instruction_length(next_instruction);
155                    if next_inst.rd() != head_inst.rs2()
156                        || head_inst.rs2() != next_inst.rs2()
157                        || next_inst.rs1() != head_inst.rs1()
158                    {
159                        return Ok(None);
160                    }
161                    let neck_instruction =
162                        decoder.decode_raw(memory, pc + head_size as u64 + next_size as u64)?;
163                    let neck_opcode = extract_opcode(neck_instruction);
164                    if neck_opcode != insts::OP_ADD {
165                        return Ok(None);
166                    }
167                    let neck_inst = Rtype(neck_instruction);
168                    let neck_size = instruction_length(neck_instruction);
169                    if neck_inst.rd() != neck_inst.rs1()
170                        || neck_inst.rs1() != next_inst.rs1()
171                        || neck_inst.rs2() == head_inst.rs1()
172                        || neck_inst.rs2() == head_inst.rs2()
173                    {
174                        return Ok(None);
175                    }
176                    let body_instruction = decoder.decode_raw(
177                        memory,
178                        pc + head_size as u64 + next_size as u64 + neck_size as u64,
179                    )?;
180                    let body_opcode = extract_opcode(body_instruction);
181                    if body_opcode != insts::OP_SLTU {
182                        return Ok(None);
183                    }
184                    let body_inst = Rtype(body_instruction);
185                    let body_size = instruction_length(body_instruction);
186                    if body_inst.rd() != body_inst.rs2()
187                        || body_inst.rs2() != neck_inst.rs2()
188                        || body_inst.rs1() != neck_inst.rs1()
189                    {
190                        return Ok(None);
191                    }
192                    let tail_instruction = decoder.decode_raw(
193                        memory,
194                        pc + head_size as u64
195                            + next_size as u64
196                            + neck_size as u64
197                            + body_size as u64,
198                    )?;
199                    let tail_opcode = extract_opcode(tail_instruction);
200                    if tail_opcode != insts::OP_OR {
201                        return Ok(None);
202                    }
203                    let tail_inst = Rtype(tail_instruction);
204                    let tail_size = instruction_length(tail_instruction);
205                    if tail_inst.rd() != tail_inst.rs1()
206                        || tail_inst.rs1() != head_inst.rs2()
207                        || tail_inst.rs2() != body_inst.rs2()
208                    {
209                        return Ok(None);
210                    }
211                    if head_inst.rd() == ZERO || next_inst.rd() == ZERO || body_inst.rd() == ZERO {
212                        return Ok(None);
213                    }
214                    let fuze_inst = Rtype::new(
215                        insts::OP_ADC,
216                        head_inst.rd(),
217                        next_inst.rd(),
218                        body_inst.rd(),
219                    );
220                    let fuze_size = head_size + next_size + neck_size + body_size + tail_size;
221                    Ok(Some(set_instruction_length_n(fuze_inst.0, fuze_size)))
222                };
223                let rule_add3 =
224                    |decoder: &mut Self, memory: &mut M| -> Result<Option<Instruction>, Error> {
225                        if decoder.version < VERSION2 {
226                            return Ok(None);
227                        }
228
229                        let i0 = Rtype(head_instruction);
230                        let i0_size = instruction_length(head_instruction);
231
232                        let (i1, i1_size) = {
233                            let i1 = decoder.decode_raw(memory, pc + i0_size as u64)?;
234                            let i1_opcode = extract_opcode(i1);
235                            if i1_opcode != insts::OP_SLTU {
236                                return Ok(None);
237                            }
238                            (Rtype(i1), instruction_length(i1))
239                        };
240
241                        let (i2, i2_size) = {
242                            let i2 =
243                                decoder.decode_raw(memory, pc + i0_size as u64 + i1_size as u64)?;
244                            let i2_opcode = extract_opcode(i2);
245                            if i2_opcode != insts::OP_ADD {
246                                return Ok(None);
247                            }
248                            (Rtype(i2), instruction_length(i2))
249                        };
250
251                        let fuze_size = i0_size + i1_size + i2_size;
252
253                        {
254                            // add r0, r1, r0
255                            // sltu r2, r0, r1
256                            // add r3, r2, r4
257                            //
258                            // r0 != r1
259                            // r0 != r4
260                            // r2 != r4
261                            // r0 != x0
262                            // r2 != x0
263                            let r0 = i0.rd();
264                            let r1 = i0.rs1();
265                            let r2 = i1.rd();
266                            let r3 = i2.rd();
267                            let r4 = i2.rs2();
268
269                            if i0.rd() == r0
270                                && i0.rs1() == r1
271                                && i0.rs2() == r0
272                                && i1.rd() == r2
273                                && i1.rs1() == r0
274                                && i1.rs2() == r1
275                                && i2.rd() == r3
276                                && i2.rs1() == r2
277                                && i2.rs2() == r4
278                                && r0 != r1
279                                && r0 != r4
280                                && r2 != r4
281                                && r0 != ZERO
282                                && r2 != ZERO
283                            {
284                                let fuze_inst = R5type::new(insts::OP_ADD3A, r0, r1, r2, r3, r4);
285                                return Ok(Some(set_instruction_length_n(fuze_inst.0, fuze_size)));
286                            }
287                        }
288
289                        {
290                            // add r0, r1, r2
291                            // sltu r1, r0, r1
292                            // add r3, r1, r4
293                            //
294                            // r0 != r1
295                            // r0 != r4
296                            // r1 != r4
297                            // r0 != x0
298                            // r1 != x0
299                            let r0 = i0.rd();
300                            let r1 = i0.rs1();
301                            let r2 = i0.rs2();
302                            let r3 = i2.rd();
303                            let r4 = i2.rs2();
304
305                            if i0.rd() == r0
306                                && i0.rs1() == r1
307                                && i0.rs2() == r2
308                                && i1.rd() == r1
309                                && i1.rs1() == r0
310                                && i1.rs2() == r1
311                                && i2.rd() == r3
312                                && i2.rs1() == r1
313                                && i2.rs2() == r4
314                                && r0 != r1
315                                && r0 != r4
316                                && r1 != r4
317                                && r0 != ZERO
318                                && r1 != ZERO
319                            {
320                                let fuze_inst = R5type::new(insts::OP_ADD3B, r0, r1, r2, r3, r4);
321                                return Ok(Some(set_instruction_length_n(fuze_inst.0, fuze_size)));
322                            }
323                        }
324                        {
325                            // add r0, r1, r2
326                            // sltu r3, r0, r1
327                            // add r3, r3, r4
328                            //
329                            // r0 != r1
330                            // r0 != r4
331                            // r3 != r4
332                            // r0 != x0
333                            // r3 != x0
334                            let r0 = i0.rd();
335                            let r1 = i0.rs1();
336                            let r2 = i0.rs2();
337                            let r3 = i1.rd();
338                            let r4 = i2.rs2();
339
340                            if i0.rd() == r0
341                                && i0.rs1() == r1
342                                && i0.rs2() == r2
343                                && i1.rd() == r3
344                                && i1.rs1() == r0
345                                && i1.rs2() == r1
346                                && i2.rd() == r3
347                                && i2.rs1() == r3
348                                && i2.rs2() == r4
349                                && r0 != r1
350                                && r0 != r4
351                                && r3 != r4
352                                && r0 != ZERO
353                                && r3 != ZERO
354                            {
355                                let fuze_inst = R5type::new(insts::OP_ADD3C, r0, r1, r2, r3, r4);
356                                return Ok(Some(set_instruction_length_n(fuze_inst.0, fuze_size)));
357                            }
358                        }
359                        Ok(None)
360                    };
361                let rule_adcs =
362                    |decoder: &mut Self, memory: &mut M| -> Result<Option<Instruction>, Error> {
363                        // add r0, r1, r2
364                        // sltu r3, r0, r1
365                        //
366                        // or
367                        //
368                        // add r0, r2, r1
369                        // sltu r3, r0, r1
370                        //
371                        // r0 != r1
372                        // r0 != x0
373                        if decoder.version < VERSION2 {
374                            return Ok(None);
375                        }
376
377                        let mut i0 = Rtype(head_instruction);
378                        let i0_size = instruction_length(head_instruction);
379
380                        if i0.rd() == i0.rs1() && i0.rd() != i0.rs2() {
381                            i0 = Rtype::new(i0.op(), i0.rd(), i0.rs2(), i0.rs1());
382                        }
383
384                        let (i1, i1_size) = {
385                            let i1 = decoder.decode_raw(memory, pc + i0_size as u64)?;
386                            let i1_opcode = extract_opcode(i1);
387                            if i1_opcode != insts::OP_SLTU {
388                                return Ok(None);
389                            }
390                            (Rtype(i1), instruction_length(i1))
391                        };
392
393                        let r0 = i0.rd();
394                        let r1 = i0.rs1();
395                        let r2 = i0.rs2();
396                        let r3 = i1.rd();
397
398                        if i0.rd() == r0
399                            && i0.rs1() == r1
400                            && i0.rs2() == r2
401                            && i1.rd() == r3
402                            && i1.rs1() == r0
403                            && i1.rs2() == r1
404                            && r0 != r1
405                            && r0 != ZERO
406                        {
407                            let fuze_inst = R4type::new(insts::OP_ADCS, r0, r1, r2, r3);
408                            let fuze_size = i0_size + i1_size;
409                            Ok(Some(set_instruction_length_n(fuze_inst.0, fuze_size)))
410                        } else {
411                            Ok(None)
412                        }
413                    };
414                if let Ok(Some(i)) = rule_adc(self, memory) {
415                    Ok(i)
416                } else if let Ok(Some(i)) = rule_add3(self, memory) {
417                    Ok(i)
418                } else if let Ok(Some(i)) = rule_adcs(self, memory) {
419                    Ok(i)
420                } else {
421                    Ok(head_instruction)
422                }
423            }
424            insts::OP_SUB => {
425                let rule_sbb =
426                    |decoder: &mut Self, memory: &mut M| -> Result<Option<Instruction>, Error> {
427                        let head_inst = Rtype(head_instruction);
428                        let head_size = instruction_length(head_instruction);
429                        if head_inst.rd() != head_inst.rs2() || head_inst.rs1() == head_inst.rs2() {
430                            return Ok(None);
431                        }
432                        let next_instruction = decoder.decode_raw(memory, pc + head_size as u64)?;
433                        let next_opcode = extract_opcode(next_instruction);
434                        if next_opcode != insts::OP_SLTU {
435                            return Ok(None);
436                        }
437                        let next_inst = Rtype(next_instruction);
438                        let next_size = instruction_length(next_instruction);
439                        if next_inst.rd() == head_inst.rs1()
440                            || next_inst.rd() == head_inst.rs2()
441                            || next_inst.rs1() != head_inst.rs1()
442                            || next_inst.rs2() != next_inst.rs2()
443                        {
444                            return Ok(None);
445                        }
446                        let neck_instruction =
447                            decoder.decode_raw(memory, pc + head_size as u64 + next_size as u64)?;
448                        let neck_opcode = extract_opcode(neck_instruction);
449                        if neck_opcode != insts::OP_SUB {
450                            return Ok(None);
451                        }
452                        let neck_inst = Rtype(neck_instruction);
453                        let neck_size = instruction_length(neck_instruction);
454                        if neck_inst.rd() != head_inst.rs1()
455                            || neck_inst.rs1() != head_inst.rs2()
456                            || neck_inst.rs2() == head_inst.rs1()
457                            || neck_inst.rs2() == head_inst.rs2()
458                            || neck_inst.rs2() == next_inst.rd()
459                        {
460                            return Ok(None);
461                        }
462                        let body_instruction = decoder.decode_raw(
463                            memory,
464                            pc + head_size as u64 + next_size as u64 + neck_size as u64,
465                        )?;
466                        let body_opcode = extract_opcode(body_instruction);
467                        if body_opcode != insts::OP_SLTU {
468                            return Ok(None);
469                        }
470                        let body_inst = Rtype(body_instruction);
471                        let body_size = instruction_length(body_instruction);
472                        if body_inst.rd() != neck_inst.rs2()
473                            || body_inst.rs1() != head_inst.rs2()
474                            || body_inst.rs2() != head_inst.rs1()
475                        {
476                            return Ok(None);
477                        }
478                        let tail_instruction = decoder.decode_raw(
479                            memory,
480                            pc + head_size as u64
481                                + next_size as u64
482                                + neck_size as u64
483                                + body_size as u64,
484                        )?;
485                        let tail_opcode = extract_opcode(tail_instruction);
486                        if tail_opcode != insts::OP_OR {
487                            return Ok(None);
488                        }
489                        let tail_inst = Rtype(tail_instruction);
490                        let tail_size = instruction_length(tail_instruction);
491                        if tail_inst.rd() != head_inst.rd()
492                            || tail_inst.rs1() != neck_inst.rs2()
493                            || tail_inst.rs2() != next_inst.rd()
494                        {
495                            return Ok(None);
496                        }
497                        let fuze_inst = R4type::new(
498                            insts::OP_SBB,
499                            head_inst.rs1(),
500                            head_inst.rs2(),
501                            neck_inst.rs2(),
502                            next_inst.rd(),
503                        );
504                        if head_inst.rs1() == ZERO
505                            || head_inst.rs2() == ZERO
506                            || neck_inst.rs2() == ZERO
507                            || next_inst.rd() == ZERO
508                        {
509                            return Ok(None);
510                        }
511                        let fuze_size = head_size + next_size + neck_size + body_size + tail_size;
512                        Ok(Some(set_instruction_length_n(fuze_inst.0, fuze_size)))
513                    };
514                let rule_sbbs =
515                    |decoder: &mut Self, memory: &mut M| -> Result<Option<Instruction>, Error> {
516                        // sub r0, r1, r2
517                        // sltu r3, r1, r2
518                        //
519                        // r0 != r1
520                        // r0 != r2
521                        if decoder.version < VERSION2 {
522                            return Ok(None);
523                        }
524
525                        let i0 = Rtype(head_instruction);
526                        let i0_size = instruction_length(head_instruction);
527
528                        let (i1, i1_size) = {
529                            let i1 = decoder.decode_raw(memory, pc + i0_size as u64)?;
530                            let i1_opcode = extract_opcode(i1);
531                            if i1_opcode != insts::OP_SLTU {
532                                return Ok(None);
533                            }
534                            (Rtype(i1), instruction_length(i1))
535                        };
536
537                        let r0 = i0.rd();
538                        let r1 = i0.rs1();
539                        let r2 = i0.rs2();
540                        let r3 = i1.rd();
541
542                        if i0.rd() == r0
543                            && i0.rs1() == r1
544                            && i0.rs2() == r2
545                            && i1.rd() == r3
546                            && i1.rs1() == r1
547                            && i1.rs2() == r2
548                            && r0 != r1
549                            && r0 != r2
550                        {
551                            let fuze_inst = R4type::new(insts::OP_SBBS, r0, r1, r2, r3);
552                            let fuze_size = i0_size + i1_size;
553                            Ok(Some(set_instruction_length_n(fuze_inst.0, fuze_size)))
554                        } else {
555                            Ok(None)
556                        }
557                    };
558                if let Ok(Some(i)) = rule_sbb(self, memory) {
559                    Ok(i)
560                } else if let Ok(Some(i)) = rule_sbbs(self, memory) {
561                    Ok(i)
562                } else {
563                    Ok(head_instruction)
564                }
565            }
566            insts::OP_LUI => {
567                let head_inst = Utype(head_instruction);
568                let head_size = instruction_length(head_instruction);
569                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
570                    Ok(ni) => ni,
571                    Err(_) => return Ok(head_instruction),
572                };
573                let next_opcode = extract_opcode(next_instruction);
574                match next_opcode {
575                    insts::OP_JALR_VERSION1 => {
576                        let next_inst = Itype(next_instruction);
577                        let test_condition = if self.version >= VERSION2 {
578                            next_inst.rs1() == head_inst.rd()
579                                && next_inst.rd() == RA
580                                && next_inst.rs1() == RA
581                        } else {
582                            next_inst.rs1() == head_inst.rd() && next_inst.rd() == RA
583                        };
584                        if test_condition {
585                            let fuze_imm = head_inst
586                                .immediate_s()
587                                .wrapping_add(next_inst.immediate_s());
588                            let fuze_inst = Utype::new_s(insts::OP_FAR_JUMP_ABS, RA, fuze_imm);
589                            let next_size = instruction_length(next_instruction);
590                            let fuze_size = head_size + next_size;
591                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
592                        } else {
593                            Ok(head_instruction)
594                        }
595                    }
596                    insts::OP_ADDIW => {
597                        let next_inst = Itype(next_instruction);
598                        if next_inst.rs1() == next_inst.rd() && next_inst.rd() == head_inst.rd() {
599                            let fuze_imm = head_inst
600                                .immediate_s()
601                                .wrapping_add(next_inst.immediate_s());
602                            let fuze_inst =
603                                Utype::new_s(insts::OP_CUSTOM_LOAD_IMM, head_inst.rd(), fuze_imm);
604                            let next_size = instruction_length(next_instruction);
605                            let fuze_size = head_size + next_size;
606                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
607                        } else {
608                            Ok(head_instruction)
609                        }
610                    }
611                    _ => Ok(head_instruction),
612                }
613            }
614            insts::OP_AUIPC => {
615                let head_inst = Utype(head_instruction);
616                let head_size = instruction_length(head_instruction);
617                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
618                    Ok(ni) => ni,
619                    Err(_) => return Ok(head_instruction),
620                };
621                let next_opcode = extract_opcode(next_instruction);
622                match next_opcode {
623                    insts::OP_JALR_VERSION1 => {
624                        let next_inst = Itype(next_instruction);
625                        let mut result = head_instruction;
626
627                        if self.version >= VERSION2 {
628                            if next_inst.rs1() == head_inst.rd()
629                                && next_inst.rd() == RA
630                                && next_inst.rs1() == RA
631                            {
632                                if let Some(fuze_imm) =
633                                    head_inst.immediate_s().checked_add(next_inst.immediate_s())
634                                {
635                                    let fuze_inst =
636                                        Utype::new_s(insts::OP_FAR_JUMP_REL, RA, fuze_imm);
637                                    let next_size = instruction_length(next_instruction);
638                                    let fuze_size = head_size + next_size;
639                                    result = set_instruction_length_n(fuze_inst.0, fuze_size);
640                                }
641                            }
642                        } else {
643                            if next_inst.rs1() == head_inst.rd() && next_inst.rd() == RA {
644                                let fuze_imm = head_inst
645                                    .immediate_s()
646                                    .wrapping_add(next_inst.immediate_s());
647                                let fuze_inst = Utype::new_s(insts::OP_FAR_JUMP_REL, RA, fuze_imm);
648                                let next_size = instruction_length(next_instruction);
649                                let fuze_size = head_size + next_size;
650                                result = set_instruction_length_n(fuze_inst.0, fuze_size);
651                            }
652                        }
653                        Ok(result)
654                    }
655                    insts::OP_ADDI if self.version >= VERSION2 => {
656                        let next_inst = Itype(next_instruction);
657                        let mut result = head_instruction;
658
659                        if next_inst.rs1() == next_inst.rd() && next_inst.rd() == head_inst.rd() {
660                            if let Ok(pc) = i32::try_from(pc) {
661                                if let Some(fuze_imm) = head_inst
662                                    .immediate_s()
663                                    .checked_add(next_inst.immediate_s())
664                                    .and_then(|s| s.checked_add(pc))
665                                {
666                                    let fuze_inst = Utype::new_s(
667                                        insts::OP_CUSTOM_LOAD_IMM,
668                                        head_inst.rd(),
669                                        fuze_imm,
670                                    );
671                                    let next_size = instruction_length(next_instruction);
672                                    let fuze_size = head_size + next_size;
673                                    result = set_instruction_length_n(fuze_inst.0, fuze_size);
674                                }
675                            }
676                        }
677                        Ok(result)
678                    }
679                    _ => Ok(head_instruction),
680                }
681            }
682            insts::OP_MULH => {
683                let head_inst = Rtype(head_instruction);
684                let head_size = instruction_length(head_instruction);
685                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
686                    Ok(ni) => ni,
687                    Err(_) => return Ok(head_instruction),
688                };
689                let next_opcode = extract_opcode(next_instruction);
690                match next_opcode {
691                    insts::OP_MUL => {
692                        let next_inst = Rtype(next_instruction);
693                        if head_inst.rd() != head_inst.rs1()
694                            && head_inst.rd() != head_inst.rs2()
695                            && head_inst.rs1() == next_inst.rs1()
696                            && head_inst.rs2() == next_inst.rs2()
697                            && head_inst.rd() != next_inst.rd()
698                        {
699                            let next_size = instruction_length(next_instruction);
700                            let fuze_inst = R4type::new(
701                                insts::OP_WIDE_MUL,
702                                head_inst.rd(),
703                                head_inst.rs1(),
704                                head_inst.rs2(),
705                                next_inst.rd(),
706                            );
707                            let fuze_size = head_size + next_size;
708                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
709                        } else {
710                            Ok(head_instruction)
711                        }
712                    }
713                    _ => Ok(head_instruction),
714                }
715            }
716            insts::OP_MULHU => {
717                let head_inst = Rtype(head_instruction);
718                let head_size = instruction_length(head_instruction);
719                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
720                    Ok(ni) => ni,
721                    Err(_) => return Ok(head_instruction),
722                };
723                let next_opcode = extract_opcode(next_instruction);
724                match next_opcode {
725                    insts::OP_MUL => {
726                        let next_inst = Rtype(next_instruction);
727                        if head_inst.rd() != head_inst.rs1()
728                            && head_inst.rd() != head_inst.rs2()
729                            && head_inst.rs1() == next_inst.rs1()
730                            && head_inst.rs2() == next_inst.rs2()
731                            && head_inst.rd() != next_inst.rd()
732                        {
733                            let next_size = instruction_length(next_instruction);
734                            let fuze_inst = R4type::new(
735                                insts::OP_WIDE_MULU,
736                                head_inst.rd(),
737                                head_inst.rs1(),
738                                head_inst.rs2(),
739                                next_inst.rd(),
740                            );
741                            let fuze_size = head_size + next_size;
742                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
743                        } else {
744                            Ok(head_instruction)
745                        }
746                    }
747                    _ => Ok(head_instruction),
748                }
749            }
750            insts::OP_MULHSU => {
751                let head_inst = Rtype(head_instruction);
752                let head_size = instruction_length(head_instruction);
753                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
754                    Ok(ni) => ni,
755                    Err(_) => return Ok(head_instruction),
756                };
757                let next_opcode = extract_opcode(next_instruction);
758                match next_opcode {
759                    insts::OP_MUL => {
760                        let next_inst = Rtype(next_instruction);
761                        if head_inst.rd() != head_inst.rs1()
762                            && head_inst.rd() != head_inst.rs2()
763                            && head_inst.rs1() == next_inst.rs1()
764                            && head_inst.rs2() == next_inst.rs2()
765                            && head_inst.rd() != next_inst.rd()
766                        {
767                            let next_size = instruction_length(next_instruction);
768                            let fuze_inst = R4type::new(
769                                insts::OP_WIDE_MULSU,
770                                head_inst.rd(),
771                                head_inst.rs1(),
772                                head_inst.rs2(),
773                                next_inst.rd(),
774                            );
775                            let fuze_size = head_size + next_size;
776                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
777                        } else {
778                            Ok(head_instruction)
779                        }
780                    }
781                    _ => Ok(head_instruction),
782                }
783            }
784            insts::OP_DIV => {
785                let head_inst = Rtype(head_instruction);
786                let head_size = instruction_length(head_instruction);
787                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
788                    Ok(ni) => ni,
789                    Err(_) => return Ok(head_instruction),
790                };
791                let next_opcode = extract_opcode(next_instruction);
792                match next_opcode {
793                    insts::OP_REM => {
794                        let next_inst = Rtype(next_instruction);
795                        if head_inst.rd() != head_inst.rs1()
796                            && head_inst.rd() != head_inst.rs2()
797                            && head_inst.rs1() == next_inst.rs1()
798                            && head_inst.rs2() == next_inst.rs2()
799                            && head_inst.rd() != next_inst.rd()
800                        {
801                            let next_size = instruction_length(next_instruction);
802                            let fuze_inst = R4type::new(
803                                insts::OP_WIDE_DIV,
804                                head_inst.rd(),
805                                head_inst.rs1(),
806                                head_inst.rs2(),
807                                next_inst.rd(),
808                            );
809                            let fuze_size = head_size + next_size;
810                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
811                        } else {
812                            Ok(head_instruction)
813                        }
814                    }
815                    _ => Ok(head_instruction),
816                }
817            }
818            insts::OP_DIVU => {
819                let head_inst = Rtype(head_instruction);
820                let head_size = instruction_length(head_instruction);
821                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
822                    Ok(ni) => ni,
823                    Err(_) => return Ok(head_instruction),
824                };
825                let next_opcode = extract_opcode(next_instruction);
826                match next_opcode {
827                    insts::OP_REMU => {
828                        let next_inst = Rtype(next_instruction);
829                        if head_inst.rd() != head_inst.rs1()
830                            && head_inst.rd() != head_inst.rs2()
831                            && head_inst.rs1() == next_inst.rs1()
832                            && head_inst.rs2() == next_inst.rs2()
833                            && head_inst.rd() != next_inst.rd()
834                        {
835                            let next_size = instruction_length(next_instruction);
836                            let fuze_inst = R4type::new(
837                                insts::OP_WIDE_DIVU,
838                                head_inst.rd(),
839                                head_inst.rs1(),
840                                head_inst.rs2(),
841                                next_inst.rd(),
842                            );
843                            let fuze_size = head_size + next_size;
844                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
845                        } else {
846                            Ok(head_instruction)
847                        }
848                    }
849                    _ => Ok(head_instruction),
850                }
851            }
852            _ => Ok(head_instruction),
853        }
854    }
855
856    pub fn decode<M: Memory>(&mut self, memory: &mut M, pc: u64) -> Result<Instruction, Error> {
857        if self.mop {
858            self.decode_mop(memory, pc)
859        } else {
860            self.decode_raw(memory, pc)
861        }
862    }
863
864    pub fn reset_instructions_cache(&mut self) {
865        self.instructions_cache = vec![(u64::MAX, 0); INSTRUCTION_CACHE_SIZE];
866    }
867}
868
869pub fn build_decoder<R: Register>(isa: u8, version: u32) -> Decoder {
870    let mut decoder = Decoder::new(isa & ISA_MOP != 0, version);
871    decoder.add_instruction_factory(rvc::factory::<R>);
872    decoder.add_instruction_factory(i::factory::<R>);
873    decoder.add_instruction_factory(m::factory::<R>);
874    if isa & ISA_B != 0 {
875        decoder.add_instruction_factory(b::factory::<R>);
876    }
877    if isa & ISA_A != 0 {
878        decoder.add_instruction_factory(a::factory::<R>);
879    }
880    decoder
881}