1pub mod generated_code;
5
6use 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
41pub(crate) fn lower(
43 lower_ctx: &mut Lower<MInst>,
44 backend: &S390xBackend,
45 inst: Inst,
46) -> Option<InstOutput> {
47 let mut isle_ctx = IsleContext { lower_ctx, backend };
50 generated_code::constructor_lower(&mut isle_ctx, inst)
51}
52
53pub(crate) fn lower_branch(
55 lower_ctx: &mut Lower<MInst>,
56 backend: &S390xBackend,
57 branch: Inst,
58 targets: &[MachLabel],
59) -> Option<()> {
60 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 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 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 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 MemArg::reg(stack_reg(), MemFlagsData::trusted())
758 }
759
760 #[inline]
761 fn memarg_return_address_offset(&mut self) -> MemArg {
762 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#[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#[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#[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}