Skip to main content

cranelift_codegen/isa/s390x/lower/
isle.rs

1//! ISLE integration glue code for s390x lowering.
2
3// Pull in the ISLE generated code.
4pub mod generated_code;
5
6// Types that the generated ISLE code uses via `use super::*`.
7use crate::ir::ExternalName;
8use crate::isa::s390x::S390xBackend;
9use crate::isa::s390x::abi::REG_SAVE_AREA_SIZE;
10use crate::isa::s390x::inst::{
11    CallInstDest, Cond, Inst as MInst, LaneOrder, MemArg, RegPair, ReturnCallInfo, SImm20,
12    SymbolReloc, UImm12, UImm16Shifted, UImm32Shifted, WritableRegPair, gpr, stack_reg,
13    writable_gpr, zero_reg,
14};
15use crate::machinst::isle::*;
16use crate::machinst::{CallInfo, MachLabel, Reg, TryCallInfo, non_writable_value_regs};
17use crate::{
18    ir::{
19        AtomicRmwOp, BlockCall, Endianness, Inst, InstructionData, KnownSymbol, MemFlagsData,
20        Opcode, TrapCode, Value, ValueList, condcodes::*, immediates::*, types::*,
21    },
22    isa::CallConv,
23    machinst::{
24        ArgPair, CallArgList, CallRetList, InstOutput, MachInst, VCodeConstant, VCodeConstantData,
25    },
26};
27use alloc::boxed::Box;
28use alloc::vec::Vec;
29use core::cell::Cell;
30use regalloc2::PReg;
31
32type BoxCallInfo = Box<CallInfo<CallInstDest>>;
33type BoxReturnCallInfo = Box<ReturnCallInfo<CallInstDest>>;
34type VecMachLabel = Vec<MachLabel>;
35type BoxExternalName = Box<ExternalName>;
36type BoxSymbolReloc = Box<SymbolReloc>;
37type VecMInst = Vec<MInst>;
38type VecMInstBuilder = Cell<Vec<MInst>>;
39type VecArgPair = Vec<ArgPair>;
40
41/// The main entry point for lowering with ISLE.
42pub(crate) fn lower(
43    lower_ctx: &mut Lower<MInst>,
44    backend: &S390xBackend,
45    inst: Inst,
46) -> Option<InstOutput> {
47    // TODO: reuse the ISLE context across lowerings so we can reuse its
48    // internal heap allocations.
49    let mut isle_ctx = IsleContext { lower_ctx, backend };
50    generated_code::constructor_lower(&mut isle_ctx, inst)
51}
52
53/// The main entry point for branch lowering with ISLE.
54pub(crate) fn lower_branch(
55    lower_ctx: &mut Lower<MInst>,
56    backend: &S390xBackend,
57    branch: Inst,
58    targets: &[MachLabel],
59) -> Option<()> {
60    // TODO: reuse the ISLE context across lowerings so we can reuse its
61    // internal heap allocations.
62    let mut isle_ctx = IsleContext { lower_ctx, backend };
63    generated_code::constructor_lower_branch(&mut isle_ctx, branch, targets)
64}
65
66impl generated_code::Context for IsleContext<'_, '_, MInst, S390xBackend> {
67    isle_lower_prelude_methods!();
68
69    #[inline]
70    fn call_inst_dest_direct(&mut self, name: ExternalName) -> CallInstDest {
71        CallInstDest::Direct { name }
72    }
73
74    #[inline]
75    fn call_inst_dest_indirect(&mut self, reg: Reg) -> CallInstDest {
76        CallInstDest::Indirect { reg }
77    }
78
79    // Adjust the stack before performing a (regular) call to a function
80    // using the tail-call ABI.  We need to allocate the part of the callee's
81    // frame holding the incoming argument area.  If necessary for unwinding,
82    // we also create a (temporary) copy of the backchain.
83    fn abi_emit_call_adjust_stack(&mut self, abi: Sig) -> Unit {
84        let sig_data = &self.lower_ctx.sigs()[abi];
85        if sig_data.call_conv() == CallConv::Tail {
86            let arg_space = sig_data.sized_stack_arg_space();
87            if arg_space > 0 {
88                if self.backend.flags.preserve_frame_pointers() {
89                    let tmp = self.lower_ctx.alloc_tmp(I64).only_reg().unwrap();
90                    let src_mem = MemArg::reg(stack_reg(), MemFlagsData::trusted());
91                    let dst_mem = MemArg::reg(stack_reg(), MemFlagsData::trusted());
92                    self.emit(&MInst::Load64 {
93                        rd: tmp,
94                        mem: src_mem,
95                    });
96                    self.emit(&MInst::AllocateArgs { size: arg_space });
97                    self.emit(&MInst::Store64 {
98                        rd: tmp.to_reg(),
99                        mem: dst_mem,
100                    });
101                } else {
102                    self.emit(&MInst::AllocateArgs { size: arg_space });
103                }
104            }
105        }
106    }
107
108    // Adjust the stack before performing a tail call.  The actual stack
109    // adjustment is deferred to the call instruction itself, but we create
110    // a temporary backchain copy in the proper place here, if necessary
111    // for unwinding.
112    fn abi_emit_return_call_adjust_stack(&mut self, abi: Sig) -> Unit {
113        let sig_data = &self.lower_ctx.sigs()[abi];
114        let arg_space = sig_data.sized_stack_arg_space();
115        if arg_space > 0 && self.backend.flags.preserve_frame_pointers() {
116            let tmp = self.lower_ctx.alloc_tmp(I64).only_reg().unwrap();
117            let src_mem = MemArg::InitialSPOffset { off: 0 };
118            let dst_mem = MemArg::InitialSPOffset {
119                off: -(arg_space as i64),
120            };
121            self.emit(&MInst::Load64 {
122                rd: tmp,
123                mem: src_mem,
124            });
125            self.emit(&MInst::Store64 {
126                rd: tmp.to_reg(),
127                mem: dst_mem,
128            });
129        }
130    }
131
132    // Load call arguments into a vector of ValueRegs.  This is the same as
133    // the common-code put_in_regs_vec routine, except that we also handle
134    // vector lane swaps if caller and callee differ in lane order.
135    fn abi_prepare_args(&mut self, abi: Sig, (list, off): ValueSlice) -> ValueRegsVec {
136        let lane_order = LaneOrder::from(self.lower_ctx.sigs()[abi].call_conv());
137        let lane_swap_needed = self.lane_order() != lane_order;
138
139        (off..list.len(&self.lower_ctx.dfg().value_lists))
140            .map(|ix| {
141                let val = list.get(ix, &self.lower_ctx.dfg().value_lists).unwrap();
142                let ty = self.lower_ctx.dfg().value_type(val);
143                let regs = self.put_in_regs(val);
144
145                if lane_swap_needed && ty.is_vector() && ty.lane_count() >= 2 {
146                    let tmp_regs = self.lower_ctx.alloc_tmp(ty);
147                    self.emit(&MInst::VecEltRev {
148                        lane_count: ty.lane_count(),
149                        rd: tmp_regs.only_reg().unwrap(),
150                        rn: regs.only_reg().unwrap(),
151                    });
152                    non_writable_value_regs(tmp_regs)
153                } else {
154                    regs
155                }
156            })
157            .collect()
158    }
159
160    fn gen_call_info(
161        &mut self,
162        sig: Sig,
163        dest: CallInstDest,
164        uses: CallArgList,
165        defs: CallRetList,
166        try_call_info: Option<TryCallInfo>,
167        patchable: bool,
168    ) -> BoxCallInfo {
169        let stack_ret_space = self.lower_ctx.sigs()[sig].sized_stack_ret_space();
170        let stack_arg_space = self.lower_ctx.sigs()[sig].sized_stack_arg_space();
171        let total_space = if self.lower_ctx.sigs()[sig].call_conv() != CallConv::Tail {
172            REG_SAVE_AREA_SIZE + stack_arg_space + stack_ret_space
173        } else {
174            REG_SAVE_AREA_SIZE + stack_ret_space
175        };
176        self.lower_ctx
177            .abi_mut()
178            .accumulate_outgoing_args_size(total_space);
179
180        Box::new(
181            self.lower_ctx
182                .gen_call_info(sig, dest, uses, defs, try_call_info, patchable),
183        )
184    }
185
186    fn gen_return_call_info(
187        &mut self,
188        sig: Sig,
189        dest: CallInstDest,
190        uses: CallArgList,
191    ) -> BoxReturnCallInfo {
192        let callee_pop_size = self.lower_ctx.sigs()[sig].sized_stack_arg_space();
193        self.lower_ctx
194            .abi_mut()
195            .accumulate_tail_args_size(callee_pop_size);
196
197        Box::new(ReturnCallInfo {
198            dest,
199            uses,
200            callee_pop_size,
201        })
202    }
203
204    fn abi_for_elf_tls_get_offset(&mut self) {
205        self.lower_ctx
206            .abi_mut()
207            .accumulate_outgoing_args_size(REG_SAVE_AREA_SIZE);
208    }
209
210    #[inline]
211    fn box_symbol_reloc(&mut self, symbol_reloc: &SymbolReloc) -> BoxSymbolReloc {
212        Box::new(symbol_reloc.clone())
213    }
214
215    #[inline]
216    fn has_mie3(&mut self) -> bool {
217        self.backend.isa_flags.has_mie3()
218    }
219
220    #[inline]
221    fn has_mie4(&mut self) -> bool {
222        self.backend.isa_flags.has_mie4()
223    }
224
225    #[inline]
226    fn has_vxrs_ext2(&mut self) -> bool {
227        self.backend.isa_flags.has_vxrs_ext2()
228    }
229
230    #[inline]
231    fn has_vxrs_ext3(&mut self) -> bool {
232        self.backend.isa_flags.has_vxrs_ext3()
233    }
234
235    #[inline]
236    fn writable_gpr(&mut self, regno: u8) -> WritableReg {
237        writable_gpr(regno)
238    }
239
240    #[inline]
241    fn zero_reg(&mut self) -> Reg {
242        zero_reg()
243    }
244
245    #[inline]
246    fn gpr32_ty(&mut self, ty: Type) -> Option<Type> {
247        match ty {
248            I8 | I16 | I32 => Some(ty),
249            _ => None,
250        }
251    }
252
253    #[inline]
254    fn gpr64_ty(&mut self, ty: Type) -> Option<Type> {
255        match ty {
256            I64 => Some(ty),
257            _ => None,
258        }
259    }
260
261    #[inline]
262    fn vr128_ty(&mut self, ty: Type) -> Option<Type> {
263        match ty {
264            I128 | F128 => Some(ty),
265            _ if ty.is_vector() && ty.bits() == 128 => Some(ty),
266            _ => None,
267        }
268    }
269
270    #[inline]
271    fn uimm32shifted(&mut self, n: u32, shift: u8) -> UImm32Shifted {
272        UImm32Shifted::maybe_with_shift(n, shift).unwrap()
273    }
274
275    #[inline]
276    fn uimm16shifted(&mut self, n: u16, shift: u8) -> UImm16Shifted {
277        UImm16Shifted::maybe_with_shift(n, shift).unwrap()
278    }
279
280    #[inline]
281    fn i64_nonequal(&mut self, val: i64, cmp: i64) -> Option<i64> {
282        if val != cmp { Some(val) } else { None }
283    }
284
285    #[inline]
286    fn u64_pair_split(&mut self, n: u128) -> (u64, u64) {
287        ((n >> 64) as u64, n as u64)
288    }
289
290    #[inline]
291    fn u64_pair_concat(&mut self, hi: u64, lo: u64) -> u128 {
292        (hi as u128) << 64 | (lo as u128)
293    }
294
295    #[inline]
296    fn u32_pair_split(&mut self, n: u64) -> (u32, u32) {
297        ((n >> 32) as u32, n as u32)
298    }
299
300    #[inline]
301    fn u32_pair_concat(&mut self, hi: u32, lo: u32) -> u64 {
302        (hi as u64) << 32 | (lo as u64)
303    }
304
305    #[inline]
306    fn u16_pair_split(&mut self, n: u32) -> (u16, u16) {
307        ((n >> 16) as u16, n as u16)
308    }
309
310    #[inline]
311    fn u16_pair_concat(&mut self, hi: u16, lo: u16) -> u32 {
312        (hi as u32) << 16 | (lo as u32)
313    }
314
315    #[inline]
316    fn u8_pair_split(&mut self, n: u16) -> (u8, u8) {
317        ((n >> 8) as u8, n as u8)
318    }
319
320    #[inline]
321    fn u8_pair_concat(&mut self, hi: u8, lo: u8) -> u16 {
322        (hi as u16) << 8 | (lo as u16)
323    }
324
325    #[inline]
326    fn u64_nonzero_hipart(&mut self, n: u64) -> Option<u64> {
327        let part = n & 0xffff_ffff_0000_0000;
328        if part != 0 { Some(part) } else { None }
329    }
330
331    #[inline]
332    fn u64_nonzero_lopart(&mut self, n: u64) -> Option<u64> {
333        let part = n & 0x0000_0000_ffff_ffff;
334        if part != 0 { Some(part) } else { None }
335    }
336
337    #[inline]
338    fn uimm32shifted_from_u64(&mut self, n: u64) -> Option<UImm32Shifted> {
339        UImm32Shifted::maybe_from_u64(n)
340    }
341
342    #[inline]
343    fn uimm16shifted_from_u64(&mut self, n: u64) -> Option<UImm16Shifted> {
344        UImm16Shifted::maybe_from_u64(n)
345    }
346
347    #[inline]
348    fn lane_order(&mut self) -> LaneOrder {
349        LaneOrder::from(self.lower_ctx.abi().call_conv())
350    }
351
352    #[inline]
353    fn be_lane_idx(&mut self, ty: Type, idx: u8) -> u8 {
354        match self.lane_order() {
355            LaneOrder::LittleEndian => ty.lane_count() as u8 - 1 - idx,
356            LaneOrder::BigEndian => idx,
357        }
358    }
359
360    #[inline]
361    fn be_vec_const(&mut self, ty: Type, n: u128) -> u128 {
362        match self.lane_order() {
363            LaneOrder::LittleEndian => n,
364            LaneOrder::BigEndian if ty.lane_count() == 1 => n,
365            LaneOrder::BigEndian => {
366                let lane_count = ty.lane_count();
367                let lane_bits = ty.lane_bits();
368                let lane_mask = (1u128 << lane_bits) - 1;
369                let mut n_le = n;
370                let mut n_be = 0u128;
371                for _ in 0..lane_count {
372                    n_be = (n_be << lane_bits) | (n_le & lane_mask);
373                    n_le = n_le >> lane_bits;
374                }
375                n_be
376            }
377        }
378    }
379
380    #[inline]
381    fn lane_byte_mask(&mut self, ty: Type, idx: u8) -> u16 {
382        let lane_bytes = (ty.lane_bits() / 8) as u8;
383        let lane_mask = (1u16 << lane_bytes) - 1;
384        lane_mask << (16 - ((idx + 1) * lane_bytes))
385    }
386
387    #[inline]
388    fn shuffle_mask_from_u128(&mut self, idx: u128) -> (u128, u16) {
389        let bytes = match self.lane_order() {
390            LaneOrder::LittleEndian => idx.to_be_bytes().map(|x| {
391                if x < 16 {
392                    15 - x
393                } else if x < 32 {
394                    47 - x
395                } else {
396                    128
397                }
398            }),
399            LaneOrder::BigEndian => idx.to_le_bytes().map(|x| if x < 32 { x } else { 128 }),
400        };
401        let and_mask = bytes.iter().fold(0, |acc, &x| (acc << 1) | (x < 32) as u16);
402        let permute_mask = u128::from_be_bytes(bytes);
403        (permute_mask, and_mask)
404    }
405
406    #[inline]
407    fn u64_from_value(&mut self, val: Value) -> Option<u64> {
408        let inst = self.lower_ctx.dfg().value_def(val).inst()?;
409        let constant = self.lower_ctx.get_constant(inst)?;
410        let ty = self.lower_ctx.output_ty(inst, 0);
411        Some(zero_extend_to_u64(constant, self.ty_bits(ty)))
412    }
413
414    #[inline]
415    fn u64_from_inverted_value(&mut self, val: Value) -> Option<u64> {
416        let inst = self.lower_ctx.dfg().value_def(val).inst()?;
417        let constant = self.lower_ctx.get_constant(inst)?;
418        let ty = self.lower_ctx.output_ty(inst, 0);
419        Some(zero_extend_to_u64(!constant, self.ty_bits(ty)))
420    }
421
422    #[inline]
423    fn u32_from_value(&mut self, val: Value) -> Option<u32> {
424        let constant = self.u64_from_value(val)?;
425        let imm = u32::try_from(constant).ok()?;
426        Some(imm)
427    }
428
429    #[inline]
430    fn u8_from_value(&mut self, val: Value) -> Option<u8> {
431        let constant = self.u64_from_value(val)?;
432        let imm = u8::try_from(constant).ok()?;
433        Some(imm)
434    }
435
436    #[inline]
437    fn u64_from_signed_value(&mut self, val: Value) -> Option<u64> {
438        let inst = self.lower_ctx.dfg().value_def(val).inst()?;
439        let constant = self.lower_ctx.get_constant(inst)?;
440        let ty = self.lower_ctx.output_ty(inst, 0);
441        Some(sign_extend_to_u64(constant, self.ty_bits(ty)))
442    }
443
444    #[inline]
445    fn i64_from_value(&mut self, val: Value) -> Option<i64> {
446        let constant = self.u64_from_signed_value(val)? as i64;
447        Some(constant)
448    }
449
450    #[inline]
451    fn i32_from_value(&mut self, val: Value) -> Option<i32> {
452        let constant = self.u64_from_signed_value(val)? as i64;
453        let imm = i32::try_from(constant).ok()?;
454        Some(imm)
455    }
456
457    #[inline]
458    fn i16_from_value(&mut self, val: Value) -> Option<i16> {
459        let constant = self.u64_from_signed_value(val)? as i64;
460        let imm = i16::try_from(constant).ok()?;
461        Some(imm)
462    }
463
464    #[inline]
465    fn i16_from_swapped_value(&mut self, val: Value) -> Option<i16> {
466        let constant = self.u64_from_signed_value(val)? as i64;
467        let imm = i16::try_from(constant).ok()?;
468        Some(imm.swap_bytes())
469    }
470
471    #[inline]
472    fn i64_from_negated_value(&mut self, val: Value) -> Option<i64> {
473        let constant = self.u64_from_signed_value(val)? as i64;
474        let imm = constant.wrapping_neg();
475        Some(imm)
476    }
477
478    #[inline]
479    fn i32_from_negated_value(&mut self, val: Value) -> Option<i32> {
480        let constant = self.u64_from_signed_value(val)? as i64;
481        let imm = i32::try_from(constant.wrapping_neg()).ok()?;
482        Some(imm)
483    }
484
485    #[inline]
486    fn i16_from_negated_value(&mut self, val: Value) -> Option<i16> {
487        let constant = self.u64_from_signed_value(val)? as i64;
488        let imm = i16::try_from(constant.wrapping_neg()).ok()?;
489        Some(imm)
490    }
491
492    #[inline]
493    fn uimm16shifted_from_value(&mut self, val: Value) -> Option<UImm16Shifted> {
494        let constant = self.u64_from_value(val)?;
495        UImm16Shifted::maybe_from_u64(constant)
496    }
497
498    #[inline]
499    fn simm20_from_value(&mut self, val: Value) -> Option<SImm20> {
500        let constant = self.u64_from_signed_value(val)? as i64;
501        SImm20::maybe_from_i64(constant)
502    }
503
504    #[inline]
505    fn uimm32shifted_from_value(&mut self, val: Value) -> Option<UImm32Shifted> {
506        let constant = self.u64_from_value(val)?;
507        UImm32Shifted::maybe_from_u64(constant)
508    }
509
510    #[inline]
511    fn uimm16shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm16Shifted> {
512        let constant = self.u64_from_inverted_value(val)?;
513        let imm = UImm16Shifted::maybe_from_u64(constant)?;
514        Some(imm.negate_bits())
515    }
516
517    #[inline]
518    fn uimm32shifted_from_inverted_value(&mut self, val: Value) -> Option<UImm32Shifted> {
519        let constant = self.u64_from_inverted_value(val)?;
520        let imm = UImm32Shifted::maybe_from_u64(constant)?;
521        Some(imm.negate_bits())
522    }
523
524    #[inline]
525    fn len_minus_one(&mut self, len: u64) -> Option<u8> {
526        if len > 0 && len <= 256 {
527            Some((len - 1) as u8)
528        } else {
529            None
530        }
531    }
532
533    #[inline]
534    fn mask_amt_imm(&mut self, ty: Type, amt: i64) -> u8 {
535        let mask = ty.lane_bits() - 1;
536        (amt as u8) & (mask as u8)
537    }
538
539    #[inline]
540    fn mask_as_cond(&mut self, mask: u8) -> Cond {
541        Cond::from_mask(mask)
542    }
543
544    #[inline]
545    fn intcc_as_cond(&mut self, cc: &IntCC) -> Cond {
546        Cond::from_intcc(*cc)
547    }
548
549    #[inline]
550    fn floatcc_as_cond(&mut self, cc: &FloatCC) -> Cond {
551        Cond::from_floatcc(*cc)
552    }
553
554    #[inline]
555    fn invert_cond(&mut self, cond: &Cond) -> Cond {
556        Cond::invert(*cond)
557    }
558
559    #[inline]
560    fn signed(&mut self, cc: &IntCC) -> Option<()> {
561        if condcode_is_signed(*cc) {
562            Some(())
563        } else {
564            None
565        }
566    }
567
568    #[inline]
569    fn unsigned(&mut self, cc: &IntCC) -> Option<()> {
570        if !condcode_is_signed(*cc) {
571            Some(())
572        } else {
573            None
574        }
575    }
576
577    #[inline]
578    fn zero_offset(&mut self) -> Offset32 {
579        Offset32::new(0)
580    }
581
582    #[inline]
583    fn i64_from_offset(&mut self, off: Offset32) -> i64 {
584        i64::from(off)
585    }
586
587    #[inline]
588    fn fcvt_to_uint_ub32(&mut self, size: u8) -> u64 {
589        (2.0_f32).powi(size.into()).to_bits() as u64
590    }
591
592    #[inline]
593    fn fcvt_to_uint_lb32(&mut self) -> u64 {
594        (-1.0_f32).to_bits() as u64
595    }
596
597    #[inline]
598    fn fcvt_to_uint_ub64(&mut self, size: u8) -> u64 {
599        (2.0_f64).powi(size.into()).to_bits()
600    }
601
602    #[inline]
603    fn fcvt_to_uint_lb64(&mut self) -> u64 {
604        (-1.0_f64).to_bits()
605    }
606
607    #[inline]
608    fn fcvt_to_uint_ub128(&mut self, size: u8) -> u128 {
609        Ieee128::pow2(size).bits()
610    }
611
612    #[inline]
613    fn fcvt_to_uint_lb128(&mut self) -> u128 {
614        (-Ieee128::pow2(0)).bits()
615    }
616
617    #[inline]
618    fn fcvt_to_sint_ub32(&mut self, size: u8) -> u64 {
619        (2.0_f32).powi((size - 1).into()).to_bits() as u64
620    }
621
622    #[inline]
623    fn fcvt_to_sint_lb32(&mut self, size: u8) -> u64 {
624        let lb = (-2.0_f32).powi((size - 1).into());
625        core::cmp::max(lb.to_bits() + 1, (lb - 1.0).to_bits()) as u64
626    }
627
628    #[inline]
629    fn fcvt_to_sint_ub64(&mut self, size: u8) -> u64 {
630        (2.0_f64).powi((size - 1).into()).to_bits()
631    }
632
633    #[inline]
634    fn fcvt_to_sint_lb64(&mut self, size: u8) -> u64 {
635        let lb = (-2.0_f64).powi((size - 1).into());
636        core::cmp::max(lb.to_bits() + 1, (lb - 1.0).to_bits())
637    }
638
639    #[inline]
640    fn fcvt_to_sint_ub128(&mut self, size: u8) -> u128 {
641        Ieee128::pow2(size - 1).bits()
642    }
643
644    #[inline]
645    fn fcvt_to_sint_lb128(&mut self, size: u8) -> u128 {
646        Ieee128::fcvt_to_sint_negative_overflow(size).bits()
647    }
648
649    #[inline]
650    fn littleendian(&mut self, flags: MemFlagsData) -> Option<()> {
651        let endianness = flags.endianness(Endianness::Big);
652        if endianness == Endianness::Little {
653            Some(())
654        } else {
655            None
656        }
657    }
658
659    #[inline]
660    fn bigendian(&mut self, flags: MemFlagsData) -> Option<()> {
661        let endianness = flags.endianness(Endianness::Big);
662        if endianness == Endianness::Big {
663            Some(())
664        } else {
665            None
666        }
667    }
668
669    #[inline]
670    fn memflags_trusted(&mut self) -> MemFlagsData {
671        MemFlagsData::trusted()
672    }
673
674    #[inline]
675    fn memarg_imm_from_offset(&mut self, imm: Offset32) -> Option<SImm20> {
676        SImm20::maybe_from_i64(i64::from(imm))
677    }
678
679    #[inline]
680    fn memarg_imm_from_offset_plus_bias(&mut self, imm: Offset32, bias: u8) -> Option<SImm20> {
681        let final_offset = i64::from(imm) + bias as i64;
682        SImm20::maybe_from_i64(final_offset)
683    }
684
685    #[inline]
686    fn memarg_reg_plus_reg(&mut self, x: Reg, y: Reg, bias: u8, flags: MemFlagsData) -> MemArg {
687        MemArg::BXD12 {
688            base: x,
689            index: y,
690            disp: UImm12::maybe_from_u64(bias as u64).unwrap(),
691            flags,
692        }
693    }
694
695    #[inline]
696    fn memarg_reg_plus_reg_plus_off(
697        &mut self,
698        x: Reg,
699        y: Reg,
700        offset: &SImm20,
701        flags: MemFlagsData,
702    ) -> MemArg {
703        if let Some(imm) = UImm12::maybe_from_simm20(*offset) {
704            MemArg::BXD12 {
705                base: x,
706                index: y,
707                disp: imm,
708                flags,
709            }
710        } else {
711            MemArg::BXD20 {
712                base: x,
713                index: y,
714                disp: *offset,
715                flags,
716            }
717        }
718    }
719
720    #[inline]
721    fn memarg_reg_plus_off(&mut self, reg: Reg, off: i64, bias: u8, flags: MemFlagsData) -> MemArg {
722        MemArg::reg_plus_off(reg, off + (bias as i64), flags)
723    }
724
725    #[inline]
726    fn memarg_symbol(&mut self, name: ExternalName, offset: i32, flags: MemFlagsData) -> MemArg {
727        MemArg::Symbol {
728            name: Box::new(name),
729            offset,
730            flags,
731        }
732    }
733
734    #[inline]
735    fn memarg_got(&mut self) -> MemArg {
736        MemArg::Symbol {
737            name: Box::new(ExternalName::KnownSymbol(KnownSymbol::ElfGlobalOffsetTable)),
738            offset: 0,
739            flags: MemFlagsData::trusted(),
740        }
741    }
742
743    #[inline]
744    fn memarg_const(&mut self, constant: VCodeConstant) -> MemArg {
745        MemArg::Constant { constant }
746    }
747
748    #[inline]
749    fn memarg_symbol_offset_sum(&mut self, off1: i64, off2: i64) -> Option<i32> {
750        let off = i32::try_from(off1 + off2).ok()?;
751        if off & 1 == 0 { Some(off) } else { None }
752    }
753
754    #[inline]
755    fn memarg_frame_pointer_offset(&mut self) -> MemArg {
756        // The frame pointer (back chain) is stored directly at SP.
757        MemArg::reg(stack_reg(), MemFlagsData::trusted())
758    }
759
760    #[inline]
761    fn memarg_return_address_offset(&mut self) -> MemArg {
762        // The return address is stored 14 pointer-sized slots above the initial SP.
763        MemArg::InitialSPOffset { off: 14 * 8 }
764    }
765
766    #[inline]
767    fn inst_builder_new(&mut self) -> VecMInstBuilder {
768        Cell::new(Vec::<MInst>::new())
769    }
770
771    #[inline]
772    fn inst_builder_push(&mut self, builder: &VecMInstBuilder, inst: &MInst) -> Unit {
773        let mut vec = builder.take();
774        vec.push(inst.clone());
775        builder.set(vec);
776    }
777
778    #[inline]
779    fn inst_builder_finish(&mut self, builder: &VecMInstBuilder) -> Vec<MInst> {
780        builder.take()
781    }
782
783    #[inline]
784    fn real_reg(&mut self, reg: WritableReg) -> Option<WritableReg> {
785        if reg.to_reg().is_real() {
786            Some(reg)
787        } else {
788            None
789        }
790    }
791
792    #[inline]
793    fn same_reg(&mut self, dst: WritableReg, src: Reg) -> Option<Reg> {
794        if dst.to_reg() == src { Some(src) } else { None }
795    }
796
797    #[inline]
798    fn sinkable_inst(&mut self, val: Value) -> Option<Inst> {
799        self.is_sinkable_inst(val)
800    }
801
802    #[inline]
803    fn emit(&mut self, inst: &MInst) -> Unit {
804        self.lower_ctx.emit(inst.clone());
805    }
806
807    #[inline]
808    fn preg_stack(&mut self) -> PReg {
809        stack_reg().to_real_reg().unwrap().into()
810    }
811
812    #[inline]
813    fn preg_gpr_0(&mut self) -> PReg {
814        gpr(0).to_real_reg().unwrap().into()
815    }
816
817    #[inline]
818    fn writable_regpair(&mut self, hi: WritableReg, lo: WritableReg) -> WritableRegPair {
819        WritableRegPair { hi, lo }
820    }
821
822    #[inline]
823    fn writable_regpair_hi(&mut self, w: WritableRegPair) -> WritableReg {
824        w.hi
825    }
826
827    #[inline]
828    fn writable_regpair_lo(&mut self, w: WritableRegPair) -> WritableReg {
829        w.lo
830    }
831
832    #[inline]
833    fn regpair(&mut self, hi: Reg, lo: Reg) -> RegPair {
834        RegPair { hi, lo }
835    }
836
837    #[inline]
838    fn regpair_hi(&mut self, w: RegPair) -> Reg {
839        w.hi
840    }
841
842    #[inline]
843    fn regpair_lo(&mut self, w: RegPair) -> Reg {
844        w.lo
845    }
846}
847
848/// Zero-extend the low `from_bits` bits of `value` to a full u64.
849#[inline]
850fn zero_extend_to_u64(value: u64, from_bits: u8) -> u64 {
851    assert!(from_bits <= 64);
852    if from_bits >= 64 {
853        value
854    } else {
855        value & ((1u64 << from_bits) - 1)
856    }
857}
858
859/// Sign-extend the low `from_bits` bits of `value` to a full u64.
860#[inline]
861fn sign_extend_to_u64(value: u64, from_bits: u8) -> u64 {
862    assert!(from_bits <= 64);
863    if from_bits >= 64 {
864        value
865    } else {
866        (((value << (64 - from_bits)) as i64) >> (64 - from_bits)) as u64
867    }
868}
869
870/// Determines whether this condcode interprets inputs as signed or
871/// unsigned.  See the documentation for the `icmp` instruction in
872/// cranelift-codegen/meta/src/shared/instructions.rs for further insights
873/// into this.
874#[inline]
875fn condcode_is_signed(cc: IntCC) -> bool {
876    match cc {
877        IntCC::Equal => false,
878        IntCC::NotEqual => false,
879        IntCC::SignedGreaterThanOrEqual => true,
880        IntCC::SignedGreaterThan => true,
881        IntCC::SignedLessThanOrEqual => true,
882        IntCC::SignedLessThan => true,
883        IntCC::UnsignedGreaterThanOrEqual => false,
884        IntCC::UnsignedGreaterThan => false,
885        IntCC::UnsignedLessThanOrEqual => false,
886        IntCC::UnsignedLessThan => false,
887    }
888}