1use std::ffi::{CStr, c_char};
2use std::marker::PhantomData;
3use std::ptr::{NonNull, null_mut};
4use std::{fmt, ops};
5
6use paste::paste;
7use smallvec::SmallVec;
8
9use crate::{MemoryFile, MirContext, ffi};
10
11#[derive(Clone, Copy, PartialEq, Eq)]
13#[repr(transparent)]
14pub struct Ty(pub(crate) ffi::MIR_type_t);
15
16macro_rules! impl_ty_variants {
17 ($($var:ident),* $(,)?) => {
18 impl Ty {
19 $(
20 #[doc = concat!("`MIR_T_", stringify!($var), "`")]
21 pub const $var: Self = Self(paste!(ffi::[<MIR_T_ $var>]));
22 )*
23 }
24
25 impl fmt::Debug for Ty {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 let s = match *self {
28 $(Self::$var => concat!("Ty(MIR_T_", stringify!($var), ")"),)*
29 Self(raw) => return f.debug_tuple("Ty").field(&raw).finish(),
30 };
31 f.write_str(s)
32 }
33 }
34 };
35}
36
37impl_ty_variants! {
38 I8, U8, I16, U16, I32, U32, I64, U64,
39 F, D, LD, P,
40 BLK, RBLK, UNDEF, BOUND,
41}
42
43#[test]
44fn ty_debug() {
45 assert_eq!(format!("{:?}", Ty::I64), "Ty(MIR_T_I64)");
46 assert_eq!(format!("{:?}", Ty(99)), "Ty(99)");
47}
48
49#[derive(Debug, Clone, Copy)]
51#[repr(transparent)]
52pub struct Reg(pub(crate) ffi::MIR_reg_t);
53
54#[derive(Clone, Copy, PartialEq, Eq)]
56#[repr(transparent)]
57pub struct ItemType(pub(crate) ffi::MIR_item_type_t);
58
59macro_rules! impl_item_type_variants {
60 ($($var:ident),* $(,)?) => {
61 impl ItemType {
62 $(
63 #[doc = paste!(concat!("`MIR_", stringify!([<$var:lower>]), "_item"))]
64 pub const $var: Self = Self(paste!(ffi::[<MIR_ $var:lower _item>]));
65 )*
66 }
67
68 impl fmt::Debug for ItemType {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 let s = match *self {
71 $(Self::$var => paste!(concat!("ItemType(MIR_", stringify!($var:lower), "_item)")),)*
72 Self(raw) => return f.debug_tuple("ItemType").field(&raw).finish(),
73 };
74 f.write_str(s)
75 }
76 }
77 };
78}
79
80impl_item_type_variants! {
81 FUNC, PROTO,
82 IMPORT, EXPORT, FORWARD,
83 DATA, REF_DATA, LREF_DATA, EXPR_DATA,
84 BSS,
85}
86
87#[derive(Clone, Copy)]
89#[repr(transparent)]
90pub struct ItemRef<'a>(
91 pub(crate) NonNull<ffi::MIR_item>,
92 pub(crate) PhantomData<&'a ffi::MIR_item>,
93);
94
95impl ItemRef<'_> {
96 pub(crate) unsafe fn from_raw(raw: *mut ffi::MIR_item) -> Self {
97 let raw = NonNull::new(raw).expect("item must not be null");
98 Self(raw, PhantomData)
99 }
100
101 #[must_use]
103 pub fn as_raw(&self) -> *mut ffi::MIR_item {
104 self.0.as_ptr()
105 }
106
107 #[must_use]
109 pub fn dump(&self, ctx: &MirContext) -> String {
110 MemoryFile::with(|file| unsafe { ffi::MIR_output_item(ctx.as_raw(), file, self.as_raw()) })
111 .1
112 }
113
114 #[must_use]
116 pub fn type_(&self) -> ItemType {
117 unsafe { ItemType(self.0.as_ref().item_type) }
118 }
119
120 #[must_use]
122 pub fn name(&self) -> Option<&CStr> {
123 let item = unsafe { self.0.as_ref() };
124 let data = &item.u;
125 let ptr = unsafe {
126 match item.item_type {
127 ffi::MIR_func_item => (*data.func.cast::<FuncItemData>()).0.name,
128 ffi::MIR_proto_item => (*data.func.cast::<ProtoItemData>()).0.name,
129 ffi::MIR_import_item => data.import_id,
130 ffi::MIR_export_item => data.export_id,
131 ffi::MIR_forward_item => data.forward_id,
132 ffi::MIR_data_item => (*data.data.cast::<DataItemData>()).0.name,
133 ffi::MIR_ref_data_item => (*data.ref_data.cast::<RefDataItemData>()).0.name,
134 ffi::MIR_lref_data_item => (*data.lref_data.cast::<LabelRefDataItemData>()).0.name,
135 ffi::MIR_expr_data_item => (*data.expr_data.cast::<ExprDataItemData>()).0.name,
136 ffi::MIR_bss_item => (*data.bss.cast::<BssItemData>()).0.name,
137 _ => return None,
138 }
139 };
140 if ptr.is_null() {
141 None
142 } else {
143 unsafe { Some(CStr::from_ptr(ptr)) }
144 }
145 }
146}
147
148impl<'a> From<ItemRef<'a>> for Operand<'a> {
149 fn from(item: ItemRef<'a>) -> Self {
150 Operand {
151 op: unsafe { ffi::MIR_new_ref_op(null_mut(), item.as_raw()) },
152 _marker: PhantomData,
153 }
154 }
155}
156
157impl fmt::Debug for ItemRef<'_> {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 let mut fs = f.debug_struct("ItemRef");
160 let item = unsafe { self.0.as_ref() };
161 fs.field("ptr", &std::ptr::from_ref(self))
162 .field("module", &item.module)
163 .field("addr", &item.addr)
164 .field("type", &self.type_());
165 let data = &item.u;
166 let mut cb = |data| {
167 fs.field("u", data);
168 };
169 match item.item_type {
170 ffi::MIR_func_item => cb(unsafe { &*data.func.cast::<FuncItemData>() }),
171 ffi::MIR_proto_item => cb(unsafe { &*data.func.cast::<ProtoItemData>() }),
172 ffi::MIR_import_item => cb(&DebugImportLikeItemData(
173 "ImportItemData",
174 "import_id",
175 unsafe { data.import_id },
176 )),
177 ffi::MIR_export_item => cb(&DebugImportLikeItemData(
178 "ExportItemData",
179 "export_id",
180 unsafe { data.export_id },
181 )),
182 ffi::MIR_forward_item => cb(&DebugImportLikeItemData(
183 "ForwardItemData",
184 "forward_id",
185 unsafe { data.forward_id },
186 )),
187 ffi::MIR_data_item => cb(unsafe { &*data.data.cast::<DataItemData>() }),
188 ffi::MIR_ref_data_item => cb(unsafe { &*data.ref_data.cast::<RefDataItemData>() }),
189 ffi::MIR_lref_data_item => {
190 cb(unsafe { &*data.lref_data.cast::<LabelRefDataItemData>() });
191 }
192 ffi::MIR_expr_data_item => cb(unsafe { &*data.expr_data.cast::<ExprDataItemData>() }),
193 ffi::MIR_bss_item => cb(unsafe { &*data.bss.cast::<BssItemData>() }),
194 _ => {}
195 }
196 fs.finish_non_exhaustive()
197 }
198}
199
200#[derive(Debug, Clone)]
202pub struct ItemRefDowncastError(());
203
204impl fmt::Display for ItemRefDowncastError {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 f.write_str("item type mismatch")
207 }
208}
209
210impl std::error::Error for ItemRefDowncastError {}
211
212macro_rules! def_item_ref_variant {
213 ($name:ident, $item_type:expr, $doc:literal) => {
214 #[doc = $doc]
216 #[derive(Debug, Clone, Copy)]
218 #[repr(transparent)]
219 pub struct $name<'a>(pub(crate) ItemRef<'a>);
220
221 impl<'a> ops::Deref for $name<'a> {
222 type Target = ItemRef<'a>;
223
224 fn deref(&self) -> &Self::Target {
225 &self.0
226 }
227 }
228
229 impl<'a> From<$name<'a>> for Operand<'a> {
230 fn from(item: $name<'a>) -> Self {
231 item.0.into()
232 }
233 }
234
235 impl<'a> TryFrom<ItemRef<'a>> for $name<'a> {
236 type Error = ItemRefDowncastError;
237 fn try_from(item: ItemRef<'a>) -> Result<Self, Self::Error> {
238 if unsafe { item.0.as_ref().item_type } == $item_type {
239 Ok(Self(item))
240 } else {
241 Err(ItemRefDowncastError(()))
242 }
243 }
244 }
245 };
246}
247
248def_item_ref_variant!(FuncItemRef, ffi::MIR_func_item, "function");
249
250impl FuncItemRef<'_> {
251 #[cfg(feature = "interp")]
254 pub(crate) unsafe fn data(&self) -> &ffi::MIR_func {
255 unsafe { &*self.0.0.as_ref().u.func }
256 }
257}
258
259#[repr(transparent)]
260struct FuncItemData(ffi::MIR_func);
261
262impl fmt::Debug for FuncItemData {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 let u = &self.0;
265 f.debug_struct("FuncItemData")
266 .field("name", &unsafe { CStr::from_ptr(u.name) })
267 .field("func_item", &u.func_item)
268 .field("original_vars_num", &u.original_insns)
269 .field("nres", &u.nres)
270 .field("nargs", &u.nargs)
271 .field("res_types", &unsafe {
272 std::slice::from_raw_parts(u.res_types.cast::<Ty>(), u.nres as usize)
273 })
274 .field("varargs_p", &(u.vararg_p != 0))
275 .field("expr_p", &(u.expr_p != 0))
276 .field("jret_p", &(u.jret_p != 0))
277 .field("vars", &DebugVars(u.vars))
278 .field("global_vars", &DebugVars(u.global_vars))
279 .finish_non_exhaustive()
280 }
281}
282
283#[repr(transparent)]
284struct DebugVar(ffi::MIR_var);
285
286impl fmt::Debug for DebugVar {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 f.debug_struct("Var")
289 .field("type", &Ty(self.0.type_))
290 .field("name", &unsafe { CStr::from_ptr(self.0.name) })
291 .finish_non_exhaustive()
293 }
294}
295
296struct DebugVars(*mut ffi::VARR_MIR_var_t);
297
298impl fmt::Debug for DebugVars {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 let vars = if self.0.is_null() {
301 &[]
302 } else {
303 unsafe {
304 let varr = &*self.0;
305 std::slice::from_raw_parts(varr.varr.cast::<DebugVar>().cast_const(), varr.els_num)
306 }
307 };
308 vars.fmt(f)
309 }
310}
311
312def_item_ref_variant!(ProtoItemRef, ffi::MIR_proto_item, "prototype");
313
314#[repr(transparent)]
315struct ProtoItemData(ffi::MIR_proto);
316
317impl fmt::Debug for ProtoItemData {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 let u = &self.0;
320 f.debug_struct("ProtoItemData")
321 .field("name", &unsafe { CStr::from_ptr(u.name) })
322 .field("nres", &u.nres)
323 .field("res_types", &unsafe {
324 std::slice::from_raw_parts(u.res_types.cast::<Ty>(), u.nres as usize)
325 })
326 .finish_non_exhaustive()
327 }
328}
329
330def_item_ref_variant!(ImportItemRef, ffi::MIR_import_item, "import");
331def_item_ref_variant!(ExportItemRef, ffi::MIR_export_item, "export");
332def_item_ref_variant!(ForwardItemRef, ffi::MIR_forward_item, "forward declaration");
333
334struct DebugImportLikeItemData(&'static str, &'static str, *const c_char);
335
336impl fmt::Debug for DebugImportLikeItemData {
337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338 f.debug_struct(self.0)
339 .field(self.1, &unsafe { CStr::from_ptr(self.2) })
340 .finish()
341 }
342}
343
344def_item_ref_variant!(DataItemRef, ffi::MIR_data_item, "data");
345
346#[repr(transparent)]
347struct DataItemData(ffi::MIR_data);
348
349impl fmt::Debug for DataItemData {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 let u = &self.0;
352 f.debug_struct("DataItemData")
353 .field("name", &unsafe { CStr::from_ptr(u.name) })
354 .field("el_type", &Ty(u.el_type))
355 .field("nel", &u.nel)
356 .finish_non_exhaustive()
357 }
358}
359
360def_item_ref_variant!(RefDataItemRef, ffi::MIR_ref_data_item, "referential data");
361
362#[repr(transparent)]
363struct RefDataItemData(ffi::MIR_ref_data);
364
365impl fmt::Debug for RefDataItemData {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 let u = &self.0;
368 f.debug_struct("RefDataItemData")
369 .field("name", &unsafe { CStr::from_ptr(u.name) })
370 .field("ref_item", &unsafe { ItemRef::from_raw(u.ref_item) })
371 .field("disp", &u.disp)
372 .field("load_addr", &u.load_addr)
373 .finish()
374 }
375}
376
377def_item_ref_variant!(LabelRefDataItemRef, ffi::MIR_lref_data_item, "label data");
378
379#[repr(transparent)]
380struct LabelRefDataItemData(ffi::MIR_lref_data);
381
382impl fmt::Debug for LabelRefDataItemData {
383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384 let u = &self.0;
385 f.debug_struct("LabelRefDataItemData")
386 .field("name", &unsafe { CStr::from_ptr(u.name) })
387 .field("disp", &u.disp)
388 .field("load_addr", &u.load_addr)
389 .finish()
390 }
391}
392
393def_item_ref_variant!(ExprDataItemRef, ffi::MIR_expr_data_item, "computed data");
394
395#[repr(transparent)]
396struct ExprDataItemData(ffi::MIR_expr_data);
397
398impl fmt::Debug for ExprDataItemData {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 let u = &self.0;
401 f.debug_struct("ExprItemData")
402 .field("name", &unsafe { CStr::from_ptr(u.name) })
403 .field("expr_item", &unsafe { ItemRef::from_raw(u.expr_item) })
404 .finish_non_exhaustive()
405 }
406}
407
408def_item_ref_variant!(BssItemRef, ffi::MIR_bss_item, "writable memory segment");
409
410#[repr(transparent)]
411struct BssItemData(ffi::MIR_bss);
412
413impl fmt::Debug for BssItemData {
414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
415 let u = &self.0;
416 f.debug_struct("BssItemData")
417 .field("name", &unsafe { CStr::from_ptr(u.name) })
418 .field("len", &u.len)
419 .finish()
420 }
421}
422
423#[derive(Clone, Copy)]
425#[repr(transparent)]
426pub struct Operand<'a> {
427 pub(crate) op: ffi::MIR_op_t,
428 pub(crate) _marker: PhantomData<&'a ()>,
429}
430
431impl fmt::Debug for Operand<'_> {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 let mut s = f.debug_struct("Operand");
434 unsafe {
435 match ffi::MIR_op_mode_t::from(self.op.mode) {
436 ffi::MIR_OP_REG => s.field("reg", &self.op.u.reg),
437 ffi::MIR_OP_VAR => s.field("var", &self.op.u.var),
438 ffi::MIR_OP_INT => s.field("int", &self.op.u.i),
439 ffi::MIR_OP_UINT => s.field("uint", &self.op.u.u),
440 ffi::MIR_OP_FLOAT => s.field("float", &self.op.u.f),
441 ffi::MIR_OP_DOUBLE => s.field("double", &self.op.u.d),
442 ffi::MIR_OP_REF => s.field("ref", &ItemRef::from_raw(self.op.u.ref_)),
443 ffi::MIR_OP_MEM => s.field("mem", &self.op.u.mem),
444 ffi::MIR_OP_LABEL => s.field("label", &..),
445 _ => return s.finish_non_exhaustive(),
450 }
451 .finish()
452 }
453 }
454}
455
456pub trait IntoOperand<'a>: Into<Operand<'a>> {}
458
459pub trait IntoOutOperand<'a>: IntoOperand<'a> {}
461
462impl<'a, T> IntoOperand<'a> for T where Operand<'a>: From<T> {}
463
464impl IntoOutOperand<'_> for Reg {}
465impl From<Reg> for Operand<'_> {
466 fn from(reg: Reg) -> Self {
467 Self {
468 op: unsafe { ffi::MIR_new_reg_op(null_mut(), reg.0) },
469 _marker: PhantomData,
470 }
471 }
472}
473
474#[derive(Debug, Clone, Copy)]
476#[repr(transparent)]
477pub struct Label<'a>(pub(crate) ffi::MIR_label_t, pub(crate) PhantomData<&'a ()>);
478
479impl<'a> From<Label<'a>> for Operand<'a> {
480 fn from(label: Label<'a>) -> Self {
481 Self {
482 op: unsafe { ffi::MIR_new_label_op(null_mut(), label.0) },
483 _marker: PhantomData,
484 }
485 }
486}
487
488#[derive(Debug, Clone, Copy)]
493pub struct MemOp {
494 ty: Ty,
495 disp: i64,
496 base: Reg,
497 index: Reg,
498 scale: u8,
499}
500
501impl MemOp {
502 #[must_use]
504 pub fn new_base(ty: Ty, base: Reg) -> Self {
505 Self {
506 ty,
507 disp: 0,
508 base,
509 index: Reg(0),
510 scale: 1,
511 }
512 }
513
514 #[must_use]
516 pub fn disp(self, disp: i64) -> Self {
517 Self { disp, ..self }
518 }
519
520 #[must_use]
522 pub fn index(self, index: Reg) -> Self {
523 Self { index, ..self }
524 }
525
526 #[must_use]
532 pub fn scale(self, scale: u8) -> Self {
533 assert!(matches!(scale, 1 | 2 | 4 | 8), "scale must be 1, 2, 4 or 8");
534 Self { scale, ..self }
535 }
536}
537
538impl IntoOutOperand<'_> for MemOp {}
539impl From<MemOp> for Operand<'_> {
540 fn from(mem: MemOp) -> Self {
541 Self {
542 op: unsafe {
543 ffi::MIR_new_mem_op(
544 null_mut(),
545 mem.ty.0,
546 mem.disp,
547 mem.base.0,
548 mem.index.0,
549 mem.scale,
550 )
551 },
552 _marker: PhantomData,
553 }
554 }
555}
556
557macro_rules! impl_literal_into_op {
558 ($($ty:ident, $func:ident;)*) => {
559 $(
560 impl From<$ty> for Operand<'_> {
561 fn from(v: $ty) -> Self {
562 Self {
563 op: unsafe { ffi::$func(null_mut(), v) },
564 _marker: PhantomData,
565 }
566 }
567 }
568 )*
569 };
570}
571
572impl_literal_into_op! {
573 i64, MIR_new_int_op;
574 u64, MIR_new_uint_op;
575 f32, MIR_new_float_op;
576 f64, MIR_new_double_op;
577}
578
579macro_rules! def_simple_insn {
580 (__impl $args:tt $name:ident) => {
581 def_simple_insn!(__impl $args $name paste!(ffi::[<MIR_ $name:upper>]));
582 };
583 (__impl (dst $(, $src:ident)*) $name:ident $code:expr) => {
584 fn $name<'o>(self, dst: impl IntoOutOperand<'o>, $($src: impl IntoOperand<'o>),*) {
585 build_insn(self, $code, [dst.into(), $($src.into()),*]);
586 }
587 };
588 (__impl (_ $(, $src:ident)*) $name:ident $code:expr) => {
589 fn $name<'o>(self, $($src: impl IntoOperand<'o>),*) {
590 build_insn(self, $code, [$($src.into()),*]);
591 }
592 };
593 (
594 $args:tt;
595 $($name:ident $(($code:expr))?),*
596 $(,)?
597 ) => {
598 $(def_simple_insn!(__impl $args $name $($code)?);)*
599 };
600}
601
602macro_rules! def_jump_insn {
603 (__impl (label $(, $src:ident)*) $name:ident) => {
604 #[allow(clippy::needless_lifetimes)]
605 fn $name<'o>(self, label: Label<'o>, $($src: impl IntoOperand<'o>),*) {
606 build_insn(self, paste!(ffi::[<MIR_ $name:upper>]), [label.into(), $($src.into()),*]);
607 }
608 };
609 (
610 $args:tt;
611 $($name:ident $(($code:expr))?),*
612 $(,)?
613 ) => {
614 $(def_jump_insn!(__impl $args $name $($code)?);)*
615 };
616}
617
618macro_rules! def_call_insn {
619 ($($name:ident),* $(,)?) => {
620 $(
621 fn $name<'o>(
622 self,
623 proto: ProtoItemRef<'o>,
624 func: impl IntoOperand<'o>,
625 results: impl IntoIterator<Item = Operand<'o>>,
626 args: impl IntoIterator<Item = Operand<'o>>,
627 ) {
628 build_insn(
629 self,
630 paste!(ffi::[<MIR_ $name:upper>]),
631 [proto.into(), func.into()]
632 .into_iter()
633 .chain(results)
634 .chain(args),
635 );
636 }
637 )*
638 };
639}
640
641#[doc(hidden)]
646pub unsafe trait InsnBuilderBase<'func>: Sized {
647 fn get_raw_ctx(&self) -> ffi::MIR_context_t;
648 unsafe fn insert(self, insn: ffi::MIR_insn_t);
651}
652
653impl<'func, T: InsnBuilderBase<'func>> InsnBuilder<'func> for T {}
654
655#[allow(missing_docs)]
673pub trait InsnBuilder<'func>: InsnBuilderBase<'func> {
674 def_simple_insn! {
678 (dst, src);
679
680 mov, fmov, dmov, ext8, ext16, ext32, uext8, uext16, uext32,
683
684 i2f, i2d, ui2f, ui2d, f2i, d2i, f2d, d2f, neg, negs, fneg, dneg, addr, addr8, addr16, addr32,
692 }
693
694 def_simple_insn! {
696 (dst, a, b);
697
698 add, adds, fadd, dadd, sub, subs, fsub, dsub, mul, muls, fmul, dmul, div, divs, udiv, udivs, fdiv, ddiv, mod_(ffi::MIR_MOD), mods, umod, umods,
703
704 and, ands, or, ors, xor, xors,
705 lsh, lshs, rsh, rshs, ursh, urshs,
706
707 eq, eqs, feq, deq, ne, nes, fne, dne, lt, lts, ult, ults, flt, dlt, le, les, ule, ules, fle, dle, gt, gts, ugt, ugts, fgt, dgt, ge, ges, uge, uges, fge, dge, addo, addos, subo, subos, mulo, mulos, umulo, umulos,
715 }
716
717 def_jump_insn!((label); jmp, bo, bno, ubo, ubno);
719 def_simple_insn!((_, label_op); jmpi);
720 def_jump_insn!((label, v); bt, bts, bf, bfs);
721 def_jump_insn! {
722 (label, a, b);
723 beq, beqs, fbeq, dbeq, bne, bnes, fbne, dbne, blt, blts, ublt, ublts, fblt, dblt, ble, bles, uble, ubles, fble, dble, bgt, bgts, ubgt, ubgts, fbgt, dbgt, bge, bges, ubge, ubges, fbge, dbge, }
730 fn laddr<'o>(self, dst: impl IntoOutOperand<'o>, label: Label<'_>) {
731 build_insn(self, ffi::MIR_LADDR, [dst.into(), label.into()]);
732 }
733
734 def_call_insn!(call, inline, jcall);
736 def_simple_insn!((_, v); ret, jret);
737
738 def_simple_insn!((dst, len); alloca);
740 def_simple_insn!((_, va_list); va_start, va_end);
741 def_simple_insn!((dst, va_list, size, block_type); va_block_arg);
742 fn va_arg<'o>(self, dst: impl IntoOutOperand<'o>, va_list: impl IntoOperand<'o>, mem: MemOp) {
743 build_insn(
744 self,
745 ffi::MIR_VA_ARG,
746 [dst.into(), va_list.into(), mem.into()],
747 );
748 }
749
750 fn label(self, label: Label<'_>) {
753 unsafe { self.insert(label.0) };
754 }
755 fn new_label(self) -> Label<'func> {
757 let insn = unsafe { ffi::MIR_new_label(self.get_raw_ctx()) };
758 unsafe { self.insert(insn) };
759 Label(insn, PhantomData)
760 }
761}
762
763fn build_insn<'func, 'o>(
764 this: impl InsnBuilderBase<'func>,
765 code: mir_sys::MIR_insn_code_t,
766 ops: impl IntoIterator<Item = Operand<'o>>,
767) {
768 let ctx = this.get_raw_ctx();
769 let ops = ops.into_iter().collect::<SmallVec<[Operand; 6]>>();
770 let insn = unsafe {
771 ffi::MIR_new_insn_arr(
772 ctx,
773 code,
774 ops.len(),
775 ops.as_ptr().cast::<ffi::MIR_op_t>().cast_mut(),
776 )
777 };
778 unsafe { this.insert(insn) };
779}