Skip to main content

ckb_vm/
decoder.rs

1use ckb_vm_definitions::instructions::{self as insts};
2use ckb_vm_definitions::registers::{RA, ZERO};
3
4use crate::instructions::{
5    Instruction, InstructionFactory, Itype, R4type, R5type, Register, Rtype, Utype, a, b,
6    extract_opcode, i, instruction_length, m, rvc, set_instruction_length_n,
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                                && let Some(fuze_imm) =
632                                    head_inst.immediate_s().checked_add(next_inst.immediate_s())
633                            {
634                                let fuze_inst = Utype::new_s(insts::OP_FAR_JUMP_REL, RA, fuze_imm);
635                                let next_size = instruction_length(next_instruction);
636                                let fuze_size = head_size + next_size;
637                                result = set_instruction_length_n(fuze_inst.0, fuze_size);
638                            }
639                        } else {
640                            if next_inst.rs1() == head_inst.rd() && next_inst.rd() == RA {
641                                let fuze_imm = head_inst
642                                    .immediate_s()
643                                    .wrapping_add(next_inst.immediate_s());
644                                let fuze_inst = Utype::new_s(insts::OP_FAR_JUMP_REL, RA, fuze_imm);
645                                let next_size = instruction_length(next_instruction);
646                                let fuze_size = head_size + next_size;
647                                result = set_instruction_length_n(fuze_inst.0, fuze_size);
648                            }
649                        }
650                        Ok(result)
651                    }
652                    insts::OP_ADDI if self.version >= VERSION2 => {
653                        let next_inst = Itype(next_instruction);
654                        let mut result = head_instruction;
655
656                        if next_inst.rs1() == next_inst.rd()
657                            && next_inst.rd() == head_inst.rd()
658                            && let Ok(pc) = i32::try_from(pc)
659                            && let Some(fuze_imm) = head_inst
660                                .immediate_s()
661                                .checked_add(next_inst.immediate_s())
662                                .and_then(|s| s.checked_add(pc))
663                        {
664                            let fuze_inst =
665                                Utype::new_s(insts::OP_CUSTOM_LOAD_IMM, head_inst.rd(), fuze_imm);
666                            let next_size = instruction_length(next_instruction);
667                            let fuze_size = head_size + next_size;
668                            result = set_instruction_length_n(fuze_inst.0, fuze_size);
669                        }
670                        Ok(result)
671                    }
672                    _ => Ok(head_instruction),
673                }
674            }
675            insts::OP_MULH => {
676                let head_inst = Rtype(head_instruction);
677                let head_size = instruction_length(head_instruction);
678                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
679                    Ok(ni) => ni,
680                    Err(_) => return Ok(head_instruction),
681                };
682                let next_opcode = extract_opcode(next_instruction);
683                match next_opcode {
684                    insts::OP_MUL => {
685                        let next_inst = Rtype(next_instruction);
686                        if head_inst.rd() != head_inst.rs1()
687                            && head_inst.rd() != head_inst.rs2()
688                            && head_inst.rs1() == next_inst.rs1()
689                            && head_inst.rs2() == next_inst.rs2()
690                            && head_inst.rd() != next_inst.rd()
691                        {
692                            let next_size = instruction_length(next_instruction);
693                            let fuze_inst = R4type::new(
694                                insts::OP_WIDE_MUL,
695                                head_inst.rd(),
696                                head_inst.rs1(),
697                                head_inst.rs2(),
698                                next_inst.rd(),
699                            );
700                            let fuze_size = head_size + next_size;
701                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
702                        } else {
703                            Ok(head_instruction)
704                        }
705                    }
706                    _ => Ok(head_instruction),
707                }
708            }
709            insts::OP_MULHU => {
710                let head_inst = Rtype(head_instruction);
711                let head_size = instruction_length(head_instruction);
712                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
713                    Ok(ni) => ni,
714                    Err(_) => return Ok(head_instruction),
715                };
716                let next_opcode = extract_opcode(next_instruction);
717                match next_opcode {
718                    insts::OP_MUL => {
719                        let next_inst = Rtype(next_instruction);
720                        if head_inst.rd() != head_inst.rs1()
721                            && head_inst.rd() != head_inst.rs2()
722                            && head_inst.rs1() == next_inst.rs1()
723                            && head_inst.rs2() == next_inst.rs2()
724                            && head_inst.rd() != next_inst.rd()
725                        {
726                            let next_size = instruction_length(next_instruction);
727                            let fuze_inst = R4type::new(
728                                insts::OP_WIDE_MULU,
729                                head_inst.rd(),
730                                head_inst.rs1(),
731                                head_inst.rs2(),
732                                next_inst.rd(),
733                            );
734                            let fuze_size = head_size + next_size;
735                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
736                        } else {
737                            Ok(head_instruction)
738                        }
739                    }
740                    _ => Ok(head_instruction),
741                }
742            }
743            insts::OP_MULHSU => {
744                let head_inst = Rtype(head_instruction);
745                let head_size = instruction_length(head_instruction);
746                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
747                    Ok(ni) => ni,
748                    Err(_) => return Ok(head_instruction),
749                };
750                let next_opcode = extract_opcode(next_instruction);
751                match next_opcode {
752                    insts::OP_MUL => {
753                        let next_inst = Rtype(next_instruction);
754                        if head_inst.rd() != head_inst.rs1()
755                            && head_inst.rd() != head_inst.rs2()
756                            && head_inst.rs1() == next_inst.rs1()
757                            && head_inst.rs2() == next_inst.rs2()
758                            && head_inst.rd() != next_inst.rd()
759                        {
760                            let next_size = instruction_length(next_instruction);
761                            let fuze_inst = R4type::new(
762                                insts::OP_WIDE_MULSU,
763                                head_inst.rd(),
764                                head_inst.rs1(),
765                                head_inst.rs2(),
766                                next_inst.rd(),
767                            );
768                            let fuze_size = head_size + next_size;
769                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
770                        } else {
771                            Ok(head_instruction)
772                        }
773                    }
774                    _ => Ok(head_instruction),
775                }
776            }
777            insts::OP_DIV => {
778                let head_inst = Rtype(head_instruction);
779                let head_size = instruction_length(head_instruction);
780                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
781                    Ok(ni) => ni,
782                    Err(_) => return Ok(head_instruction),
783                };
784                let next_opcode = extract_opcode(next_instruction);
785                match next_opcode {
786                    insts::OP_REM => {
787                        let next_inst = Rtype(next_instruction);
788                        if head_inst.rd() != head_inst.rs1()
789                            && head_inst.rd() != head_inst.rs2()
790                            && head_inst.rs1() == next_inst.rs1()
791                            && head_inst.rs2() == next_inst.rs2()
792                            && head_inst.rd() != next_inst.rd()
793                        {
794                            let next_size = instruction_length(next_instruction);
795                            let fuze_inst = R4type::new(
796                                insts::OP_WIDE_DIV,
797                                head_inst.rd(),
798                                head_inst.rs1(),
799                                head_inst.rs2(),
800                                next_inst.rd(),
801                            );
802                            let fuze_size = head_size + next_size;
803                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
804                        } else {
805                            Ok(head_instruction)
806                        }
807                    }
808                    _ => Ok(head_instruction),
809                }
810            }
811            insts::OP_DIVU => {
812                let head_inst = Rtype(head_instruction);
813                let head_size = instruction_length(head_instruction);
814                let next_instruction = match self.decode_raw(memory, pc + head_size as u64) {
815                    Ok(ni) => ni,
816                    Err(_) => return Ok(head_instruction),
817                };
818                let next_opcode = extract_opcode(next_instruction);
819                match next_opcode {
820                    insts::OP_REMU => {
821                        let next_inst = Rtype(next_instruction);
822                        if head_inst.rd() != head_inst.rs1()
823                            && head_inst.rd() != head_inst.rs2()
824                            && head_inst.rs1() == next_inst.rs1()
825                            && head_inst.rs2() == next_inst.rs2()
826                            && head_inst.rd() != next_inst.rd()
827                        {
828                            let next_size = instruction_length(next_instruction);
829                            let fuze_inst = R4type::new(
830                                insts::OP_WIDE_DIVU,
831                                head_inst.rd(),
832                                head_inst.rs1(),
833                                head_inst.rs2(),
834                                next_inst.rd(),
835                            );
836                            let fuze_size = head_size + next_size;
837                            Ok(set_instruction_length_n(fuze_inst.0, fuze_size))
838                        } else {
839                            Ok(head_instruction)
840                        }
841                    }
842                    _ => Ok(head_instruction),
843                }
844            }
845            _ => Ok(head_instruction),
846        }
847    }
848
849    pub fn decode<M: Memory>(&mut self, memory: &mut M, pc: u64) -> Result<Instruction, Error> {
850        if self.mop {
851            self.decode_mop(memory, pc)
852        } else {
853            self.decode_raw(memory, pc)
854        }
855    }
856
857    pub fn reset_instructions_cache(&mut self) {
858        self.instructions_cache = vec![(u64::MAX, 0); INSTRUCTION_CACHE_SIZE];
859    }
860}
861
862pub fn build_decoder<R: Register>(isa: u8, version: u32) -> Decoder {
863    let mut decoder = Decoder::new(isa & ISA_MOP != 0, version);
864    decoder.add_instruction_factory(rvc::factory::<R>);
865    decoder.add_instruction_factory(i::factory::<R>);
866    decoder.add_instruction_factory(m::factory::<R>);
867    if isa & ISA_B != 0 {
868        decoder.add_instruction_factory(b::factory::<R>);
869    }
870    if isa & ISA_A != 0 {
871        decoder.add_instruction_factory(a::factory::<R>);
872    }
873    decoder
874}