1use crate::opcodes::{
9 AtomicOp, BitOpType, CmpOp, ControlOp, CvtType, F16Op, F16PackedOp, F64DivSqrtOp, F64Op,
10 FUnaryOp, MemWidth, MiscOp, Opcode, Scope, SyncOp, WaveOpType, WaveReduceType,
11};
12
13#[derive(Debug, Clone, PartialEq)]
15pub struct DecodedInstruction {
16 pub offset: u32,
18 pub size: u8,
20 pub operation: Operation,
22 pub predicate: u8,
24 pub predicate_negated: bool,
26}
27
28#[derive(Debug, Clone, PartialEq)]
30pub enum Operation {
31 Iadd {
32 rd: u8,
33 rs1: u8,
34 rs2: u8,
35 },
36 Isub {
37 rd: u8,
38 rs1: u8,
39 rs2: u8,
40 },
41 Imul {
42 rd: u8,
43 rs1: u8,
44 rs2: u8,
45 },
46 ImulHi {
47 rd: u8,
48 rs1: u8,
49 rs2: u8,
50 },
51 Imad {
52 rd: u8,
53 rs1: u8,
54 rs2: u8,
55 rs3: u8,
56 },
57 Idiv {
58 rd: u8,
59 rs1: u8,
60 rs2: u8,
61 },
62 Imod {
63 rd: u8,
64 rs1: u8,
65 rs2: u8,
66 },
67 Ineg {
68 rd: u8,
69 rs1: u8,
70 },
71 Iabs {
72 rd: u8,
73 rs1: u8,
74 },
75 Imin {
76 rd: u8,
77 rs1: u8,
78 rs2: u8,
79 },
80 Imax {
81 rd: u8,
82 rs1: u8,
83 rs2: u8,
84 },
85 Iclamp {
86 rd: u8,
87 rs1: u8,
88 rs2: u8,
89 rs3: u8,
90 },
91
92 Fadd {
93 rd: u8,
94 rs1: u8,
95 rs2: u8,
96 },
97 Fsub {
98 rd: u8,
99 rs1: u8,
100 rs2: u8,
101 },
102 Fmul {
103 rd: u8,
104 rs1: u8,
105 rs2: u8,
106 },
107 Fma {
108 rd: u8,
109 rs1: u8,
110 rs2: u8,
111 rs3: u8,
112 },
113 Fdiv {
114 rd: u8,
115 rs1: u8,
116 rs2: u8,
117 },
118 Fneg {
119 rd: u8,
120 rs1: u8,
121 },
122 Fabs {
123 rd: u8,
124 rs1: u8,
125 },
126 Fmin {
127 rd: u8,
128 rs1: u8,
129 rs2: u8,
130 },
131 Fmax {
132 rd: u8,
133 rs1: u8,
134 rs2: u8,
135 },
136 Fclamp {
137 rd: u8,
138 rs1: u8,
139 rs2: u8,
140 rs3: u8,
141 },
142 Fsqrt {
143 rd: u8,
144 rs1: u8,
145 },
146 FUnary {
147 op: FUnaryOp,
148 rd: u8,
149 rs1: u8,
150 },
151
152 F16 {
153 op: F16Op,
154 rd: u8,
155 rs1: u8,
156 rs2: u8,
157 rs3: Option<u8>,
158 },
159 F16Packed {
160 op: F16PackedOp,
161 rd: u8,
162 rs1: u8,
163 rs2: u8,
164 rs3: Option<u8>,
165 },
166
167 F64 {
168 op: F64Op,
169 rd: u8,
170 rs1: u8,
171 rs2: u8,
172 rs3: Option<u8>,
173 },
174 F64DivSqrt {
175 op: F64DivSqrtOp,
176 rd: u8,
177 rs1: u8,
178 rs2: Option<u8>,
179 },
180
181 And {
182 rd: u8,
183 rs1: u8,
184 rs2: u8,
185 },
186 Or {
187 rd: u8,
188 rs1: u8,
189 rs2: u8,
190 },
191 Xor {
192 rd: u8,
193 rs1: u8,
194 rs2: u8,
195 },
196 Not {
197 rd: u8,
198 rs1: u8,
199 },
200 Shl {
201 rd: u8,
202 rs1: u8,
203 rs2: u8,
204 },
205 Shr {
206 rd: u8,
207 rs1: u8,
208 rs2: u8,
209 },
210 Sar {
211 rd: u8,
212 rs1: u8,
213 rs2: u8,
214 },
215 BitOp {
216 op: BitOpType,
217 rd: u8,
218 rs1: u8,
219 rs2: Option<u8>,
220 rs3: Option<u8>,
221 rs4: Option<u8>,
222 },
223
224 Icmp {
225 op: CmpOp,
226 pd: u8,
227 rs1: u8,
228 rs2: u8,
229 },
230 Ucmp {
231 op: CmpOp,
232 pd: u8,
233 rs1: u8,
234 rs2: u8,
235 },
236 Fcmp {
237 op: CmpOp,
238 pd: u8,
239 rs1: u8,
240 rs2: u8,
241 },
242
243 Select {
244 rd: u8,
245 ps: u8,
246 rs1: u8,
247 rs2: u8,
248 },
249 Cvt {
250 cvt_type: CvtType,
251 rd: u8,
252 rs1: u8,
253 },
254
255 LocalLoad {
256 width: MemWidth,
257 rd: u8,
258 addr: u8,
259 },
260 LocalStore {
261 width: MemWidth,
262 addr: u8,
263 value: u8,
264 },
265
266 DeviceLoad {
267 width: MemWidth,
268 rd: u8,
269 addr: u8,
270 },
271 DeviceStore {
272 width: MemWidth,
273 addr: u8,
274 value: u8,
275 },
276
277 LocalAtomic {
278 op: AtomicOp,
279 rd: Option<u8>,
280 addr: u8,
281 value: u8,
282 },
283 LocalAtomicCas {
284 rd: Option<u8>,
285 addr: u8,
286 expected: u8,
287 desired: u8,
288 },
289
290 DeviceAtomic {
291 op: AtomicOp,
292 rd: Option<u8>,
293 addr: u8,
294 value: u8,
295 scope: Scope,
296 },
297 DeviceAtomicCas {
298 rd: Option<u8>,
299 addr: u8,
300 expected: u8,
301 desired: u8,
302 scope: Scope,
303 },
304
305 WaveOp {
306 op: WaveOpType,
307 rd: u8,
308 rs1: u8,
309 rs2: Option<u8>,
310 },
311 WaveReduce {
312 op: WaveReduceType,
313 rd: u8,
314 rs1: u8,
315 },
316 WaveBallot {
317 rd: u8,
318 ps: u8,
319 },
320 WaveVote {
321 op: WaveOpType,
322 pd: u8,
323 ps: u8,
324 },
325
326 If {
327 ps: u8,
328 },
329 Else,
330 Endif,
331 Loop,
332 Break {
333 ps: u8,
334 },
335 Continue {
336 ps: u8,
337 },
338 Endloop,
339 Call {
340 target: u32,
341 },
342
343 Return,
344 Halt,
345 Barrier,
346 FenceAcquire {
347 scope: Scope,
348 },
349 FenceRelease {
350 scope: Scope,
351 },
352 FenceAcqRel {
353 scope: Scope,
354 },
355 Wait,
356 Nop,
357
358 Mov {
359 rd: u8,
360 rs1: u8,
361 },
362 MovImm {
363 rd: u8,
364 imm: u32,
365 },
366 MovSr {
367 rd: u8,
368 sr_index: u8,
369 },
370
371 Unknown {
372 opcode: u8,
373 word0: u32,
374 word1: Option<u32>,
375 },
376}
377
378impl DecodedInstruction {
379 #[must_use]
381 pub fn mnemonic(&self) -> String {
382 match &self.operation {
383 Operation::Iadd { .. } => "iadd".to_string(),
384 Operation::Isub { .. } => "isub".to_string(),
385 Operation::Imul { .. } => "imul".to_string(),
386 Operation::ImulHi { .. } => "imul_hi".to_string(),
387 Operation::Imad { .. } => "imad".to_string(),
388 Operation::Idiv { .. } => "idiv".to_string(),
389 Operation::Imod { .. } => "imod".to_string(),
390 Operation::Ineg { .. } => "ineg".to_string(),
391 Operation::Iabs { .. } => "iabs".to_string(),
392 Operation::Imin { .. } => "imin".to_string(),
393 Operation::Imax { .. } => "imax".to_string(),
394 Operation::Iclamp { .. } => "iclamp".to_string(),
395
396 Operation::Fadd { .. } => "fadd".to_string(),
397 Operation::Fsub { .. } => "fsub".to_string(),
398 Operation::Fmul { .. } => "fmul".to_string(),
399 Operation::Fma { .. } => "fma".to_string(),
400 Operation::Fdiv { .. } => "fdiv".to_string(),
401 Operation::Fneg { .. } => "fneg".to_string(),
402 Operation::Fabs { .. } => "fabs".to_string(),
403 Operation::Fmin { .. } => "fmin".to_string(),
404 Operation::Fmax { .. } => "fmax".to_string(),
405 Operation::Fclamp { .. } => "fclamp".to_string(),
406 Operation::Fsqrt { .. } => "fsqrt".to_string(),
407 Operation::FUnary { op, .. } => op.mnemonic().to_string(),
408
409 Operation::F16 { op, .. } => op.mnemonic().to_string(),
410 Operation::F16Packed { op, .. } => op.mnemonic().to_string(),
411 Operation::F64 { op, .. } => op.mnemonic().to_string(),
412 Operation::F64DivSqrt { op, .. } => op.mnemonic().to_string(),
413
414 Operation::And { .. } => "and".to_string(),
415 Operation::Or { .. } => "or".to_string(),
416 Operation::Xor { .. } => "xor".to_string(),
417 Operation::Not { .. } => "not".to_string(),
418 Operation::Shl { .. } => "shl".to_string(),
419 Operation::Shr { .. } => "shr".to_string(),
420 Operation::Sar { .. } => "sar".to_string(),
421 Operation::BitOp { op, .. } => op.mnemonic().to_string(),
422
423 Operation::Icmp { op, .. } => format!("icmp_{}", op.suffix()),
424 Operation::Ucmp { op, .. } => format!("ucmp_{}", op.suffix()),
425 Operation::Fcmp { op, .. } => format!("fcmp_{}", op.suffix()),
426
427 Operation::Select { .. } => "select".to_string(),
428 Operation::Cvt { cvt_type, .. } => cvt_type.mnemonic().to_string(),
429
430 Operation::LocalLoad { width, .. } => format!("local_load_{}", width.suffix()),
431 Operation::LocalStore { width, .. } => format!("local_store_{}", width.suffix()),
432 Operation::DeviceLoad { width, .. } => format!("device_load_{}", width.suffix()),
433 Operation::DeviceStore { width, .. } => format!("device_store_{}", width.suffix()),
434
435 Operation::LocalAtomic { op, .. } => format!("local_atomic_{}", op.suffix()),
436 Operation::LocalAtomicCas { .. } => "local_atomic_cas".to_string(),
437 Operation::DeviceAtomic { op, .. } => format!("atomic_{}", op.suffix()),
438 Operation::DeviceAtomicCas { .. } => "atomic_cas".to_string(),
439
440 Operation::WaveOp { op, .. } | Operation::WaveVote { op, .. } => {
441 op.mnemonic().to_string()
442 }
443 Operation::WaveReduce { op, .. } => op.mnemonic().to_string(),
444 Operation::WaveBallot { .. } => "wave_ballot".to_string(),
445
446 Operation::If { .. } => "if".to_string(),
447 Operation::Else => "else".to_string(),
448 Operation::Endif => "endif".to_string(),
449 Operation::Loop => "loop".to_string(),
450 Operation::Break { .. } => "break".to_string(),
451 Operation::Continue { .. } => "continue".to_string(),
452 Operation::Endloop => "endloop".to_string(),
453 Operation::Call { .. } => "call".to_string(),
454
455 Operation::Return => "return".to_string(),
456 Operation::Halt => "halt".to_string(),
457 Operation::Barrier => "barrier".to_string(),
458 Operation::FenceAcquire { .. } => "fence_acquire".to_string(),
459 Operation::FenceRelease { .. } => "fence_release".to_string(),
460 Operation::FenceAcqRel { .. } => "fence_acq_rel".to_string(),
461 Operation::Wait => "wait".to_string(),
462 Operation::Nop => "nop".to_string(),
463
464 Operation::Mov { .. } | Operation::MovSr { .. } => "mov".to_string(),
465 Operation::MovImm { .. } => "mov_imm".to_string(),
466
467 Operation::Unknown { opcode, .. } => format!(".unknown 0x{opcode:02x}"),
468 }
469 }
470
471 #[must_use]
473 pub fn is_control_flow(&self) -> bool {
474 matches!(
475 self.operation,
476 Operation::If { .. }
477 | Operation::Else
478 | Operation::Endif
479 | Operation::Loop
480 | Operation::Break { .. }
481 | Operation::Continue { .. }
482 | Operation::Endloop
483 | Operation::Call { .. }
484 | Operation::Return
485 | Operation::Halt
486 )
487 }
488
489 #[must_use]
491 pub fn is_memory(&self) -> bool {
492 matches!(
493 self.operation,
494 Operation::LocalLoad { .. }
495 | Operation::LocalStore { .. }
496 | Operation::DeviceLoad { .. }
497 | Operation::DeviceStore { .. }
498 | Operation::LocalAtomic { .. }
499 | Operation::LocalAtomicCas { .. }
500 | Operation::DeviceAtomic { .. }
501 | Operation::DeviceAtomicCas { .. }
502 )
503 }
504
505 #[must_use]
507 pub fn is_sync(&self) -> bool {
508 matches!(
509 self.operation,
510 Operation::Barrier
511 | Operation::FenceAcquire { .. }
512 | Operation::FenceRelease { .. }
513 | Operation::FenceAcqRel { .. }
514 | Operation::Wait
515 )
516 }
517
518 #[must_use]
520 pub fn is_wave_op(&self) -> bool {
521 matches!(
522 self.operation,
523 Operation::WaveOp { .. }
524 | Operation::WaveReduce { .. }
525 | Operation::WaveBallot { .. }
526 | Operation::WaveVote { .. }
527 )
528 }
529}
530
531#[must_use]
533pub fn extract_opcode_modifier(instruction: &DecodedInstruction) -> (Opcode, Option<u8>) {
534 match &instruction.operation {
535 Operation::Iadd { .. } => (Opcode::Iadd, None),
536 Operation::Isub { .. } => (Opcode::Isub, None),
537 Operation::Imul { .. } => (Opcode::Imul, None),
538 Operation::ImulHi { .. } => (Opcode::ImulHi, None),
539 Operation::Imad { .. } => (Opcode::Imad, None),
540 Operation::Idiv { .. } => (Opcode::Idiv, None),
541 Operation::Imod { .. } => (Opcode::Imod, None),
542 Operation::Ineg { .. } => (Opcode::Ineg, None),
543 Operation::Iabs { .. } => (Opcode::Iabs, None),
544 Operation::Imin { .. } => (Opcode::Imin, None),
545 Operation::Imax { .. } => (Opcode::Imax, None),
546 Operation::Iclamp { .. } => (Opcode::Iclamp, None),
547
548 Operation::Fadd { .. } => (Opcode::Fadd, None),
549 Operation::Fsub { .. } => (Opcode::Fsub, None),
550 Operation::Fmul { .. } => (Opcode::Fmul, None),
551 Operation::Fma { .. } => (Opcode::Fma, None),
552 Operation::Fdiv { .. } => (Opcode::Fdiv, None),
553 Operation::Fneg { .. } => (Opcode::Fneg, None),
554 Operation::Fabs { .. } => (Opcode::Fabs, None),
555 Operation::Fmin { .. } => (Opcode::Fmin, None),
556 Operation::Fmax { .. } => (Opcode::Fmax, None),
557 Operation::Fclamp { .. } => (Opcode::Fclamp, None),
558 Operation::Fsqrt { .. } => (Opcode::Fsqrt, None),
559 Operation::FUnary { op, .. } => (Opcode::FUnaryOps, Some(*op as u8)),
560
561 Operation::F16 { op, .. } => (Opcode::F16Ops, Some(*op as u8)),
562 Operation::F16Packed { op, .. } => (Opcode::F16PackedOps, Some(*op as u8)),
563 Operation::F64 { op, .. } => (Opcode::F64Ops, Some(*op as u8)),
564 Operation::F64DivSqrt { op, .. } => (Opcode::F64DivSqrt, Some(*op as u8)),
565
566 Operation::And { .. } => (Opcode::And, None),
567 Operation::Or { .. } => (Opcode::Or, None),
568 Operation::Xor { .. } => (Opcode::Xor, None),
569 Operation::Not { .. } => (Opcode::Not, None),
570 Operation::Shl { .. } => (Opcode::Shl, None),
571 Operation::Shr { .. } => (Opcode::Shr, None),
572 Operation::Sar { .. } => (Opcode::Sar, None),
573 Operation::BitOp { op, .. } => (Opcode::BitOps, Some(*op as u8)),
574
575 Operation::Icmp { op, .. } => (Opcode::Icmp, Some(*op as u8)),
576 Operation::Ucmp { op, .. } => (Opcode::Ucmp, Some(*op as u8)),
577 Operation::Fcmp { op, .. } => (Opcode::Fcmp, Some(*op as u8)),
578
579 Operation::Select { .. } => (Opcode::Select, None),
580 Operation::Cvt { cvt_type, .. } => (Opcode::Cvt, Some(*cvt_type as u8)),
581
582 Operation::LocalLoad { width, .. } => (Opcode::LocalLoad, Some(*width as u8)),
583 Operation::LocalStore { width, .. } => (Opcode::LocalStore, Some(*width as u8)),
584 Operation::DeviceLoad { width, .. } => (Opcode::DeviceLoad, Some(*width as u8)),
585 Operation::DeviceStore { width, .. } => (Opcode::DeviceStore, Some(*width as u8)),
586
587 Operation::LocalAtomic { op, .. } => (Opcode::LocalAtomic, Some(*op as u8)),
588 Operation::LocalAtomicCas { .. } => (Opcode::LocalAtomic, None),
589 Operation::DeviceAtomic { op, .. } => (Opcode::DeviceAtomic, Some(*op as u8)),
590 Operation::DeviceAtomicCas { .. } => (Opcode::DeviceAtomic, None),
591
592 Operation::WaveOp { op, .. } | Operation::WaveVote { op, .. } => {
593 (Opcode::WaveOp, Some(*op as u8))
594 }
595 Operation::WaveReduce { op, .. } => (Opcode::WaveOp, Some(*op as u8)),
596 Operation::WaveBallot { .. } => (Opcode::WaveOp, Some(WaveOpType::Ballot as u8)),
597
598 Operation::If { .. } => (Opcode::Control, Some(ControlOp::If as u8)),
599 Operation::Else => (Opcode::Control, Some(ControlOp::Else as u8)),
600 Operation::Endif => (Opcode::Control, Some(ControlOp::Endif as u8)),
601 Operation::Loop => (Opcode::Control, Some(ControlOp::Loop as u8)),
602 Operation::Break { .. } => (Opcode::Control, Some(ControlOp::Break as u8)),
603 Operation::Continue { .. } => (Opcode::Control, Some(ControlOp::Continue as u8)),
604 Operation::Endloop => (Opcode::Control, Some(ControlOp::Endloop as u8)),
605 Operation::Call { .. } => (Opcode::Control, Some(ControlOp::Call as u8)),
606
607 Operation::Return => (Opcode::Control, Some(SyncOp::Return as u8)),
608 Operation::Halt => (Opcode::Control, Some(SyncOp::Halt as u8)),
609 Operation::Barrier => (Opcode::Control, Some(SyncOp::Barrier as u8)),
610 Operation::FenceAcquire { .. } => (Opcode::Control, Some(SyncOp::FenceAcquire as u8)),
611 Operation::FenceRelease { .. } => (Opcode::Control, Some(SyncOp::FenceRelease as u8)),
612 Operation::FenceAcqRel { .. } => (Opcode::Control, Some(SyncOp::FenceAcqRel as u8)),
613 Operation::Wait => (Opcode::Control, Some(SyncOp::Wait as u8)),
614 Operation::Nop => (Opcode::Control, Some(SyncOp::Nop as u8)),
615
616 Operation::Mov { .. } => (Opcode::Control, Some(MiscOp::Mov as u8)),
617 Operation::MovImm { .. } => (Opcode::Control, Some(MiscOp::MovImm as u8)),
618 Operation::MovSr { .. } => (Opcode::Control, Some(MiscOp::MovSr as u8)),
619
620 Operation::Unknown { opcode, .. } => {
621 Opcode::from_u8(*opcode).map_or((Opcode::Control, None), |op| (op, None))
622 }
623 }
624}