1use super::opcodes::Opcode;
2use crate::AsmError;
3use crate::core::arch_traits::Arch;
4use crate::core::buffer::{CodeBuffer, CodeOffset, ConstantData, LabelUse, Reloc, RelocTarget};
5use crate::core::operand::*;
6use crate::core::operand::{Imm, Sym};
7use crate::core::patch::PatchSiteId;
8use crate::core::target::Environment;
9use crate::riscv::instdb::{ANY, OPCODE_FEATURE_CONTEXT, OPCODE_FEATURE_MASKS, SIGNATURE_TABLE};
10use crate::riscv::opcodes::Inst;
11use crate::riscv::opcodes::{ALL_OPCODES, Encoding, OPCODE_XLEN, SHORT_OPCODE};
12use crate::riscv::{Gp, RA};
13pub struct Assembler<'a> {
14 pub(crate) buffer: &'a mut CodeBuffer,
15 last_error: Option<AsmError>,
17}
18
19fn validate_raw_operand(op: &Operand) -> bool {
20 let Some(op_type) = op.signature.try_op_type() else {
21 return false;
22 };
23
24 match op_type {
25 OperandType::None => op.signature.bits() == 0,
26 OperandType::Reg => {
27 let Some(reg_type) = op.signature.try_reg_type() else {
28 return false;
29 };
30 let Some(_) = op.signature.try_reg_group() else {
31 return false;
32 };
33 let expected = crate::riscv::Reg::signature_of(reg_type);
34 let mask = OperandSignature::OP_TYPE_MASK
35 | OperandSignature::REG_TYPE_MASK
36 | OperandSignature::REG_GROUP_MASK
37 | OperandSignature::SIZE_MASK;
38 expected.bits() != 0
39 && op.signature.subset(mask) == expected.subset(mask)
40 && op.id() <= 31
41 }
42 OperandType::Mem => {
43 op.signature.try_mem_base_type().is_some()
44 && op.signature.try_mem_index_type().is_some()
45 }
46 OperandType::Imm | OperandType::Label | OperandType::Sym => true,
47 OperandType::RegList => false,
48 }
49}
50
51impl<'a> Assembler<'a> {
52 pub fn new(buffer: &'a mut CodeBuffer) -> Self {
53 if !matches!(buffer.env().arch(), Arch::RISCV32 | Arch::RISCV64) {
54 return Self::poisoned(buffer, AsmError::InvalidArch);
55 }
56 Self::unchecked(buffer)
57 }
58
59 pub fn try_new(buffer: &'a mut CodeBuffer) -> Result<Self, AsmError> {
60 if !matches!(buffer.env().arch(), Arch::RISCV32 | Arch::RISCV64) {
61 return Err(AsmError::InvalidArch);
62 }
63 Ok(Self::unchecked(buffer))
64 }
65
66 fn unchecked(buffer: &'a mut CodeBuffer) -> Self {
67 Self {
68 buffer,
69 last_error: None,
70 }
71 }
72
73 fn poisoned(buffer: &'a mut CodeBuffer, error: AsmError) -> Self {
74 buffer.record_error(error);
75 Self::unchecked(buffer)
76 }
77
78 pub fn environment(&self) -> &Environment {
80 self.buffer.env()
81 }
82
83 pub fn is_32bit(&self) -> bool {
85 self.buffer.env().is_32bit()
86 }
87
88 pub fn is_64bit(&self) -> bool {
90 self.buffer.env().is_64bit()
91 }
92
93 #[cfg(test)]
94 fn last_error(&self) -> Option<AsmError> {
95 self.buffer.error().cloned()
96 }
97
98 pub fn get_label(&mut self) -> Label {
99 self.buffer.get_label()
100 }
101
102 pub fn bind_label(&mut self, label: Label) {
103 if let Err(error) = self.try_bind_label(label) {
104 self.buffer.record_error(error);
105 }
106 }
107
108 pub fn try_bind_label(&mut self, label: Label) -> Result<(), AsmError> {
109 self.buffer.try_bind_label(label)
110 }
111
112 pub fn add_constant(&mut self, c: impl Into<ConstantData>) -> Label {
113 let c = self.buffer.add_constant(c);
114 self.buffer.get_label_for_constant(c)
115 }
116
117 pub fn label_offset(&self, label: Label) -> CodeOffset {
118 self.buffer.label_offset(label)
119 }
120
121 pub fn data(&self) -> &[u8] {
122 self.buffer.data()
123 }
124
125 pub fn error(&self) -> Option<&AsmError> {
126 self.buffer.error()
127 }
128
129 pub fn patchable_j(&mut self, label: Label) -> PatchSiteId {
130 if self.buffer.error().is_some() {
131 return PatchSiteId::from_index(usize::MAX);
132 }
133 let checkpoint = self.buffer.checkpoint();
134 let offset = self.buffer.cur_offset();
135 self.j(label);
136 let site = self
137 .buffer
138 .record_label_patch_site(offset, label, LabelUse::RVJal20);
139 if self.buffer.error().is_some() {
140 self.buffer.rollback(checkpoint);
141 return PatchSiteId::from_index(usize::MAX);
142 }
143 site
144 }
145
146 pub fn patchable_call(&mut self, label: Label) -> PatchSiteId {
147 if self.buffer.error().is_some() {
148 return PatchSiteId::from_index(usize::MAX);
149 }
150 let checkpoint = self.buffer.checkpoint();
151 let offset = self.buffer.cur_offset();
152 self.jal(RA, label);
153 let site = self
154 .buffer
155 .record_label_patch_site(offset, label, LabelUse::RVJal20);
156 if self.buffer.error().is_some() {
157 self.buffer.rollback(checkpoint);
158 return PatchSiteId::from_index(usize::MAX);
159 }
160 site
161 }
162
163 pub fn la(&mut self, rd: Gp, target: impl OperandCast) {
164 if self.buffer.error().is_some() {
165 return;
166 }
167 let checkpoint = self.buffer.checkpoint();
168 let target = target.as_operand();
169
170 if target.is_label() {
171 let off = self.buffer.cur_offset();
172 self.buffer
173 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelHi20);
174 self.auipc(rd, imm(0));
175 let off = self.buffer.cur_offset();
176 self.buffer
177 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelLo12I);
178 self.addi(rd, rd, imm(0));
179 } else if target.is_sym() {
180 if self.buffer.env().pic() {
181 let sym = target.as_::<Sym>();
193
194 let auipc_label = self.get_label();
196 self.bind_label(auipc_label);
197 self.buffer
198 .add_reloc(Reloc::RiscvGotHi20, RelocTarget::Sym(sym), 0);
199
200 self.auipc(rd, imm(0));
202 self.buffer
204 .add_reloc(Reloc::RiscvPCRelLo12I, RelocTarget::Label(auipc_label), 0);
205 if self.is_32bit() {
206 self.lw(rd, rd, imm(0));
207 } else {
208 self.ld(rd, rd, imm(0));
209 }
210 } else {
211 let label_data = self.get_label();
221 let label_end = self.get_label();
222
223 if self.is_32bit() {
224 self.emit_n(
225 Opcode::LW as i64,
226 &[rd.as_operand(), rd.as_operand(), label_data.as_operand()],
227 );
228 } else {
229 self.emit_n(
230 Opcode::LD as i64,
231 &[rd.as_operand(), rd.as_operand(), label_data.as_operand()],
232 );
233 }
234 self.j(label_end);
235 self.bind_label(label_data);
236 if self.is_32bit() {
237 self.buffer
238 .add_reloc(Reloc::Abs4, RelocTarget::Sym(target.as_::<Sym>()), 0);
239 self.buffer.put4(0);
240 } else {
241 self.buffer
242 .add_reloc(Reloc::Abs8, RelocTarget::Sym(target.as_::<Sym>()), 0);
243 self.buffer.put8(0);
244 }
245 self.bind_label(label_end);
246 }
247 } else {
248 self.buffer.record_error(AsmError::InvalidOperand);
249 }
250 if self.buffer.error().is_some() {
251 self.buffer.rollback(checkpoint);
252 }
253 }
254
255 pub fn call(&mut self, target: impl OperandCast) {
256 if self.buffer.error().is_some() {
257 return;
258 }
259 let checkpoint = self.buffer.checkpoint();
260 let target = target.as_operand();
261
262 if target.is_label() {
263 let off = self.buffer.cur_offset();
264 self.buffer
265 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelHi20);
266 self.auipc(RA, imm(0));
267 let off = self.buffer.cur_offset();
268 self.buffer
269 .use_label_at_offset(off, target.as_::<Label>(), LabelUse::RVPCRelLo12I);
270 self.jalr(RA, RA, imm(0));
271 } else if target.is_sym() {
272 let sym = target.as_::<Sym>();
273
274 let reloc = Reloc::RiscvCallPlt;
275
276 self.buffer.add_reloc(reloc, RelocTarget::Sym(sym), 0);
277 self.auipc(RA, imm(0));
278 self.jalr(RA, RA, imm(0));
279 } else if target.is_imm() {
280 self.jalr(RA, RA, target.as_::<Imm>());
281 } else if target.is_reg() {
282 self.jalr(RA, target.as_::<Gp>(), imm(0));
283 } else {
284 self.buffer.record_error(AsmError::InvalidOperand);
285 }
286 if self.buffer.error().is_some() {
287 self.buffer.rollback(checkpoint);
288 }
289 }
290}
291macro_rules! enc_ops1 {
292 ($op0:ident) => {
293 OperandType::$op0 as u32
294 };
295}
296
297macro_rules! enc_ops2 {
298 ($op0:ident, $op1:ident) => {
299 (OperandType::$op0 as u32) | ((OperandType::$op1 as u32) << 3)
300 };
301}
302
303macro_rules! enc_ops3 {
304 ($op0:ident, $op1:ident, $op2:ident) => {
305 (OperandType::$op0 as u32)
306 | ((OperandType::$op1 as u32) << 3)
307 | ((OperandType::$op2 as u32) << 6)
308 };
309}
310
311macro_rules! enc_ops4 {
312 ($op0:ident, $op1:ident, $op2:ident, $op3:ident) => {
313 (OperandType::$op0 as u32)
314 | ((OperandType::$op1 as u32) << 3)
315 | ((OperandType::$op2 as u32) << 6)
316 | ((OperandType::$op3 as u32) << 9)
317 };
318}
319
320impl<'a> Assembler<'a> {
321 pub fn emit_n(&mut self, opcode: i64, ops: &[&Operand]) {
322 if let Err(error) = self.try_emit_n(opcode, ops) {
323 self.buffer.record_error(error);
324 }
325 }
326
327 pub fn try_emit_n(&mut self, opcode: i64, ops: &[&Operand]) -> Result<(), AsmError> {
328 if let Some(error) = self.buffer.error().cloned() {
329 return Err(error);
330 }
331 if ops.len() > 5 || ops.iter().any(|op| !validate_raw_operand(op)) {
332 return Err(AsmError::InvalidOperand);
333 }
334 let checkpoint = self.buffer.checkpoint();
335 self.last_error = None;
336 self.emit_n_inner(opcode, ops);
337 if let Some(error) = self.last_error.take() {
338 self.buffer.rollback(checkpoint);
339 return Err(error);
340 }
341 if let Some(error) = self.buffer.error().cloned() {
342 self.buffer.rollback(checkpoint);
343 return Err(error);
344 }
345 Ok(())
346 }
347
348 #[allow(unused_assignments)]
349 fn emit_n_inner(&mut self, opcode: i64, ops: &[&crate::core::operand::Operand]) {
350 let Ok(opcode) = usize::try_from(opcode) else {
351 self.last_error = Some(AsmError::InvalidInstruction);
352 return;
353 };
354 let Some(opcode) = ALL_OPCODES.get(opcode).copied() else {
355 self.last_error = Some(AsmError::InvalidInstruction);
356 return;
357 };
358 if !self
359 .environment()
360 .supports_any_riscv_feature(&OPCODE_FEATURE_MASKS[opcode as usize])
361 {
362 self.last_error = Some(AsmError::MissingCpuFeature {
363 feature: OPCODE_FEATURE_CONTEXT[opcode as usize],
364 });
365 return;
366 }
367 let signature = &SIGNATURE_TABLE[opcode.inst_info().signature_index as usize];
368 let expected_operands = signature
369 .iter()
370 .position(|operand_class| *operand_class == ANY)
371 .unwrap_or(signature.len());
372 if ops.len() != expected_operands {
373 self.last_error = Some(AsmError::InvalidOperand);
374 return;
375 }
376
377 let xlen_bit = if self.is_32bit() { 1 } else { 2 };
380 if OPCODE_XLEN[opcode as usize] & xlen_bit == 0 {
381 self.last_error = Some(AsmError::InvalidInstruction);
382 return;
383 }
384
385 let encoding = opcode.encoding();
386 let is_prime_register = |id| (8..=15).contains(&id);
387
388 let mut inst = Inst::new(opcode).encode();
389 let mut label_use = None;
390
391 let isign3 = match ops {
392 [] => 0,
393 [op0] => op0.op_type() as u32,
394 [op0, op1] => op0.op_type() as u32 + ((op1.op_type() as u32) << 3),
395 [op0, op1, op2, ..] => {
396 op0.op_type() as u32 + ((op1.op_type() as u32) << 3) + ((op2.op_type() as u32) << 6)
397 }
398 };
399
400 let isign4 = match ops {
401 [] => 0,
402 [op0] => op0.op_type() as u32,
403 [op0, op1] => op0.op_type() as u32 + ((op1.op_type() as u32) << 3),
404 [op0, op1, op2] => {
405 op0.op_type() as u32 + ((op1.op_type() as u32) << 3) + ((op2.op_type() as u32) << 6)
406 }
407 [op0, op1, op2, op3, ..] => {
408 op0.op_type() as u32
409 + ((op1.op_type() as u32) << 3)
410 + ((op2.op_type() as u32) << 6)
411 + ((op3.op_type() as u32) << 9)
412 }
413 };
414 let mut short = SHORT_OPCODE[opcode as usize];
415 match encoding {
416 Encoding::Bimm12HiRs1Bimm12lo => {
417 let rs1 = ops[0].id();
418 let imm = if ops[1].is_imm() {
419 ops[1].as_::<Imm>().value() as i32
420 } else if ops[1].is_label() {
421 label_use = Some((ops[1], LabelUse::RVB12));
422 0
423 } else {
424 self.last_error = Some(AsmError::InvalidOperand);
425 return;
426 };
427
428 inst = inst.set_rs1(rs1).set_bimm12lohi(imm);
429 }
430
431 Encoding::Bimm12HiRs1Rs2Bimm12lo => {
432 let rs1 = ops[0].id();
433 let rs2 = ops[1].id();
434
435 let imm = if ops[2].is_imm() {
436 ops[2].as_::<Imm>().value() as i32
437 } else if ops[2].is_label() {
438 label_use = Some((ops[2], LabelUse::RVB12));
439 0
440 } else {
441 self.last_error = Some(AsmError::InvalidOperand);
442 return;
443 };
444
445 inst = inst.set_rs1(rs1).set_rs2(rs2).set_bimm12lohi(imm);
446 }
447
448 Encoding::Bimm12HiRs2Rs1Bimm12lo => {
449 let rs1 = ops[0].id();
450 let rs2 = ops[1].id();
451 let imm = if ops[2].is_imm() {
452 ops[2].as_::<Imm>().value() as i32
453 } else if ops[2].is_label() {
454 label_use = Some((ops[2], LabelUse::RVB12));
455 0
456 } else {
457 self.last_error = Some(AsmError::InvalidOperand);
458 return;
459 };
460
461 inst = inst.set_rs2(rs2).set_rs1(rs1).set_bimm12lohi(imm);
462 }
463
464 Encoding::Bimm12HiRs2Bimm12lo => {
465 let rs2 = ops[0].id();
466 let imm = if ops[1].is_imm() {
467 ops[1].as_::<Imm>().value() as i32
468 } else if ops[1].is_label() {
469 label_use = Some((ops[1], LabelUse::RVB12));
470 0
471 } else {
472 self.last_error = Some(AsmError::InvalidOperand);
473 return;
474 };
475
476 inst = inst.set_rs2(rs2).set_bimm12lohi(imm);
477 }
478
479 Encoding::CImm12 => {
480 short = true;
481 let imm = if ops[0].is_imm() {
482 ops[0].as_::<Imm>().value() as i32
483 } else if ops[0].is_label() {
484 label_use = Some((ops[0], LabelUse::RVCJump));
485 0
486 } else {
487 self.last_error = Some(AsmError::InvalidOperand);
488 return;
489 };
490
491 inst = inst.set_c_imm12(imm)
492 }
493
494 Encoding::CIndex => {
495 short = true;
496 let imm = if ops[0].is_imm() {
497 ops[0].as_::<Imm>().value() as i32
498 } else {
499 self.last_error = Some(AsmError::InvalidOperand);
500 return;
501 };
502 inst = inst.set_c_index(imm as _);
503 }
504
505 Encoding::CMopT => {
506 short = true;
507 let imm = if ops[0].is_imm() {
508 ops[0].as_::<Imm>().value() as i32
509 } else {
510 self.last_error = Some(AsmError::InvalidOperand);
511 return;
512 };
513
514 inst = inst.set_c_mop_t(imm as _);
515 }
516
517 Encoding::CNzimm10hiCNzimm10lo => {
518 short = true;
519 let imm = if ops[0].is_imm() {
520 ops[0].as_::<Imm>().value() as i32
521 } else {
522 self.last_error = Some(AsmError::InvalidOperand);
523 return;
524 };
525
526 if imm == 0 || !(-1024..=1024).contains(&imm) {
527 self.last_error = Some(AsmError::InvalidOperand);
528 return;
529 }
530
531 inst = inst.set_c_nzimm10lohi(imm);
532 }
533
534 Encoding::CNzimm6hiCNzimm6lo => {
535 short = true;
536 let imm = if ops[0].is_imm() {
537 ops[0].as_::<Imm>().value() as i32
538 } else {
539 self.last_error = Some(AsmError::InvalidOperand);
540 return;
541 };
542
543 if imm == 0 || imm > 64 {
544 self.last_error = Some(AsmError::InvalidOperand);
545 return;
546 }
547
548 inst = inst.set_c_nzimm6lohi(imm)
549 }
550
551 Encoding::CRlistCSpimm => {
552 self.last_error = Some(AsmError::UnsupportedInstruction {
553 reason: "RISC-V compressed register-list instructions are not implemented",
554 });
555 return;
556 }
557
558 Encoding::CRs1N0 => {
559 short = true;
560 let rs1 = ops[0].id();
561 inst = inst.set_rs1_n0(rs1);
562 }
563
564 Encoding::CRs2CUimm8spS => {
565 short = true;
566 let rs2 = ops[0].id();
567 let imm = if ops[1].is_imm() {
568 ops[1].as_::<Imm>().value() as i32
569 } else {
570 self.last_error = Some(AsmError::InvalidOperand);
571 return;
572 };
573 if !(0..=256).contains(&imm) {
574 self.last_error = Some(AsmError::InvalidOperand);
575 return;
576 }
577 inst = inst.set_c_uimm8lohi(imm as _).set_c_rs2(rs2);
578 }
579
580 Encoding::CRs2CUimm9spS => {
581 short = true;
582 let rs2 = ops[0].id();
583 let imm = if ops[1].is_imm() {
584 ops[1].as_::<Imm>().value() as i32
585 } else {
586 self.last_error = Some(AsmError::InvalidOperand);
587 return;
588 };
589 if !(0..=511).contains(&imm) {
590 self.last_error = Some(AsmError::InvalidOperand);
591 return;
592 }
593 inst = inst.set_c_rs2(rs2).set_c_uimm9sp_s(imm as _);
594 }
595
596 Encoding::CSreg1CSreg2 => {
597 self.last_error = Some(AsmError::UnsupportedInstruction {
598 reason: "RISC-V compressed saved-register moves are not implemented",
599 });
600 return;
601 }
602
603 Encoding::CsrZimm5 => {
604 let csr_imm = if ops[0].is_imm() {
605 ops[0].as_::<Imm>().value() as i32
606 } else {
607 self.last_error = Some(AsmError::InvalidOperand);
608 return;
609 };
610
611 let zimm = if ops[1].is_imm() {
612 ops[1].as_::<Imm>().value()
613 } else {
614 self.last_error = Some(AsmError::InvalidOperand);
615 return;
616 };
617
618 inst = inst.set_csr(csr_imm as _).set_zimm5(zimm as _);
619 }
620
621 Encoding::Empty => {}
622 Encoding::FmPredSuccRs1Rd => {
623 let fm = if ops[0].is_imm() {
624 ops[0].as_::<Imm>().value() as u8
625 } else {
626 self.last_error = Some(AsmError::InvalidOperand);
627 return;
628 };
629
630 let pred = if ops[1].is_imm() {
631 ops[1].as_::<Imm>().value() as u8
632 } else {
633 self.last_error = Some(AsmError::InvalidOperand);
634 return;
635 };
636
637 let succ = if ops[2].is_imm() {
638 ops[2].as_::<Imm>().value() as u8
639 } else {
640 self.last_error = Some(AsmError::InvalidOperand);
641 return;
642 };
643
644 let rs1 = ops[3].id();
645 let rd = ops[4].id();
646
647 inst = inst
648 .set_fm(fm as _)
649 .set_pred(pred as _)
650 .set_succ(succ as _)
651 .set_rs1(rs1)
652 .set_rd(rd);
653 }
654
655 Encoding::Imm12HiRs1Rs2Imm12lo => {
656 if isign3 == enc_ops3!(Reg, Reg, Imm) {
657 let rs1 = ops[0].id();
658 let rs2 = ops[1].id();
659 let imm = ops[2].as_::<Imm>().value() as i32;
660
661 inst = inst.set_rs1(rs1).set_rs2(rs2).set_imm12lohi(imm);
662 } else {
663 self.last_error = Some(AsmError::InvalidOperand);
664 return;
665 };
666 }
667
668 Encoding::Imm12Rs1Rd => {
669 if opcode == Opcode::FENCEI {
670 } else if isign3 == enc_ops3!(Reg, Reg, Imm) {
672 let rs1 = ops[0].id();
673 let rd = ops[1].id();
674 let imm = ops[2].as_::<Imm>().value() as i32;
675
676 inst = inst.set_rs1(rs1).set_rd(rd).set_imm12(imm);
677 } else {
678 self.last_error = Some(AsmError::InvalidOperand);
679 return;
680 }
681 }
682
683 Encoding::Imm20 => {
684 if isign3 == enc_ops1!(Imm) {
685 let imm = ops[0].as_::<Imm>().value() as i32;
686 inst = inst.set_imm20(imm);
687 } else {
688 self.last_error = Some(AsmError::InvalidOperand);
689 return;
690 }
691 }
692
693 Encoding::Jimm20 => {
694 if isign3 == enc_ops1!(Imm) {
695 let imm = ops[0].as_::<Imm>().value() as i32;
696 inst = inst.set_jimm20(imm);
697 } else if isign3 == enc_ops1!(Label) {
698 label_use = Some((ops[0], LabelUse::RVJal20));
699 inst = inst.set_jimm20(0);
700 } else {
701 self.last_error = Some(AsmError::InvalidOperand);
702 return;
703 }
704 }
705
706 Encoding::MopRT30MopRT2726MopRT2120RdRs1 => {
707 self.last_error = Some(AsmError::UnsupportedInstruction {
708 reason: "RISC-V MOP.RN instructions are not implemented",
709 });
710 return;
711 }
712 Encoding::MopRrT30MopRrT2726RdRs1Rs2 => {
713 self.last_error = Some(AsmError::UnsupportedInstruction {
714 reason: "RISC-V MOP.RR.N instructions are not implemented",
715 });
716 return;
717 }
718
719 Encoding::NfVmRs1Vd => {
720 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
721 let vd = ops[0].id();
722 let rs1 = ops[1].id();
723 let vm = ops[2].as_::<Imm>().value();
724 let nf = ops[3].as_::<Imm>().value();
725 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
726 self.last_error = Some(AsmError::InvalidOperand);
727 return;
728 }
729
730 inst = inst.set_vd(vd).set_rs1(rs1).set_vm(vm as _).set_nf(nf as _);
731 } else {
732 self.last_error = Some(AsmError::InvalidOperand);
733 return;
734 }
735 }
736
737 Encoding::NfVmRs1Vs3 => {
738 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
739 let vs3 = ops[0].id();
740 let rs1 = ops[1].id();
741 let vm = ops[2].as_::<Imm>().value();
742 let nf = ops[3].as_::<Imm>().value();
743 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
744 self.last_error = Some(AsmError::InvalidOperand);
745 return;
746 }
747
748 inst = inst
749 .set_vs3(vs3)
750 .set_rs1(rs1)
751 .set_vm(vm as _)
752 .set_nf(nf as _);
753 } else {
754 self.last_error = Some(AsmError::InvalidOperand);
755 return;
756 }
757 }
758
759 Encoding::NfVmRs2Rs1Vd => {
760 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
761 && ops.get(4).is_some_and(|op| op.is_imm())
762 {
763 let vd = ops[0].id();
764 let rs1 = ops[1].id();
765 let vm = ops[3].as_::<Imm>().value();
766 let nf = ops[4].as_::<Imm>().value();
767 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
768 self.last_error = Some(AsmError::InvalidOperand);
769 return;
770 }
771 let rs2 = ops[2].id();
772 inst = inst
773 .set_rs1(rs1)
774 .set_rs2(rs2)
775 .set_vd(vd)
776 .set_vm(vm as _)
777 .set_nf(nf as _);
778 } else {
779 self.last_error = Some(AsmError::InvalidOperand);
780 return;
781 }
782 }
783
784 Encoding::NfVmRs2Rs1Vs3 => {
785 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
786 && ops.get(4).is_some_and(|op| op.is_imm())
787 {
788 let vs3 = ops[0].id();
789 let rs1 = ops[1].id();
790 let vm = ops[3].as_::<Imm>().value();
791 let nf = ops[4].as_::<Imm>().value();
792 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
793 self.last_error = Some(AsmError::InvalidOperand);
794 return;
795 }
796 let rs2 = ops[2].id();
797 inst = inst
798 .set_rs1(rs1)
799 .set_rs2(rs2)
800 .set_vs3(vs3)
801 .set_vm(vm as _)
802 .set_nf(nf as _);
803 } else {
804 self.last_error = Some(AsmError::InvalidOperand);
805 return;
806 }
807 }
808
809 Encoding::NfVmVs2Rs1Vd => {
810 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
811 && ops.get(4).is_some_and(|op| op.is_imm())
812 {
813 let vd = ops[0].id();
814 let rs1 = ops[1].id();
815 let vs2 = ops[2].id();
816 let vm = ops[3].as_::<Imm>().value();
817 let nf = ops[4].as_::<Imm>().value();
818 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
819 self.last_error = Some(AsmError::InvalidOperand);
820 return;
821 }
822
823 inst = inst
824 .set_rs1(rs1)
825 .set_vd(vd)
826 .set_vs2(vs2)
827 .set_vm(vm as _)
828 .set_nf(nf as _);
829 } else {
830 self.last_error = Some(AsmError::InvalidOperand);
831 return;
832 }
833 }
834
835 Encoding::NfVmVs2Rs1Vs3 => {
836 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
837 && ops.get(4).is_some_and(|op| op.is_imm())
838 {
839 let vs3 = ops[0].id();
840 let rs1 = ops[1].id();
841 let vs2 = ops[2].id();
842 let vm = ops[3].as_::<Imm>().value();
843 let nf = ops[4].as_::<Imm>().value();
844 if !(0..=1).contains(&vm) || !(0..=7).contains(&nf) {
845 self.last_error = Some(AsmError::InvalidOperand);
846 return;
847 }
848
849 inst = inst
850 .set_vs3(vs3)
851 .set_rs1(rs1)
852 .set_vs2(vs2)
853 .set_vm(vm as _)
854 .set_nf(nf as _);
855 } else {
856 self.last_error = Some(AsmError::InvalidOperand);
857 return;
858 }
859 }
860
861 Encoding::Rd => {
862 if isign3 == enc_ops1!(Reg) {
863 let rd = ops[0].id();
864 inst = inst.set_rd(rd);
865 } else {
866 self.last_error = Some(AsmError::InvalidOperand);
867 return;
868 }
869 }
870
871 Encoding::RdCUimm8sphiCUimm8splo => {
872 if isign3 == enc_ops2!(Reg, Imm) {
873 let rd = ops[0].id();
874 let imm = ops[1].as_::<Imm>().value() as u32;
875
876 inst = inst.set_rd(rd).set_c_uimm8splohi(imm);
877 } else {
878 self.last_error = Some(AsmError::InvalidOperand);
879 return;
880 }
881 }
882
883 Encoding::RdCUimm9sphiCUimm9splo => {
884 if isign3 == enc_ops2!(Reg, Imm) {
885 let rd = ops[0].id();
886 let imm = ops[1].as_::<Imm>().value() as u32;
887
888 inst = inst.set_rd(rd).set_c_uimm9splohi(imm);
889 } else {
890 self.last_error = Some(AsmError::InvalidOperand);
891 return;
892 }
893 }
894
895 Encoding::RdCsr => {
896 if isign3 == enc_ops2!(Reg, Imm) {
897 let rd = ops[0].id();
898 let csr = ops[1].as_::<Imm>().value() as u32;
899 inst = inst.set_rd(rd).set_csr(csr);
900 } else {
901 self.last_error = Some(AsmError::InvalidOperand);
902 return;
903 }
904 }
905
906 Encoding::RdCsrZimm5 => {
907 if isign3 == enc_ops3!(Reg, Imm, Imm) {
908 let rd = ops[0].id();
909 let csr = ops[1].as_::<Imm>().value() as u32;
910 let zimm = ops[2].as_::<Imm>().value() as i32;
911 inst = inst.set_rd(rd).set_csr(csr).set_zimm5(zimm);
912 } else {
913 self.last_error = Some(AsmError::InvalidOperand);
914 return;
915 }
916 }
917 Encoding::RdImm20 => {
918 if isign3 == enc_ops2!(Reg, Imm) {
919 let rd = ops[0].id();
920 let imm = ops[1].as_::<Imm>().value() as i32;
921 inst = inst.set_rd(rd).set_imm20(imm);
922 } else if isign3 == enc_ops2!(Reg, Label) {
923 let rd = ops[0].id();
924 label_use = Some((ops[1], LabelUse::RVPCRelHi20));
925 inst = inst.set_rd(rd).set_imm20(0);
926 } else {
927 self.last_error = Some(AsmError::InvalidOperand);
928 return;
929 };
930 }
931
932 Encoding::RdJimm20 => {
933 if isign3 == enc_ops2!(Reg, Imm) {
934 let rd = ops[0].id();
935 let imm = ops[1].as_::<Imm>().value() as i32;
936 inst = inst.set_rd(rd).set_jimm20(imm);
937 } else if isign3 == enc_ops2!(Reg, Label) {
938 let rd = ops[0].id();
939 label_use = Some((ops[1], LabelUse::RVJal20));
940 inst = inst.set_rd(rd).set_jimm20(0);
941 } else {
942 self.last_error = Some(AsmError::InvalidOperand);
943 return;
944 };
945 }
946
947 Encoding::RdN0 => {
948 if isign3 == enc_ops1!(Reg) {
949 let rd = ops[0].id();
950 inst = inst.set_rd_n0(rd);
951 } else {
952 self.last_error = Some(AsmError::InvalidOperand);
953 return;
954 }
955 }
956
957 Encoding::RdN0CImm6loCImm6hi => {
958 short = true;
959 if isign3 == enc_ops2!(Reg, Imm) {
960 let rd = ops[0].id();
961 let imm = ops[1].as_::<Imm>().value() as i32;
962 inst = inst.set_rd_n0(rd).set_c_imm6lohi(imm);
963 } else {
964 self.last_error = Some(AsmError::InvalidOperand);
965 return;
966 }
967 }
968
969 Encoding::RdN0CRs2N0 => {
970 short = true;
971 if isign3 == enc_ops2!(Reg, Reg) {
972 let rd = ops[0].id();
973 let rs1 = ops[1].id();
974 inst = inst.set_rd_n0(rd).set_c_rs2(rs1);
975 } else {
976 self.last_error = Some(AsmError::InvalidOperand);
977 return;
978 }
979 }
980
981 Encoding::RdN0CUimm8sphiCUimm8splo => {
982 short = true;
983 if isign3 == enc_ops2!(Reg, Imm) {
984 let rd = ops[0].id();
985 let imm = ops[1].as_::<Imm>().value() as i32;
986 inst = inst.set_rd_n0(rd).set_c_uimm8splohi(imm as _);
987 } else {
988 self.last_error = Some(AsmError::InvalidOperand);
989 return;
990 }
991 }
992
993 Encoding::RdN0CUimm9sphiCUimm9splo => {
994 short = true;
995 if isign3 == enc_ops2!(Reg, Imm) {
996 let rd = ops[0].id();
997 let imm = ops[1].as_::<Imm>().value() as i32;
998 inst = inst.set_rd_n0(rd).set_c_uimm9splohi(imm as _);
999 } else {
1000 self.last_error = Some(AsmError::InvalidOperand);
1001 return;
1002 }
1003 }
1004
1005 Encoding::RdN2CNzimm18hiCNzimm18lo => {
1006 short = true;
1007 if isign3 == enc_ops2!(Reg, Imm) {
1008 let rd = ops[0].id();
1009 let imm = ops[1].as_::<Imm>().value() as i32;
1010 if imm == 0 {
1011 self.last_error = Some(AsmError::InvalidOperand);
1012 return;
1013 } else {
1014 inst = inst.set_rd_n2(rd).set_c_nzimm18lohi(imm);
1015 }
1016 } else {
1017 self.last_error = Some(AsmError::InvalidOperand);
1018 return;
1019 }
1020 }
1021
1022 Encoding::RdPCNzuimm10 => {
1023 if isign3 == enc_ops2!(Reg, Imm) {
1024 let rd = ops[0].id();
1025 if !is_prime_register(rd) {
1026 self.last_error = Some(AsmError::InvalidOperand);
1027 return;
1028 }
1029 let imm = ops[1].as_::<Imm>().value() as i32;
1030 inst = inst.set_rd_p(rd).set_c_nzimm10lohi(imm);
1031 } else {
1032 self.last_error = Some(AsmError::InvalidOperand);
1033 return;
1034 }
1035 }
1036
1037 Encoding::RdPRs1PCUimm1 => {
1038 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1039 let rd = ops[0].id();
1040 let rs1 = ops[1].id();
1041 if !is_prime_register(rd) || !is_prime_register(rs1) {
1042 self.last_error = Some(AsmError::InvalidOperand);
1043 return;
1044 }
1045 let imm = ops[2].as_::<Imm>().value() as i32;
1046
1047 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm1(imm as _);
1048 } else {
1049 self.last_error = Some(AsmError::InvalidOperand);
1050 return;
1051 }
1052 }
1053
1054 Encoding::RdPRs1PCUimm2 => {
1055 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1056 let rd = ops[0].id();
1057 let rs1 = ops[1].id();
1058 if !is_prime_register(rd) || !is_prime_register(rs1) {
1059 self.last_error = Some(AsmError::InvalidOperand);
1060 return;
1061 }
1062 let imm = ops[2].as_::<Imm>().value() as i32;
1063
1064 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm2(imm as _);
1065 } else {
1066 self.last_error = Some(AsmError::InvalidOperand);
1067 return;
1068 }
1069 }
1070
1071 Encoding::RdPRs1PCUimm7loCUimm7hi => {
1072 short = true;
1073 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1074 let rd = ops[0].id();
1075 let rs1 = ops[1].id();
1076 if !is_prime_register(rd) || !is_prime_register(rs1) {
1077 self.last_error = Some(AsmError::InvalidOperand);
1078 return;
1079 }
1080 let imm = ops[2].as_::<Imm>().value() as i32;
1081 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm7lohi(imm as _);
1082 } else {
1083 self.last_error = Some(AsmError::InvalidOperand);
1084 return;
1085 }
1086 }
1087
1088 Encoding::RdPRs1PCUimm8loCUimm8hi => {
1089 short = true;
1090 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1091 let rd = ops[0].id();
1092 let rs1 = ops[1].id();
1093 if !is_prime_register(rd) || !is_prime_register(rs1) {
1094 self.last_error = Some(AsmError::InvalidOperand);
1095 return;
1096 }
1097 let imm = ops[2].as_::<Imm>().value() as i32;
1098 inst = inst.set_rd_p(rd).set_rs1_p(rs1).set_c_uimm8lohi(imm as _);
1099 } else {
1100 self.last_error = Some(AsmError::InvalidOperand);
1101 return;
1102 }
1103 }
1104
1105 Encoding::RdRs1 => {
1106 if isign3 == enc_ops2!(Reg, Reg) {
1107 let rd = ops[0].id();
1108 let rs1 = ops[1].id();
1109 inst = inst.set_rd(rd).set_rs1(rs1);
1110 } else {
1111 self.last_error = Some(AsmError::InvalidOperand);
1112 return;
1113 }
1114 }
1115
1116 Encoding::RdRs1AqRl => {
1117 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1118 let rd = ops[0].id();
1119 let rs1 = ops[1].id();
1120 let aq = ops[2].as_::<Imm>().value();
1121 let rl = ops[3].as_::<Imm>().value();
1122 if !(0..=1).contains(&aq) || !(0..=1).contains(&rl) {
1123 self.last_error = Some(AsmError::InvalidOperand);
1124 return;
1125 }
1126 inst = inst.set_rd(rd).set_rs1(rs1).set_aq(aq as _).set_rl(rl as _);
1127 } else {
1128 self.last_error = Some(AsmError::InvalidOperand);
1129 return;
1130 }
1131 }
1132
1133 Encoding::RdRs1Csr => {
1134 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1135 let rd = ops[0].id();
1136 let rs1 = ops[1].id();
1137 let imm = ops[2].as_::<Imm>().value() as i32;
1138 inst = inst.set_rd(rd).set_rs1(rs1).set_csr(imm as _);
1139 } else {
1140 self.last_error = Some(AsmError::InvalidOperand);
1141 return;
1142 }
1143 }
1144
1145 Encoding::RdRs1Imm12 => {
1146 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1147 let rd = ops[0].id();
1148 let rs1 = ops[1].id();
1149 let imm = ops[2].as_::<Imm>().value() as i32;
1150 inst = inst.set_rd(rd).set_rs1(rs1).set_imm12(imm);
1151 } else if isign3 == enc_ops3!(Reg, Reg, Label) {
1152 let rd = ops[0].id();
1153 let rs1 = ops[1].id();
1154 if rd != rs1 {
1155 self.last_error = Some(AsmError::InvalidOperand);
1156 return;
1157 }
1158 let off = self.buffer.cur_offset();
1159 self.buffer
1160 .use_label_at_offset(off, ops[2].as_(), LabelUse::RVPCRelHi20);
1161 self.auipc(ops[0].as_::<Gp>(), imm(0));
1162 label_use = Some((ops[2], LabelUse::RVPCRelLo12I));
1163 inst = inst.set_rd(rd).set_rs1(rs1).set_imm12(0);
1164 } else {
1165 self.last_error = Some(AsmError::InvalidOperand);
1166 return;
1167 }
1168 }
1169
1170 Encoding::RdRs1N0 => {
1171 self.last_error = Some(AsmError::UnsupportedInstruction {
1172 reason: "RISC-V RdRs1N0 instructions are not implemented",
1173 });
1174 return;
1175 }
1176
1177 Encoding::RdRs1Rm => {
1178 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1179 let rd = ops[0].id();
1180 let rs1 = ops[1].id();
1181 let rm = ops[2].as_::<Imm>().value() as i32;
1182 if !matches!(rm, 0..=4 | 7) {
1183 self.last_error = Some(AsmError::InvalidOperand);
1184 return;
1185 }
1186 inst = inst.set_rd(rd).set_rs1(rs1).set_rm(rm as _);
1187 } else {
1188 self.last_error = Some(AsmError::InvalidOperand);
1189 return;
1190 }
1191 }
1192 Encoding::RdRs1Rnum => {
1193 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1194 let rd = ops[0].id();
1195 let rs1 = ops[1].id();
1196 let rm = ops[2].as_::<Imm>().value() as i32;
1197 inst = inst.set_rd(rd).set_rs1(rs1).set_rnum(rm as _);
1198 } else {
1199 self.last_error = Some(AsmError::InvalidOperand);
1200 return;
1201 }
1202 }
1203
1204 Encoding::RdRs1Rs2 => {
1205 if isign3 == enc_ops3!(Reg, Reg, Reg) {
1206 let rd = ops[0].id();
1207 let rs1 = ops[1].id();
1208 let rs2 = ops[2].id();
1209 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2);
1210 } else {
1211 self.last_error = Some(AsmError::InvalidOperand);
1212 return;
1213 }
1214 }
1215
1216 Encoding::RdRs1Rs2AqRl => {
1217 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm)
1218 && ops.get(4).is_some_and(|op| op.is_imm())
1219 {
1220 let rd = ops[0].id();
1221 let rs1 = ops[1].id();
1222 let rs2 = ops[2].id();
1223 let aq = ops[3].as_::<Imm>().value();
1224 let rl = ops[4].as_::<Imm>().value();
1225 if !(0..=1).contains(&aq) || !(0..=1).contains(&rl) {
1226 self.last_error = Some(AsmError::InvalidOperand);
1227 return;
1228 }
1229 inst = inst
1230 .set_rd(rd)
1231 .set_rs1(rs1)
1232 .set_rs2(rs2)
1233 .set_aq(aq as _)
1234 .set_rl(rl as _);
1235 } else {
1236 self.last_error = Some(AsmError::InvalidOperand);
1237 return;
1238 }
1239 }
1240
1241 Encoding::RdRs1Rs2Bs => {
1242 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1243 let rd = ops[0].id();
1244 let rs1 = ops[1].id();
1245 let rs2 = ops[2].id();
1246 let imm = ops[3].as_::<Imm>().value() as i32;
1247 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2).set_bs(imm as _);
1248 } else {
1249 self.last_error = Some(AsmError::InvalidOperand);
1250 return;
1251 }
1252 }
1253
1254 Encoding::RdRs1Rs2EqRs1 => {
1255 if isign3 == enc_ops3!(Reg, Reg, Reg) {
1256 let rd = ops[0].id();
1257 let rs1 = ops[1].id();
1258 let rs2 = ops[2].id();
1259 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2_eq_rs1(rs2);
1260 } else {
1261 self.last_error = Some(AsmError::InvalidOperand);
1262 return;
1263 }
1264 }
1265
1266 Encoding::RdRs1Rs2Rm => {
1267 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1268 let rd = ops[0].id();
1269 let rs1 = ops[1].id();
1270 let rs2 = ops[2].id();
1271 let rm = ops[3].as_::<Imm>().value() as i32;
1272 if !matches!(rm, 0..=4 | 7) {
1273 self.last_error = Some(AsmError::InvalidOperand);
1274 return;
1275 }
1276 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2).set_rm(rm as _);
1277 } else {
1278 self.last_error = Some(AsmError::InvalidOperand);
1279 return;
1280 }
1281 }
1282
1283 Encoding::RdRs1Rs2Rs3Rm => {
1284 if isign4 == enc_ops4!(Reg, Reg, Reg, Reg) && ops[4].op_type() == OperandType::Imm {
1285 let rd = ops[0].id();
1286 let rs1 = ops[1].id();
1287 let rs2 = ops[2].id();
1288 let rs3 = ops[3].id();
1289 let rm = ops[4].as_::<Imm>().value() as i32;
1290 if !matches!(rm, 0..=4 | 7) {
1291 self.last_error = Some(AsmError::InvalidOperand);
1292 return;
1293 }
1294
1295 inst = inst
1296 .set_rd(rd)
1297 .set_rs1(rs1)
1298 .set_rs2(rs2)
1299 .set_rs3(rs3)
1300 .set_rm(rm as _);
1301 } else {
1302 self.last_error = Some(AsmError::InvalidOperand);
1303 return;
1304 }
1305 }
1306
1307 Encoding::RdRs1Shamtw => {
1308 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1309 let rd = ops[0].id();
1310 let rs1 = ops[1].id();
1311 let shamt = ops[2].as_::<Imm>().value() as i32;
1312 inst = inst.set_rd(rd).set_rs1(rs1).set_shamtw(shamt as _);
1313 } else {
1314 self.last_error = Some(AsmError::InvalidOperand);
1315 return;
1316 }
1317 }
1318 Encoding::RdRs2 => {
1319 if isign3 == enc_ops2!(Reg, Reg) {
1320 let rd = ops[0].id();
1321 let rs1 = ops[1].id();
1322 inst = inst.set_rd(rd).set_rs1(rs1);
1323 } else {
1324 self.last_error = Some(AsmError::InvalidOperand);
1325 return;
1326 }
1327 }
1328
1329 Encoding::RdZimm5 => {
1330 if isign3 == enc_ops2!(Reg, Imm) {
1331 let rd = ops[0].id();
1332 let imm = ops[1].as_::<Imm>().value() as i32;
1333 inst = inst.set_rd(rd).set_zimm5(imm);
1334 } else {
1335 self.last_error = Some(AsmError::InvalidOperand);
1336 return;
1337 }
1338 }
1339
1340 Encoding::Rs1 => {
1341 if isign3 == enc_ops1!(Reg) {
1342 let rs1 = ops[0].id();
1343 inst = inst.set_rs1(rs1);
1344 } else {
1345 self.last_error = Some(AsmError::InvalidOperand);
1346 return;
1347 }
1348 }
1349
1350 Encoding::Rs1Csr => {
1351 if isign3 == enc_ops2!(Reg, Imm) {
1352 let rs1 = ops[0].id();
1353 let csr = ops[1].as_::<Imm>().value() as i32;
1354 inst = inst.set_rs1(rs1).set_csr(csr as _);
1355 } else {
1356 self.last_error = Some(AsmError::InvalidOperand);
1357 return;
1358 }
1359 }
1360
1361 Encoding::Rs1Imm12hi => {
1362 if isign3 == enc_ops2!(Reg, Imm) {
1363 let rs1 = ops[0].id();
1364 let imm = ops[1].as_::<Imm>().value() as i32;
1365 inst = inst.set_rs1(rs1).set_imm12hi_raw(imm as _);
1366 } else {
1367 self.last_error = Some(AsmError::InvalidOperand);
1368 return;
1369 }
1370 }
1371
1372 Encoding::Rs1N0 => {
1373 short = true;
1374 if isign3 == enc_ops1!(Reg) {
1375 let rs1 = ops[0].id();
1376 inst = inst.set_rs1_n0(rs1);
1377 } else {
1378 self.last_error = Some(AsmError::InvalidOperand);
1379 return;
1380 }
1381 }
1382
1383 Encoding::Rs1PCBimm9loCBimm9hi => {
1384 short = true;
1385 if isign3 == enc_ops2!(Reg, Imm) {
1386 let rs1 = ops[0].id();
1387 let imm = ops[1].as_::<Imm>().value();
1388
1389 inst = inst.set_rs1(rs1).set_c_bimm9lohi(imm as _);
1390 } else if isign3 == enc_ops2!(Reg, Label) {
1391 let rs1 = ops[0].id();
1392 label_use = Some((ops[1], LabelUse::RVCB9));
1393 inst = inst.set_rs1(rs1).set_c_bimm9lohi(0);
1394 } else {
1395 self.last_error = Some(AsmError::InvalidOperand);
1396 return;
1397 }
1398 }
1399
1400 Encoding::Rs1PRs2PCUimm7loCUimm7hi => {
1401 short = true;
1402 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1403 let rs1 = ops[0].id();
1404 let rs2 = ops[1].id();
1405 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1406 self.last_error = Some(AsmError::InvalidOperand);
1407 return;
1408 }
1409 let imm = ops[2].as_::<Imm>().value() as i32;
1410 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm7lohi(imm as _);
1411 } else {
1412 self.last_error = Some(AsmError::InvalidOperand);
1413 return;
1414 }
1415 }
1416
1417 Encoding::Rs1PRs2PCUimm8loCUimm8hi => {
1418 short = true;
1419 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1420 let rs1 = ops[0].id();
1421 let rs2 = ops[1].id();
1422 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1423 self.last_error = Some(AsmError::InvalidOperand);
1424 return;
1425 }
1426 let imm = ops[2].as_::<Imm>().value() as i32;
1427 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm8lohi(imm as _);
1428 } else {
1429 self.last_error = Some(AsmError::InvalidOperand);
1430 return;
1431 }
1432 }
1433
1434 Encoding::Rs1PRs2PCUimm8hiCUimm8lo => {
1435 short = true;
1436 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1437 let rs1 = ops[0].id();
1438 let rs2 = ops[1].id();
1439 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1440 self.last_error = Some(AsmError::InvalidOperand);
1441 return;
1442 }
1443 let imm = ops[2].as_::<Imm>().value() as i32;
1444 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm8lohi(imm as _);
1445 } else {
1446 self.last_error = Some(AsmError::InvalidOperand);
1447 return;
1448 }
1449 }
1450
1451 Encoding::Rs1Rd => {
1452 if opcode == Opcode::FENCETSO {
1453 } else if isign3 == enc_ops2!(Reg, Reg) {
1455 let rd = ops[0].id();
1456 let rs1 = ops[1].id();
1457
1458 inst = inst.set_rd(rd).set_rs1(rs1);
1459 } else {
1460 self.last_error = Some(AsmError::InvalidOperand);
1461 return;
1462 }
1463 }
1464
1465 Encoding::Rs1Rs2 => {
1466 if isign3 == enc_ops2!(Reg, Reg) {
1467 let rs1 = ops[0].id();
1468 let rs2 = ops[1].id();
1469 inst = inst.set_rs1(rs1).set_rs2(rs2);
1470 } else {
1471 self.last_error = Some(AsmError::InvalidOperand);
1472 return;
1473 }
1474 }
1475
1476 Encoding::Rs1Vd => {
1477 if isign3 == enc_ops2!(Reg, Reg) {
1478 let rs1 = ops[1].id();
1479 let vd = ops[0].id();
1480 inst = inst.set_vd(vd).set_rs1(rs1);
1481 } else {
1482 self.last_error = Some(AsmError::InvalidOperand);
1483 return;
1484 }
1485 }
1486 Encoding::Rs1Vs3 => {
1487 if isign3 == enc_ops2!(Reg, Reg) {
1488 let rs1 = ops[1].id();
1489 let vs3 = ops[0].id();
1490 inst = inst.set_rs1(rs1).set_vs3(vs3);
1491 } else {
1492 self.last_error = Some(AsmError::InvalidOperand);
1493 return;
1494 }
1495 }
1496
1497 Encoding::Rs2PRs1PCUimm1 => {
1498 short = true;
1499 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1500 let rs1 = ops[0].id();
1501 let rs2 = ops[1].id();
1502 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1503 self.last_error = Some(AsmError::InvalidOperand);
1504 return;
1505 }
1506 let imm = ops[2].as_::<Imm>().value() as i32;
1507 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm1(imm as _);
1508 } else {
1509 self.last_error = Some(AsmError::InvalidOperand);
1510 return;
1511 }
1512 }
1513
1514 Encoding::Rs2PRs1PCUimm2 => {
1515 short = true;
1516 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1517 let rs1 = ops[0].id();
1518 let rs2 = ops[1].id();
1519 if !is_prime_register(rs1) || !is_prime_register(rs2) {
1520 self.last_error = Some(AsmError::InvalidOperand);
1521 return;
1522 }
1523 let imm = ops[2].as_::<Imm>().value() as i32;
1524 inst = inst.set_rs1_p(rs1).set_rs2_p(rs2).set_c_uimm2(imm as _);
1525 } else {
1526 self.last_error = Some(AsmError::InvalidOperand);
1527 return;
1528 }
1529 }
1530 Encoding::Rs2Rs1Rd => {
1531 if isign3 == enc_ops3!(Reg, Reg, Reg) {
1532 let rd = ops[0].id();
1533 let rs1 = ops[1].id();
1534 let rs2 = ops[2].id();
1535
1536 inst = inst.set_rd(rd).set_rs1(rs1).set_rs2(rs2);
1537 } else {
1538 self.last_error = Some(AsmError::InvalidOperand);
1539 return;
1540 }
1541 }
1542
1543 Encoding::Simm5Vd => {
1544 if isign3 == enc_ops2!(Reg, Imm) {
1545 let vd = ops[0].id();
1546 let imm = ops[1].as_::<Imm>().value() as i8;
1547 inst = inst.set_vd(vd).set_simm5(imm as _);
1548 } else {
1549 self.last_error = Some(AsmError::InvalidOperand);
1550 return;
1551 }
1552 }
1553
1554 Encoding::VmVs2Rd => {
1555 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1556 let rd = ops[0].id();
1557 let vs2 = ops[1].id();
1558 let vm = ops[2].as_::<Imm>().value();
1559 if !(0..=1).contains(&vm) {
1560 self.last_error = Some(AsmError::InvalidOperand);
1561 return;
1562 }
1563 inst = inst.set_rd(rd).set_vs2(vs2).set_vm(vm as _);
1564 } else {
1565 self.last_error = Some(AsmError::InvalidOperand);
1566 return;
1567 }
1568 }
1569
1570 Encoding::VmVd => {
1571 if isign3 == enc_ops2!(Reg, Imm) {
1572 let vd = ops[0].id();
1573 let vm = ops[1].as_::<Imm>().value();
1574 if !(0..=1).contains(&vm) {
1575 self.last_error = Some(AsmError::InvalidOperand);
1576 return;
1577 }
1578 inst = inst.set_vd(vd).set_vm(vm as _);
1579 } else {
1580 self.last_error = Some(AsmError::InvalidOperand);
1581 return;
1582 }
1583 }
1584
1585 Encoding::VmVs2Rs1Vd => {
1586 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1587 let rs1 = ops[2].id();
1588 let vs2 = ops[1].id();
1589 let vm = ops[3].as_::<Imm>().value();
1590 if !(0..=1).contains(&vm) {
1591 self.last_error = Some(AsmError::InvalidOperand);
1592 return;
1593 }
1594 let vd = ops[0].id();
1595 inst = inst.set_vd(vd).set_vm(vm as _).set_rs1(rs1).set_vs2(vs2);
1596 } else {
1597 self.last_error = Some(AsmError::InvalidOperand);
1598 return;
1599 }
1600 }
1601
1602 Encoding::VmVs2Simm5Vd => {
1603 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1604 let simm5 = ops[2].as_::<Imm>().value() as i32;
1605 let vs2 = ops[1].id();
1606 let vm = ops[3].as_::<Imm>().value();
1607 if !(0..=1).contains(&vm) {
1608 self.last_error = Some(AsmError::InvalidOperand);
1609 return;
1610 }
1611 let vd = ops[0].id();
1612 inst = inst
1613 .set_vd(vd)
1614 .set_vm(vm as _)
1615 .set_simm5(simm5)
1616 .set_vs2(vs2);
1617 } else {
1618 self.last_error = Some(AsmError::InvalidOperand);
1619 return;
1620 }
1621 }
1622
1623 Encoding::VmVs2Vd => {
1624 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1625 let vd = ops[0].id();
1626 let vs2 = ops[1].id();
1627 let vm = ops[2].as_::<Imm>().value();
1628 if !(0..=1).contains(&vm) {
1629 self.last_error = Some(AsmError::InvalidOperand);
1630 return;
1631 }
1632
1633 inst = inst.set_vd(vd).set_vs2(vs2).set_vm(vm as _);
1634 } else {
1635 self.last_error = Some(AsmError::InvalidOperand);
1636 return;
1637 }
1638 }
1639
1640 Encoding::VmVs2Vs1Vd => {
1641 if isign4 == enc_ops4!(Reg, Reg, Reg, Imm) {
1642 let vd = ops[0].id();
1643 let vs1 = ops[1].id();
1644 let vs2 = ops[2].id();
1645 let vm = ops[3].as_::<Imm>().value();
1646 if !(0..=1).contains(&vm) {
1647 self.last_error = Some(AsmError::InvalidOperand);
1648 return;
1649 }
1650 inst = inst.set_vd(vd).set_vs1(vs1).set_vs2(vs2).set_vm(vm as _);
1651 } else {
1652 self.last_error = Some(AsmError::InvalidOperand);
1653 return;
1654 }
1655 }
1656
1657 Encoding::VmVs2Zimm5Vd => {
1658 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1659 let vd = ops[0].id();
1660 let vs2 = ops[1].id();
1661 let vm = ops[3].as_::<Imm>().value();
1662 if !(0..=1).contains(&vm) {
1663 self.last_error = Some(AsmError::InvalidOperand);
1664 return;
1665 }
1666 let zimm5 = ops[2].as_::<Imm>().value() as i8;
1667 inst = inst
1668 .set_vd(vd)
1669 .set_vs2(vs2)
1670 .set_vm(vm as _)
1671 .set_zimm5(zimm5 as _);
1672 } else {
1673 self.last_error = Some(AsmError::InvalidOperand);
1674 return;
1675 }
1676 }
1677
1678 Encoding::Vs1Vd => {
1679 if isign3 == enc_ops2!(Reg, Reg) {
1680 let vd = ops[0].id();
1681 let vs1 = ops[1].id();
1682 inst = inst.set_vd(vd).set_vs1(vs1);
1683 } else {
1684 self.last_error = Some(AsmError::InvalidOperand);
1685 return;
1686 }
1687 }
1688
1689 Encoding::Vs2Rd => {
1690 if isign3 == enc_ops2!(Reg, Reg) {
1691 let rd = ops[0].id();
1692 let vs2 = ops[1].id();
1693 inst = inst.set_rd(rd).set_vs2(vs2);
1694 } else {
1695 self.last_error = Some(AsmError::InvalidOperand);
1696 return;
1697 }
1698 }
1699
1700 Encoding::Vs2Rs1Vd => {
1701 if isign4 == enc_ops3!(Reg, Reg, Reg) {
1702 let rs1 = ops[1].id();
1703 let vs2 = ops[2].id();
1704 let vd = ops[0].id();
1705 inst = inst.set_vd(vd).set_vs2(vs2).set_rs1(rs1);
1706 } else {
1707 self.last_error = Some(AsmError::InvalidOperand);
1708 return;
1709 }
1710 }
1711
1712 Encoding::Vs2Simm5Vd => {
1713 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1714 let vd = ops[0].id();
1715 let vs2 = ops[1].id();
1716 let imm = ops[2].as_::<Imm>().value();
1717
1718 inst = inst.set_vd(vd).set_vs2(vs2).set_simm5(imm as _);
1719 } else {
1720 self.last_error = Some(AsmError::InvalidOperand);
1721 return;
1722 }
1723 }
1724
1725 Encoding::Vs2Vd => {
1726 if isign3 == enc_ops2!(Reg, Reg) {
1727 let vd = ops[0].id();
1728 let vs2 = ops[1].id();
1729 inst = inst.set_vd(vd).set_vs2(vs2);
1730 } else {
1731 self.last_error = Some(AsmError::InvalidOperand);
1732 return;
1733 }
1734 }
1735
1736 Encoding::Vs2Vs1Vd => {
1737 if isign4 == enc_ops3!(Reg, Reg, Reg) {
1738 let vd = ops[0].id();
1739 let vs1 = ops[1].id();
1740 let vs2 = ops[2].id();
1741
1742 inst = inst.set_vd(vd).set_vs1(vs1).set_vs2(vs2);
1743 } else {
1744 self.last_error = Some(AsmError::InvalidOperand);
1745 return;
1746 }
1747 }
1748
1749 Encoding::Vs2Zimm5Vd => {
1750 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1751 let vd = ops[0].id();
1752 let vs2 = ops[1].id();
1753 let zimm5 = ops[2].as_::<Imm>().value() as i8;
1754 inst = inst.set_vd(vd).set_vs2(vs2).set_zimm5(zimm5 as _);
1755 } else {
1756 self.last_error = Some(AsmError::InvalidOperand);
1757 return;
1758 }
1759 }
1760
1761 Encoding::Zimm10Zimm5Rd => {
1762 if isign3 == enc_ops3!(Reg, Imm, Imm) {
1763 let rd = ops[0].id();
1764 let uimm = ops[1].as_::<Imm>().value() as i8;
1765 let vtypei = ops[2].as_::<Imm>().value() as i8;
1766 inst = inst.set_rd(rd).set_zimm10(vtypei as _).set_zimm5(uimm as _);
1767 } else {
1768 self.last_error = Some(AsmError::InvalidOperand);
1769 return;
1770 }
1771 }
1772
1773 Encoding::Zimm11Rs1Rd => {
1774 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1775 let rd = ops[0].id();
1776 let rs1 = ops[1].id();
1777 let imm = ops[2].as_::<Imm>().value() as i32;
1778 inst = inst.set_rd(rd).set_rs1(rs1).set_zimm11(imm);
1779 } else {
1780 self.last_error = Some(AsmError::InvalidOperand);
1781 return;
1782 }
1783 }
1784
1785 Encoding::Zimm6HiVmVs2Zimm6loVd => {
1786 if isign4 == enc_ops4!(Reg, Reg, Imm, Imm) {
1787 let vd = ops[0].id();
1788 let vs2 = ops[1].id();
1789 let imm = ops[2].as_::<Imm>().value();
1790 let vm = ops[3].as_::<Imm>().value();
1791 if !(0..=1).contains(&vm) {
1792 self.last_error = Some(AsmError::InvalidOperand);
1793 return;
1794 }
1795
1796 inst = inst
1797 .set_vd(vd)
1798 .set_vs2(vs2)
1799 .set_zimm6lohi(imm as _)
1800 .set_vm(vm as _);
1801 } else {
1802 self.last_error = Some(AsmError::InvalidOperand);
1803 return;
1804 }
1805 }
1806 Encoding::RdRs1N0CNzimm6loCNzimm6hi => {
1807 short = true;
1808 if isign3 == enc_ops2!(Reg, Imm) {
1809 let rd = ops[0].id();
1810 let imm = ops[1].as_::<Imm>().value() as i32;
1811 if imm == 0 {
1812 self.last_error = Some(AsmError::InvalidOperand);
1813 return;
1814 } else {
1815 inst = inst.set_rd_rs1_n0(rd).set_c_nzimm6lohi(imm);
1816 }
1817 } else {
1818 self.last_error = Some(AsmError::InvalidOperand);
1819 return;
1820 }
1821 }
1822
1823 Encoding::RdRs1N0CImm6loCImm6hi => {
1824 short = true;
1825 if isign3 == enc_ops2!(Reg, Imm) {
1826 let rd = ops[0].id();
1827 let imm = ops[1].as_::<Imm>().value() as i32;
1828 inst = inst.set_rd_rs1_n0(rd).set_c_imm6lohi(imm);
1829 } else {
1830 self.last_error = Some(AsmError::InvalidOperand);
1831 return;
1832 }
1833 }
1834
1835 Encoding::RdRs1N0CNzuimm6hiCNzuimm6lo => {
1836 short = true;
1837 if isign3 == enc_ops2!(Reg, Imm) {
1838 let rd = ops[0].id();
1839 let imm = ops[1].as_::<Imm>().value() as i32;
1840 if imm == 0 {
1841 self.last_error = Some(AsmError::InvalidOperand);
1842 return;
1843 } else {
1844 inst = inst.set_rd_rs1_n0(rd).set_c_nzuimm6lohi(imm as u32);
1845 }
1846 } else {
1847 self.last_error = Some(AsmError::InvalidOperand);
1848 return;
1849 }
1850 }
1851
1852 Encoding::RdRs1N0CNzuimm6lo => {
1853 short = true;
1854 if isign3 == enc_ops2!(Reg, Imm) {
1855 let rd = ops[0].id();
1856 let imm = ops[1].as_::<Imm>().value() as i32;
1857 if imm == 0 {
1858 self.last_error = Some(AsmError::InvalidOperand);
1859 return;
1860 } else {
1861 inst = inst.set_rd_rs1_n0(rd).set_c_nzuimm6lo_raw(imm as u32);
1862 }
1863 } else {
1864 self.last_error = Some(AsmError::InvalidOperand);
1865 return;
1866 }
1867 }
1868
1869 Encoding::RdRs1N0CRs2N0 => {
1870 short = true;
1871 if isign3 == enc_ops2!(Reg, Reg) {
1872 let rd = ops[0].id();
1873 let rs1 = ops[1].id();
1874 inst = inst.set_rd_rs1_n0(rd).set_c_rs2_n0(rs1);
1875 } else {
1876 self.last_error = Some(AsmError::InvalidOperand);
1877 return;
1878 }
1879 }
1880
1881 Encoding::RdRs1P => {
1882 short = true;
1883 if isign3 == enc_ops1!(Reg) {
1884 let rd = ops[0].id();
1885 if !is_prime_register(rd) {
1886 self.last_error = Some(AsmError::InvalidOperand);
1887 return;
1888 }
1889
1890 inst = inst.set_rd_rs1_p(rd);
1891 } else {
1892 self.last_error = Some(AsmError::InvalidOperand);
1893 return;
1894 }
1895 }
1896
1897 Encoding::RdRs1PCImm6hiCImm6lo => {
1898 short = true;
1899 if isign3 == enc_ops2!(Reg, Imm) {
1900 let rd = ops[0].id();
1901 if !is_prime_register(rd) {
1902 self.last_error = Some(AsmError::InvalidOperand);
1903 return;
1904 }
1905 let imm = ops[1].as_::<Imm>().value() as i32;
1906 inst = inst.set_rd_rs1_p(rd).set_c_imm6lohi(imm);
1907 } else {
1908 self.last_error = Some(AsmError::InvalidOperand);
1909 return;
1910 }
1911 }
1912
1913 Encoding::RdRs1PCNzuimm5 => {
1914 short = true;
1915 if isign3 == enc_ops2!(Reg, Imm) {
1916 let rd = ops[0].id();
1917 let imm = ops[1].as_::<Imm>().value() as i32;
1918 if imm == 0 {
1919 self.last_error = Some(AsmError::InvalidOperand);
1920 return;
1921 } else {
1922 inst = inst.set_rd(rd).set_rs1(0).set_c_nzuimm5(imm as u32);
1923 }
1924 } else {
1925 self.last_error = Some(AsmError::InvalidOperand);
1926 return;
1927 }
1928 }
1929
1930 Encoding::RdRs1PCNzuimm6loCNzuimm6hi => {
1931 short = true;
1932 if isign3 == enc_ops2!(Reg, Imm) {
1933 let rd = ops[0].id();
1934 if !is_prime_register(rd) {
1935 self.last_error = Some(AsmError::InvalidOperand);
1936 return;
1937 }
1938 let imm = ops[1].as_::<Imm>().value() as i32;
1939 if imm == 0 {
1940 self.last_error = Some(AsmError::InvalidOperand);
1941 return;
1942 } else {
1943 inst = inst.set_rd_rs1_p(rd).set_c_nzuimm6lohi(imm as u32);
1944 }
1945 } else {
1946 self.last_error = Some(AsmError::InvalidOperand);
1947 return;
1948 }
1949 }
1950
1951 Encoding::RdRs1PRs2P => {
1952 short = true;
1953 if isign3 == enc_ops2!(Reg, Reg) {
1954 let rd = ops[0].id();
1955 let rs2 = ops[1].id();
1956 if !is_prime_register(rd) || !is_prime_register(rs2) {
1957 self.last_error = Some(AsmError::InvalidOperand);
1958 return;
1959 }
1960 inst = inst.set_rd_rs1_p(rd).set_rs2_p(rs2);
1961 } else {
1962 self.last_error = Some(AsmError::InvalidOperand);
1963 return;
1964 }
1965 }
1966
1967 Encoding::RdRs1Shamtd => {
1968 if isign3 == enc_ops3!(Reg, Reg, Imm) {
1969 let rd = ops[0].id();
1970 let rs1 = ops[1].id();
1971 let shamt = ops[2].as_::<Imm>().value() as i32;
1972 inst = inst.set_rd(rd).set_rs1(rs1).set_shamtd(shamt as _);
1973 } else {
1974 self.last_error = Some(AsmError::InvalidOperand);
1975 return;
1976 }
1977 }
1978 }
1979 let offset = self.buffer.cur_offset();
1980 if let Some((label, kind)) = label_use {
1981 self.buffer
1982 .use_label_at_offset(offset, label.as_::<Label>(), kind);
1983 }
1984
1985 if short {
1986 self.buffer.put2(inst.value as u16);
1987 } else {
1988 self.buffer.put4(inst.value);
1989 }
1990 }
1991}
1992
1993impl crate::core::builder::InstSink for Assembler<'_> {
1994 fn arch(&self) -> Arch {
1995 self.environment().arch()
1996 }
1997
1998 fn emit_inst(&mut self, inst: &crate::core::inst::Inst) -> Result<(), AsmError> {
1999 let ops = inst.operands();
2000 let mut refs: smallvec::SmallVec<[&Operand; 6]> = smallvec::SmallVec::new();
2001 refs.extend(ops.iter());
2002 self.try_emit_n(inst.id as i64, &refs)
2003 }
2004
2005 fn bind_label(&mut self, label: Label) -> Result<(), AsmError> {
2006 self.try_bind_label(label)
2007 }
2008}
2009
2010#[cfg(test)]
2011mod tests {
2012 use super::*;
2013 use crate::core::target::Environment;
2014 use crate::riscv::opcodes::{
2015 MATCH_C_LW, MATCH_C_NOT, MATCH_FADD_S, MATCH_FMADD_S, MATCH_FMV_W_X, MATCH_FMV_X_W,
2016 MATCH_LR_W, MATCH_SSAMOSWAP_W, MATCH_SSRDP, MATCH_VAESKF1_VI, MATCH_VFADD_VF, MATCH_VLE8_V,
2017 };
2018 use crate::riscv::operands::regs::*;
2019 use std::vec::Vec;
2020
2021 fn rv32(buf: &mut CodeBuffer) -> Assembler<'_> {
2022 Assembler::new(buf)
2023 }
2024
2025 fn data(buf: &mut CodeBuffer) -> Vec<u8> {
2026 buf.finish().unwrap().data().to_vec()
2027 }
2028
2029 #[test]
2030 fn default_environment_is_rv64() {
2031 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2032 let asm = Assembler::new(&mut buf);
2033 assert!(!asm.is_32bit());
2034 assert_eq!(asm.environment().arch(), Arch::RISCV64);
2035 }
2036
2037 #[test]
2038 fn fixed_fences_have_no_artificial_operands() {
2039 for arch in [Arch::RISCV32, Arch::RISCV64] {
2040 let mut buf = CodeBuffer::new(Environment::new(arch));
2041 {
2042 let mut asm = Assembler::new(&mut buf);
2043 asm.fence_i();
2044 asm.fence_tso();
2045 assert_eq!(asm.last_error(), None);
2046 }
2047 assert_eq!(
2048 data(&mut buf),
2049 [0x0000_100fu32.to_le_bytes(), 0x8330_000fu32.to_le_bytes()].concat()
2050 );
2051 }
2052 }
2053
2054 #[test]
2055 fn baseline_rejects_optional_extensions_before_writing() {
2056 let mut buf = CodeBuffer::new(Environment::baseline(Arch::RISCV64));
2057 let mut asm = Assembler::new(&mut buf);
2058 let vm = imm(1);
2059
2060 let error = asm
2061 .try_emit_n(
2062 Opcode::VADDVV as i64,
2063 &[
2064 V0.as_operand(),
2065 V1.as_operand(),
2066 V2.as_operand(),
2067 vm.as_operand(),
2068 ],
2069 )
2070 .unwrap_err();
2071
2072 assert!(
2073 matches!(error, AsmError::MissingCpuFeature { feature } if feature.contains("vadd.vv") && feature.contains("rv_v"))
2074 );
2075 assert!(asm.buffer.data().is_empty());
2076 }
2077
2078 #[test]
2079 fn optional_extensions_are_enabled_by_default() {
2080 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2081 let mut asm = Assembler::new(&mut buf);
2082 let vm = imm(1);
2083
2084 asm.try_emit_n(
2085 Opcode::VADDVV as i64,
2086 &[
2087 V0.as_operand(),
2088 V1.as_operand(),
2089 V2.as_operand(),
2090 vm.as_operand(),
2091 ],
2092 )
2093 .unwrap();
2094
2095 assert_eq!(asm.buffer.data().len(), 4);
2096 }
2097
2098 #[test]
2099 fn invalid_raw_opcode_is_rejected_without_writing() {
2100 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2101 let mut asm = Assembler::new(&mut buf);
2102
2103 asm.emit_n(-1, &[]);
2104 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2105 assert!(asm.buffer.data().is_empty());
2106
2107 asm.buffer.clear();
2108 asm.emit_n(i64::MAX, &[]);
2109 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2110 assert!(asm.buffer.data().is_empty());
2111 }
2112
2113 #[test]
2114 fn raw_emission_rejects_malformed_or_extra_operands_without_mutation() {
2115 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2116 let mut asm = Assembler::new(&mut buf);
2117 let malformed = Operand {
2118 signature: OperandSignature::from(7),
2119 base_id: 0,
2120 data: [0; 2],
2121 };
2122 let invalid_register = Operand {
2123 signature: OperandSignature::from(
2124 OperandType::Reg as u32 | (31 << OperandSignature::REG_TYPE_SHIFT),
2125 ),
2126 base_id: 0,
2127 data: [0; 2],
2128 };
2129 let none = Operand::new();
2130
2131 assert_eq!(
2132 asm.try_emit_n(Opcode::ADD as i64, &[&malformed]),
2133 Err(AsmError::InvalidOperand)
2134 );
2135 assert_eq!(
2136 asm.try_emit_n(Opcode::ADD as i64, &[&invalid_register]),
2137 Err(AsmError::InvalidOperand)
2138 );
2139 assert_eq!(
2140 asm.try_emit_n(Opcode::ADD as i64, &[RA.as_operand()]),
2141 Err(AsmError::InvalidOperand)
2142 );
2143 assert_eq!(
2144 asm.try_emit_n(
2145 Opcode::ADD as i64,
2146 &[&none, &none, &none, &none, &none, &none],
2147 ),
2148 Err(AsmError::InvalidOperand)
2149 );
2150 assert!(asm.buffer.error().is_none());
2151 assert!(asm.buffer.data().is_empty());
2152 }
2153
2154 #[test]
2155 fn macro_helpers_reject_wrong_operand_kinds_without_panicking() {
2156 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2157 let mut asm = Assembler::new(&mut buf);
2158
2159 asm.la(RA, imm(0));
2160 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidOperand));
2161 assert!(asm.buffer.data().is_empty());
2162
2163 asm.buffer.clear();
2164 asm.call(Operand::new());
2165 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidOperand));
2166 assert!(asm.buffer.data().is_empty());
2167 }
2168
2169 #[test]
2170 fn raw_label_registration_error_rolls_back_emission() {
2171 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2172 let mut asm = Assembler::new(&mut buf);
2173 let invalid_label = Label::from_id(0);
2174
2175 assert_eq!(
2176 asm.try_emit_n(
2177 Opcode::JAL as i64,
2178 &[RA.as_operand(), invalid_label.as_operand()]
2179 ),
2180 Err(AsmError::InvalidArgument)
2181 );
2182 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidArgument));
2183 assert!(asm.buffer.data().is_empty());
2184 }
2185
2186 #[test]
2187 fn failed_call_rolls_back_the_whole_sequence() {
2188 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2189 let mut asm = Assembler::new(&mut buf);
2190
2191 asm.call(Label::from_id(0));
2192
2193 assert_eq!(asm.buffer.error(), Some(&AsmError::InvalidArgument));
2194 assert!(asm.buffer.data().is_empty());
2195 }
2196
2197 #[test]
2198 fn unimplemented_encodings_return_typed_errors() {
2199 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2200 let mut asm = Assembler::new(&mut buf);
2201 let one = imm(1);
2202 let sixteen = imm(16);
2203 let zero = imm(0);
2204
2205 asm.emit_n(
2206 Opcode::CMPOP as i64,
2207 &[one.as_operand(), sixteen.as_operand()],
2208 );
2209 assert!(matches!(
2210 asm.last_error(),
2211 Some(AsmError::UnsupportedInstruction { .. })
2212 ));
2213 assert!(asm.buffer.data().is_empty());
2214
2215 asm.buffer.clear();
2216 asm.emit_n(Opcode::CMMVA01S as i64, &[A0.as_operand(), A1.as_operand()]);
2217 assert!(matches!(
2218 asm.last_error(),
2219 Some(AsmError::UnsupportedInstruction { .. })
2220 ));
2221 assert!(asm.buffer.data().is_empty());
2222
2223 asm.buffer.clear();
2224 asm.emit_n(
2225 Opcode::MOPRN as i64,
2226 &[
2227 zero.as_operand(),
2228 zero.as_operand(),
2229 zero.as_operand(),
2230 A0.as_operand(),
2231 A1.as_operand(),
2232 ],
2233 );
2234 assert!(matches!(
2235 asm.last_error(),
2236 Some(AsmError::UnsupportedInstruction { .. })
2237 ));
2238 assert!(asm.buffer.data().is_empty());
2239
2240 asm.buffer.clear();
2241 asm.emit_n(
2242 Opcode::MOPRRN as i64,
2243 &[
2244 zero.as_operand(),
2245 zero.as_operand(),
2246 A0.as_operand(),
2247 A1.as_operand(),
2248 A2.as_operand(),
2249 ],
2250 );
2251 assert!(matches!(
2252 asm.last_error(),
2253 Some(AsmError::UnsupportedInstruction { .. })
2254 ));
2255 assert!(asm.buffer.data().is_empty());
2256
2257 asm.buffer.clear();
2258 asm.emit_n(Opcode::CSEXTW as i64, &[A0.as_operand()]);
2259 assert!(matches!(
2260 asm.last_error(),
2261 Some(AsmError::UnsupportedInstruction { .. })
2262 ));
2263 assert!(asm.buffer.data().is_empty());
2264 }
2265
2266 #[test]
2267 fn rv32_encodes_base_and_rv32_only_instructions() {
2268 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2269 {
2270 let mut asm = rv32(&mut buf);
2271 asm.add(A0, A1, A2);
2272 asm.slli_rv32(A0, A1, 5);
2274 assert_eq!(asm.last_error(), None);
2275 }
2276 let expected = [0x00C58533u32.to_le_bytes(), 0x00559513u32.to_le_bytes()].concat();
2277 assert_eq!(data(&mut buf), expected);
2278 }
2279
2280 #[test]
2281 fn rv32_rejects_rv64_only_instructions() {
2282 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2283 {
2284 let mut asm = rv32(&mut buf);
2285 asm.ld(A0, A1, imm(0));
2286 asm.addw(A0, A1, A2);
2287 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2288 }
2289 assert_eq!(buf.finish().err(), Some(AsmError::InvalidInstruction));
2290 }
2291
2292 #[test]
2293 fn rv64_rejects_rv32_only_instructions() {
2294 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2295 {
2296 let mut asm = Assembler::new(&mut buf);
2297 asm.slli_rv32(A0, A1, imm(5));
2298 assert_eq!(asm.last_error(), Some(AsmError::InvalidInstruction));
2299 }
2300 assert_eq!(buf.finish().err(), Some(AsmError::InvalidInstruction));
2301 }
2302
2303 #[test]
2304 fn rv64_encodes_rv64_only_instructions() {
2305 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2306 {
2307 let mut asm = Assembler::new(&mut buf);
2308 asm.ld(A0, A1, imm(0));
2309 asm.addw(A0, A1, A2);
2310 assert_eq!(asm.last_error(), None);
2311 }
2312 let expected = [0x0005B503u32.to_le_bytes(), 0x00C5853Bu32.to_le_bytes()].concat();
2313 assert_eq!(data(&mut buf), expected);
2314 }
2315
2316 #[test]
2317 fn lpad_encodes_on_both_xlen() {
2318 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2321 {
2322 let mut asm = rv32(&mut buf);
2323 asm.lpad(imm(0x12345 << 12));
2324 assert_eq!(asm.last_error(), None);
2325 }
2326 assert_eq!(data(&mut buf), 0x12345017u32.to_le_bytes());
2327
2328 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2329 {
2330 let mut asm = Assembler::new(&mut buf);
2331 asm.lpad(imm(0x12345 << 12));
2332 assert_eq!(asm.last_error(), None);
2333 }
2334 assert_eq!(data(&mut buf), 0x12345017u32.to_le_bytes());
2335 }
2336
2337 #[test]
2338 fn zicfiss_shadow_stack_instructions_encode() {
2339 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2340 {
2341 let mut asm = rv32(&mut buf);
2342 asm.sspush_x1();
2343 asm.ssrdp(A0);
2344 asm.ssamoswap_w(A0, A1, A2, imm(0), imm(0));
2345 assert_eq!(asm.last_error(), None);
2346 }
2347 let sspush_x1 = 0xCE104073u32; let ssrdp_a0 = MATCH_SSRDP | (10 << 7);
2349 let ssamoswap_w = MATCH_SSAMOSWAP_W | (10 << 7) | (11 << 15) | (12 << 20);
2350 let expected = [
2351 sspush_x1.to_le_bytes(),
2352 ssrdp_a0.to_le_bytes(),
2353 ssamoswap_w.to_le_bytes(),
2354 ]
2355 .concat();
2356 assert_eq!(data(&mut buf), expected);
2357 }
2358
2359 #[test]
2360 fn rv32_accepts_zclsd_compressed_load_store_pair() {
2361 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV32));
2364 {
2365 let mut asm = rv32(&mut buf);
2366 asm.c_ld(A0, A1, imm(0));
2367 asm.c_sd(A1, A0, imm(0));
2369 assert_eq!(asm.last_error(), None);
2370 }
2371 assert_eq!(data(&mut buf), [0x88, 0x61, 0x88, 0xE1]);
2373 }
2374
2375 #[test]
2376 fn compressed_loads_use_prime_register_fields() {
2377 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2379 {
2380 let mut asm = Assembler::new(&mut buf);
2381 asm.c_lw(S0, A5, imm(0));
2382 assert_eq!(asm.last_error(), None);
2383 }
2384 assert_eq!(
2385 data(&mut buf),
2386 ((MATCH_C_LW | (7 << 7)) as u16).to_le_bytes()
2387 );
2388 }
2389
2390 #[test]
2391 fn typed_vector_fields_encode_and_validate() {
2392 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2393 {
2394 let mut asm = Assembler::new(&mut buf);
2395 asm.vle8_v(V1, A0, imm(1), imm(3));
2396 assert_eq!(asm.last_error(), None);
2397 }
2398 let expected = MATCH_VLE8_V | (1 << 7) | (10 << 15) | (1 << 25) | (3 << 29);
2399 assert_eq!(data(&mut buf), expected.to_le_bytes());
2400
2401 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2402 let mut asm = Assembler::new(&mut buf);
2403 asm.vle8_v(V1, A0, imm(2), imm(0));
2404 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2405 asm.buffer.clear();
2406 asm.vle8_v(V1, A0, imm(1), imm(8));
2407 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2408
2409 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2410 let mut asm = Assembler::new(&mut buf);
2411 asm.vaeskf1_vi(V1, V2, 3);
2412 assert_eq!(asm.last_error(), None);
2413 let expected = MATCH_VAESKF1_VI | (1 << 7) | (3 << 15) | (2 << 20);
2414 assert_eq!(asm.buffer.data(), expected.to_le_bytes());
2415
2416 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2417 let mut asm = Assembler::new(&mut buf);
2418 asm.vfadd_vf(V1, V2, F0, 1);
2419 asm.fmv_w_x(F1, A0);
2420 asm.fmv_x_w(A1, F2);
2421 assert_eq!(asm.last_error(), None);
2422 let expected = [
2423 (MATCH_VFADD_VF | (1 << 7) | (2 << 20) | (1 << 25)).to_le_bytes(),
2424 (MATCH_FMV_W_X | (1 << 7) | (10 << 15)).to_le_bytes(),
2425 (MATCH_FMV_X_W | (11 << 7) | (2 << 15)).to_le_bytes(),
2426 ]
2427 .concat();
2428 assert_eq!(asm.buffer.data(), expected);
2429 }
2430
2431 #[test]
2432 fn pc_relative_label_register_coupling_is_transactional() {
2433 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2434 let mut asm = Assembler::new(&mut buf);
2435 let label = asm.get_label();
2436 asm.emit_n(
2437 Opcode::JALR as i64,
2438 &[A0.as_operand(), A1.as_operand(), label.as_operand()],
2439 );
2440 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2441 assert!(asm.buffer.data().is_empty());
2442
2443 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2444 let mut asm = Assembler::new(&mut buf);
2445 let label = asm.get_label();
2446 asm.emit_n(
2447 Opcode::LW as i64,
2448 &[A0.as_operand(), A1.as_operand(), label.as_operand()],
2449 );
2450 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2451 assert!(asm.buffer.data().is_empty());
2452
2453 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2454 let mut asm = Assembler::new(&mut buf);
2455 let label = asm.get_label();
2456 asm.emit_n(
2457 Opcode::JALR as i64,
2458 &[A0.as_operand(), A0.as_operand(), label.as_operand()],
2459 );
2460 assert_eq!(asm.last_error(), None);
2461 assert_eq!(asm.buffer.data().len(), 8);
2462
2463 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2464 let mut asm = Assembler::new(&mut buf);
2465 let label = asm.get_label();
2466 asm.emit_n(
2467 Opcode::LW as i64,
2468 &[A0.as_operand(), A0.as_operand(), label.as_operand()],
2469 );
2470 assert_eq!(asm.last_error(), None);
2471 assert_eq!(asm.buffer.data().len(), 8);
2472 }
2473
2474 #[test]
2475 fn typed_atomic_and_rounding_fields_validate() {
2476 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2477 {
2478 let mut asm = Assembler::new(&mut buf);
2479 asm.lr_w(A0, A1, 0, 0);
2480 asm.lr_w(A0, A1, 0, 1);
2481 asm.lr_w(A0, A1, 1, 0);
2482 asm.lr_w(A0, A1, 1, 1);
2483 assert_eq!(asm.last_error(), None);
2484 }
2485 let base = MATCH_LR_W | (10 << 7) | (11 << 15);
2486 let expected = [
2487 base.to_le_bytes(),
2488 (base | (1 << 25)).to_le_bytes(),
2489 (base | (1 << 26)).to_le_bytes(),
2490 (base | (3 << 25)).to_le_bytes(),
2491 ]
2492 .concat();
2493 assert_eq!(data(&mut buf), expected);
2494
2495 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2496 let mut asm = Assembler::new(&mut buf);
2497 asm.fadd_s(F0, F1, F2, imm(5));
2498 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2499 asm.buffer.clear();
2500 asm.fadd_s(F0, F1, F2, imm(7));
2501 assert_eq!(asm.last_error(), None);
2502 let expected = MATCH_FADD_S | (1 << 15) | (2 << 20) | (7 << 12);
2503 assert_eq!(asm.buffer.data(), expected.to_le_bytes());
2504
2505 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2506 let mut asm = Assembler::new(&mut buf);
2507 asm.fmadd_s(F0, F1, F2, F3, 0);
2508 assert_eq!(asm.last_error(), None);
2509 let expected = MATCH_FMADD_S | (1 << 15) | (2 << 20) | (3 << 27);
2510 assert_eq!(asm.buffer.data(), expected.to_le_bytes());
2511 }
2512
2513 #[test]
2514 fn compressed_prime_registers_reject_non_prime_ids() {
2515 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2516 let mut asm = Assembler::new(&mut buf);
2517 asm.c_lw(T2, A1, imm(0));
2518 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2519 assert!(asm.buffer.data().is_empty());
2520
2521 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2522 {
2523 let mut asm = Assembler::new(&mut buf);
2524 asm.c_not(S0);
2525 assert_eq!(asm.last_error(), None);
2526 }
2527 assert_eq!(
2528 data(&mut buf),
2529 ((MATCH_C_NOT & !(0x7 << 7)) as u16).to_le_bytes()
2530 );
2531
2532 let mut buf = CodeBuffer::new(Environment::new(Arch::RISCV64));
2533 let mut asm = Assembler::new(&mut buf);
2534 asm.c_not(T2);
2535 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2536 assert!(asm.buffer.data().is_empty());
2537
2538 asm.buffer.clear();
2539 asm.c_lw(A0, T2, imm(0));
2540 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2541 assert!(asm.buffer.data().is_empty());
2542
2543 asm.buffer.clear();
2544 asm.c_lw(A6, A1, imm(0));
2545 assert_eq!(asm.last_error(), Some(AsmError::InvalidOperand));
2546 assert!(asm.buffer.data().is_empty());
2547 }
2548
2549 #[test]
2550 fn register_label_encodings_use_the_label_operand() {
2551 for arch in [Arch::RISCV32, Arch::RISCV64] {
2552 let mut buf = CodeBuffer::new(Environment::new(arch));
2553 let target = buf.get_label();
2554 {
2555 let mut asm = Assembler::new(&mut buf);
2556 asm.auipc(A0, target);
2557 asm.jal(A1, target);
2558 asm.bind_label(target);
2559 assert_eq!(asm.last_error(), None);
2560 }
2561 assert_eq!(buf.label_offset(target), 8);
2562 assert_eq!(
2563 data(&mut buf),
2564 [0x0000_0517u32.to_le_bytes(), 0x0040_05EFu32.to_le_bytes()].concat()
2565 );
2566
2567 let mut buf = CodeBuffer::new(Environment::new(arch));
2568 let target = buf.get_label();
2569 {
2570 let mut asm = Assembler::new(&mut buf);
2571 asm.bind_label(target);
2572 asm.auipc(A0, target);
2573 asm.jal(A1, target);
2574 assert_eq!(asm.last_error(), None);
2575 }
2576 assert_eq!(buf.label_offset(target), 0);
2577 assert_eq!(
2578 data(&mut buf),
2579 [0x0000_0517u32.to_le_bytes(), 0xFFDFF5EFu32.to_le_bytes()].concat()
2580 );
2581 }
2582 }
2583}